Merge tag 'efi-fixes-for-v5.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi into efi/urgent

Pull EFI fixes from Ard Biesheuvel:

"- fix EFI framebuffer earlycon for wide fonts
- avoid filling screen_info with garbage if the EFI framebuffer is not
available
- fix a potential host tool build error due to a symbol clash on x86
- work around a EFI firmware bug regarding the binary format of the TPM
final events table
- fix a missing memory free by reworking the E820 table sizing routine to
not do the allocation in the first place
- add CPER parsing for firmware errors"

Changed files
+124 -39
arch
x86
boot
tools
drivers
include
linux
+8 -8
arch/x86/boot/tools/build.c
··· 59 59 #define PECOFF_COMPAT_RESERVE 0x0 60 60 #endif 61 61 62 - unsigned long efi32_stub_entry; 63 - unsigned long efi64_stub_entry; 64 - unsigned long efi_pe_entry; 65 - unsigned long efi32_pe_entry; 66 - unsigned long kernel_info; 67 - unsigned long startup_64; 68 - unsigned long _ehead; 69 - unsigned long _end; 62 + static unsigned long efi32_stub_entry; 63 + static unsigned long efi64_stub_entry; 64 + static unsigned long efi_pe_entry; 65 + static unsigned long efi32_pe_entry; 66 + static unsigned long kernel_info; 67 + static unsigned long startup_64; 68 + static unsigned long _ehead; 69 + static unsigned long _end; 70 70 71 71 /*----------------------------------------------------------------------*/ 72 72
+62
drivers/firmware/efi/cper.c
··· 407 407 } 408 408 } 409 409 410 + static const char * const fw_err_rec_type_strs[] = { 411 + "IPF SAL Error Record", 412 + "SOC Firmware Error Record Type1 (Legacy CrashLog Support)", 413 + "SOC Firmware Error Record Type2", 414 + }; 415 + 416 + static void cper_print_fw_err(const char *pfx, 417 + struct acpi_hest_generic_data *gdata, 418 + const struct cper_sec_fw_err_rec_ref *fw_err) 419 + { 420 + void *buf = acpi_hest_get_payload(gdata); 421 + u32 offset, length = gdata->error_data_length; 422 + 423 + printk("%s""Firmware Error Record Type: %s\n", pfx, 424 + fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ? 425 + fw_err_rec_type_strs[fw_err->record_type] : "unknown"); 426 + printk("%s""Revision: %d\n", pfx, fw_err->revision); 427 + 428 + /* Record Type based on UEFI 2.7 */ 429 + if (fw_err->revision == 0) { 430 + printk("%s""Record Identifier: %08llx\n", pfx, 431 + fw_err->record_identifier); 432 + } else if (fw_err->revision == 2) { 433 + printk("%s""Record Identifier: %pUl\n", pfx, 434 + &fw_err->record_identifier_guid); 435 + } 436 + 437 + /* 438 + * The FW error record may contain trailing data beyond the 439 + * structure defined by the specification. As the fields 440 + * defined (and hence the offset of any trailing data) vary 441 + * with the revision, set the offset to account for this 442 + * variation. 443 + */ 444 + if (fw_err->revision == 0) { 445 + /* record_identifier_guid not defined */ 446 + offset = offsetof(struct cper_sec_fw_err_rec_ref, 447 + record_identifier_guid); 448 + } else if (fw_err->revision == 1) { 449 + /* record_identifier not defined */ 450 + offset = offsetof(struct cper_sec_fw_err_rec_ref, 451 + record_identifier); 452 + } else { 453 + offset = sizeof(*fw_err); 454 + } 455 + 456 + buf += offset; 457 + length -= offset; 458 + 459 + print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true); 460 + } 461 + 410 462 static void cper_print_tstamp(const char *pfx, 411 463 struct acpi_hest_generic_data_v300 *gdata) 412 464 { ··· 546 494 else 547 495 goto err_section_too_small; 548 496 #endif 497 + } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) { 498 + struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata); 499 + 500 + printk("%ssection_type: Firmware Error Record Reference\n", 501 + newpfx); 502 + /* The minimal FW Error Record contains 16 bytes */ 503 + if (gdata->error_data_length >= SZ_16) 504 + cper_print_fw_err(newpfx, gdata, fw_err); 505 + else 506 + goto err_section_too_small; 549 507 } else { 550 508 const void *err = acpi_hest_get_payload(gdata); 551 509
+8 -6
drivers/firmware/efi/earlycon.c
··· 114 114 const u32 color_black = 0x00000000; 115 115 const u32 color_white = 0x00ffffff; 116 116 const u8 *src; 117 - u8 s8; 118 - int m; 117 + int m, n, bytes; 118 + u8 x; 119 119 120 - src = font->data + c * font->height; 121 - s8 = *(src + h); 120 + bytes = BITS_TO_BYTES(font->width); 121 + src = font->data + c * font->height * bytes + h * bytes; 122 122 123 - for (m = 0; m < 8; m++) { 124 - if ((s8 >> (7 - m)) & 1) 123 + for (m = 0; m < font->width; m++) { 124 + n = m % 8; 125 + x = *(src + m / 8); 126 + if ((x >> (7 - n)) & 1) 125 127 *dst = color_white; 126 128 else 127 129 *dst = color_black;
+1 -4
drivers/firmware/efi/efi.c
··· 130 130 if (efi.smbios != EFI_INVALID_TABLE_ADDR) 131 131 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); 132 132 133 - if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86)) { 134 - extern char *efi_systab_show_arch(char *str); 135 - 133 + if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86)) 136 134 str = efi_systab_show_arch(str); 137 - } 138 135 139 136 return str - buf; 140 137 }
+5 -1
drivers/firmware/efi/libstub/arm-stub.c
··· 60 60 si = alloc_screen_info(); 61 61 if (!si) 62 62 return NULL; 63 - efi_setup_gop(si, &gop_proto, size); 63 + status = efi_setup_gop(si, &gop_proto, size); 64 + if (status != EFI_SUCCESS) { 65 + free_screen_info(si); 66 + return NULL; 67 + } 64 68 } 65 69 return si; 66 70 }
+13
drivers/firmware/efi/libstub/efistub.h
··· 92 92 #define EFI_LOCATE_BY_REGISTER_NOTIFY 1 93 93 #define EFI_LOCATE_BY_PROTOCOL 2 94 94 95 + /* 96 + * An efi_boot_memmap is used by efi_get_memory_map() to return the 97 + * EFI memory map in a dynamically allocated buffer. 98 + * 99 + * The buffer allocated for the EFI memory map includes extra room for 100 + * a minimum of EFI_MMAP_NR_SLACK_SLOTS additional EFI memory descriptors. 101 + * This facilitates the reuse of the EFI memory map buffer when a second 102 + * call to ExitBootServices() is needed because of intervening changes to 103 + * the EFI memory map. Other related structures, e.g. x86 e820ext, need 104 + * to factor in this headroom requirement as well. 105 + */ 106 + #define EFI_MMAP_NR_SLACK_SLOTS 8 107 + 95 108 struct efi_boot_memmap { 96 109 efi_memory_desc_t **map; 97 110 unsigned long *map_size;
-2
drivers/firmware/efi/libstub/mem.c
··· 5 5 6 6 #include "efistub.h" 7 7 8 - #define EFI_MMAP_NR_SLACK_SLOTS 8 9 - 10 8 static inline bool mmap_has_headroom(unsigned long buff_size, 11 9 unsigned long map_size, 12 10 unsigned long desc_size)
+3 -2
drivers/firmware/efi/libstub/tpm.c
··· 54 54 efi_status_t status; 55 55 efi_physical_addr_t log_location = 0, log_last_entry = 0; 56 56 struct linux_efi_tpm_eventlog *log_tbl = NULL; 57 - struct efi_tcg2_final_events_table *final_events_table; 57 + struct efi_tcg2_final_events_table *final_events_table = NULL; 58 58 unsigned long first_entry_addr, last_entry_addr; 59 59 size_t log_size, last_entry_size; 60 60 efi_bool_t truncated; ··· 127 127 * Figure out whether any events have already been logged to the 128 128 * final events structure, and if so how much space they take up 129 129 */ 130 - final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID); 130 + if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) 131 + final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID); 131 132 if (final_events_table && final_events_table->nr_events) { 132 133 struct tcg_pcr_event2_head *header; 133 134 int offset;
+9 -15
drivers/firmware/efi/libstub/x86-stub.c
··· 606 606 struct setup_data **e820ext, 607 607 u32 *e820ext_size) 608 608 { 609 - unsigned long map_size, desc_size, buff_size; 610 - struct efi_boot_memmap boot_map; 611 - efi_memory_desc_t *map; 609 + unsigned long map_size, desc_size, map_key; 612 610 efi_status_t status; 613 - __u32 nr_desc; 611 + __u32 nr_desc, desc_version; 614 612 615 - boot_map.map = &map; 616 - boot_map.map_size = &map_size; 617 - boot_map.desc_size = &desc_size; 618 - boot_map.desc_ver = NULL; 619 - boot_map.key_ptr = NULL; 620 - boot_map.buff_size = &buff_size; 613 + /* Only need the size of the mem map and size of each mem descriptor */ 614 + map_size = 0; 615 + status = efi_bs_call(get_memory_map, &map_size, NULL, &map_key, 616 + &desc_size, &desc_version); 617 + if (status != EFI_BUFFER_TOO_SMALL) 618 + return (status != EFI_SUCCESS) ? status : EFI_UNSUPPORTED; 621 619 622 - status = efi_get_memory_map(&boot_map); 623 - if (status != EFI_SUCCESS) 624 - return status; 625 - 626 - nr_desc = buff_size / desc_size; 620 + nr_desc = map_size / desc_size + EFI_MMAP_NR_SLACK_SLOTS; 627 621 628 622 if (nr_desc > ARRAY_SIZE(params->e820_table)) { 629 623 u32 nr_e820ext = nr_desc - ARRAY_SIZE(params->e820_table);
+4 -1
drivers/firmware/efi/tpm.c
··· 62 62 tbl_size = sizeof(*log_tbl) + log_tbl->size; 63 63 memblock_reserve(efi.tpm_log, tbl_size); 64 64 65 - if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) 65 + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || 66 + log_tbl->version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { 67 + pr_warn(FW_BUG "TPM Final Events table missing or invalid\n"); 66 68 goto out; 69 + } 67 70 68 71 final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl)); 69 72
+9
include/linux/cper.h
··· 521 521 u8 aer_info[96]; 522 522 }; 523 523 524 + /* Firmware Error Record Reference, UEFI v2.7 sec N.2.10 */ 525 + struct cper_sec_fw_err_rec_ref { 526 + u8 record_type; 527 + u8 revision; 528 + u8 reserved[6]; 529 + u64 record_identifier; 530 + guid_t record_identifier_guid; 531 + }; 532 + 524 533 /* Reset to default packing */ 525 534 #pragma pack() 526 535
+2
include/linux/efi.h
··· 1245 1245 1246 1246 void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size); 1247 1247 1248 + char *efi_systab_show_arch(char *str); 1249 + 1248 1250 #endif /* _LINUX_EFI_H */