124f398e7SPavel Balaev /*- 224f398e7SPavel Balaev * Copyright (c) 2021 3mdeb Embedded Systems Consulting <contact@3mdeb.com> 324f398e7SPavel Balaev * 424f398e7SPavel Balaev * Redistribution and use in source and binary forms, with or without 524f398e7SPavel Balaev * modification, are permitted provided that the following conditions 624f398e7SPavel Balaev * are met: 724f398e7SPavel Balaev * 1. Redistributions of source code must retain the above copyright 824f398e7SPavel Balaev * notice, this list of conditions and the following disclaimer. 924f398e7SPavel Balaev * 2. Redistributions in binary form must reproduce the above copyright 1024f398e7SPavel Balaev * notice, this list of conditions and the following disclaimer in the 1124f398e7SPavel Balaev * documentation and/or other materials provided with the distribution. 1224f398e7SPavel Balaev * 1324f398e7SPavel Balaev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1424f398e7SPavel Balaev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1524f398e7SPavel Balaev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1624f398e7SPavel Balaev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1724f398e7SPavel Balaev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1824f398e7SPavel Balaev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1924f398e7SPavel Balaev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2024f398e7SPavel Balaev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2124f398e7SPavel Balaev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2224f398e7SPavel Balaev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2324f398e7SPavel Balaev * SUCH DAMAGE. 2424f398e7SPavel Balaev */ 2524f398e7SPavel Balaev 2624f398e7SPavel Balaev #include <sys/types.h> 2724f398e7SPavel Balaev #include <sys/efi.h> 2824f398e7SPavel Balaev #include <sys/efiio.h> 2924f398e7SPavel Balaev #include <sys/param.h> 3024f398e7SPavel Balaev #include <sys/stat.h> 3124f398e7SPavel Balaev #include <fcntl.h> 3224f398e7SPavel Balaev #include <getopt.h> 3324f398e7SPavel Balaev #include <stdbool.h> 3424f398e7SPavel Balaev #include <stdio.h> 3524f398e7SPavel Balaev #include <stdlib.h> 3624f398e7SPavel Balaev #include <string.h> 3724f398e7SPavel Balaev #include <sysexits.h> 3824f398e7SPavel Balaev #include <unistd.h> 3924f398e7SPavel Balaev #include <uuid.h> 4024f398e7SPavel Balaev #include <libxo/xo.h> 4124f398e7SPavel Balaev 4224f398e7SPavel Balaev #define TABLE_MAX_LEN 30 4324f398e7SPavel Balaev #define EFITABLE_XO_VERSION "1" 4424f398e7SPavel Balaev 4524f398e7SPavel Balaev static void efi_table_print_esrt(const void *data); 4624f398e7SPavel Balaev static void efi_table_print_prop(const void *data); 4772e1ea2fSAlfonso Gregory static void usage(void) __dead2; 4824f398e7SPavel Balaev 4924f398e7SPavel Balaev struct efi_table_op { 5024f398e7SPavel Balaev char name[TABLE_MAX_LEN]; 5124f398e7SPavel Balaev void (*parse) (const void *); 5224f398e7SPavel Balaev struct uuid uuid; 5324f398e7SPavel Balaev }; 5424f398e7SPavel Balaev 5524f398e7SPavel Balaev static const struct efi_table_op efi_table_ops[] = { 5624f398e7SPavel Balaev { .name = "esrt", .parse = efi_table_print_esrt, 5724f398e7SPavel Balaev .uuid = EFI_TABLE_ESRT }, 5824f398e7SPavel Balaev { .name = "prop", .parse = efi_table_print_prop, 5924f398e7SPavel Balaev .uuid = EFI_PROPERTIES_TABLE } 6024f398e7SPavel Balaev }; 6124f398e7SPavel Balaev 6224f398e7SPavel Balaev int 6324f398e7SPavel Balaev main(int argc, char **argv) 6424f398e7SPavel Balaev { 6524f398e7SPavel Balaev struct efi_get_table_ioc table = { 6624f398e7SPavel Balaev .buf = NULL, 6724f398e7SPavel Balaev .buf_len = 0, 6824f398e7SPavel Balaev .table_len = 0 6924f398e7SPavel Balaev }; 7024f398e7SPavel Balaev int efi_fd, ch, rc = 1, efi_idx = -1; 7124f398e7SPavel Balaev bool got_table = false; 7224f398e7SPavel Balaev bool table_set = false; 7324f398e7SPavel Balaev bool uuid_set = false; 7424f398e7SPavel Balaev struct option longopts[] = { 7524f398e7SPavel Balaev { "uuid", required_argument, NULL, 'u' }, 7624f398e7SPavel Balaev { "table", required_argument, NULL, 't' }, 7724f398e7SPavel Balaev { NULL, 0, NULL, 0 } 7824f398e7SPavel Balaev }; 7924f398e7SPavel Balaev 8024f398e7SPavel Balaev argc = xo_parse_args(argc, argv); 8124f398e7SPavel Balaev if (argc < 0) 8224f398e7SPavel Balaev exit(EXIT_FAILURE); 8324f398e7SPavel Balaev 8424f398e7SPavel Balaev while ((ch = getopt_long(argc, argv, "u:t:", longopts, NULL)) != -1) { 8524f398e7SPavel Balaev switch (ch) { 8624f398e7SPavel Balaev case 'u': 8724f398e7SPavel Balaev { 8824f398e7SPavel Balaev char *uuid_str = optarg; 8924f398e7SPavel Balaev struct uuid uuid; 9024f398e7SPavel Balaev uint32_t status; 9124f398e7SPavel Balaev 9224f398e7SPavel Balaev uuid_set = 1; 9324f398e7SPavel Balaev 9424f398e7SPavel Balaev uuid_from_string(uuid_str, &uuid, &status); 9524f398e7SPavel Balaev if (status != uuid_s_ok) 9624f398e7SPavel Balaev xo_errx(EX_DATAERR, "invalid UUID"); 9724f398e7SPavel Balaev 9824f398e7SPavel Balaev for (size_t n = 0; n < nitems(efi_table_ops); n++) { 9924f398e7SPavel Balaev if (!memcmp(&uuid, &efi_table_ops[n].uuid, 10024f398e7SPavel Balaev sizeof(uuid))) { 10124f398e7SPavel Balaev efi_idx = n; 10224f398e7SPavel Balaev got_table = true; 10324f398e7SPavel Balaev break; 10424f398e7SPavel Balaev } 10524f398e7SPavel Balaev } 10624f398e7SPavel Balaev break; 10724f398e7SPavel Balaev } 10824f398e7SPavel Balaev case 't': 10924f398e7SPavel Balaev { 11024f398e7SPavel Balaev char *table_name = optarg; 11124f398e7SPavel Balaev 11224f398e7SPavel Balaev table_set = true; 11324f398e7SPavel Balaev 11424f398e7SPavel Balaev for (size_t n = 0; n < nitems(efi_table_ops); n++) { 11524f398e7SPavel Balaev if (!strcmp(table_name, 11624f398e7SPavel Balaev efi_table_ops[n].name)) { 11724f398e7SPavel Balaev efi_idx = n; 11824f398e7SPavel Balaev got_table = true; 11924f398e7SPavel Balaev break; 12024f398e7SPavel Balaev } 12124f398e7SPavel Balaev } 12224f398e7SPavel Balaev 12324f398e7SPavel Balaev if (!got_table) 12424f398e7SPavel Balaev xo_errx(EX_DATAERR, "unsupported efi table"); 12524f398e7SPavel Balaev 12624f398e7SPavel Balaev break; 12724f398e7SPavel Balaev } 12824f398e7SPavel Balaev default: 12924f398e7SPavel Balaev usage(); 13024f398e7SPavel Balaev } 13124f398e7SPavel Balaev } 13224f398e7SPavel Balaev 13324f398e7SPavel Balaev if (!table_set && !uuid_set) 13424f398e7SPavel Balaev xo_errx(EX_USAGE, "table is not set"); 13524f398e7SPavel Balaev 13624f398e7SPavel Balaev if (!got_table) 13724f398e7SPavel Balaev xo_errx(EX_DATAERR, "unsupported table"); 13824f398e7SPavel Balaev 13924f398e7SPavel Balaev efi_fd = open("/dev/efi", O_RDWR); 14024f398e7SPavel Balaev if (efi_fd < 0) 14124f398e7SPavel Balaev xo_err(EX_OSFILE, "/dev/efi"); 14224f398e7SPavel Balaev 14324f398e7SPavel Balaev table.uuid = efi_table_ops[efi_idx].uuid; 14424f398e7SPavel Balaev if (ioctl(efi_fd, EFIIOC_GET_TABLE, &table) == -1) 145b14cd3a8SJohn Baldwin xo_err(EX_OSERR, "EFIIOC_GET_TABLE (len == 0)"); 14624f398e7SPavel Balaev 14724f398e7SPavel Balaev table.buf = malloc(table.table_len); 14824f398e7SPavel Balaev table.buf_len = table.table_len; 14924f398e7SPavel Balaev 15024f398e7SPavel Balaev if (ioctl(efi_fd, EFIIOC_GET_TABLE, &table) == -1) 151b14cd3a8SJohn Baldwin xo_err(EX_OSERR, "EFIIOC_GET_TABLE"); 15224f398e7SPavel Balaev 15324f398e7SPavel Balaev efi_table_ops[efi_idx].parse(table.buf); 15424f398e7SPavel Balaev close(efi_fd); 15524f398e7SPavel Balaev 15624f398e7SPavel Balaev return (rc); 15724f398e7SPavel Balaev } 15824f398e7SPavel Balaev 15924f398e7SPavel Balaev static void 16024f398e7SPavel Balaev efi_table_print_esrt(const void *data) 16124f398e7SPavel Balaev { 16224f398e7SPavel Balaev const struct efi_esrt_entry_v1 *entries_v1; 16324f398e7SPavel Balaev const struct efi_esrt_table *esrt; 16424f398e7SPavel Balaev 16524f398e7SPavel Balaev esrt = (const struct efi_esrt_table *)data; 16624f398e7SPavel Balaev 16724f398e7SPavel Balaev xo_set_version(EFITABLE_XO_VERSION); 16824f398e7SPavel Balaev xo_open_container("esrt"); 16924f398e7SPavel Balaev xo_emit("{Lwc:FwResourceCount}{:fw_resource_count/%u}\n", 17024f398e7SPavel Balaev esrt->fw_resource_count); 17124f398e7SPavel Balaev xo_emit("{Lwc:FwResourceCountMax}{:fw_resource_count_max/%u}\n", 17224f398e7SPavel Balaev esrt->fw_resource_count_max); 17324f398e7SPavel Balaev xo_emit("{Lwc:FwResourceVersion}{:fw_resource_version/%u}\n", 17424f398e7SPavel Balaev esrt->fw_resource_version); 17524f398e7SPavel Balaev xo_open_list("entries"); 17624f398e7SPavel Balaev xo_emit("\nEntries:\n"); 17724f398e7SPavel Balaev 17824f398e7SPavel Balaev entries_v1 = (const void *) esrt->entries; 17924f398e7SPavel Balaev for (uint32_t i = 0; i < esrt->fw_resource_count; i++) { 18024f398e7SPavel Balaev const struct efi_esrt_entry_v1 *e = &entries_v1[i]; 18124f398e7SPavel Balaev uint32_t status; 18224f398e7SPavel Balaev char *uuid; 18324f398e7SPavel Balaev 18424f398e7SPavel Balaev uuid_to_string(&e->fw_class, &uuid, &status); 18524f398e7SPavel Balaev if (status != uuid_s_ok) { 18624f398e7SPavel Balaev xo_errx(EX_DATAERR, "uuid_to_string error"); 18724f398e7SPavel Balaev } 18824f398e7SPavel Balaev 18924f398e7SPavel Balaev xo_open_instance("entries"); 19024f398e7SPavel Balaev xo_emit("\n"); 19124f398e7SPavel Balaev xo_emit("{P: }{Lwc:FwClass}{:fw_class/%s}\n", uuid); 19224f398e7SPavel Balaev xo_emit("{P: }{Lwc:FwType}{:fw_type/%u}\n", e->fw_type); 19324f398e7SPavel Balaev xo_emit("{P: }{Lwc:FwVersion}{:fw_version/%u}\n", 19424f398e7SPavel Balaev e->fw_version); 19524f398e7SPavel Balaev xo_emit("{P: }{Lwc:LowestSupportedFwVersion}" 19624f398e7SPavel Balaev "{:lowest_supported_fw_version/%u}\n", 19724f398e7SPavel Balaev e->lowest_supported_fw_version); 19824f398e7SPavel Balaev xo_emit("{P: }{Lwc:CapsuleFlags}{:capsule_flags/%#x}\n", 19924f398e7SPavel Balaev e->capsule_flags); 20024f398e7SPavel Balaev xo_emit("{P: }{Lwc:LastAttemptVersion" 20124f398e7SPavel Balaev "}{:last_attempt_version/%u}\n", e->last_attempt_version); 20224f398e7SPavel Balaev xo_emit("{P: }{Lwc:LastAttemptStatus" 20324f398e7SPavel Balaev "}{:last_attempt_status/%u}\n", e->last_attempt_status); 20424f398e7SPavel Balaev 20524f398e7SPavel Balaev xo_close_instance("entries"); 20624f398e7SPavel Balaev } 20724f398e7SPavel Balaev 20824f398e7SPavel Balaev xo_close_list("entries"); 20924f398e7SPavel Balaev xo_close_container("esrt"); 210*1caa5d08SYan-Hao Wang if (xo_finish() < 0) 211*1caa5d08SYan-Hao Wang xo_err(EX_IOERR, "stdout"); 21224f398e7SPavel Balaev } 21324f398e7SPavel Balaev 21424f398e7SPavel Balaev static void 21524f398e7SPavel Balaev efi_table_print_prop(const void *data) 21624f398e7SPavel Balaev { 21724f398e7SPavel Balaev const struct efi_prop_table *prop; 21824f398e7SPavel Balaev 21924f398e7SPavel Balaev prop = (const struct efi_prop_table *)data; 22024f398e7SPavel Balaev 22124f398e7SPavel Balaev xo_set_version(EFITABLE_XO_VERSION); 22224f398e7SPavel Balaev xo_open_container("prop"); 22324f398e7SPavel Balaev xo_emit("{Lwc:Version}{:version/%#x}\n", prop->version); 22424f398e7SPavel Balaev xo_emit("{Lwc:Length}{:length/%u}\n", prop->length); 22524f398e7SPavel Balaev xo_emit("{Lwc:MemoryProtectionAttribute}" 22624f398e7SPavel Balaev "{:memory_protection_attribute/%#lx}\n", 22724f398e7SPavel Balaev prop->memory_protection_attribute); 22824f398e7SPavel Balaev xo_close_container("prop"); 229*1caa5d08SYan-Hao Wang if (xo_finish() < 0) 230*1caa5d08SYan-Hao Wang xo_err(EX_IOERR, "stdout"); 23124f398e7SPavel Balaev } 23224f398e7SPavel Balaev 23324f398e7SPavel Balaev static void usage(void) 23424f398e7SPavel Balaev { 23524f398e7SPavel Balaev xo_error("usage: efitable [-d uuid | -t name] [--libxo]\n"); 23624f398e7SPavel Balaev exit(EX_USAGE); 23724f398e7SPavel Balaev } 238