1*24f398e7SPavel Balaev /*- 2*24f398e7SPavel Balaev * Copyright (c) 2021 3mdeb Embedded Systems Consulting <contact@3mdeb.com> 3*24f398e7SPavel Balaev * 4*24f398e7SPavel Balaev * Redistribution and use in source and binary forms, with or without 5*24f398e7SPavel Balaev * modification, are permitted provided that the following conditions 6*24f398e7SPavel Balaev * are met: 7*24f398e7SPavel Balaev * 1. Redistributions of source code must retain the above copyright 8*24f398e7SPavel Balaev * notice, this list of conditions and the following disclaimer. 9*24f398e7SPavel Balaev * 2. Redistributions in binary form must reproduce the above copyright 10*24f398e7SPavel Balaev * notice, this list of conditions and the following disclaimer in the 11*24f398e7SPavel Balaev * documentation and/or other materials provided with the distribution. 12*24f398e7SPavel Balaev * 13*24f398e7SPavel Balaev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*24f398e7SPavel Balaev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*24f398e7SPavel Balaev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*24f398e7SPavel Balaev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*24f398e7SPavel Balaev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*24f398e7SPavel Balaev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*24f398e7SPavel Balaev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*24f398e7SPavel Balaev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*24f398e7SPavel Balaev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*24f398e7SPavel Balaev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*24f398e7SPavel Balaev * SUCH DAMAGE. 24*24f398e7SPavel Balaev */ 25*24f398e7SPavel Balaev 26*24f398e7SPavel Balaev #include <sys/cdefs.h> 27*24f398e7SPavel Balaev __FBSDID("$FreeBSD$"); 28*24f398e7SPavel Balaev 29*24f398e7SPavel Balaev #include <sys/types.h> 30*24f398e7SPavel Balaev #include <sys/efi.h> 31*24f398e7SPavel Balaev #include <sys/efiio.h> 32*24f398e7SPavel Balaev #include <sys/param.h> 33*24f398e7SPavel Balaev #include <sys/stat.h> 34*24f398e7SPavel Balaev #include <err.h> 35*24f398e7SPavel Balaev #include <fcntl.h> 36*24f398e7SPavel Balaev #include <getopt.h> 37*24f398e7SPavel Balaev #include <stdbool.h> 38*24f398e7SPavel Balaev #include <stdio.h> 39*24f398e7SPavel Balaev #include <stdlib.h> 40*24f398e7SPavel Balaev #include <string.h> 41*24f398e7SPavel Balaev #include <sysexits.h> 42*24f398e7SPavel Balaev #include <unistd.h> 43*24f398e7SPavel Balaev #include <uuid.h> 44*24f398e7SPavel Balaev #include <libxo/xo.h> 45*24f398e7SPavel Balaev 46*24f398e7SPavel Balaev #define TABLE_MAX_LEN 30 47*24f398e7SPavel Balaev #define EFITABLE_XO_VERSION "1" 48*24f398e7SPavel Balaev 49*24f398e7SPavel Balaev static void efi_table_print_esrt(const void *data); 50*24f398e7SPavel Balaev static void efi_table_print_prop(const void *data); 51*24f398e7SPavel Balaev static void usage(void); 52*24f398e7SPavel Balaev 53*24f398e7SPavel Balaev struct efi_table_op { 54*24f398e7SPavel Balaev char name[TABLE_MAX_LEN]; 55*24f398e7SPavel Balaev void (*parse) (const void *); 56*24f398e7SPavel Balaev struct uuid uuid; 57*24f398e7SPavel Balaev }; 58*24f398e7SPavel Balaev 59*24f398e7SPavel Balaev static const struct efi_table_op efi_table_ops[] = { 60*24f398e7SPavel Balaev { .name = "esrt", .parse = efi_table_print_esrt, 61*24f398e7SPavel Balaev .uuid = EFI_TABLE_ESRT }, 62*24f398e7SPavel Balaev { .name = "prop", .parse = efi_table_print_prop, 63*24f398e7SPavel Balaev .uuid = EFI_PROPERTIES_TABLE } 64*24f398e7SPavel Balaev }; 65*24f398e7SPavel Balaev 66*24f398e7SPavel Balaev int 67*24f398e7SPavel Balaev main(int argc, char **argv) 68*24f398e7SPavel Balaev { 69*24f398e7SPavel Balaev struct efi_get_table_ioc table = { 70*24f398e7SPavel Balaev .buf = NULL, 71*24f398e7SPavel Balaev .buf_len = 0, 72*24f398e7SPavel Balaev .table_len = 0 73*24f398e7SPavel Balaev }; 74*24f398e7SPavel Balaev int efi_fd, ch, rc = 1, efi_idx = -1; 75*24f398e7SPavel Balaev bool got_table = false; 76*24f398e7SPavel Balaev bool table_set = false; 77*24f398e7SPavel Balaev bool uuid_set = false; 78*24f398e7SPavel Balaev struct option longopts[] = { 79*24f398e7SPavel Balaev { "uuid", required_argument, NULL, 'u' }, 80*24f398e7SPavel Balaev { "table", required_argument, NULL, 't' }, 81*24f398e7SPavel Balaev { NULL, 0, NULL, 0 } 82*24f398e7SPavel Balaev }; 83*24f398e7SPavel Balaev 84*24f398e7SPavel Balaev argc = xo_parse_args(argc, argv); 85*24f398e7SPavel Balaev if (argc < 0) 86*24f398e7SPavel Balaev exit(EXIT_FAILURE); 87*24f398e7SPavel Balaev 88*24f398e7SPavel Balaev while ((ch = getopt_long(argc, argv, "u:t:", longopts, NULL)) != -1) { 89*24f398e7SPavel Balaev switch (ch) { 90*24f398e7SPavel Balaev case 'u': 91*24f398e7SPavel Balaev { 92*24f398e7SPavel Balaev char *uuid_str = optarg; 93*24f398e7SPavel Balaev struct uuid uuid; 94*24f398e7SPavel Balaev uint32_t status; 95*24f398e7SPavel Balaev 96*24f398e7SPavel Balaev uuid_set = 1; 97*24f398e7SPavel Balaev 98*24f398e7SPavel Balaev uuid_from_string(uuid_str, &uuid, &status); 99*24f398e7SPavel Balaev if (status != uuid_s_ok) 100*24f398e7SPavel Balaev xo_errx(EX_DATAERR, "invalid UUID"); 101*24f398e7SPavel Balaev 102*24f398e7SPavel Balaev for (size_t n = 0; n < nitems(efi_table_ops); n++) { 103*24f398e7SPavel Balaev if (!memcmp(&uuid, &efi_table_ops[n].uuid, 104*24f398e7SPavel Balaev sizeof(uuid))) { 105*24f398e7SPavel Balaev efi_idx = n; 106*24f398e7SPavel Balaev got_table = true; 107*24f398e7SPavel Balaev break; 108*24f398e7SPavel Balaev } 109*24f398e7SPavel Balaev } 110*24f398e7SPavel Balaev break; 111*24f398e7SPavel Balaev } 112*24f398e7SPavel Balaev case 't': 113*24f398e7SPavel Balaev { 114*24f398e7SPavel Balaev char *table_name = optarg; 115*24f398e7SPavel Balaev 116*24f398e7SPavel Balaev table_set = true; 117*24f398e7SPavel Balaev 118*24f398e7SPavel Balaev for (size_t n = 0; n < nitems(efi_table_ops); n++) { 119*24f398e7SPavel Balaev if (!strcmp(table_name, 120*24f398e7SPavel Balaev efi_table_ops[n].name)) { 121*24f398e7SPavel Balaev efi_idx = n; 122*24f398e7SPavel Balaev got_table = true; 123*24f398e7SPavel Balaev break; 124*24f398e7SPavel Balaev } 125*24f398e7SPavel Balaev } 126*24f398e7SPavel Balaev 127*24f398e7SPavel Balaev if (!got_table) 128*24f398e7SPavel Balaev xo_errx(EX_DATAERR, "unsupported efi table"); 129*24f398e7SPavel Balaev 130*24f398e7SPavel Balaev break; 131*24f398e7SPavel Balaev } 132*24f398e7SPavel Balaev default: 133*24f398e7SPavel Balaev usage(); 134*24f398e7SPavel Balaev } 135*24f398e7SPavel Balaev } 136*24f398e7SPavel Balaev 137*24f398e7SPavel Balaev if (!table_set && !uuid_set) 138*24f398e7SPavel Balaev xo_errx(EX_USAGE, "table is not set"); 139*24f398e7SPavel Balaev 140*24f398e7SPavel Balaev if (!got_table) 141*24f398e7SPavel Balaev xo_errx(EX_DATAERR, "unsupported table"); 142*24f398e7SPavel Balaev 143*24f398e7SPavel Balaev efi_fd = open("/dev/efi", O_RDWR); 144*24f398e7SPavel Balaev if (efi_fd < 0) 145*24f398e7SPavel Balaev xo_err(EX_OSFILE, "/dev/efi"); 146*24f398e7SPavel Balaev 147*24f398e7SPavel Balaev table.uuid = efi_table_ops[efi_idx].uuid; 148*24f398e7SPavel Balaev if (ioctl(efi_fd, EFIIOC_GET_TABLE, &table) == -1) 149*24f398e7SPavel Balaev xo_err(EX_OSERR, NULL); 150*24f398e7SPavel Balaev 151*24f398e7SPavel Balaev table.buf = malloc(table.table_len); 152*24f398e7SPavel Balaev table.buf_len = table.table_len; 153*24f398e7SPavel Balaev 154*24f398e7SPavel Balaev if (ioctl(efi_fd, EFIIOC_GET_TABLE, &table) == -1) 155*24f398e7SPavel Balaev xo_err(EX_OSERR, NULL); 156*24f398e7SPavel Balaev 157*24f398e7SPavel Balaev efi_table_ops[efi_idx].parse(table.buf); 158*24f398e7SPavel Balaev close(efi_fd); 159*24f398e7SPavel Balaev 160*24f398e7SPavel Balaev return (rc); 161*24f398e7SPavel Balaev } 162*24f398e7SPavel Balaev 163*24f398e7SPavel Balaev static void 164*24f398e7SPavel Balaev efi_table_print_esrt(const void *data) 165*24f398e7SPavel Balaev { 166*24f398e7SPavel Balaev const struct efi_esrt_entry_v1 *entries_v1; 167*24f398e7SPavel Balaev const struct efi_esrt_table *esrt; 168*24f398e7SPavel Balaev 169*24f398e7SPavel Balaev esrt = (const struct efi_esrt_table *)data; 170*24f398e7SPavel Balaev 171*24f398e7SPavel Balaev xo_set_version(EFITABLE_XO_VERSION); 172*24f398e7SPavel Balaev xo_open_container("esrt"); 173*24f398e7SPavel Balaev xo_emit("{Lwc:FwResourceCount}{:fw_resource_count/%u}\n", 174*24f398e7SPavel Balaev esrt->fw_resource_count); 175*24f398e7SPavel Balaev xo_emit("{Lwc:FwResourceCountMax}{:fw_resource_count_max/%u}\n", 176*24f398e7SPavel Balaev esrt->fw_resource_count_max); 177*24f398e7SPavel Balaev xo_emit("{Lwc:FwResourceVersion}{:fw_resource_version/%u}\n", 178*24f398e7SPavel Balaev esrt->fw_resource_version); 179*24f398e7SPavel Balaev xo_open_list("entries"); 180*24f398e7SPavel Balaev xo_emit("\nEntries:\n"); 181*24f398e7SPavel Balaev 182*24f398e7SPavel Balaev entries_v1 = (const void *) esrt->entries; 183*24f398e7SPavel Balaev for (uint32_t i = 0; i < esrt->fw_resource_count; i++) { 184*24f398e7SPavel Balaev const struct efi_esrt_entry_v1 *e = &entries_v1[i]; 185*24f398e7SPavel Balaev uint32_t status; 186*24f398e7SPavel Balaev char *uuid; 187*24f398e7SPavel Balaev 188*24f398e7SPavel Balaev uuid_to_string(&e->fw_class, &uuid, &status); 189*24f398e7SPavel Balaev if (status != uuid_s_ok) { 190*24f398e7SPavel Balaev xo_errx(EX_DATAERR, "uuid_to_string error"); 191*24f398e7SPavel Balaev } 192*24f398e7SPavel Balaev 193*24f398e7SPavel Balaev xo_open_instance("entries"); 194*24f398e7SPavel Balaev xo_emit("\n"); 195*24f398e7SPavel Balaev xo_emit("{P: }{Lwc:FwClass}{:fw_class/%s}\n", uuid); 196*24f398e7SPavel Balaev xo_emit("{P: }{Lwc:FwType}{:fw_type/%u}\n", e->fw_type); 197*24f398e7SPavel Balaev xo_emit("{P: }{Lwc:FwVersion}{:fw_version/%u}\n", 198*24f398e7SPavel Balaev e->fw_version); 199*24f398e7SPavel Balaev xo_emit("{P: }{Lwc:LowestSupportedFwVersion}" 200*24f398e7SPavel Balaev "{:lowest_supported_fw_version/%u}\n", 201*24f398e7SPavel Balaev e->lowest_supported_fw_version); 202*24f398e7SPavel Balaev xo_emit("{P: }{Lwc:CapsuleFlags}{:capsule_flags/%#x}\n", 203*24f398e7SPavel Balaev e->capsule_flags); 204*24f398e7SPavel Balaev xo_emit("{P: }{Lwc:LastAttemptVersion" 205*24f398e7SPavel Balaev "}{:last_attempt_version/%u}\n", e->last_attempt_version); 206*24f398e7SPavel Balaev xo_emit("{P: }{Lwc:LastAttemptStatus" 207*24f398e7SPavel Balaev "}{:last_attempt_status/%u}\n", e->last_attempt_status); 208*24f398e7SPavel Balaev 209*24f398e7SPavel Balaev xo_close_instance("entries"); 210*24f398e7SPavel Balaev } 211*24f398e7SPavel Balaev 212*24f398e7SPavel Balaev xo_close_list("entries"); 213*24f398e7SPavel Balaev xo_close_container("esrt"); 214*24f398e7SPavel Balaev xo_finish(); 215*24f398e7SPavel Balaev } 216*24f398e7SPavel Balaev 217*24f398e7SPavel Balaev static void 218*24f398e7SPavel Balaev efi_table_print_prop(const void *data) 219*24f398e7SPavel Balaev { 220*24f398e7SPavel Balaev const struct efi_prop_table *prop; 221*24f398e7SPavel Balaev 222*24f398e7SPavel Balaev prop = (const struct efi_prop_table *)data; 223*24f398e7SPavel Balaev 224*24f398e7SPavel Balaev xo_set_version(EFITABLE_XO_VERSION); 225*24f398e7SPavel Balaev xo_open_container("prop"); 226*24f398e7SPavel Balaev xo_emit("{Lwc:Version}{:version/%#x}\n", prop->version); 227*24f398e7SPavel Balaev xo_emit("{Lwc:Length}{:length/%u}\n", prop->length); 228*24f398e7SPavel Balaev xo_emit("{Lwc:MemoryProtectionAttribute}" 229*24f398e7SPavel Balaev "{:memory_protection_attribute/%#lx}\n", 230*24f398e7SPavel Balaev prop->memory_protection_attribute); 231*24f398e7SPavel Balaev xo_close_container("prop"); 232*24f398e7SPavel Balaev xo_finish(); 233*24f398e7SPavel Balaev } 234*24f398e7SPavel Balaev 235*24f398e7SPavel Balaev static void usage(void) 236*24f398e7SPavel Balaev { 237*24f398e7SPavel Balaev xo_error("usage: efitable [-d uuid | -t name] [--libxo]\n"); 238*24f398e7SPavel Balaev exit(EX_USAGE); 239*24f398e7SPavel Balaev } 240