From a641e36fdbf09a6db046e9afe7531e9c623e70d3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 1 Sep 2022 22:23:47 +0200 Subject: [PATCH 1/7] efi_loader: printing UEFI revision in helloworld.efi We need to support multiple digits in the parts of the UEFI verision number. E.g. EFI_SPECIFICATION_VERSION = (123 << 16) | 456 must be printed as 123.45.6 Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- lib/efi_loader/helloworld.c | 64 ++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 10666dc0f2..d565f32745 100644 --- a/lib/efi_loader/helloworld.c +++ b/lib/efi_loader/helloworld.c @@ -29,24 +29,66 @@ static struct efi_system_table *systable; static struct efi_boot_services *boottime; static struct efi_simple_text_output_protocol *con_out; +/* + * Print an unsigned 32bit value as decimal number to an u16 string + * + * @value: value to be printed + * @buf: pointer to buffer address + * on return position of terminating zero word + */ +static void uint2dec(u32 value, u16 **buf) +{ + u16 *pos = *buf; + int i; + u16 c; + u64 f; + + /* + * Increment by .5 and multiply with + * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC + * to move the first digit to bit 60-63. + */ + f = 0x225C17D0; + f += (0x9B5A52DULL * value) >> 28; + f += 0x44B82FA0ULL * value; + + for (i = 0; i < 10; ++i) { + /* Write current digit */ + c = f >> 60; + if (c || pos != *buf) + *pos++ = c + '0'; + /* Eliminate current digit */ + f &= 0xfffffffffffffff; + /* Get next digit */ + f *= 0xaULL; + } + if (pos == *buf) + *pos++ = '0'; + *pos = 0; + *buf = pos; +} + /** * print_uefi_revision() - print UEFI revision number */ static void print_uefi_revision(void) { - u16 rev[] = u"0.0.0"; + u16 rev[13] = {0}; + u16 *buf = rev; + u16 digit; - rev[0] = (systable->hdr.revision >> 16) + '0'; - rev[4] = systable->hdr.revision & 0xffff; - for (; rev[4] >= 10;) { - rev[4] -= 10; - ++rev[2]; + uint2dec(systable->hdr.revision >> 16, &buf); + *buf++ = '.'; + uint2dec(systable->hdr.revision & 0xffff, &buf); + + /* Minor revision is only to be shown if non-zero */ + digit = *--buf; + if (digit == '0') { + *buf = 0; + } else { + *buf++ = '.'; + *buf = digit; } - /* Third digit is only to be shown if non-zero */ - if (rev[4]) - rev[4] += '0'; - else - rev[3] = 0; con_out->output_string(con_out, u"Running on UEFI "); con_out->output_string(con_out, rev); From 0b7b56d7d7446ab24d2b8da2236ec44ea7edf2cc Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 1 Sep 2022 23:30:09 +0200 Subject: [PATCH 2/7] efi_loader: compliance Simple Text Input Ex Protocol We cannot expect the buffers passed to the input protocols to be zero filled. If only modifier keys are pressed, we have to return EFI_NOT_READY but we still have to fill the key structure. Signed-off-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- lib/efi_loader/efi_console.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 3164fd484e..1fcaabe1c4 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -987,6 +987,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex( efi_cin_check(); if (!key_available) { + memset(key_data, 0, sizeof(struct efi_key_data)); ret = EFI_NOT_READY; goto out; } From e053a144ca85ffbc8649bc3e170c408b42f92536 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 2 Sep 2022 00:49:12 +0200 Subject: [PATCH 3/7] efi_loader: support CTRL+\ - CTRL+_ In the extended text input protocol support input of control letters 0x1c - 0x1f. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Reviewed-by: Ilias Apalodimas --- lib/efi_loader/efi_console.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 1fcaabe1c4..ee9dc6bbd8 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -994,6 +994,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex( /* * CTRL+A - CTRL+Z have to be signaled as a - z. * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z. + * CTRL+\ - CTRL+_ have to be signaled as \ - _. */ switch (next_key.key.unicode_char) { case 0x01 ... 0x07: @@ -1006,6 +1007,9 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex( next_key.key.unicode_char += 0x40; else next_key.key.unicode_char += 0x60; + break; + case 0x1c ... 0x1f: + next_key.key.unicode_char += 0x40; } *key_data = next_key; key_available = false; From 2b7a6e013fe9c4f8c8ed29d79f6757f8c482dc72 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 2 Sep 2022 02:46:37 +0200 Subject: [PATCH 4/7] efi_selftest: on sandbox use host specific assembly The selftest checking the handling of exceptions in UEFI binaries is using assembly to provide an undefined instruction. On the sandbox the correct form of the instruction depends on the host architecture. Signed-off-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- lib/efi_selftest/efi_selftest_miniapp_exception.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_miniapp_exception.c b/lib/efi_selftest/efi_selftest_miniapp_exception.c index 79f9a67859..a9ad381001 100644 --- a/lib/efi_selftest/efi_selftest_miniapp_exception.c +++ b/lib/efi_selftest/efi_selftest_miniapp_exception.c @@ -9,6 +9,7 @@ #include #include +#include /* * Entry point of the EFI application. @@ -33,10 +34,16 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, asm volatile (".word 0xe7f7defb\n"); #elif defined(CONFIG_RISCV) asm volatile (".word 0xffffffff\n"); -#elif defined(CONFIG_SANDBOX) - asm volatile (".word 0xffffffff\n"); #elif defined(CONFIG_X86) asm volatile (".word 0xffff\n"); +#elif defined(CONFIG_SANDBOX) +#if (HOST_ARCH == HOST_ARCH_ARM || HOST_ARCH == HOST_ARCH_AARCH64) + asm volatile (".word 0xe7f7defb\n"); +#elif (HOST_ARCH == HOST_ARCH_RISCV32 || HOST_ARCH == HOST_ARCH_RISCV64) + asm volatile (".word 0xffffffff\n"); +#elif (HOST_ARCH == HOST_ARCH_X86 || HOST_ARCH == HOST_ARCH_X86_64) + asm volatile (".word 0xffff\n"); +#endif #endif con_out->output_string(con_out, u"Exception not triggered.\n"); return EFI_ABORTED; From 6b92c1735205eef308a9e33ec90330a3e6d27fc3 Mon Sep 17 00:00:00 2001 From: Jose Marinho Date: Thu, 23 Dec 2021 14:51:07 +0000 Subject: [PATCH 5/7] efi: Create ECPT table The ECPT table will be included in the UEFI specification 2.9+. The ECPT table was introduced in UEFI following the code-first path. The acceptance ticket can be viewed at: https://bugzilla.tianocore.org/show_bug.cgi?id=3591 The Conformance Profiles table is a UEFI configuration table that contains GUID of the UEFI profiles that the UEFI implementation conforms with. The ECPT table is created when CONFIG_EFI_ECPT=y. The config is set by default. Signed-off-by: Jose Marinho Reviewed-by: Heinrich Schuchardt --- include/efi_api.h | 12 +++++++ include/efi_loader.h | 7 +++++ lib/efi_loader/Kconfig | 6 ++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_conformance.c | 54 ++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 ++++ lib/uuid.c | 4 +++ 7 files changed, 90 insertions(+) create mode 100644 lib/efi_loader/efi_conformance.c diff --git a/include/efi_api.h b/include/efi_api.h index 83c01085fd..58934bd0d5 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -226,6 +226,18 @@ enum efi_reset_type { EFI_GUID(0x6dcbd5ed, 0xe82d, 0x4c44, 0xbd, 0xa1, \ 0x71, 0x94, 0x19, 0x9a, 0xd9, 0x2a) +#define EFI_CONFORMANCE_PROFILES_TABLE_GUID \ + EFI_GUID(0x36122546, 0xf7ef, 0x4c8f, 0xbd, 0x9b, \ + 0xeb, 0x85, 0x25, 0xb5, 0x0c, 0x0b) + +#define EFI_CONFORMANCE_PROFILES_TABLE_VERSION 1 + +struct efi_conformance_profiles_table { + u16 version; + u16 number_of_profiles; + efi_guid_t conformance_profiles[]; +} __packed; + struct efi_capsule_header { efi_guid_t capsule_guid; u32 header_size; diff --git a/include/efi_loader.h b/include/efi_loader.h index 9611aec2de..545ba06d94 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -1052,6 +1052,13 @@ extern u8 num_image_type_guids; */ efi_status_t efi_esrt_register(void); +/** + * efi_ecpt_register() - Install the ECPT system table. + * + * Return: status code + */ +efi_status_t efi_ecpt_register(void); + /** * efi_esrt_populate() - Populates the ESRT entries from the FMP instances * present in the system. diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 5cfff8c56b..2b2e9ae03b 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -385,6 +385,12 @@ config EFI_ESRT help Enabling this option creates the ESRT UEFI system table. +config EFI_ECPT + bool "Enable the UEFI ECPT generation" + default y + help + Enabling this option created the ECPT UEFI table. + config EFI_RISCV_BOOT_PROTOCOL bool "RISCV_EFI_BOOT_PROTOCOL support" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index f54c244c32..e187d2a914 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o +obj-$(CONFIG_EFI_ECPT) += efi_conformance.o EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) diff --git a/lib/efi_loader/efi_conformance.c b/lib/efi_loader/efi_conformance.c new file mode 100644 index 0000000000..385d76c793 --- /dev/null +++ b/lib/efi_loader/efi_conformance.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * EFI conformance profile table + * + * Copyright (C) 2022 Arm Ltd. + */ + +#include +#include +#include +#include +#include + +static const efi_guid_t efi_ecpt_guid = EFI_CONFORMANCE_PROFILES_TABLE_GUID; + +/** + * efi_ecpt_register() - Install the ECPT system table. + * + * Return: status code + */ +efi_status_t efi_ecpt_register(void) +{ + int num_entries = 0; + struct efi_conformance_profiles_table *ecpt; + efi_status_t ret; + size_t ecpt_size; + + ecpt_size = num_entries * sizeof(efi_guid_t) + + sizeof(struct efi_conformance_profiles_table); + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, ecpt_size, + (void **)&ecpt); + + if (ret != EFI_SUCCESS) { + log_err("Out of memory\n"); + + return ret; + } + + ecpt->version = EFI_CONFORMANCE_PROFILES_TABLE_VERSION; + ecpt->number_of_profiles = num_entries; + + /* Install the ECPT in the system configuration table. */ + ret = efi_install_configuration_table(&efi_ecpt_guid, (void *)ecpt); + if (ret != EFI_SUCCESS) { + log_err("Failed to install ECPT\n"); + efi_free_pool(ecpt); + + return ret; + } + + log_debug("ECPT created\n"); + + return EFI_SUCCESS; +} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 45a9a1d500..c633fcd91e 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -274,6 +274,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; + if (IS_ENABLED(CONFIG_EFI_ECPT)) { + ret = efi_ecpt_register(); + if (ret != EFI_SUCCESS) + goto out; + } + if (IS_ENABLED(CONFIG_EFI_ESRT)) { ret = efi_esrt_register(); if (ret != EFI_SUCCESS) diff --git a/lib/uuid.c b/lib/uuid.c index 284f8113ff..465e1ac38f 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -220,6 +220,10 @@ static const struct { "TCG2 Final Events Table", EFI_TCG2_FINAL_EVENTS_TABLE_GUID, }, + { + "EFI Conformance Profiles Table", + EFI_CONFORMANCE_PROFILES_TABLE_GUID, + }, #ifdef CONFIG_EFI_RISCV_BOOT_PROTOCOL { "RISC-V Boot", From 648a8dcb39306ebd32353d6c503ac3b69e064190 Mon Sep 17 00:00:00 2001 From: Jose Marinho Date: Fri, 17 Dec 2021 12:55:05 +0000 Subject: [PATCH 6/7] efi: ECPT add EBBRv2.0 conformance profile Display the EBBRv2.0 conformance in the ECPT table. The EBBRv2.0 conformance profile is set in the ECPT if CONFIG_EFI_EBBR_2_0_CONFORMANCE=y. Signed-off-by: Jose Marinho Add dependencies for CONFIG_EFI_EBBR_2_0_CONFORMANCE. Enable the setting by default. Reviewed-by: Heinrich Schuchardt --- include/efi_api.h | 4 ++++ lib/efi_loader/Kconfig | 11 +++++++++++ lib/efi_loader/efi_conformance.c | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/include/efi_api.h b/include/efi_api.h index 58934bd0d5..9bb0d44ac8 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -232,6 +232,10 @@ enum efi_reset_type { #define EFI_CONFORMANCE_PROFILES_TABLE_VERSION 1 +#define EFI_CONFORMANCE_PROFILE_EBBR_2_0_GUID \ + EFI_GUID(0xcce33c35, 0x74ac, 0x4087, 0xbc, 0xe7, \ + 0x8b, 0x29, 0xb0, 0x2e, 0xeb, 0x27) + struct efi_conformance_profiles_table { u16 version; u16 number_of_profiles; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 2b2e9ae03b..b8fb2701a7 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -391,6 +391,17 @@ config EFI_ECPT help Enabling this option created the ECPT UEFI table. +config EFI_EBBR_2_0_CONFORMANCE + bool "Add the EBBRv2.0 conformance entry to the ECPT table" + depends on EFI_ECPT + depends on EFI_LOADER_HII + depends on EFI_RISCV_BOOT_PROTOCOL || !RISCV + depends on EFI_RNG_PROTOCOL || !DM_RNG + depends on EFI_UNICODE_COLLATION_PROTOCOL2 + default y + help + Enabling this option adds the EBBRv2.0 conformance entry to the ECPT UEFI table. + config EFI_RISCV_BOOT_PROTOCOL bool "RISCV_EFI_BOOT_PROTOCOL support" default y diff --git a/lib/efi_loader/efi_conformance.c b/lib/efi_loader/efi_conformance.c index 385d76c793..a49aae9249 100644 --- a/lib/efi_loader/efi_conformance.c +++ b/lib/efi_loader/efi_conformance.c @@ -12,6 +12,8 @@ #include static const efi_guid_t efi_ecpt_guid = EFI_CONFORMANCE_PROFILES_TABLE_GUID; +static const efi_guid_t efi_ebbr_2_0_guid = + EFI_CONFORMANCE_PROFILE_EBBR_2_0_GUID; /** * efi_ecpt_register() - Install the ECPT system table. @@ -36,6 +38,10 @@ efi_status_t efi_ecpt_register(void) return ret; } + if (CONFIG_IS_ENABLED(EFI_EBBR_2_0_CONFORMANCE)) + guidcpy(&ecpt->conformance_profiles[num_entries++], + &efi_ebbr_2_0_guid); + ecpt->version = EFI_CONFORMANCE_PROFILES_TABLE_VERSION; ecpt->number_of_profiles = num_entries; From fbc04c0dab139c12ed61500fac3cc204009e8c54 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 23 Feb 2022 09:06:24 +0100 Subject: [PATCH 7/7] efi_loader: fix display of NVMe EUI-64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UEFI specification 2.9A requires to display the EUI-64 "in hexadecimal format with byte 7 first (i.e., on the left) and byte 0 last". This is in contrast to what the NVMe specification wants. But it is what EDK II has been implementing. Here is an example with the patch applied: qemu-system-aarch64 -machine virt -cpu cortex-a72 -nographic \ -bios denx/u-boot.bin \ -device nvme,id=nvme1,serial=9ff81223 \ -device nvme-ns,bus=nvme1,drive=nvme1n0,eui64=0x123456789ABCDEF0 \ -drive file=arm64.img,if=none,format=raw,id=nvme1n0 => nvme scan => efidebug devices Device Path ==================== /VenHw(…)/NVMe(0x1,f0-de-bc-9a-78-56-34-12) Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_device_path_to_text.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 6c428ee061..9062058ac2 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -190,13 +190,14 @@ static char *dp_msging(char *s, struct efi_device_path *dp) struct efi_device_path_nvme *ndp = (struct efi_device_path_nvme *)dp; u32 ns_id; - int i; memcpy(&ns_id, &ndp->ns_id, sizeof(ns_id)); s += sprintf(s, "NVMe(0x%x,", ns_id); - for (i = 0; i < sizeof(ndp->eui64); ++i) + + /* Display byte 7 first, byte 0 last */ + for (int i = 0; i < 8; ++i) s += sprintf(s, "%s%02x", i ? "-" : "", - ndp->eui64[i]); + ndp->eui64[i ^ 7]); s += sprintf(s, ")"); break;