diff options
Diffstat (limited to 'errlog.c')
| -rw-r--r-- | errlog.c | 181 |
1 files changed, 181 insertions, 0 deletions
@@ -99,4 +99,185 @@ ClearErrors(VOID) errs = NULL; } +static size_t +format_error_log(UINT8 *dest, size_t dest_sz) +{ + size_t err_log_sz = 0; + size_t pos = 0; + + for (UINTN i = 0; i < nerrs; i++) + err_log_sz += StrSize(errs[i]); + + if (!dest || dest_sz < err_log_sz) + return err_log_sz; + + ZeroMem(dest, err_log_sz); + for (UINTN i = 0; i < nerrs; i++) { + UINTN sz = StrSize(errs[i]); + CopyMem(&dest[pos], errs[i], sz); + pos += sz; + } + + return err_log_sz; +} + +static UINT8 *debug_log = NULL; +static size_t debug_log_sz = 0; +static size_t debug_log_alloc = 0; + +UINTN EFIAPI +log_debug_print(const CHAR16 *fmt, ...) +{ + ms_va_list args; + CHAR16 *buf; + size_t buf_sz; + UINTN ret = 0; + + ms_va_start(args, fmt); + buf = VPoolPrint(fmt, args); + if (!buf) + return 0; + ms_va_end(args); + + ret = StrLen(buf); + buf_sz = StrSize(buf); + if (debug_log_sz + buf_sz > debug_log_alloc) { + size_t new_alloc_sz = debug_log_alloc; + CHAR16 *new_debug_log; + + new_alloc_sz += buf_sz; + new_alloc_sz = ALIGN_UP(new_alloc_sz, EFI_PAGE_SIZE); + + new_debug_log = ReallocatePool(debug_log, debug_log_alloc, new_alloc_sz); + if (!new_debug_log) + return 0; + debug_log = (UINT8 *)new_debug_log; + debug_log_alloc = new_alloc_sz; + } + + CopyMem(&debug_log[debug_log_sz], buf, buf_sz); + debug_log_sz += buf_sz; + FreePool(buf); + return ret; +} + +static size_t +format_debug_log(UINT8 *dest, size_t dest_sz) +{ + if (!dest || dest_sz < debug_log_sz) + return debug_log_sz; + + ZeroMem(dest, debug_log_sz); + CopyMem(dest, debug_log, debug_log_sz); + return debug_log_sz; +} + +void +replace_config_table(EFI_CONFIGURATION_TABLE *CT, EFI_PHYSICAL_ADDRESS new_table, UINTN new_table_pages) +{ + EFI_GUID bogus_guid = { 0x29f2f0db, 0xd025, 0x4aa6, { 0x99, 0x58, 0xa0, 0x21, 0x8b, 0x1d, 0xec, 0x0e }}; + EFI_STATUS efi_status; + + if (CT) { + CopyMem(&CT->VendorGuid, &bogus_guid, sizeof(bogus_guid)); + if (CT->VendorTable && + CT->VendorTable == (void *)(uintptr_t)mok_config_table) { + BS->FreePages(mok_config_table, mok_config_table_pages); + CT->VendorTable = NULL; + } + } + + efi_status = BS->InstallConfigurationTable(&MOK_VARIABLE_STORE, + (void *)(uintptr_t)new_table); + if (EFI_ERROR(efi_status)) { + console_print(L"Could not re-install MoK configuration table: %r\n", efi_status); + } else { + mok_config_table = new_table; + mok_config_table_pages = new_table_pages; + } +} + +void +save_logs(void) +{ + struct mok_variable_config_entry *cfg_table = NULL; + struct mok_variable_config_entry *new_table = NULL; + struct mok_variable_config_entry *entry = NULL; + EFI_PHYSICAL_ADDRESS physaddr = 0; + UINTN new_table_pages = 0; + size_t new_table_sz; + UINTN pos = 0; + EFI_STATUS efi_status; + size_t errlog_sz, dbglog_sz; + + errlog_sz = format_error_log(NULL, 0); + dbglog_sz = format_debug_log(NULL, 0); + + if (errlog_sz == 0 && dbglog_sz == 0) { + console_print(L"No console or debug log?!?!?\n"); + return; + } + + for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) { + EFI_CONFIGURATION_TABLE *CT; + CT = &ST->ConfigurationTable[i]; + + if (CompareGuid(&MOK_VARIABLE_STORE, &CT->VendorGuid) == 0) { + cfg_table = CT->VendorTable; + break; + } + CT = NULL; + } + + entry = cfg_table; + while (entry && entry->name[0] != 0) { + size_t entry_sz; + entry = (struct mok_variable_config_entry *)((uintptr_t)cfg_table + pos); + + if (entry->name[0] != 0) { + entry_sz = sizeof(*entry); + entry_sz += entry->data_size; + pos += entry_sz; + } + } + + new_table_sz = pos + + (errlog_sz ? sizeof(*entry) + errlog_sz : 0) + + (dbglog_sz ? sizeof(*entry) + dbglog_sz : 0) + + sizeof(*entry); + new_table = NULL; + new_table_pages = ALIGN_UP(new_table_sz + 4*EFI_PAGE_SIZE, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + efi_status = BS->AllocatePages(AllocateAnyPages, EfiRuntimeServicesData, new_table_pages, &physaddr); + if (EFI_ERROR(efi_status)) { + perror(L"Couldn't allocate %llu pages\n", new_table_pages); + return; + } + new_table = (void *)(uintptr_t)physaddr; + if (!new_table) + return; + ZeroMem(new_table, new_table_pages * EFI_PAGE_SIZE); + CopyMem(new_table, cfg_table, pos); + + entry = (struct mok_variable_config_entry *)((uintptr_t)new_table + pos); + if (errlog_sz) { + strcpy(entry->name, "shim-err.txt"); + entry->data_size = errlog_sz; + format_error_log(&entry->data[0], errlog_sz); + + pos += sizeof(*entry) + errlog_sz; + entry = (struct mok_variable_config_entry *)((uintptr_t)new_table + pos); + } + if (dbglog_sz) { + strcpy(entry->name, "shim-dbg.txt"); + entry->data_size = dbglog_sz; + format_debug_log(&entry->data[0], dbglog_sz); + + pos += sizeof(*entry) + dbglog_sz; + + entry = (struct mok_variable_config_entry *)((uintptr_t)new_table + pos); + } + + replace_config_table((EFI_CONFIGURATION_TABLE *)cfg_table, physaddr, new_table_pages); +} + // vim:fenc=utf-8:tw=75 |
