- // dump-efivars.c -- EFI NVRAM variables dumper for QNX8 by Pierre-Marie Baty <pm@pmbaty.com>. Yup, from user space. 
-   
- #include <stdint.h> 
- #include <stdio.h> 
- #include <stdlib.h> 
- #include <string.h> 
- #include <sys/mman.h> 
- #include <sys/syspage.h> 
- #include <errno.h> 
- #include <ctype.h> 
-   
- #define EFI_SYSTEM_TABLE_SIGNATURE "IBI SYST" // 0x5453595320494249 
- #define NVRAM_NVAR_ENTRY_SIGNATURE "NVAR" // 0x5241564e 
-   
- #define NVRAM_NVAR_ENTRY_RUNTIME         (1 << 0) 
- #define NVRAM_NVAR_ENTRY_ASCII_NAME      (1 << 1) 
- #define NVRAM_NVAR_ENTRY_GUID            (1 << 2) 
- #define NVRAM_NVAR_ENTRY_DATA_ONLY       (1 << 3) 
- #define NVRAM_NVAR_ENTRY_EXT_HEADER      (1 << 4) 
- #define NVRAM_NVAR_ENTRY_HW_ERROR_RECORD (1 << 5) 
- #define NVRAM_NVAR_ENTRY_AUTH_WRITE      (1 << 6) 
- #define NVRAM_NVAR_ENTRY_VALID           (1 << 7) 
-   
- #define NVRAM_NVAR_ENTRY_EXT_CHECKSUM   (1 << 0) 
- #define NVRAM_NVAR_ENTRY_EXT_AUTH_WRITE (1 << 4) 
- #define NVRAM_NVAR_ENTRY_EXT_TIME_BASED (1 << 5) 
-   
- #define ROUND_UP(x,multiple) ((((x) + ((multiple) - 1)) / (multiple)) * (multiple)) 
-   
-   
- typedef struct __attribute__((packed)) efi_table_header_s 
- { 
-         uint64_t signature; 
-         uint32_t revision; 
-         uint32_t size; 
-         uint32_t crc32; 
-         uint32_t reserved; 
- } efi_table_header_t; 
-   
-   
- typedef struct __attribute__((packed)) efi_system_table_s // NOTE: entries are NATURAL SIZE INTEGERS AND POINTERS! 
- { 
-         efi_table_header_t header; 
-         size_t firmware_vendor_physptr; // CHAR16 *FirmwareVendor; 
-         size_t firmware_revision; // normally uint32_t, but would break alignment 
-         size_t console_in_handle; 
-         size_t console_in_ptr; // EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; 
-         size_t console_out_handle; 
-         size_t console_out_ptr; // EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; 
-         size_t standard_error_handle; 
-         size_t standard_error_ptr; // EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; 
-         size_t runtime_services_ptr; // EFI_RUNTIME_SERVICES *RuntimeServices; 
-         size_t boot_services_ptr; // EFI_BOOT_SERVICES *BootServices; 
-         size_t configuration_entry_count; 
-         size_t configuration_table_ptr; // EFI_CONFIGURATION_TABLE *ConfigurationTable; 
- } efi_system_table_t; 
-   
-   
- typedef struct __attribute__((packed)) nvar_entry_s 
- { 
-         uint8_t magic[4]; // "NVAR" 
-         uint16_t len; // size of entry, including header 
-         uint8_t next[3]; // offset to next entry in list, or empty if latest in the store 
-         uint8_t flags; 
- } nvar_entry_t; 
-   
-   
- // global variables 
- static efi_system_table_t *systable = NULL; 
- static size_t systable_physaddr = 0; 
-   
-   
- static uint32_t crc32_efi_table (uint8_t *data, size_t data_len) 
- { 
-         // computes the CRC32 of an EFI table, skipping the relevant bytes on the fly as the UEFI specs say 
-   
-         static uint32_t table[256] = { 0 }; 
-         static int is_table_filled = 0; 
-         const uint32_t polynomial = 0xedb88320; 
-   
-         size_t array_index; 
-         size_t bit_index; 
-         uint32_t remainder; 
-         uint32_t byte; 
-         uint32_t crc; 
-   
-         if (!is_table_filled) // someone could be lazy here and use a precomputed table. Whatever. 
-         { 
-                 for (array_index = 0; array_index < 256; array_index++) 
-                 { 
-                         remainder = array_index; 
-                         for (bit_index = 0; bit_index < 8; bit_index++) 
-                                 if (remainder & 1) 
-                                         remainder = (remainder >> 1) ^ polynomial; 
-                                 else 
-                                         remainder = (remainder >> 1); 
-                         table[array_index] = remainder; 
-                 } 
-                 is_table_filled = 1; 
-         } 
-   
-         crc = 0xffffffff; 
-         for (array_index = 0; array_index < data_len; array_index++) 
-         { 
-                 if ((array_index >= 16) && (array_index < 20)) 
-                         byte = 0; // don't account for the table's claimed CRC when computing it 
-                 else 
-                         byte = data[array_index]; 
-                 crc = table[byte ^ (crc & 0xff)] ^ (crc >> 8); 
-         } 
-   
-         return (~crc); 
- } 
-   
-   
- int main (int argc, char **argv) 
- { 
-         // program entrypoint 
-          
-         const size_t asinfo_count = SYSPAGE_ENTRY_SIZE (asinfo) / sizeof (struct asinfo_entry); 
-         const struct asinfo_entry *asinfo_slots = SYSPAGE_ENTRY (asinfo); 
-         const struct asinfo_entry *asinfo_slot; 
-         const char *strings = SYSPAGE_ENTRY (strings)->data; 
-         char nvar_name[256]; 
-         char flags_string[256]; 
-         uint32_t actual_crc; 
-         nvar_entry_t *nvar; 
-         char *outfile_pathname = NULL; 
-         char *wanted_name = NULL; 
-         void *region; 
-         uint8_t *ptr; 
-         int want_fulldata = 0; 
-         int verbose_level = 0; 
-         int match_found = 0; 
-         int arg_index; 
-         size_t attached_datalen; 
-         size_t asinfo_idx; 
-         size_t guid_idx; 
-         size_t byte_idx; 
-         size_t size; 
-         FILE *fp; 
-   
-         // parse command-line arguments 
-         for (arg_index = 1; arg_index < argc; arg_index++) 
-         { 
-                 if ((strcmp (- argv [- arg_index ], "-?") == 0) || (strcmp (- argv [- arg_index ], "--help") == 0))
 
-                 { 
-                         printf ("usage: dump-efivars [-v|-vv] [--fulldata] [VarName] [outfile]\n"); 
-                 } 
-                 else if (strcmp (- argv [- arg_index ], "-v") == 0)
 
-                         verbose_level = 1; 
-                 else if (strcmp (- argv [- arg_index ], "-vv") == 0)
 
-                         verbose_level = 2; 
-                 else if (strcmp (- argv [- arg_index ], "--fulldata") == 0)
 
-                         want_fulldata = 1; 
-                 else if (wanted_name == NULL) 
-                         wanted_name = argv[arg_index]; 
-                 else if (outfile_pathname == NULL) 
-                         outfile_pathname = argv[arg_index]; 
-                 else 
-                 { 
-                         fprintf (- stderr , "error: unknown argument '%s'\n",-  argv [- arg_index ]);
 
-                         fprintf (- stderr , "usage: dump-efivars [-v|-vv] [VarName] [outfile]\n");
 
-                 } 
-         } 
-   
-         // we got the start of the asinfo array through the syspage pointer in asinfo_slots 
-         // now scan all accessible physical RAM regions that the firmware doesn't want allocated to applications 
-         for (asinfo_idx = 0; asinfo_idx < asinfo_count; asinfo_idx++) 
-         { 
-                 asinfo_slot = &asinfo_slots[asinfo_idx]; 
-                 if (asinfo_slot->start == 0) 
-                         continue; // skip the first slot (ISA space) - there's no chance our stuff is in it 
-                 else if (strcmp (- strings  +-  asinfo_slot ->- name , "ram") != 0)
 
-                         continue; // skip anything that's NOT non-allocatable RAM 
-   
-                 // ask the kernel to map this physical region to a pointer in our virtual address space 
-                 size = asinfo_slot->end - asinfo_slot->start; 
-                 region = mmap (NULL, size, PROT_READ, MAP_PRIVATE | MAP_PHYS, NOFD, asinfo_slot->start); 
-                 if (region == NULL) 
-                         continue; // if this region can't be mapped (for whatever reason), skip it 
-   
-                 // now scan this physical memory region for the EFI system table signature 
-                 for (ptr = (uint8_t *) ROUND_UP ((size_t) region, sizeof (size_t)); (size_t) ptr + sizeof (efi_system_table_t) < (size_t) region + size; ptr += sizeof (size_t)) 
-                 { 
-                         if (*((uint64_t *) ptr) != *((uint64_t *) EFI_SYSTEM_TABLE_SIGNATURE)) 
-                                 continue; // skip anything that doesn't look like an EFI system table signature 
-                         else if ((((efi_system_table_t *) ptr)->header.size < sizeof (efi_system_table_t)) || (((efi_system_table_t *) ptr)->header.size > 255)) 
-                                 continue; // if table is too short or claims more than 255 bytes, skip it 
-                         else if (ptr + ((efi_system_table_t *) ptr)->header.size >= (uint8_t *) region + size) 
-                                 continue; // if table's claimed size doesn't fit in region, skip it 
-                         else if ((ptr[10] != 2) || (ptr[11] != 0)) 
-                                 continue; // if revision is NOT 2.xx, skip it 
-                         else if (((efi_system_table_t *) ptr)->header.reserved != 0) 
-                                 continue; // if reserved field is not 0 as the specs say, skip it 
-   
-                         actual_crc = crc32_efi_table (ptr, ((efi_system_table_t *) ptr)->header.size); 
-                         if (actual_crc != ((efi_system_table_t *) ptr)->header.crc32) 
-                                 continue; // if CRCs mismatch, forget about this table and skip it 
-   
-                         // CRC is valid: this is a usable UEFI system table 
-                         systable = (efi_system_table_t *) ptr; 
-                         systable_physaddr = asinfo_slot->start + ((size_t) ptr - (size_t) region); 
-                         break; // stop looking right here 
-                 } 
-   
-                 if (systable != NULL) 
-                         break; // if we found the system table already, no need to scan other regions 
-                 munmap (region, size); // unmap this physical memory region after it's been scanned 
-         } 
-   
-         // consistency check 
-         if (systable == NULL) 
-         { 
-                 fprintf (- stderr , "EFI system table not found\n");
 
-                 exit (1); // if we found nothing, bail out 
-         } 
-   
-         // in verbose mode, jump in joy and yell the world what we found 
-         if (verbose_level > 1) 
-         { 
-                 fprintf (- stderr , "Valid EFI header at Address %016zx\n",-  systable_physaddr );
 
-                 fprintf (- stderr , "---------------------------------------------\n");
 
-                 fprintf (- stderr , "System: Table Structure size %08x revision %08x\n",-  systable ->- header. size,-  systable ->- header. revision);
 
-                 fprintf (- stderr , "ConIn (%016zx) ConOut (%016zx) StdErr (%016zx)\n",-  systable ->- console_in_ptr ,-  systable ->- console_out_ptr ,-  systable ->- standard_error_ptr );
 
-                 fprintf (- stderr , "Runtime Services %016zx\n",-  systable ->- runtime_services_ptr );
 
-                 fprintf (- stderr , "Boot Services    %016zx\n",-  systable ->- boot_services_ptr );
 
-         } 
-   
-         // the EFI header is in the memory region [asinfo_slot->start - asinfo_slot->end] 
-         // This region will also contain the NVARs, so let's scan for them, brute-force way. 
-         // Yes, this is awful. My mother definitely told me not to do that, but I couldn't help it 0:-* 
-         // FIXME: do a proper hierarchical reconstruction and assign GUIDs and detached payloads etc... 
-         for (ptr = region;;) 
-         { 
-                 while (   ((size_t) ptr + sizeof (nvar_entry_t) < (size_t) region + size) 
-                        && (*((uint32_t *) ptr) != *((uint32_t *) NVRAM_NVAR_ENTRY_SIGNATURE))) 
-                         ptr++; // look for the next "NVAR" tag (NOTE THAT THEY ARE STORED UNALIGNED!) 
-   
-                 if ((size_t) ptr + sizeof (nvar_entry_t) >= (size_t) region + size) 
-                         break; // end of region reached 
-   
-                 nvar = (nvar_entry_t *) ptr; // access it as a NVRAM UEFI variable 
-   
-                 // translate NVAR flags 
-                 flags_string[0] = 0; 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_RUNTIME )         strcat (- flags_string , ", runtime");
 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_ASCII_NAME )      strcat (- flags_string , ", ASCII name");
 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_GUID )            strcat (- flags_string , ", GUID");
 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_DATA_ONLY )       strcat (- flags_string , ", data only");
 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_EXT_HEADER )      strcat (- flags_string , ", ext. hdr");
 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_HW_ERROR_RECORD ) strcat (- flags_string , ", HW err rec");
 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_AUTH_WRITE )      strcat (- flags_string , ", auth write");
 
-                 if (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_VALID )           strcat (- flags_string , ", valid");
 
-   
-                 // skip header 
-                 ptr += sizeof (nvar_entry_t); 
-   
-                 // read GUID index and advance 
-                 guid_idx = *ptr++; 
-   
-                 // read name and advance 
-                 for (byte_idx = 0; ; byte_idx++) 
-                 { 
-                         nvar_name[byte_idx] = *ptr; // either ASCII or UTF-16LE, so read first byte 
-                         ptr += (nvar->flags & NVRAM_NVAR_ENTRY_ASCII_NAME ? 1 : 2); 
-                         if ((- nvar_name [- byte_idx ] == 0) || !isalnum (- nvar_name [- byte_idx ]))
 
-                                 break; // stop on end of name or invalid character 
-                 } 
-                 if ((byte_idx == 0) || (nvar_name[byte_idx] != 0)) 
-                         continue; // if varname is empty or invalid, skip this NVAR 
-   
-                 if ((- wanted_name  !=-  NULL ) && (strcmp (- nvar_name ,-  wanted_name ) != 0))
 
-                         continue; // if this variable isn't the one we want, skip it 
-   
-                 // if we shouldn't display this variable because it's invalid for the firmware itself, skip it 
-                 if (!(nvar->flags & NVRAM_NVAR_ENTRY_VALID)) 
-                         continue; // there's no point in displaying junk data 
-   
-                 match_found = 1; // remember we found a match 
-   
-                 // measure attached data length 
-                 attached_datalen  =-  nvar ->- len  - (sizeof (- nvar_entry_t ) + 1 + (- nvar ->- flags  &-  NVRAM_NVAR_ENTRY_ASCII_NAME  ? 1 : 2) * (strlen (- nvar_name ) + 1));
-   
-                 // do we just want ONE variable AND its content dumped to a file ? 
-                 if ((wanted_name != NULL) && (outfile_pathname != NULL)) 
-                 { 
-                         fp  = fopen (- outfile_pathname , "wb"); // open outfile if we have one
-                         if (fp == NULL) 
-                         { 
-                                 fprintf (- stderr , "error: can't open \"%s\" for writing: %s\n",-  outfile_pathname , strerror (- errno ));
 
-                         } 
-                         fwrite (- ptr , 1,-  attached_datalen ,-  fp ); // dump NVAR data to file if that's what we want
 
-                         fclose (- fp ); // close the output file
 
-                 } 
-                 else // print all variables, or just one to stdout 
-                 { 
-                         // in verbose mode, print NVAR size, 'next' field and attributes 
-                         if (verbose_level > 0) 
-                                 fprintf (- stdout , "%04x %02x%02x%02x %02x ",-  nvar ->- len ,-  nvar ->- next [0],-  nvar ->- next [1],-  nvar ->- next [2],-  nvar ->- flags );
 
-   
-                         // print NVAR name and data 
-                         fprintf (- stdout , "%s = ",-  nvar_name );
 
-                         if (want_fulldata || (attached_datalen < 48)) 
-                         { 
-                                 while ((size_t) ptr < (size_t) nvar + nvar->len) 
-                                         fprintf (- stdout , "%02x", *- ptr ++); // print data bytes if it's short enough, or if we requested it explicitly
 
-                         } 
-                         else 
-                                 fprintf (- stdout , "<%zd bytes>",-  attached_datalen ); // else just print data size
 
-   
-                         // now print flags string 
-                         if (verbose_level > 0) 
-                                 fprintf (- stdout , "%s - GUID idx %zu",-  flags_string ,-  guid_idx );
 
-                         else if (nvar->flags & NVRAM_NVAR_ENTRY_AUTH_WRITE) 
-   
-                 } 
-         } 
-   
-         munmap (region, size); // unmap the physical region upon exit 
-   
-         // if we found nothing, print an error message 
-         if ((wanted_name != NULL) && !match_found) 
-                 fprintf (- stderr , "No variable named \"%s\" found.\n",-  wanted_name );
 
-   
-         // and return with a relevant exit code 
-         exit (- match_found  ? 0 : 1);
 
- } 
-