From 081d5150845ba3fa49151a2f55d3cc03b0987509 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Apr 2020 21:49:46 +0200 Subject: efi/libstub: Avoid returning uninitialized data from setup_graphics() Currently, setup_graphics() ignores the return value of efi_setup_gop(). As AllocatePool() does not zero out memory, the screen information table will contain uninitialized data in this case. We should free the screen information table if efi_setup_gop() returns an error code. Signed-off-by: Heinrich Schuchardt Link: https://lore.kernel.org/r/20200426194946.112768-1-xypron.glpk@gmx.de Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/arm-stub.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 99a5cde7c2d8..48161b1dd098 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -60,7 +60,11 @@ static struct screen_info *setup_graphics(void) si = alloc_screen_info(); if (!si) return NULL; - efi_setup_gop(si, &gop_proto, size); + status = efi_setup_gop(si, &gop_proto, size); + if (status != EFI_SUCCESS) { + free_screen_info(si); + return NULL; + } } return si; } -- cgit From 8f592ada59b321d248391bae175cd78a12972223 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Sun, 12 Apr 2020 10:49:27 +0800 Subject: efi/earlycon: Fix early printk for wider fonts When I play with terminus fonts I noticed the efi early printk does not work because the earlycon code assumes font width is 8. Here add the code to adapt with larger fonts. Tested with all kinds of kernel built-in fonts on my laptop. Also tested with a local draft patch for 14x28 !bold terminus font. Signed-off-by: Dave Young Link: https://lore.kernel.org/r/20200412024927.GA6884@dhcp-128-65.nay.redhat.com Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/earlycon.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c index 5d4f84781aa0..a52236e11e5f 100644 --- a/drivers/firmware/efi/earlycon.c +++ b/drivers/firmware/efi/earlycon.c @@ -114,14 +114,16 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h) const u32 color_black = 0x00000000; const u32 color_white = 0x00ffffff; const u8 *src; - u8 s8; - int m; + int m, n, bytes; + u8 x; - src = font->data + c * font->height; - s8 = *(src + h); + bytes = BITS_TO_BYTES(font->width); + src = font->data + c * font->height * bytes + h * bytes; - for (m = 0; m < 8; m++) { - if ((s8 >> (7 - m)) & 1) + for (m = 0; m < font->width; m++) { + n = m % 8; + x = *(src + m / 8); + if ((x >> (7 - n)) & 1) *dst = color_white; else *dst = color_black; -- cgit From fd62619598069c974739476d1851a00d665041d7 Mon Sep 17 00:00:00 2001 From: Lenny Szubowicz Date: Thu, 7 May 2020 14:33:32 -0400 Subject: efi/libstub/x86: Avoid EFI map buffer alloc in allocate_e820() In allocate_e820(), call the EFI get_memory_map() service directly instead of indirectly via efi_get_memory_map(). This avoids allocation of a buffer and return of the full EFI memory map, which is not needed here and would otherwise need to be freed. Routine allocate_e820() only needs to know how many EFI memory descriptors there are in the map to allocate an adequately sized e820ext buffer, if it's needed. Note that since efi_get_memory_map() returns a memory map buffer sized with extra headroom, allocate_e820() now needs to explicitly factor that into the e820ext size calculation. Signed-off-by: Lenny Szubowicz Suggested-by: Ard Biesheuvel Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/efistub.h | 13 +++++++++++++ drivers/firmware/efi/libstub/mem.c | 2 -- drivers/firmware/efi/libstub/x86-stub.c | 24 +++++++++--------------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 67d26949fd26..62943992f02f 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -92,6 +92,19 @@ extern __pure efi_system_table_t *efi_system_table(void); #define EFI_LOCATE_BY_REGISTER_NOTIFY 1 #define EFI_LOCATE_BY_PROTOCOL 2 +/* + * An efi_boot_memmap is used by efi_get_memory_map() to return the + * EFI memory map in a dynamically allocated buffer. + * + * The buffer allocated for the EFI memory map includes extra room for + * a minimum of EFI_MMAP_NR_SLACK_SLOTS additional EFI memory descriptors. + * This facilitates the reuse of the EFI memory map buffer when a second + * call to ExitBootServices() is needed because of intervening changes to + * the EFI memory map. Other related structures, e.g. x86 e820ext, need + * to factor in this headroom requirement as well. + */ +#define EFI_MMAP_NR_SLACK_SLOTS 8 + struct efi_boot_memmap { efi_memory_desc_t **map; unsigned long *map_size; diff --git a/drivers/firmware/efi/libstub/mem.c b/drivers/firmware/efi/libstub/mem.c index 869a79c8946f..09f4fa01914e 100644 --- a/drivers/firmware/efi/libstub/mem.c +++ b/drivers/firmware/efi/libstub/mem.c @@ -5,8 +5,6 @@ #include "efistub.h" -#define EFI_MMAP_NR_SLACK_SLOTS 8 - static inline bool mmap_has_headroom(unsigned long buff_size, unsigned long map_size, unsigned long desc_size) diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index 05ccb229fb45..f0339b5d3658 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -606,24 +606,18 @@ static efi_status_t allocate_e820(struct boot_params *params, struct setup_data **e820ext, u32 *e820ext_size) { - unsigned long map_size, desc_size, buff_size; - struct efi_boot_memmap boot_map; - efi_memory_desc_t *map; + unsigned long map_size, desc_size, map_key; efi_status_t status; - __u32 nr_desc; + __u32 nr_desc, desc_version; - boot_map.map = ↦ - boot_map.map_size = &map_size; - boot_map.desc_size = &desc_size; - boot_map.desc_ver = NULL; - boot_map.key_ptr = NULL; - boot_map.buff_size = &buff_size; + /* Only need the size of the mem map and size of each mem descriptor */ + map_size = 0; + status = efi_bs_call(get_memory_map, &map_size, NULL, &map_key, + &desc_size, &desc_version); + if (status != EFI_BUFFER_TOO_SMALL) + return (status != EFI_SUCCESS) ? status : EFI_UNSUPPORTED; - status = efi_get_memory_map(&boot_map); - if (status != EFI_SUCCESS) - return status; - - nr_desc = buff_size / desc_size; + nr_desc = map_size / desc_size + EFI_MMAP_NR_SLACK_SLOTS; if (nr_desc > ARRAY_SIZE(params->e820_table)) { u32 nr_e820ext = nr_desc - ARRAY_SIZE(params->e820_table); -- cgit From 3d8c11efd528d56972d44ed0de51c4e11a9a4fa9 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 12 May 2020 13:55:02 +0900 Subject: efi: cper: Add support for printing Firmware Error Record Reference While debugging a boot failure, the following unknown error record was seen in the boot logs. <...> BERT: Error records from previous boot: [Hardware Error]: event severity: fatal [Hardware Error]: Error 0, type: fatal [Hardware Error]: section type: unknown, 81212a96-09ed-4996-9471-8d729c8e69ed [Hardware Error]: section length: 0x290 [Hardware Error]: 00000000: 00000001 00000000 00000000 00020002 ................ [Hardware Error]: 00000010: 00020002 0000001f 00000320 00000000 ........ ....... [Hardware Error]: 00000020: 00000000 00000000 00000000 00000000 ................ [Hardware Error]: 00000030: 00000000 00000000 00000000 00000000 ................ <...> On further investigation, it was found that the error record with UUID (81212a96-09ed-4996-9471-8d729c8e69ed) has been defined in the UEFI Specification at least since v2.4 and has recently had additional fields defined in v2.7 Section N.2.10 Firmware Error Record Reference. Add support for parsing and printing the defined fields to give users a chance to figure out what went wrong. Signed-off-by: Punit Agrawal Cc: Ard Biesheuvel Cc: "Rafael J. Wysocki" Cc: Borislav Petkov Cc: James Morse Cc: linux-acpi@vger.kernel.org Cc: linux-efi@vger.kernel.org Link: https://lore.kernel.org/r/20200512045502.3810339-1-punit1.agrawal@toshiba.co.jp Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/cper.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/cper.h | 9 +++++++ 2 files changed, 71 insertions(+) diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 9d2512913d25..f564e15fbc7e 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -407,6 +407,58 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, } } +static const char * const fw_err_rec_type_strs[] = { + "IPF SAL Error Record", + "SOC Firmware Error Record Type1 (Legacy CrashLog Support)", + "SOC Firmware Error Record Type2", +}; + +static void cper_print_fw_err(const char *pfx, + struct acpi_hest_generic_data *gdata, + const struct cper_sec_fw_err_rec_ref *fw_err) +{ + void *buf = acpi_hest_get_payload(gdata); + u32 offset, length = gdata->error_data_length; + + printk("%s""Firmware Error Record Type: %s\n", pfx, + fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ? + fw_err_rec_type_strs[fw_err->record_type] : "unknown"); + printk("%s""Revision: %d\n", pfx, fw_err->revision); + + /* Record Type based on UEFI 2.7 */ + if (fw_err->revision == 0) { + printk("%s""Record Identifier: %08llx\n", pfx, + fw_err->record_identifier); + } else if (fw_err->revision == 2) { + printk("%s""Record Identifier: %pUl\n", pfx, + &fw_err->record_identifier_guid); + } + + /* + * The FW error record may contain trailing data beyond the + * structure defined by the specification. As the fields + * defined (and hence the offset of any trailing data) vary + * with the revision, set the offset to account for this + * variation. + */ + if (fw_err->revision == 0) { + /* record_identifier_guid not defined */ + offset = offsetof(struct cper_sec_fw_err_rec_ref, + record_identifier_guid); + } else if (fw_err->revision == 1) { + /* record_identifier not defined */ + offset = offsetof(struct cper_sec_fw_err_rec_ref, + record_identifier); + } else { + offset = sizeof(*fw_err); + } + + buf += offset; + length -= offset; + + print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true); +} + static void cper_print_tstamp(const char *pfx, struct acpi_hest_generic_data_v300 *gdata) { @@ -494,6 +546,16 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata else goto err_section_too_small; #endif + } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) { + struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata); + + printk("%ssection_type: Firmware Error Record Reference\n", + newpfx); + /* The minimal FW Error Record contains 16 bytes */ + if (gdata->error_data_length >= SZ_16) + cper_print_fw_err(newpfx, gdata, fw_err); + else + goto err_section_too_small; } else { const void *err = acpi_hest_get_payload(gdata); diff --git a/include/linux/cper.h b/include/linux/cper.h index 4f005d95ce88..8537e9282a65 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h @@ -521,6 +521,15 @@ struct cper_sec_pcie { u8 aer_info[96]; }; +/* Firmware Error Record Reference, UEFI v2.7 sec N.2.10 */ +struct cper_sec_fw_err_rec_ref { + u8 record_type; + u8 revision; + u8 reserved[6]; + u64 record_identifier; + guid_t record_identifier_guid; +}; + /* Reset to default packing */ #pragma pack() -- cgit From e78d334a5470ead861590ec83158f3b17bd6c807 Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Mon, 11 May 2020 18:58:49 -0400 Subject: x86/boot: Mark global variables as static Mike Lothian reports that after commit 964124a97b97 ("efi/x86: Remove extra headroom for setup block") gcc 10.1.0 fails with HOSTCC arch/x86/boot/tools/build /usr/lib/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../x86_64-pc-linux-gnu/bin/ld: error: linker defined: multiple definition of '_end' /usr/lib/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccEkW0jM.o: previous definition here collect2: error: ld returned 1 exit status make[1]: *** [scripts/Makefile.host:103: arch/x86/boot/tools/build] Error 1 make: *** [arch/x86/Makefile:303: bzImage] Error 2 The issue is with the _end variable that was added, to hold the end of the compressed kernel from zoffsets.h (ZO__end). The name clashes with the linker-defined _end symbol that indicates the end of the build program itself. Even when there is no compile-time error, this causes build to use memory past the end of its .bss section. To solve this, mark _end as static, and for symmetry, mark the rest of the variables that keep track of symbols from the compressed kernel as static as well. Fixes: 964124a97b97 ("efi/x86: Remove extra headroom for setup block") Reported-by: Mike Lothian Tested-by: Mike Lothian Signed-off-by: Arvind Sankar Link: https://lore.kernel.org/r/20200511225849.1311869-1-nivedita@alum.mit.edu Signed-off-by: Ard Biesheuvel --- arch/x86/boot/tools/build.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c index 8f8c8e386cea..c8b8c1a8d1fc 100644 --- a/arch/x86/boot/tools/build.c +++ b/arch/x86/boot/tools/build.c @@ -59,14 +59,14 @@ u8 buf[SETUP_SECT_MAX*512]; #define PECOFF_COMPAT_RESERVE 0x0 #endif -unsigned long efi32_stub_entry; -unsigned long efi64_stub_entry; -unsigned long efi_pe_entry; -unsigned long efi32_pe_entry; -unsigned long kernel_info; -unsigned long startup_64; -unsigned long _ehead; -unsigned long _end; +static unsigned long efi32_stub_entry; +static unsigned long efi64_stub_entry; +static unsigned long efi_pe_entry; +static unsigned long efi32_pe_entry; +static unsigned long kernel_info; +static unsigned long startup_64; +static unsigned long _ehead; +static unsigned long _end; /*----------------------------------------------------------------------*/ -- cgit From e8da08a088236aff4b51d4ec97c750051f9fe417 Mon Sep 17 00:00:00 2001 From: Benjamin Thiel Date: Sat, 16 May 2020 15:26:47 +0200 Subject: efi: Pull up arch-specific prototype efi_systab_show_arch() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull up arch-specific prototype efi_systab_show_arch() in order to fix a -Wmissing-prototypes warning: arch/x86/platform/efi/efi.c:957:7: warning: no previous prototype for ‘efi_systab_show_arch’ [-Wmissing-prototypes] char *efi_systab_show_arch(char *str) Signed-off-by: Benjamin Thiel Link: https://lore.kernel.org/r/20200516132647.14568-1-b.thiel@posteo.de Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/efi.c | 5 +---- include/linux/efi.h | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 911a2bd0f6b7..4e3055238f31 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -130,11 +130,8 @@ static ssize_t systab_show(struct kobject *kobj, if (efi.smbios != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); - if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86)) { - extern char *efi_systab_show_arch(char *str); - + if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86)) str = efi_systab_show_arch(str); - } return str - buf; } diff --git a/include/linux/efi.h b/include/linux/efi.h index 251f1f783cdf..9430d01c0c3d 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1245,4 +1245,6 @@ struct linux_efi_memreserve { void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size); +char *efi_systab_show_arch(char *str); + #endif /* _LINUX_EFI_H */ -- cgit From b4f1874c62168159fdb419ced4afc77c1b51c475 Mon Sep 17 00:00:00 2001 From: Loïc Yhuel Date: Tue, 12 May 2020 06:01:13 +0200 Subject: tpm: check event log version before reading final events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the boot issues since 5.3 on several Dell models when the TPM is enabled. Depending on the exact grub binary, booting the kernel would freeze early, or just report an error parsing the final events log. We get an event log in the SHA-1 format, which doesn't have a tcg_efi_specid_event_head in the first event, and there is a final events table which doesn't match the crypto agile format. __calc_tpm2_event_size reads bad "count" and "efispecid->num_algs", and either fails, or loops long enough for the machine to be appear frozen. So we now only parse the final events table, which is per the spec always supposed to be in the crypto agile format, when we got a event log in this format. Fixes: c46f3405692de ("tpm: Reserve the TPM final events table") Fixes: 166a2809d65b2 ("tpm: Don't duplicate events from the final event log in the TCG2 log") Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1779611 Signed-off-by: Loïc Yhuel Link: https://lore.kernel.org/r/20200512040113.277768-1-loic.yhuel@gmail.com Reviewed-by: Javier Martinez Canillas Reviewed-by: Jerry Snitselaar Reviewed-by: Matthew Garrett [ardb: warn when final events table is missing or in the wrong format] Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/tpm.c | 5 +++-- drivers/firmware/efi/tpm.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 1d59e103a2e3..e9a684637b70 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -54,7 +54,7 @@ void efi_retrieve_tpm2_eventlog(void) efi_status_t status; efi_physical_addr_t log_location = 0, log_last_entry = 0; struct linux_efi_tpm_eventlog *log_tbl = NULL; - struct efi_tcg2_final_events_table *final_events_table; + struct efi_tcg2_final_events_table *final_events_table = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; efi_bool_t truncated; @@ -127,7 +127,8 @@ void efi_retrieve_tpm2_eventlog(void) * Figure out whether any events have already been logged to the * final events structure, and if so how much space they take up */ - final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID); + if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) + final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID); if (final_events_table && final_events_table->nr_events) { struct tcg_pcr_event2_head *header; int offset; diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c index 31f9f0e369b9..0543fbf60222 100644 --- a/drivers/firmware/efi/tpm.c +++ b/drivers/firmware/efi/tpm.c @@ -62,8 +62,11 @@ int __init efi_tpm_eventlog_init(void) tbl_size = sizeof(*log_tbl) + log_tbl->size; memblock_reserve(efi.tpm_log, tbl_size); - if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || + log_tbl->version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { + pr_warn(FW_BUG "TPM Final Events table missing or invalid\n"); goto out; + } final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl)); -- cgit