[U-Boot] [PATCH v2 1/6] x86: efi_loader: Build EFI memory map per E820 table

On x86 traditional E820 table is used to pass the memory information to kernel. With EFI loader we can build the EFI memory map from it.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
arch/x86/lib/e820.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
diff --git a/arch/x86/lib/e820.c b/arch/x86/lib/e820.c index 9a9ec99..8b34f67 100644 --- a/arch/x86/lib/e820.c +++ b/arch/x86/lib/e820.c @@ -4,6 +4,7 @@ */
#include <common.h> +#include <efi_loader.h> #include <asm/e820.h>
DECLARE_GLOBAL_DATA_PTR; @@ -34,3 +35,41 @@ __weak unsigned int install_e820_map(unsigned int max_entries,
return 4; } + +#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) +void efi_add_known_memory(void) +{ + struct e820_entry e820[E820MAX]; + unsigned int i, num; + u64 start, pages; + int type; + + num = install_e820_map(ARRAY_SIZE(e820), e820); + + for (i = 0; i < num; ++i) { + start = e820[i].addr; + pages = ALIGN(e820[i].size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT; + + switch (e820[i].type) { + case E820_RAM: + type = EFI_CONVENTIONAL_MEMORY; + break; + case E820_RESERVED: + type = EFI_RESERVED_MEMORY_TYPE; + break; + case E820_ACPI: + type = EFI_ACPI_RECLAIM_MEMORY; + break; + case E820_NVS: + type = EFI_ACPI_MEMORY_NVS; + break; + case E820_UNUSABLE: + default: + type = EFI_UNUSABLE_MEMORY; + break; + } + + efi_add_memory_map(start, pages, type, false); + } +} +#endif /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */

At present the number of configuration tables is set to 2. By looking at which tables the Linux EFI stub or iPXE can process, it looks 16 is a reasonable number.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
---
Changes in v2: - new patch "increase number of configuration tables to 16"
lib/efi_loader/efi_boottime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 50d3115..261d66d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -43,7 +43,7 @@ static bool efi_is_direct_boot = true; * In most cases we want to pass an FDT to the payload, so reserve one slot of * config table space for it. The pointer gets populated by do_bootefi_exec(). */ -static struct efi_configuration_table __efi_runtime_data efi_conf_table[2]; +static struct efi_configuration_table __efi_runtime_data efi_conf_table[16];
#ifdef CONFIG_ARM /*

On 06/27/2018 12:16 PM, Bin Meng wrote:
At present the number of configuration tables is set to 2. By looking at which tables the Linux EFI stub or iPXE can process, it looks 16 is a reasonable number.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- new patch "increase number of configuration tables to 16"
lib/efi_loader/efi_boottime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 50d3115..261d66d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -43,7 +43,7 @@ static bool efi_is_direct_boot = true;
- In most cases we want to pass an FDT to the payload, so reserve one slot of
- config table space for it. The pointer gets populated by do_bootefi_exec().
*/ -static struct efi_configuration_table __efi_runtime_data efi_conf_table[2]; +static struct efi_configuration_table __efi_runtime_data efi_conf_table[16];
Alex suggested to make this a pointer to be allocated at runtime. But this will involve further changes like updating the crc32 in the header.
I prefer to change this value to 16 in this patch series to cut down the size of your patch series. Later we can provide a separate patch series that allocates the space from pool, updates crc32, and provides a test case for the table management including a test if the correct event group is being notified.
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
#ifdef CONFIG_ARM /*

ACPI tables can be passed via EFI configuration table to an EFI application. This is only supported on x86 so far.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
cmd/bootefi.c | 5 +++++ include/efi_api.h | 8 ++++++++ include/efi_loader.h | 8 ++++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+) create mode 100644 lib/efi_loader/efi_acpi.c
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index f55a40d..cd755b6 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -61,6 +61,11 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; #endif +#ifdef CONFIG_GENERATE_ACPI_TABLE + ret = efi_acpi_register(); + if (ret != EFI_SUCCESS) + goto out; +#endif #ifdef CONFIG_GENERATE_SMBIOS_TABLE ret = efi_smbios_register(); if (ret != EFI_SUCCESS) diff --git a/include/efi_api.h b/include/efi_api.h index 094be6e..69dcbac 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -286,6 +286,14 @@ struct efi_runtime_services { EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+#define ACPI_TABLE_GUID \ + EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, \ + 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) + +#define ACPI_20_TABLE_GUID \ + EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, \ + 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) + struct efi_configuration_table { efi_guid_t guid; diff --git a/include/efi_loader.h b/include/efi_loader.h index c66252a..d837e7b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -215,6 +215,14 @@ efi_status_t efi_net_register(void); efi_status_t efi_watchdog_register(void); /* Called by bootefi to make SMBIOS tables available */ /** + * efi_acpi_register() - write out ACPI tables + * + * Called by bootefi to make ACPI tables available + * + * @return 0 if OK, -ENOMEM if no memory is available for the tables + */ +efi_status_t efi_acpi_register(void); +/** * efi_smbios_register() - write out SMBIOS tables * * Called by bootefi to make SMBIOS tables available diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index c6046e3..d6402c4 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -22,4 +22,5 @@ obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o obj-$(CONFIG_NET) += efi_net.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o diff --git a/lib/efi_loader/efi_acpi.c b/lib/efi_loader/efi_acpi.c new file mode 100644 index 0000000..b09292c --- /dev/null +++ b/lib/efi_loader/efi_acpi.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI application ACPI tables support + * + * Copyright (C) 2018, Bin Meng bmeng.cn@gmail.com + */ + +#include <common.h> +#include <efi_loader.h> +#include <asm/acpi_table.h> + +static const efi_guid_t acpi_guid = ACPI_20_TABLE_GUID; + +/* + * Install the ACPI table as a configuration table. + * + * @return status code + */ +efi_status_t efi_acpi_register(void) +{ + /* Map within the low 32 bits, to allow for 32bit ACPI tables */ + u64 acpi = U32_MAX; + efi_status_t ret; + + /* Reserve 64kiB page for ACPI */ + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + EFI_RUNTIME_SERVICES_DATA, 16, &acpi); + if (ret != EFI_SUCCESS) + return ret; + + /* + * Generate ACPI tables - we know that efi_allocate_pages() returns + * a 4k-aligned address, so it is safe to assume that + * write_acpi_tables() will write the table at that address. + */ + assert(!(acpi & 0xf)); + write_acpi_tables(acpi); + + /* And expose them to our EFI payload */ + return efi_install_configuration_table(&acpi_guid, + (void *)(uintptr_t)acpi); +}

On 06/27/2018 12:16 PM, Bin Meng wrote:
ACPI tables can be passed via EFI configuration table to an EFI application. This is only supported on x86 so far.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2: None
cmd/bootefi.c | 5 +++++ include/efi_api.h | 8 ++++++++ include/efi_loader.h | 8 ++++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+) create mode 100644 lib/efi_loader/efi_acpi.c
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index f55a40d..cd755b6 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -61,6 +61,11 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; #endif +#ifdef CONFIG_GENERATE_ACPI_TABLE
- ret = efi_acpi_register();
- if (ret != EFI_SUCCESS)
goto out;
+#endif #ifdef CONFIG_GENERATE_SMBIOS_TABLE ret = efi_smbios_register(); if (ret != EFI_SUCCESS) diff --git a/include/efi_api.h b/include/efi_api.h index 094be6e..69dcbac 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -286,6 +286,14 @@ struct efi_runtime_services { EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+#define ACPI_TABLE_GUID \
- EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, \
0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
This value is not used actually. The UEFI 2.7 spec mandates: "ACPI 2.0 or newer tables should use EFI_ACPI_TABLE_GUID" (which is identical to EFI_ACPI_20_TABLE_GUID).
As this value is deprecated and unused I would rather remove it.
+#define ACPI_20_TABLE_GUID \
- EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, \
0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81)
The UEFI standard calls this value EFI_ACPI_20_TABLE_GUID or EFI_ACPI_TABLE_GUID. Why should we give it another name in our code?
Best regards
Heinrich

Output ACPI configuration table if it exists.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
---
Changes in v2: - new patch "output ACPI configuration table"
lib/efi_loader/helloworld.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 046b46a..df7c82b 100644 --- a/lib/efi_loader/helloworld.c +++ b/lib/efi_loader/helloworld.c @@ -14,6 +14,7 @@
static const efi_guid_t loaded_image_guid = LOADED_IMAGE_GUID; static const efi_guid_t fdt_guid = EFI_FDT_GUID; +static const efi_guid_t acpi_guid = ACPI_20_TABLE_GUID; static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
static int hw_memcmp(const void *buf1, const void *buf2, size_t length) @@ -79,6 +80,9 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid, sizeof(efi_guid_t))) con_out->output_string(con_out, L"Have device tree\n"); + if (!hw_memcmp(&systable->tables[i].guid, &acpi_guid, + sizeof(efi_guid_t))) + con_out->output_string(con_out, L"Have ACPI table\n"); if (!hw_memcmp(&systable->tables[i].guid, &smbios_guid, sizeof(efi_guid_t))) con_out->output_string(con_out, L"Have SMBIOS table\n");

On 06/27/2018 12:16 PM, Bin Meng wrote:
Output ACPI configuration table if it exists.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- new patch "output ACPI configuration table"
lib/efi_loader/helloworld.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 046b46a..df7c82b 100644 --- a/lib/efi_loader/helloworld.c +++ b/lib/efi_loader/helloworld.c @@ -14,6 +14,7 @@
static const efi_guid_t loaded_image_guid = LOADED_IMAGE_GUID; static const efi_guid_t fdt_guid = EFI_FDT_GUID; +static const efi_guid_t acpi_guid = ACPI_20_TABLE_GUID;
The UEFI standard calls the constant EFI_ACPI_20_TABLE_GUID or EFI_ACPI_TABLE_GUID. You will have to adjust this line if you adjust the include.
static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
static int hw_memcmp(const void *buf1, const void *buf2, size_t length) @@ -79,6 +80,9 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid, sizeof(efi_guid_t))) con_out->output_string(con_out, L"Have device tree\n");
if (!hw_memcmp(&systable->tables[i].guid, &acpi_guid,
sizeof(efi_guid_t)))
con_out->output_string(con_out, L"Have ACPI table\n");
As the guid refers to ACPI 2.0 (in contrast to ACPI_TABLE_GUID) I would prefer L"Have ACPI 2.0 table\n".
Best regards
Heinrich
if (!hw_memcmp(&systable->tables[i].guid, &smbios_guid, sizeof(efi_guid_t))) con_out->output_string(con_out, L"Have SMBIOS table\n");

CONFIG_EFI_LOADER is fully supported on x86 now.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Alexander Graf agraf@suse.de ---
Changes in v2: None
doc/README.x86 | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/doc/README.x86 b/doc/README.x86 index 9f657df..9162ea1 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -1136,9 +1136,34 @@ EFI Support U-Boot supports booting as a 32-bit or 64-bit EFI payload, e.g. with UEFI. This is enabled with CONFIG_EFI_STUB to boot from both 32-bit and 64-bit UEFI BIOS. U-Boot can also run as an EFI application, with CONFIG_EFI_APP. -The CONFIG_EFI_LOADER option, where U-Booot provides an EFI environment to +The CONFIG_EFI_LOADER option, where U-Boot provides an EFI environment to the kernel (i.e. replaces UEFI completely but provides the same EFI run-time -services) is not currently supported on x86. +services) is supported too. For example, we can even use 'bootefi' command +to load a 'u-boot-payload.efi', see below test logs on QEMU. + + => load ide 0 3000000 u-boot-payload.efi + 489787 bytes read in 138 ms (3.4 MiB/s) + => bootefi 3000000 + Scanning disk ide.blk#0... + Found 2 disks + WARNING: booting without device tree + ## Starting EFI application at 03000000 ... + U-Boot EFI Payload + + + U-Boot 2018.07-rc2 (Jun 23 2018 - 17:12:58 +0800) + + CPU: x86_64, vendor AMD, device 663h + DRAM: 2 GiB + MMC: + Video: 1024x768x32 + Model: EFI x86 Payload + Net: e1000: 52:54:00:12:34:56 + + Warning: e1000#0 using MAC address from ROM + eth0: e1000#0 + No controllers found + Hit any key to stop autoboot: 0
See README.u-boot_on_efi and README.uefi for details of EFI support in U-Boot.

This updates the doc to mention chain-loading an x86 kernel via 'bootefi' command, along with several typos fix.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Alexander Graf agraf@suse.de
---
Changes in v2: None
doc/README.vxworks | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/doc/README.vxworks b/doc/README.vxworks index 1aa8e44..3e08711 100644 --- a/doc/README.vxworks +++ b/doc/README.vxworks @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ # # Copyright (C) 2013, Miao Yan miao.yan@windriver.com -# Copyright (C) 2015, Bin Meng bmeng.cn@gmail.com +# Copyright (C) 2015-2018, Bin Meng bmeng.cn@gmail.com
VxWorks Support =============== @@ -15,10 +15,13 @@ For booting old kernels (6.9.x) on PowerPC and ARM, and all kernel versions on other architectures, 'bootvx' shall be used. For booting VxWorks 7 kernels on PowerPC and ARM, 'bootm' shall be used.
+With CONFIG_EFI_LOADER option, it's possible to chain load a VxWorks x86 kernel +via the UEFI boot loader application for VxWorks loaded by 'bootefi' command. + VxWorks 7 on PowerPC and ARM --------------------------- -From VxWorks 7, VxWorks starts adopting device tree as its hardware decription -mechansim (for PowerPC and ARM), thus requiring boot interface changes. +From VxWorks 7, VxWorks starts adopting device tree as its hardware description +mechanism (for PowerPC and ARM), thus requiring boot interface changes. This section will describe the new interface.
For PowerPC, the calling convention of the new VxWorks entry point conforms to @@ -53,6 +56,9 @@ gatewayip, hostname, othbootargs. When using 'bootm', just define "bootargs" in the environment and U-Boot will handle bootline fix up for the kernel dtb automatically.
+When using 'bootefi' to chain load an x86 kernel, the UEFI boot loader +application for VxWorks takes care of the kernel bootline preparation. + Serial console -------------- It's very common that VxWorks BSPs configure a different baud rate for the @@ -63,9 +69,9 @@ look like VxWorks hangs somewhere as nothing outputs on the serial console.
x86-specific information ------------------------ -Before loading an x86 kernel, one additional environment variable need to be -provided. This is "vx_phys_mem_base", which represent the physical memory -base address of VxWorks. +Before direct loading an x86 kernel via 'bootvx', one additional environment +variable need to be provided. This is "vx_phys_mem_base", which represent the +physical memory base address of VxWorks.
Check VxWorks kernel configuration to look for LOCAL_MEM_LOCAL_ADRS. For VxWorks 7, this is normally a virtual address and you need find out its
participants (2)
-
Bin Meng
-
Heinrich Schuchardt