[U-Boot] [PATCH v2 00/47] Add support for running U-Boot as an EFI payload/application

This series allows U-Boot to be build as an EFI payload so that U-Boot can be started on almost any x86 platform that supports EFI. This is implemented as a stub which EFI can load plus a payload that is copied to RAM. The payload contains a normal U-Boot binary image and device tree.
This allows U-Boot to run on platforms that have EFI support but are not supported natively by U-Boot. It also allows testing and fiddling with the board using U-Boots memory display and other commands.
In addition, U-Boot can be built as an EFI application. This should work regardless of the board type since it only relies on EFI services. However only 32-bit EFI is supported in this case. Again it can be used to snoop around the platform.
A README provides further details of how this series operates.
Changes in v2: - Add -no-red-zone for 64-bit only - Add ALIGN() before .dynamic in the linker script - Add a blank line before return in the _relocate() function - Add a comment about special handling for backspace - Add a comment about the REX prefix - Add a comment as to where LDFLAGS_EFI is used - Add a comment as to why .hash has to be first in the linker script - Add a comment as to why debug_uart_init() is empty - Add a comment as to why interrupt_init() must be skipped for EFI - Add a comment as to why the AFLAGS_REMOVE_.. lines are needed - Add a comment as to why we must call exit_boot_services() twice - Add a comment as to why we only allocate pages below 4GB - Add a comment as to why we use global_data_ptr - Add a marker for the cold reset entry point - Add a note that bootm does not work when running as an EFI app - Add comments as to why we need efi_memset(), efi_putc(), efi_puts() - Add descriptor bits for the base and limit - Add new patch to reserve the top 16 flag bits for architecture-specific use - Avoid useless u64 cast on EFI_RUNTIME_SERVICES_SIGNATURE - Change 'link script' to 'linker script' - Check the GDT selector's base and limit against the target address - Correct the return code to avoid a test failure - Drop . = 0x0; - Drop \n\t at the end of a one-line asm statement - Drop __packed from struct efi_device_path - Drop a left-over debug printf() - Drop duplicate OBJCOPYFLAGS_EFI - Drop no-red-zone as it is not needed for i386 - Drop patch "Add a link script entry for U-Boot as a payload" - Drop the REX prefix in 32-bit mode - Drop unnecessary .section .text - Drop unnecessary SYS_CAR_ADDR/SIZE Kconfig options - Drop unneeded include of asm/ptrace.h - Drop unused DECLARE_GLOBAL_DATA_INIT - Drop unused DECLARE_GLOBAL_DATA_PTR - Drop unused board_eth_init() - Drop use of CONFIG_X86_64 since we don't support a 64-bit EFI application yet - Explain in a comment how the debug UART is implemented for the EFI app - Fix 'command problem' typo - it should say 'command prompt' - Fix 'withU-Boot.' typo - Fix _aligned() typo - Fix a few comment typos - Fix alignment of region index field in the output - Fix comment style - Fix efi_mem_desc_VERSION typo - Fix indenting in board/emulation/qemu-x86/Kconfig - Fix indenting in board/intel/minnowmax/Kconfig - Fix mention of CHAR16 which should be wchar_t - Fix missing struct comments - Fix reference to elf_ia32_efi instead of elf_x86_64_efi - Fix spacing around operators - Fix text alignment in Kconfig files - Follow existing file conventions for type definitions - Merge in Bin's implementation of adding a U-Boot payload with objcopy - Move 64-bit crt0 to a later patch - Move EFI CAR settings to arch/x86/lib/efi/Kconfig - Move crt0 and reloc files into arch/x86/lib/efi/ - Move the 64-bit crt and reloc code into this patch - Move the 64-bit efi.h additions into this patch - Move the 64-bit payload code to a later patch - Move the crt and reloc files into arch/x86/lib/efi/ - Move this patch to before the EFI start-up code patch - Output the region index in decimal - Refer to FS as F segment register instead of frame segment register - Remove CONFIG_SYS_EARLY_PCI_INIT and CONFIG_PCI_PNP - Remove KEEP in the EFI linker script since garbage collection is not enabled - Remove comment about reset_cpu() returning to EFI in the stub - Remove extraneous '+' in comment - Remove superfluous Kconfig options - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Rename CONFIG_DEBUG_UART_EFI to CONFIG_DEBUG_EFI_CONSOLE - Rename EFI debug UART to EFI_CONSOLE - Rename GDT_4GB to GDT_4KB - Rename ImageBase to image_base - Reorder this patch to after CONFIG_EFI_APP is introduced - Replace 'Coreboot' with 'coreboot' - Replace serial_s5p with serial_efi - Return early in copy_uboot_to_ram() and clear_bbs() when relocation disabled - Reword the efi_putc() unicode comment to make more sense - Set text_base to 0 to avoid possible compiler warning - Update based on the elf.h changes - Use "efi,app" instead of "efi,payload" for the compatible string - Use CONFIG_EFI_APP instead of CONFIG_ARCH_EFI - Use SPDX for the EFI start and relocation code - Use image_base instead of ImageBase - Use one-line comments when appropriate - Use reserved instead of __reserved in struct efi_boot_services - Use the now-defined top 16-bits of the global_data flags - Use toolchain instead of tool chain - Use u-boot-app.efi instead of u-boot.efi - Zero BIST when starting from EFI/coreboot
Ben Stoltz (6): efi: Avoid using non-existent text base efi: Drop CONFIG_SYS_TEXT_BASE for EFI x86: Set up toolchain flags for running as EFI application x86: Add support for U-Boot as an EFI application x86: Add EFI board code x86: Add definitions for the x86-efi board and plumb it in
Simon Glass (41): Support removing default assembler flags dm: core: Check for empty list in uclass_find_device() dm: serial: Correct logic in serial_find_console_or_panic() elf: Add a few definitions for 64-bit relocation Add a way to skip relocation Allow objcopy to work without filling gaps with 0xff Bring in __aligned_u64 and friends to linux/types.h x86: Add various minor tidy-ups to the 32-bit startup code x86: Use CR0 constants in CPU init Reserve the top 16 flag bits for architecture-specific use x86: Tidy up global_data flags x86: Drop unused copy_fdt_to_ram() x86: Tidy up the 64-bit calling code x86: Add some missing global_data declarations in files that use gd x86: Tidy up a few minor issues with interrupts pci: Use debug() instead of DEBUGF() in pci_auto.c pci: Fix up code for CONFIG_PCI_ENUM_ONLY x86: Allow use of global_data with EFI efi: Add start-up library code efi: Display the correct initcall pre-relocation values efi: Add a serial driver efi: Support building a u-boot.efi executable x86: Support skipping relocation for EFI x86: Add asm/elf.h for x86-specific ELF definitions x86: dts: Add a device tree file for EFI x86: Allow relocation code to build without text base x86: Add relocation and link script for a 64-bit EFI application efi: Add support for loading U-Boot through an EFI stub x86: Support building the EFI stub x86: Add an enum for some commonly-used GDT bits x86: Add a way to call 32-bit code from 64-bit mode efi: Add 64-bit payload support x86: Add support for passing tables into U-Boot efi: Add functions for decoding the EFI tables efi: Add a command to display the memory map x86: Handle running as EFI payload x86: Add helper code for running from EFI x86: baytrail: Support operation as an EFI payload x86: qemu: Support operation as an EFI payload x86: Gracefully disable the vesa driver when running from EFI efi: Add a README to explain how things work
Kconfig | 1 + Makefile | 34 +++- arch/x86/Kconfig | 10 + arch/x86/Makefile | 2 + arch/x86/config.mk | 48 ++++- arch/x86/cpu/Makefile | 7 + arch/x86/cpu/baytrail/Kconfig | 2 +- arch/x86/cpu/baytrail/cpu.c | 2 + arch/x86/cpu/baytrail/valleyview.c | 2 + arch/x86/cpu/call32.S | 64 ++++++ arch/x86/cpu/call64.S | 4 +- arch/x86/cpu/cpu.c | 23 ++- arch/x86/cpu/efi/Makefile | 8 + arch/x86/cpu/efi/efi.c | 42 ++++ arch/x86/cpu/efi/elf_ia32_efi.lds | 94 +++++++++ arch/x86/cpu/efi/elf_x86_64_efi.lds | 83 ++++++++ arch/x86/cpu/efi/sdram.c | 29 +++ arch/x86/cpu/interrupts.c | 25 ++- arch/x86/cpu/mp_init.c | 2 + arch/x86/cpu/qemu/Makefile | 5 +- arch/x86/cpu/qemu/qemu.c | 2 + arch/x86/cpu/start.S | 73 ++++--- arch/x86/dts/Makefile | 1 + arch/x86/dts/efi.dts | 22 +++ arch/x86/include/asm/arch-efi/gpio.h | 10 + arch/x86/include/asm/cpu.h | 27 +++ arch/x86/include/asm/elf.h | 46 +++++ arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- arch/x86/include/asm/global_data.h | 16 +- arch/x86/include/asm/relocate.h | 1 - arch/x86/include/asm/types.h | 5 +- arch/x86/lib/Makefile | 3 +- arch/x86/lib/asm-offsets.c | 1 + arch/x86/lib/bootm.c | 7 + arch/x86/lib/efi/Kconfig | 11 ++ arch/x86/lib/efi/Makefile | 27 +++ arch/x86/lib/efi/car.S | 10 + arch/x86/lib/efi/crt0-efi-ia32.S | 52 +++++ arch/x86/lib/efi/crt0-efi-x86_64.S | 51 +++++ arch/x86/lib/efi/efi.c | 151 ++++++++++++++ arch/x86/lib/efi/reloc_ia32.c | 72 +++++++ arch/x86/lib/efi/reloc_x86_64.c | 66 +++++++ arch/x86/lib/fsp/fsp_common.c | 2 + arch/x86/lib/lpc-uclass.c | 2 + arch/x86/lib/pch-uclass.c | 2 + arch/x86/lib/relocate.c | 41 ++-- board/efi/Kconfig | 19 ++ board/efi/efi-x86/Kconfig | 15 ++ board/efi/efi-x86/MAINTAINERS | 6 + board/efi/efi-x86/Makefile | 7 + board/efi/efi-x86/efi.c | 18 ++ board/emulation/qemu-x86/Kconfig | 5 +- board/intel/minnowmax/Kconfig | 5 +- common/Makefile | 1 + common/board_f.c | 14 +- common/cmd_efi.c | 257 ++++++++++++++++++++++++ config.mk | 2 - configs/efi-x86_defconfig | 16 ++ doc/README.efi | 237 ++++++++++++++++++++++ drivers/core/uclass.c | 2 + drivers/gpio/intel_ich6_gpio.c | 2 + drivers/pci/pci_auto.c | 52 ++--- drivers/serial/Kconfig | 9 + drivers/serial/Makefile | 1 + drivers/serial/serial-uclass.c | 2 +- drivers/serial/serial_efi.c | 157 +++++++++++++++ drivers/video/vesa_fb.c | 8 + include/asm-generic/global_data.h | 3 +- include/common.h | 7 + include/configs/efi-x86.h | 34 ++++ include/efi.h | 368 +++++++++++++++++++++++++++++++++++ include/efi_api.h | 244 +++++++++++++++++++++++ include/elf.h | 26 +++ include/linux/types.h | 6 +- include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 54 +++++ lib/efi/Makefile | 17 ++ lib/efi/efi.c | 101 ++++++++++ lib/efi/efi_app.c | 139 +++++++++++++ lib/efi/efi_info.c | 47 +++++ lib/efi/efi_stub.c | 363 ++++++++++++++++++++++++++++++++++ lib/initcall.c | 4 + scripts/Makefile.lib | 3 +- 85 files changed, 3329 insertions(+), 181 deletions(-) create mode 100644 arch/x86/cpu/call32.S create mode 100644 arch/x86/cpu/efi/Makefile create mode 100644 arch/x86/cpu/efi/efi.c create mode 100644 arch/x86/cpu/efi/elf_ia32_efi.lds create mode 100644 arch/x86/cpu/efi/elf_x86_64_efi.lds create mode 100644 arch/x86/cpu/efi/sdram.c create mode 100644 arch/x86/dts/efi.dts create mode 100644 arch/x86/include/asm/arch-efi/gpio.h create mode 100644 arch/x86/include/asm/elf.h create mode 100644 arch/x86/lib/efi/Kconfig create mode 100644 arch/x86/lib/efi/Makefile create mode 100644 arch/x86/lib/efi/car.S create mode 100644 arch/x86/lib/efi/crt0-efi-ia32.S create mode 100644 arch/x86/lib/efi/crt0-efi-x86_64.S create mode 100644 arch/x86/lib/efi/efi.c create mode 100644 arch/x86/lib/efi/reloc_ia32.c create mode 100644 arch/x86/lib/efi/reloc_x86_64.c create mode 100644 board/efi/Kconfig create mode 100644 board/efi/efi-x86/Kconfig create mode 100644 board/efi/efi-x86/MAINTAINERS create mode 100644 board/efi/efi-x86/Makefile create mode 100644 board/efi/efi-x86/efi.c create mode 100644 common/cmd_efi.c create mode 100644 configs/efi-x86_defconfig create mode 100644 doc/README.efi create mode 100644 drivers/serial/serial_efi.c create mode 100644 include/configs/efi-x86.h create mode 100644 include/efi.h create mode 100644 include/efi_api.h create mode 100644 lib/efi/Kconfig create mode 100644 lib/efi/Makefile create mode 100644 lib/efi/efi.c create mode 100644 lib/efi/efi_app.c create mode 100644 lib/efi/efi_info.c create mode 100644 lib/efi/efi_stub.c

The CFLAGS_REMOVE_<file> feature allows default C compiler flags to be removed for particular files. Add the same feature for assembler, using AFLAGS_REMOVE_<file>.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
scripts/Makefile.lib | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 84915d7..1c949fc 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -104,8 +104,9 @@ modname_flags = $(if $(filter 1,$(words $(modname))),\ orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \ $(ccflags-y) $(CFLAGS_$(basetarget).o) _c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) -_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \ +orig_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \ $(asflags-y) $(AFLAGS_$(basetarget).o) +_a_flags = $(filter-out $(AFLAGS_REMOVE_$(basetarget).o), $(orig_a_flags)) _cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
#

On Fri, Jul 31, 2015 at 09:31:18AM -0600, Simon Glass wrote:
The CFLAGS_REMOVE_<file> feature allows default C compiler flags to be removed for particular files. Add the same feature for assembler, using AFLAGS_REMOVE_<file>.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Reviewed-by: Tom Rini trini@konsulko.com

On 2 August 2015 at 09:55, Tom Rini trini@konsulko.com wrote:
On Fri, Jul 31, 2015 at 09:31:18AM -0600, Simon Glass wrote:
The CFLAGS_REMOVE_<file> feature allows default C compiler flags to be removed for particular files. Add the same feature for assembler, using AFLAGS_REMOVE_<file>.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Reviewed-by: Tom Rini trini@konsulko.com
Applied to u-boot-x86.

This function needs to check the list has entries before traversing it. Fix this bug.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Correct the return code to avoid a test failure
drivers/core/uclass.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index aba9880..ffe6995 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -153,6 +153,8 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) ret = uclass_get(id, &uc); if (ret) return ret; + if (list_empty(&uc->dev_head)) + return -ENODEV;
list_for_each_entry(dev, &uc->dev_head, uclass_node) { if (!index--) {

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This function needs to check the list has entries before traversing it. Fix this bug.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Correct the return code to avoid a test failure
drivers/core/uclass.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index aba9880..ffe6995 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -153,6 +153,8 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) ret = uclass_get(id, &uc); if (ret) return ret;
if (list_empty(&uc->dev_head))
return -ENODEV; list_for_each_entry(dev, &uc->dev_head, uclass_node) { if (!index--) {
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 2 August 2015 at 06:57, Bin Meng bmeng.cn@gmail.com wrote:
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This function needs to check the list has entries before traversing it. Fix this bug.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Correct the return code to avoid a test failure
drivers/core/uclass.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index aba9880..ffe6995 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -153,6 +153,8 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) ret = uclass_get(id, &uc); if (ret) return ret;
if (list_empty(&uc->dev_head))
return -ENODEV; list_for_each_entry(dev, &uc->dev_head, uclass_node) { if (!index--) {
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.

In a final attempt to find a console UART this function uses the first first available serial device. However the check for a valid device is inverted.
This code is only executed when there is in fact no serial UART, but at present it can fail to reach the panic_str() call in this case, and start trying to use a non-existent UART.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
drivers/serial/serial-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 815fec3..bbc366b 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -71,7 +71,7 @@ static void serial_find_console_or_panic(void) #endif if (!uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) || !uclass_get_device(UCLASS_SERIAL, INDEX, &dev) || - (!uclass_first_device(UCLASS_SERIAL, &dev) || dev)) { + (!uclass_first_device(UCLASS_SERIAL, &dev) && dev)) { gd->cur_serial_dev = dev; return; }

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
In a final attempt to find a console UART this function uses the first first available serial device. However the check for a valid device is inverted.
This code is only executed when there is in fact no serial UART, but at present it can fail to reach the panic_str() call in this case, and start trying to use a non-existent UART.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/serial/serial-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 815fec3..bbc366b 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -71,7 +71,7 @@ static void serial_find_console_or_panic(void) #endif if (!uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) || !uclass_get_device(UCLASS_SERIAL, INDEX, &dev) ||
(!uclass_first_device(UCLASS_SERIAL, &dev) || dev)) {
(!uclass_first_device(UCLASS_SERIAL, &dev) && dev)) { gd->cur_serial_dev = dev; return; }
-- 2.5.0.rc2.392.g76e840b
Applied to u-boot-x86.

Provide the types necessary to relocate 64-bit images.
Signed-off-by: Simon Glass sjg@chromium.org
---
Changes in v2: - Follow existing file conventions for type definitions
include/elf.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/include/elf.h b/include/elf.h index 63d9341..a35e085 100644 --- a/include/elf.h +++ b/include/elf.h @@ -28,6 +28,16 @@ typedef int32_t Elf32_Sword; /* Signed large integer */ typedef uint32_t Elf32_Word; /* Unsigned large integer */ typedef uint16_t Elf32_Half; /* Unsigned medium integer */
+/* 64-bit ELF base types. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + /* e_ident[] identification indexes */ #define EI_MAG0 0 /* file ID */ #define EI_MAG1 1 /* file ID */ @@ -379,6 +389,11 @@ typedef struct Elf32_Sword r_addend; } Elf32_Rela;
+typedef struct { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + /* Extract relocation info - r_info */ #define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((unsigned char) (i)) @@ -431,6 +446,17 @@ typedef struct
extern Elf32_Dyn _DYNAMIC[];
+typedef struct { + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + /* Dynamic Array Tags - d_tag */ #define DT_NULL 0 /* marks end of _DYNAMIC array */ #define DT_NEEDED 1 /* string table offset of needed lib */

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Provide the types necessary to relocate 64-bit images.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Follow existing file conventions for type definitions
include/elf.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/include/elf.h b/include/elf.h index 63d9341..a35e085 100644 --- a/include/elf.h +++ b/include/elf.h @@ -28,6 +28,16 @@ typedef int32_t Elf32_Sword; /* Signed large integer */ typedef uint32_t Elf32_Word; /* Unsigned large integer */ typedef uint16_t Elf32_Half; /* Unsigned medium integer */
+/* 64-bit ELF base types. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword;
/* e_ident[] identification indexes */ #define EI_MAG0 0 /* file ID */ #define EI_MAG1 1 /* file ID */ @@ -379,6 +389,11 @@ typedef struct Elf32_Sword r_addend; } Elf32_Rela;
+typedef struct {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
+} Elf64_Rel;
/* Extract relocation info - r_info */ #define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((unsigned char) (i)) @@ -431,6 +446,17 @@ typedef struct
extern Elf32_Dyn _DYNAMIC[];
+typedef struct {
Elf64_Sxword d_tag; /* entry tag value */
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
+} Elf64_Dyn;
+#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
/* Dynamic Array Tags - d_tag */ #define DT_NULL 0 /* marks end of _DYNAMIC array */
#define DT_NEEDED 1 /* string table offset of needed lib */
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 2 August 2015 at 07:00, Bin Meng bmeng.cn@gmail.com wrote:
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Provide the types necessary to relocate 64-bit images.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Follow existing file conventions for type definitions
include/elf.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
[snip]
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.

When running U-Boot as an EFI application we cannot relocate since we do not have relocation information. U-Boot has already been relocated to a suitable address.
Add a global_data flag to control skipping relocation.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
common/board_f.c | 7 +++++++ include/asm-generic/global_data.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/common/board_f.c b/common/board_f.c index 21be26f..5e09c5f 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -664,6 +664,11 @@ static int reloc_fdt(void)
static int setup_reloc(void) { + if (gd->flags & GD_FLG_SKIP_RELOC) { + debug("Skipping relocation due to flag\n"); + return 0; + } + #ifdef CONFIG_SYS_TEXT_BASE gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; #ifdef CONFIG_M68K @@ -689,6 +694,8 @@ static int setup_reloc(void)
static int jump_to_copy(void) { + if (gd->flags & GD_FLG_SKIP_RELOC) + return 0; /* * x86 is special, but in a nice way. It uses a trampoline which * enables the dcache if possible. diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 7ef3e25..cb2ec08 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -117,5 +117,6 @@ typedef struct global_data { #define GD_FLG_SERIAL_READY 0x00100 /* Pre-reloc serial console ready */ #define GD_FLG_FULL_MALLOC_INIT 0x00200 /* Full malloc() is ready */ #define GD_FLG_SPL_INIT 0x00400 /* spl_init() has been called */ +#define GD_FLG_SKIP_RELOC 0x00800 /* Don't relocate */
#endif /* __ASM_GENERIC_GBL_DATA_H */

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
When running U-Boot as an EFI application we cannot relocate since we do not have relocation information. U-Boot has already been relocated to a suitable address.
Add a global_data flag to control skipping relocation.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
common/board_f.c | 7 +++++++ include/asm-generic/global_data.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/common/board_f.c b/common/board_f.c index 21be26f..5e09c5f 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -664,6 +664,11 @@ static int reloc_fdt(void)
static int setup_reloc(void) {
if (gd->flags & GD_FLG_SKIP_RELOC) {
debug("Skipping relocation due to flag\n");
return 0;
}
#ifdef CONFIG_SYS_TEXT_BASE gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; #ifdef CONFIG_M68K @@ -689,6 +694,8 @@ static int setup_reloc(void)
static int jump_to_copy(void) {
if (gd->flags & GD_FLG_SKIP_RELOC)
return 0; /* * x86 is special, but in a nice way. It uses a trampoline which * enables the dcache if possible.
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 7ef3e25..cb2ec08 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -117,5 +117,6 @@ typedef struct global_data { #define GD_FLG_SERIAL_READY 0x00100 /* Pre-reloc serial console ready */ #define GD_FLG_FULL_MALLOC_INIT 0x00200 /* Full malloc() is ready */ #define GD_FLG_SPL_INIT 0x00400 /* spl_init() has been called */ +#define GD_FLG_SKIP_RELOC 0x00800 /* Don't relocate */
#endif /* __ASM_GENERIC_GBL_DATA_H */
Looks like you missed reloc_fdt() [1] in the v2.
[1]: http://lists.denx.de/pipermail/u-boot/2015-July/221374.html
Regards, Bin

This is currently done for all targets, since 0xff is the default erased value for most flash devices. In some cases this is not what we want (e.g. for EFI images) so provide a command to do a vanilla objcopy.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
Makefile | 8 +++++++- config.mk | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile index 394ed09..2a3119e 100644 --- a/Makefile +++ b/Makefile @@ -776,8 +776,14 @@ ifneq ($(CONFIG_SYS_TEXT_BASE),) LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE) endif
+# Normally we fill empty space with 0xff quiet_cmd_objcopy = OBJCOPY $@ -cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ +cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \ + $(OBJCOPYFLAGS_$(@F)) $< $@ + +# Provide a version which does not do this, for use by EFI +quiet_cmd_zobjcopy = OBJCOPY $@ +cmd_zobjcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
quiet_cmd_mkimage = MKIMAGE $@ cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \ diff --git a/config.mk b/config.mk index 6282919..b77d589 100644 --- a/config.mk +++ b/config.mk @@ -73,8 +73,6 @@ endif
RELFLAGS := $(PLATFORM_RELFLAGS)
-OBJCOPYFLAGS += --gap-fill=0xff - PLATFORM_CPPFLAGS += $(RELFLAGS) PLATFORM_CPPFLAGS += -pipe

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
This is currently done for all targets, since 0xff is the default erased value for most flash devices. In some cases this is not what we want (e.g. for EFI images) so provide a command to do a vanilla objcopy.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
Makefile | 8 +++++++- config.mk | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-)
Applied to u-boot-x86.

These will be used for efi.h both for U-Boot running as an EFI application and as a payload. They come from Linux 4.1.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Fix _aligned() typo
include/linux/types.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/include/linux/types.h b/include/linux/types.h index c9a8d9a..6f75be4 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -113,6 +113,11 @@ typedef __s64 int64_t;
#endif /* __KERNEL_STRICT_NAMES */
+/* this is a special 64bit data type that is 8-byte aligned */ +#define aligned_u64 __u64 __aligned(8) +#define aligned_be64 __be64 __aligned(8) +#define aligned_le64 __le64 __aligned(8) + #if defined(CONFIG_USE_STDINT) && defined(__INT64_TYPE__) typedef __UINT64_TYPE__ uint64_t; typedef __UINT64_TYPE__ u_int64_t; @@ -145,7 +150,6 @@ typedef __u64 __bitwise __be64; typedef __u16 __bitwise __sum16; typedef __u32 __bitwise __wsum;
- typedef unsigned __bitwise__ gfp_t;
struct ustat {

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
These will be used for efi.h both for U-Boot running as an EFI application and as a payload. They come from Linux 4.1.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Fix _aligned() typo
include/linux/types.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/include/linux/types.h b/include/linux/types.h index c9a8d9a..6f75be4 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -113,6 +113,11 @@ typedef __s64 int64_t;
#endif /* __KERNEL_STRICT_NAMES */
+/* this is a special 64bit data type that is 8-byte aligned */ +#define aligned_u64 __u64 __aligned(8) +#define aligned_be64 __be64 __aligned(8) +#define aligned_le64 __le64 __aligned(8)
#if defined(CONFIG_USE_STDINT) && defined(__INT64_TYPE__) typedef __UINT64_TYPE__ uint64_t; typedef __UINT64_TYPE__ u_int64_t; @@ -145,7 +150,6 @@ typedef __u64 __bitwise __be64; typedef __u16 __bitwise __sum16; typedef __u32 __bitwise __wsum;
typedef unsigned __bitwise__ gfp_t;
struct ustat {
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 2 August 2015 at 07:07, Bin Meng bmeng.cn@gmail.com wrote:
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
These will be used for efi.h both for U-Boot running as an EFI application and as a payload. They come from Linux 4.1.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Fix _aligned() typo
include/linux/types.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
[snip]
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.

Fix a typo, improve some comments and add a little more detail in some cases.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
arch/x86/cpu/start.S | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 00e585e..7ef8b88 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -25,11 +25,11 @@ .globl _x86boot_start _x86boot_start: /* - * This is the fail safe 32-bit bootstrap entry point. The - * following code is not executed from a cold-reset (actually, a - * lot of it is, but from real-mode after cold reset. It is - * repeated here to put the board into a state as close to cold - * reset as necessary) + * This is the fail-safe 32-bit bootstrap entry point. + * + * This code is used when booting from another boot loader like + * coreboot or EFI. So we repeat some of the same init found in + * start16. */ cli cld @@ -45,15 +45,15 @@ _x86boot_start: jmp 1f _start: /* - * This is the 32-bit cold-reset entry point. Initialize %bx to 0 - * in case we're preceeded by some sort of boot stub. + * This is the 32-bit cold-reset entry point, coming from start16. + * Set %bx to 0 to indicate this. */ movw $GD_FLG_COLD_BOOT, %bx 1: /* Save BIST */ movl %eax, %ebp
- /* Load the segement registes to match the gdt loaded in start16.S */ + /* Load the segement registers to match the GDT loaded in start16.S */ movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax movw %ax, %fs movw %ax, %ds @@ -64,7 +64,11 @@ _start: /* Clear the interrupt vectors */ lidt blank_idt_ptr
- /* Early platform init (setup gpio, etc ) */ + /* + * Critical early platform init - generally not used, we prefer init + * to happen later when we have a console, in case something goes + * wrong. + */ jmp early_board_init .globl early_board_init_ret early_board_init_ret: @@ -79,7 +83,7 @@ car_init_ret: * We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM, * or fully initialised SDRAM - we really don't care which) * starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack - * and early malloc area. The MRC requires some space at the top. + * and early malloc() area. The MRC requires some space at the top. * * Stack grows down from top of CAR. We have: * @@ -97,7 +101,7 @@ car_init_ret: #endif #else /* - * When we get here after car_init, esp points to a temporary stack + * When we get here after car_init(), esp points to a temporary stack * and esi holds the HOB list address returned by the FSP. */ #endif @@ -137,17 +141,18 @@ skip_hob: movl %esp, %ecx
#if defined(CONFIG_SYS_MALLOC_F_LEN) + /* Set up the pre-relocation malloc pool */ subl $CONFIG_SYS_MALLOC_F_LEN, %esp movl %eax, %edx addl $GD_MALLOC_BASE, %edx movl %esp, (%edx) #endif - /* Store BIST */ + /* Store BIST into global_data */ movl %eax, %edx addl $GD_BIST, %edx movl %ebp, (%edx)
- /* Set second parameter to setup_gdt */ + /* Set second parameter to setup_gdt() */ movl %ecx, %edx
/* Setup global descriptor table so gd->xyz works */ @@ -157,7 +162,7 @@ skip_hob: post_code(POST_START_DONE) xorl %eax, %eax
- /* Enter, U-boot! */ + /* Enter, U-Boot! */ call board_init_f
/* indicate (lack of) progress */ @@ -184,13 +189,13 @@ board_init_f_r_trampoline: /* Align global data to 16-byte boundary */ andl $0xfffffff0, %esp
- /* Setup first parameter to memcpy (and setup_gdt) */ + /* Setup first parameter to memcpy() and setup_gdt() */ movl %esp, %eax
- /* Setup second parameter to memcpy */ + /* Setup second parameter to memcpy() */ fs movl 0, %edx
- /* Set third parameter to memcpy */ + /* Set third parameter to memcpy() */ movl $GENERATED_GBL_DATA_SIZE, %ecx
/* Copy global data from CAR to SDRAM stack */ @@ -202,7 +207,7 @@ board_init_f_r_trampoline: /* Align global descriptor table to 16-byte boundary */ andl $0xfffffff0, %esp
- /* Set second parameter to setup_gdt */ + /* Set second parameter to setup_gdt() */ movl %esp, %edx
/* Setup global descriptor table so gd->xyz works */ @@ -216,7 +221,7 @@ board_init_f_r_trampoline:
call car_uninit 1: - /* Re-enter U-Boot by calling board_init_f_r */ + /* Re-enter U-Boot by calling board_init_f_r() */ call board_init_f_r
die: @@ -230,9 +235,10 @@ blank_idt_ptr:
.p2align 2 /* force 4-byte alignment */
+ /* Add a multiboot header so U-Boot can be loaded by GRUB2 */ multiboot_header: /* magic */ - .long 0x1BADB002 + .long 0x1badb002 /* flags */ .long (1 << 16) /* checksum */

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
Fix a typo, improve some comments and add a little more detail in some cases.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/cpu/start.S | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-)
Applied to u-boot-x86.

We should use these constants where possible.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
arch/x86/cpu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index b9134cf..d233a45 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -456,7 +456,7 @@ void x86_full_reset(void)
int dcache_status(void) { - return !(read_cr0() & 0x40000000); + return !(read_cr0() & X86_CR0_CD); }
/* Define these functions to allow ehch-hcd to function */

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
We should use these constants where possible.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/cpu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-x86.

Add a convention that the generic global_data only occupy the bottom 16 bits of the flags word, so that there is less chance of a conflict. At present the x86 flags conflict.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add new patch to reserve the top 16 flag bits for architecture-specific use
include/asm-generic/global_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index cb2ec08..2155265 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -104,7 +104,7 @@ typedef struct global_data { #endif
/* - * Global Data Flags + * Global Data Flags - the top 16 bits are reserved for arch-specific flags */ #define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ #define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add a convention that the generic global_data only occupy the bottom 16 bits of the flags word, so that there is less chance of a conflict. At present the x86 flags conflict.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch to reserve the top 16 flag bits for architecture-specific use
include/asm-generic/global_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index cb2ec08..2155265 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -104,7 +104,7 @@ typedef struct global_data { #endif
/*
- Global Data Flags
*/
- Global Data Flags - the top 16 bits are reserved for arch-specific flags
#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 2 August 2015 at 07:09, Bin Meng bmeng.cn@gmail.com wrote:
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add a convention that the generic global_data only occupy the bottom 16 bits of the flags word, so that there is less chance of a conflict. At present the x86 flags conflict.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch to reserve the top 16 flag bits for architecture-specific use
include/asm-generic/global_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index cb2ec08..2155265 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -104,7 +104,7 @@ typedef struct global_data { #endif
/*
- Global Data Flags
*/
- Global Data Flags - the top 16 bits are reserved for arch-specific flags
#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.

These flags now overlap some global ones. Adjust the x86-specific flags to avoid this. Since this requires a change to the start.S code, add a way for tools to find the 32-bit cold reset entry point. Previously this was at a fixed offset.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a marker for the cold reset entry point - Use the now-defined top 16-bits of the global_data flags
arch/x86/cpu/start.S | 8 ++++++-- arch/x86/include/asm/global_data.h | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 7ef8b88..9b2584d 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -41,14 +41,18 @@ _x86boot_start: wbinvd
/* Tell 32-bit code it is being entered from an in-RAM copy */ - movw $GD_FLG_WARM_BOOT, %bx + movl $GD_FLG_WARM_BOOT, %ebx jmp 1f + + /* Add a way for tools to discover the _start entry point */ + .align 4 + .long 0x12345678 _start: /* * This is the 32-bit cold-reset entry point, coming from start16. * Set %bx to 0 to indicate this. */ - movw $GD_FLG_COLD_BOOT, %bx + movl $GD_FLG_COLD_BOOT, %ebx 1: /* Save BIST */ movl %eax, %ebp diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4d9eac6..3db9a4c 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -87,14 +87,14 @@ static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void)
#define gd get_fs_gd_ptr()
+#define DECLARE_GLOBAL_DATA_PTR + #endif
/* * Our private Global Data Flags */ -#define GD_FLG_COLD_BOOT 0x00100 /* Cold Boot */ -#define GD_FLG_WARM_BOOT 0x00200 /* Warm Boot */ - -#define DECLARE_GLOBAL_DATA_PTR +#define GD_FLG_COLD_BOOT 0x10000 /* Cold Boot */ +#define GD_FLG_WARM_BOOT 0x20000 /* Warm Boot */
#endif /* __ASM_GBL_DATA_H */

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
These flags now overlap some global ones. Adjust the x86-specific flags to avoid this. Since this requires a change to the start.S code, add a way for tools to find the 32-bit cold reset entry point. Previously this was at a fixed offset.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see nits below.
Changes in v2:
- Add a marker for the cold reset entry point
- Use the now-defined top 16-bits of the global_data flags
arch/x86/cpu/start.S | 8 ++++++-- arch/x86/include/asm/global_data.h | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 7ef8b88..9b2584d 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -41,14 +41,18 @@ _x86boot_start: wbinvd
/* Tell 32-bit code it is being entered from an in-RAM copy */
movw $GD_FLG_WARM_BOOT, %bx
movl $GD_FLG_WARM_BOOT, %ebx jmp 1f
/* Add a way for tools to discover the _start entry point */
.align 4
.long 0x12345678
_start: /* * This is the 32-bit cold-reset entry point, coming from start16. * Set %bx to 0 to indicate this.
Nits: the comment is not correct. (%bx -> %ebx, 0 -> GD_FLG_COLD_BOOT)
*/
movw $GD_FLG_COLD_BOOT, %bx
movl $GD_FLG_COLD_BOOT, %ebx
1: /* Save BIST */ movl %eax, %ebp diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4d9eac6..3db9a4c 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -87,14 +87,14 @@ static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void)
#define gd get_fs_gd_ptr()
+#define DECLARE_GLOBAL_DATA_PTR
#endif
/*
- Our private Global Data Flags
*/ -#define GD_FLG_COLD_BOOT 0x00100 /* Cold Boot */ -#define GD_FLG_WARM_BOOT 0x00200 /* Warm Boot */
-#define DECLARE_GLOBAL_DATA_PTR +#define GD_FLG_COLD_BOOT 0x10000 /* Cold Boot */ +#define GD_FLG_WARM_BOOT 0x20000 /* Warm Boot */
#endif /* __ASM_GBL_DATA_H */
Regards, Bin

On 2 August 2015 at 07:17, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
These flags now overlap some global ones. Adjust the x86-specific flags to avoid this. Since this requires a change to the start.S code, add a way for tools to find the 32-bit cold reset entry point. Previously this was at a fixed offset.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see nits below.
Fixed nits and
Applied to u-boot-x86.

This is now handled by generic U-Boot code so we do not need an x86 version. It is no-longer called, so remove it.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
arch/x86/include/asm/relocate.h | 1 - arch/x86/lib/relocate.c | 18 ------------------ 2 files changed, 19 deletions(-)
diff --git a/arch/x86/include/asm/relocate.h b/arch/x86/include/asm/relocate.h index eb186b9..cff3abc 100644 --- a/arch/x86/include/asm/relocate.h +++ b/arch/x86/include/asm/relocate.h @@ -11,7 +11,6 @@ #include <common.h>
int copy_uboot_to_ram(void); -int copy_fdt_to_ram(void); int clear_bss(void); int do_elf_reloc_fixups(void);
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index b33586b..1a62142 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -17,8 +17,6 @@
#include <common.h> #include <inttypes.h> -#include <libfdt.h> -#include <malloc.h> #include <asm/u-boot-x86.h> #include <asm/relocate.h> #include <asm/sections.h> @@ -35,22 +33,6 @@ int copy_uboot_to_ram(void) return 0; }
-int copy_fdt_to_ram(void) -{ - if (gd->new_fdt) { - ulong fdt_size; - - fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32); - - memcpy(gd->new_fdt, gd->fdt_blob, fdt_size); - debug("Relocated fdt from %p to %p, size %lx\n", - gd->fdt_blob, gd->new_fdt, fdt_size); - gd->fdt_blob = gd->new_fdt; - } - - return 0; -} - int clear_bss(void) { ulong dst_addr = (ulong)&__bss_start + gd->reloc_off;

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
This is now handled by generic U-Boot code so we do not need an x86 version. It is no-longer called, so remove it.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/include/asm/relocate.h | 1 - arch/x86/lib/relocate.c | 18 ------------------ 2 files changed, 19 deletions(-)
Applied to u-boot-x86.

The GDT works but technically the length is incorrect. Fix this and add a comment.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
arch/x86/cpu/call64.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/cpu/call64.S b/arch/x86/cpu/call64.S index 74dd5a8..08dc473 100644 --- a/arch/x86/cpu/call64.S +++ b/arch/x86/cpu/call64.S @@ -82,8 +82,8 @@ lret_target:
.data gdt: - .word gdt_end - gdt - .long gdt + .word gdt_end - gdt - 1 + .long gdt /* Fixed up by code above */ .word 0 .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x00af9a000000ffff /* __KERNEL_CS */

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
The GDT works but technically the length is incorrect. Fix this and add a comment.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/cpu/call64.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Applied to u-boot-x86.

Some files use global_data but don't declare it. Fix this.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
arch/x86/cpu/mp_init.c | 2 ++ arch/x86/lib/bootm.c | 2 ++ arch/x86/lib/fsp/fsp_common.c | 2 ++ arch/x86/lib/lpc-uclass.c | 2 ++ arch/x86/lib/pch-uclass.c | 2 ++ drivers/gpio/intel_ich6_gpio.c | 2 ++ 6 files changed, 12 insertions(+)
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index e686b28..3294a50 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -24,6 +24,8 @@ #include <dm/uclass-internal.h> #include <linux/linkage.h>
+DECLARE_GLOBAL_DATA_PTR; + /* Total CPUs include BSP */ static int num_cpus;
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 86030cf..445ee6e 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -22,6 +22,8 @@ #include <asm/arch/timestamp.h> #endif
+DECLARE_GLOBAL_DATA_PTR; + #define COMMAND_LINE_OFFSET 0x9000
/* diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 5b25632..c585710 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -11,6 +11,8 @@ #include <asm/processor.h> #include <asm/fsp/fsp_support.h>
+DECLARE_GLOBAL_DATA_PTR; + int print_cpuinfo(void) { post_code(POST_CPU_INFO); diff --git a/arch/x86/lib/lpc-uclass.c b/arch/x86/lib/lpc-uclass.c index 6aeb4d4..c6e8f73 100644 --- a/arch/x86/lib/lpc-uclass.c +++ b/arch/x86/lib/lpc-uclass.c @@ -9,6 +9,8 @@ #include <dm.h> #include <dm/root.h>
+DECLARE_GLOBAL_DATA_PTR; + static int lpc_uclass_post_bind(struct udevice *bus) { /* diff --git a/arch/x86/lib/pch-uclass.c b/arch/x86/lib/pch-uclass.c index d1082e1..20dfa81 100644 --- a/arch/x86/lib/pch-uclass.c +++ b/arch/x86/lib/pch-uclass.c @@ -9,6 +9,8 @@ #include <dm.h> #include <dm/root.h>
+DECLARE_GLOBAL_DATA_PTR; + static int pch_uclass_post_bind(struct udevice *bus) { /* diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c index 8a108f3..cb408a4 100644 --- a/drivers/gpio/intel_ich6_gpio.c +++ b/drivers/gpio/intel_ich6_gpio.c @@ -35,6 +35,8 @@ #include <asm/io.h> #include <asm/pci.h>
+DECLARE_GLOBAL_DATA_PTR; + #define GPIO_PER_BANK 32
struct ich6_bank_priv {

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
Some files use global_data but don't declare it. Fix this.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/cpu/mp_init.c | 2 ++ arch/x86/lib/bootm.c | 2 ++ arch/x86/lib/fsp/fsp_common.c | 2 ++ arch/x86/lib/lpc-uclass.c | 2 ++ arch/x86/lib/pch-uclass.c | 2 ++ drivers/gpio/intel_ich6_gpio.c | 2 ++ 6 files changed, 12 insertions(+)
Applied to u-boot-x86.

Fix a typo, remove an unused field and make sure to use existing #define constants instead of open-coded values.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
arch/x86/cpu/interrupts.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 853c82f..3a9c2d4 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -19,6 +19,7 @@ #include <asm/processor-flags.h> #include <linux/compiler.h> #include <asm/msr.h> +#include <asm/processor.h> #include <asm/u-boot-x86.h> #include <asm/i8259.h>
@@ -46,7 +47,7 @@ static char *exceptions[] = { "Invalid TSS", "Segment Not Present", "Stack Segment Fault", - "Gerneral Protection", + "General Protection", "Page Fault", "Reserved", "x87 FPU Floating-Point Error", @@ -165,7 +166,6 @@ struct idt_entry { struct desc_ptr { unsigned short size; unsigned long address; - unsigned short segment; } __packed;
struct idt_entry idt[256] __aligned(16); @@ -202,14 +202,13 @@ int cpu_init_interrupts(void) for (i = 0; i < 256; i++) { idt[i].access = 0x8e; idt[i].res = 0; - idt[i].selector = 0x10; + idt[i].selector = X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE; set_vector(i, irq_entry); irq_entry += irq_entry_size; }
- idt_ptr.size = 256 * 8; + idt_ptr.size = 256 * 8 - 1; idt_ptr.address = (unsigned long) idt; - idt_ptr.segment = 0x18;
load_idt(&idt_ptr);

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Fix a typo, remove an unused field and make sure to use existing #define constants instead of open-coded values.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
arch/x86/cpu/interrupts.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 853c82f..3a9c2d4 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -19,6 +19,7 @@ #include <asm/processor-flags.h> #include <linux/compiler.h> #include <asm/msr.h> +#include <asm/processor.h> #include <asm/u-boot-x86.h> #include <asm/i8259.h>
@@ -46,7 +47,7 @@ static char *exceptions[] = { "Invalid TSS", "Segment Not Present", "Stack Segment Fault",
"Gerneral Protection",
"General Protection", "Page Fault", "Reserved", "x87 FPU Floating-Point Error",
@@ -165,7 +166,6 @@ struct idt_entry { struct desc_ptr { unsigned short size; unsigned long address;
unsigned short segment;
} __packed;
struct idt_entry idt[256] __aligned(16); @@ -202,14 +202,13 @@ int cpu_init_interrupts(void) for (i = 0; i < 256; i++) { idt[i].access = 0x8e; idt[i].res = 0;
idt[i].selector = 0x10;
idt[i].selector = X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE; set_vector(i, irq_entry); irq_entry += irq_entry_size; }
idt_ptr.size = 256 * 8;
idt_ptr.size = 256 * 8 - 1; idt_ptr.address = (unsigned long) idt;
idt_ptr.segment = 0x18; load_idt(&idt_ptr);
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 2 August 2015 at 07:19, Bin Meng bmeng.cn@gmail.com wrote:
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Fix a typo, remove an unused field and make sure to use existing #define constants instead of open-coded values.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
arch/x86/cpu/interrupts.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 853c82f..3a9c2d4 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -19,6 +19,7 @@ #include <asm/processor-flags.h> #include <linux/compiler.h> #include <asm/msr.h> +#include <asm/processor.h> #include <asm/u-boot-x86.h> #include <asm/i8259.h>
@@ -46,7 +47,7 @@ static char *exceptions[] = { "Invalid TSS", "Segment Not Present", "Stack Segment Fault",
"Gerneral Protection",
"General Protection", "Page Fault", "Reserved", "x87 FPU Floating-Point Error",
@@ -165,7 +166,6 @@ struct idt_entry { struct desc_ptr { unsigned short size; unsigned long address;
unsigned short segment;
} __packed;
struct idt_entry idt[256] __aligned(16); @@ -202,14 +202,13 @@ int cpu_init_interrupts(void) for (i = 0; i < 256; i++) { idt[i].access = 0x8e; idt[i].res = 0;
idt[i].selector = 0x10;
idt[i].selector = X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE; set_vector(i, irq_entry); irq_entry += irq_entry_size; }
idt_ptr.size = 256 * 8;
idt_ptr.size = 256 * 8 - 1; idt_ptr.address = (unsigned long) idt;
idt_ptr.segment = 0x18; load_idt(&idt_ptr);
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.

This file does not need its own way of doing debug(). Clean it up to use the new way.
Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Pavel Machek pavel@denx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
drivers/pci/pci_auto.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index a7af8cb..7ff282b 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -14,12 +14,6 @@ #include <errno.h> #include <pci.h>
-#ifdef DEBUG -#define DEBUGF(x...) printf(x) -#else -#define DEBUGF(x...) -#endif /* DEBUG */ - /* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */ #ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8 @@ -50,20 +44,21 @@ int pciauto_region_allocate(struct pci_region *res, pci_size_t size, pci_addr_t addr;
if (!res) { - DEBUGF("No resource"); + debug("No resource"); goto error; }
addr = ((res->bus_lower - 1) | (size - 1)) + 1;
if (addr - res->bus_start + size > res->size) { - DEBUGF("No room in resource"); + debug("No room in resource"); goto error; }
res->bus_lower = addr + size;
- DEBUGF("address=0x%llx bus_lower=0x%llx", (u64)addr, (u64)res->bus_lower); + debug("address=0x%llx bus_lower=0x%llx", (unsigned long long)addr, + (unsigned long long)res->bus_lower);
*bar = addr; return 0; @@ -122,7 +117,8 @@ void pciauto_setup_device(struct pci_controller *hose, bar_res = io; #endif
- DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", bar_nr, (u64)bar_size); + debug("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", + bar_nr, (unsigned long long)bar_size); } else { if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { @@ -152,7 +148,8 @@ void pciauto_setup_device(struct pci_controller *hose, bar_res = mem; #endif
- DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%llx, ", bar_nr, (u64)bar_size); + debug("PCI Autoconfig: BAR %d, Mem, size=0x%llx, ", + bar_nr, (unsigned long long)bar_size); }
#ifndef CONFIG_PCI_ENUM_ONLY @@ -179,7 +176,7 @@ void pciauto_setup_device(struct pci_controller *hose, cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ? PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
- DEBUGF("\n"); + debug("\n");
bar_nr++; } @@ -193,14 +190,15 @@ void pciauto_setup_device(struct pci_controller *hose, pci_hose_read_config_dword(hose, dev, rom_addr, &bar_response); if (bar_response) { bar_size = -(bar_response & ~1); - DEBUGF("PCI Autoconfig: ROM, size=%#x, ", bar_size); + debug("PCI Autoconfig: ROM, size=%#x, ", + (unsigned int)bar_size); if (pciauto_region_allocate(mem, bar_size, &bar_value) == 0) { pci_hose_write_config_dword(hose, dev, rom_addr, bar_value); } cmdstat |= PCI_COMMAND_MEMORY; - DEBUGF("\n"); + debug("\n"); } }
@@ -411,7 +409,7 @@ void pciauto_config_init(struct pci_controller *hose) if (hose->pci_mem) { pciauto_region_init(hose->pci_mem);
- DEBUGF("PCI Autoconfig: Bus Memory region: [0x%llx-0x%llx],\n" + debug("PCI Autoconfig: Bus Memory region: [0x%llx-0x%llx],\n" "\t\tPhysical Memory [%llx-%llxx]\n", (u64)hose->pci_mem->bus_start, (u64)(hose->pci_mem->bus_start + hose->pci_mem->size - 1), @@ -422,7 +420,7 @@ void pciauto_config_init(struct pci_controller *hose) if (hose->pci_prefetch) { pciauto_region_init(hose->pci_prefetch);
- DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [0x%llx-0x%llx],\n" + debug("PCI Autoconfig: Bus Prefetchable Mem: [0x%llx-0x%llx],\n" "\t\tPhysical Memory [%llx-%llx]\n", (u64)hose->pci_prefetch->bus_start, (u64)(hose->pci_prefetch->bus_start + @@ -435,7 +433,7 @@ void pciauto_config_init(struct pci_controller *hose) if (hose->pci_io) { pciauto_region_init(hose->pci_io);
- DEBUGF("PCI Autoconfig: Bus I/O region: [0x%llx-0x%llx],\n" + debug("PCI Autoconfig: Bus I/O region: [0x%llx-0x%llx],\n" "\t\tPhysical Memory: [%llx-%llx]\n", (u64)hose->pci_io->bus_start, (u64)(hose->pci_io->bus_start + hose->pci_io->size - 1), @@ -475,8 +473,8 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
switch (class) { case PCI_CLASS_BRIDGE_PCI: - DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", - PCI_DEV(dev)); + debug("PCI Autoconfig: Found P2P bridge, device %d\n", + PCI_DEV(dev));
pciauto_setup_device(hose, dev, 2, pci_mem, pci_prefetch, pci_io); @@ -512,8 +510,8 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) pciauto_setup_device(hose, dev, 0, pci_mem, pci_prefetch, pci_io);
- DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", - PCI_DEV(dev)); + debug("PCI Autoconfig: Found P2CardBus bridge, device %d\n", + PCI_DEV(dev));
#ifndef CONFIG_DM_PCI hose->current_busno++; @@ -522,8 +520,8 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE) case PCI_CLASS_BRIDGE_OTHER: - DEBUGF("PCI Autoconfig: Skipping bridge device %d\n", - PCI_DEV(dev)); + debug("PCI Autoconfig: Skipping bridge device %d\n", + PCI_DEV(dev)); break; #endif #if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349) @@ -534,14 +532,14 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) * device claiming resources io/mem/irq.. we only allow for * the PIMMR window to be allocated (BAR0 - 1MB size) */ - DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n"); + debug("PCI Autoconfig: Broken bridge found, only minimal config\n"); pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); break; #endif
case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */ - DEBUGF("PCI AutoConfig: Found PowerPC device\n"); + debug("PCI AutoConfig: Found PowerPC device\n");
default: pciauto_setup_device(hose, dev, 6, pci_mem,

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
This file does not need its own way of doing debug(). Clean it up to use the new way.
Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Pavel Machek pavel@denx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/pci/pci_auto.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-)
Applied to u-boot-x86.

This option is not used by any board but appears to still be useful, at least for testing. With recent commits it does not build, so fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
drivers/pci/pci_auto.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 7ff282b..51d2ac0 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -82,9 +82,9 @@ void pciauto_setup_device(struct pci_controller *hose, pci_size_t bar_size; u16 cmdstat = 0; int bar, bar_nr = 0; +#ifndef CONFIG_PCI_ENUM_ONLY u8 header_type; int rom_addr; -#ifndef CONFIG_PCI_ENUM_ONLY pci_addr_t bar_value; struct pci_region *bar_res; int found_mem64 = 0; @@ -181,6 +181,7 @@ void pciauto_setup_device(struct pci_controller *hose, bar_nr++; }
+#ifndef CONFIG_PCI_ENUM_ONLY /* Configure the expansion ROM address */ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); if (header_type != PCI_HEADER_TYPE_CARDBUS) { @@ -201,6 +202,7 @@ void pciauto_setup_device(struct pci_controller *hose, debug("\n"); } } +#endif
pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat); pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This option is not used by any board but appears to still be useful, at least for testing. With recent commits it does not build, so fix it.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/pci/pci_auto.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 7ff282b..51d2ac0 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -82,9 +82,9 @@ void pciauto_setup_device(struct pci_controller *hose, pci_size_t bar_size; u16 cmdstat = 0; int bar, bar_nr = 0; +#ifndef CONFIG_PCI_ENUM_ONLY u8 header_type; int rom_addr; -#ifndef CONFIG_PCI_ENUM_ONLY pci_addr_t bar_value; struct pci_region *bar_res; int found_mem64 = 0; @@ -181,6 +181,7 @@ void pciauto_setup_device(struct pci_controller *hose, bar_nr++; }
+#ifndef CONFIG_PCI_ENUM_ONLY /* Configure the expansion ROM address */ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); if (header_type != PCI_HEADER_TYPE_CARDBUS) { @@ -201,6 +202,7 @@ void pciauto_setup_device(struct pci_controller *hose, debug("\n"); } } +#endif
pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat); pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 2 August 2015 at 07:22, Bin Meng bmeng.cn@gmail.com wrote:
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This option is not used by any board but appears to still be useful, at least for testing. With recent commits it does not build, so fix it.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/pci/pci_auto.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 7ff282b..51d2ac0 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -82,9 +82,9 @@ void pciauto_setup_device(struct pci_controller *hose, pci_size_t bar_size; u16 cmdstat = 0; int bar, bar_nr = 0; +#ifndef CONFIG_PCI_ENUM_ONLY u8 header_type; int rom_addr; -#ifndef CONFIG_PCI_ENUM_ONLY pci_addr_t bar_value; struct pci_region *bar_res; int found_mem64 = 0; @@ -181,6 +181,7 @@ void pciauto_setup_device(struct pci_controller *hose, bar_nr++; }
+#ifndef CONFIG_PCI_ENUM_ONLY /* Configure the expansion ROM address */ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); if (header_type != PCI_HEADER_TYPE_CARDBUS) { @@ -201,6 +202,7 @@ void pciauto_setup_device(struct pci_controller *hose, debug("\n"); } } +#endif
pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat); pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.

On x86 the global_data pointer is provided through a somewhat-bizarre and x86-specific mechanism: the F segment register is set to a pointer to the start of global_data, so that accesses can use this build-in register.
When running as an EFI payload we don't want to mess with the Global Descriptor Table (GDT) and there is little advantage (in terms of code size) to doing so.
Allow global_data to be a simple variable in this case.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Move this patch to before the EFI start-up code patch - Refer to FS as F segment register instead of frame segment register - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
arch/x86/include/asm/global_data.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 3db9a4c..80ebe3e 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -76,6 +76,12 @@ struct arch_global_data { #include <asm-generic/global_data.h>
#ifndef __ASSEMBLY__ +# ifdef CONFIG_EFI_APP + +#define gd global_data_ptr + +#define DECLARE_GLOBAL_DATA_PTR extern struct global_data *global_data_ptr +# else static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void) { gd_t *gd_ptr; @@ -88,6 +94,7 @@ static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void) #define gd get_fs_gd_ptr()
#define DECLARE_GLOBAL_DATA_PTR +# endif
#endif

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
On x86 the global_data pointer is provided through a somewhat-bizarre and x86-specific mechanism: the F segment register is set to a pointer to the start of global_data, so that accesses can use this build-in register.
When running as an EFI payload we don't want to mess with the Global
Nits: running as an EFI application
Descriptor Table (GDT) and there is little advantage (in terms of code size) to doing so.
Allow global_data to be a simple variable in this case.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- Move this patch to before the EFI start-up code patch
- Refer to FS as F segment register instead of frame segment register
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
arch/x86/include/asm/global_data.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 3db9a4c..80ebe3e 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -76,6 +76,12 @@ struct arch_global_data { #include <asm-generic/global_data.h>
#ifndef __ASSEMBLY__ +# ifdef CONFIG_EFI_APP
+#define gd global_data_ptr
+#define DECLARE_GLOBAL_DATA_PTR extern struct global_data *global_data_ptr +# else static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void) { gd_t *gd_ptr; @@ -88,6 +94,7 @@ static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void) #define gd get_fs_gd_ptr()
#define DECLARE_GLOBAL_DATA_PTR +# endif
#endif
--
Regards, Bin

On 2 August 2015 at 08:32, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
On x86 the global_data pointer is provided through a somewhat-bizarre and x86-specific mechanism: the F segment register is set to a pointer to the start of global_data, so that accesses can use this build-in register.
When running as an EFI payload we don't want to mess with the Global
Nits: running as an EFI application
Descriptor Table (GDT) and there is little advantage (in terms of code size) to doing so.
Allow global_data to be a simple variable in this case.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.
Changes in v2:
- Move this patch to before the EFI start-up code patch
- Refer to FS as F segment register instead of frame segment register
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
arch/x86/include/asm/global_data.h | 7 +++++++ 1 file changed, 7 insertions(+)

When running as an EFI application, U-Boot must request memory from EFI, and provide access to the boot services U-Boot needs.
Add library code to perform these tasks. This includes efi_main() which is the entry point from EFI. U-Boot is built as a shared library.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a comment as to why we only allocate pages below 4GB - Add a comment as to why we use global_data_ptr - Add comments as to why we need efi_memset(), efi_putc(), efi_puts() - Avoid useless u64 cast on EFI_RUNTIME_SERVICES_SIGNATURE - Drop __packed from struct efi_device_path - Explain in a comment how the debug UART is implemented for the EFI app - Fix 'command problem' typo - it should say 'command prompt' - Fix 'withU-Boot.' typo - Fix a few comment typos - Fix efi_mem_desc_VERSION typo - Fix mention of CHAR16 which should be wchar_t - Fix missing struct comments - Move the 64-bit payload code to a later patch - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Reword the efi_putc() unicode comment to make more sense - Use image_base instead of ImageBase - Use one-line comments when appropriate - Use reserved instead of __reserved in struct efi_boot_services
arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- include/efi.h | 357 +++++++++++++++++++++++++++++++++++++ include/efi_api.h | 244 +++++++++++++++++++++++++ include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 33 ++++ lib/efi/Makefile | 7 + lib/efi/efi.c | 101 +++++++++++ lib/efi/efi_app.c | 139 +++++++++++++++ 10 files changed, 888 insertions(+), 64 deletions(-) create mode 100644 include/efi.h create mode 100644 include/efi_api.h create mode 100644 lib/efi/Kconfig create mode 100644 lib/efi/Makefile create mode 100644 lib/efi/efi.c create mode 100644 lib/efi/efi_app.c
diff --git a/arch/x86/include/asm/fsp/fsp_hob.h b/arch/x86/include/asm/fsp/fsp_hob.h index 6cca7f5..3fb3546 100644 --- a/arch/x86/include/asm/fsp/fsp_hob.h +++ b/arch/x86/include/asm/fsp/fsp_hob.h @@ -8,6 +8,8 @@ #ifndef __FSP_HOB_H__ #define __FSP_HOB_H__
+#include <efi.h> + /* Type of HOB Header */ #define HOB_TYPE_MEM_ALLOC 0x0002 #define HOB_TYPE_RES_DESC 0x0003 @@ -25,63 +27,6 @@ struct hob_header { u32 reserved; /* always zero */ };
-/* Enumeration of memory types introduced in UEFI */ -enum efi_mem_type { - EFI_RESERVED_MEMORY_TYPE, - /* - * The code portions of a loaded application. - * (Note that UEFI OS loaders are UEFI applications.) - */ - EFI_LOADER_CODE, - /* - * The data portions of a loaded application and - * the default data allocation type used by an application - * to allocate pool memory. - */ - EFI_LOADER_DATA, - /* The code portions of a loaded Boot Services Driver */ - EFI_BOOT_SERVICES_CODE, - /* - * The data portions of a loaded Boot Serves Driver and - * the default data allocation type used by a Boot Services - * Driver to allocate pool memory. - */ - EFI_BOOT_SERVICES_DATA, - /* The code portions of a loaded Runtime Services Driver */ - EFI_RUNTIME_SERVICES_CODE, - /* - * The data portions of a loaded Runtime Services Driver and - * the default data allocation type used by a Runtime Services - * Driver to allocate pool memory. - */ - EFI_RUNTIME_SERVICES_DATA, - /* Free (unallocated) memory */ - EFI_CONVENTIONAL_MEMORY, - /* Memory in which errors have been detected */ - EFI_UNUSABLE_MEMORY, - /* Memory that holds the ACPI tables */ - EFI_ACPI_RECLAIM_MEMORY, - /* Address space reserved for use by the firmware */ - EFI_ACPI_MEMORY_NVS, - /* - * Used by system firmware to request that a memory-mapped IO region - * be mapped by the OS to a virtual address so it can be accessed by - * EFI runtime services. - */ - EFI_MMAP_IO, - /* - * System memory-mapped IO region that is used to translate - * memory cycles to IO cycles by the processor. - */ - EFI_MMAP_IO_PORT, - /* - * Address space reserved by the firmware for code that is - * part of the processor. - */ - EFI_PAL_CODE, - EFI_MAX_MEMORY_TYPE -}; - /* * Describes all memory ranges used during the HOB producer phase that * exist outside the HOB list. This HOB type describes how memory is used, diff --git a/include/efi.h b/include/efi.h new file mode 100644 index 0000000..5d80373 --- /dev/null +++ b/include/efi.h @@ -0,0 +1,357 @@ +/* + * Extensible Firmware Interface + * Based on 'Extensible Firmware Interface Specification' version 0.9, + * April 30, 1999 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond drummond@valinux.com + * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co. + * David Mosberger-Tang davidm@hpl.hp.com + * Stephane Eranian eranian@hpl.hp.com + * + * From include/linux/efi.h in kernel 4.1 with some additions/subtractions + */ + +#ifndef _EFI_H +#define _EFI_H + +#include <linux/string.h> +#include <linux/types.h> + +struct efi_device_path; + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR (1 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_INVALID_PARAMETER (2 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_UNSUPPORTED (3 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_BAD_BUFFER_SIZE (4 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_BUFFER_TOO_SMALL (5 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_NOT_READY (6 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_DEVICE_ERROR (7 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_WRITE_PROTECTED (8 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_OUT_OF_RESOURCES (9 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG - 1))) + +typedef unsigned long efi_status_t; +typedef u64 efi_physical_addr_t; +typedef u64 efi_virtual_addr_t; +typedef void *efi_handle_t; + +#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + ((efi_guid_t) \ + {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \ + ((a) >> 24) & 0xff, \ + (b) & 0xff, ((b) >> 8) & 0xff, \ + (c) & 0xff, ((c) >> 8) & 0xff, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } }) + +/* Generic EFI table header */ +struct efi_table_hdr { + u64 signature; + u32 revision; + u32 headersize; + u32 crc32; + u32 reserved; +}; + +/* Enumeration of memory types introduced in UEFI */ +enum efi_mem_type { + EFI_RESERVED_MEMORY_TYPE, + /* + * The code portions of a loaded application. + * (Note that UEFI OS loaders are UEFI applications.) + */ + EFI_LOADER_CODE, + /* + * The data portions of a loaded application and + * the default data allocation type used by an application + * to allocate pool memory. + */ + EFI_LOADER_DATA, + /* The code portions of a loaded Boot Services Driver */ + EFI_BOOT_SERVICES_CODE, + /* + * The data portions of a loaded Boot Serves Driver and + * the default data allocation type used by a Boot Services + * Driver to allocate pool memory. + */ + EFI_BOOT_SERVICES_DATA, + /* The code portions of a loaded Runtime Services Driver */ + EFI_RUNTIME_SERVICES_CODE, + /* + * The data portions of a loaded Runtime Services Driver and + * the default data allocation type used by a Runtime Services + * Driver to allocate pool memory. + */ + EFI_RUNTIME_SERVICES_DATA, + /* Free (unallocated) memory */ + EFI_CONVENTIONAL_MEMORY, + /* Memory in which errors have been detected */ + EFI_UNUSABLE_MEMORY, + /* Memory that holds the ACPI tables */ + EFI_ACPI_RECLAIM_MEMORY, + /* Address space reserved for use by the firmware */ + EFI_ACPI_MEMORY_NVS, + /* + * Used by system firmware to request that a memory-mapped IO region + * be mapped by the OS to a virtual address so it can be accessed by + * EFI runtime services. + */ + EFI_MMAP_IO, + /* + * System memory-mapped IO region that is used to translate + * memory cycles to IO cycles by the processor. + */ + EFI_MMAP_IO_PORT, + /* + * Address space reserved by the firmware for code that is + * part of the processor. + */ + EFI_PAL_CODE, + + EFI_MAX_MEMORY_TYPE, + EFI_TABLE_END, /* For efi_build_mem_table() */ +}; + +/* Attribute values */ +enum { + EFI_MEMORY_UC_SHIFT = 0, /* uncached */ + EFI_MEMORY_WC_SHIFT = 1, /* write-coalescing */ + EFI_MEMORY_WT_SHIFT = 2, /* write-through */ + EFI_MEMORY_WB_SHIFT = 3, /* write-back */ + EFI_MEMORY_UCE_SHIFT = 4, /* uncached, exported */ + EFI_MEMORY_WP_SHIFT = 12, /* write-protect */ + EFI_MEMORY_RP_SHIFT = 13, /* read-protect */ + EFI_MEMORY_XP_SHIFT = 14, /* execute-protect */ + EFI_MEMORY_RUNTIME_SHIFT = 63, /* range requires runtime mapping */ + + EFI_MEMORY_RUNTIME = 1ULL << EFI_MEMORY_RUNTIME_SHIFT, + EFI_MEM_DESC_VERSION = 1, +}; + +#define EFI_PAGE_SHIFT 12 +#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT) + +struct efi_mem_desc { + u32 type; + u32 reserved; + efi_physical_addr_t physical_start; + efi_virtual_addr_t virtual_start; + u64 num_pages; + u64 attribute; +}; + +/* Allocation types for calls to boottime->allocate_pages*/ +#define EFI_ALLOCATE_ANY_PAGES 0 +#define EFI_ALLOCATE_MAX_ADDRESS 1 +#define EFI_ALLOCATE_ADDRESS 2 +#define EFI_MAX_ALLOCATE_TYPE 3 + +/* Types and defines for Time Services */ +#define EFI_TIME_ADJUST_DAYLIGHT 0x1 +#define EFI_TIME_IN_DAYLIGHT 0x2 +#define EFI_UNSPECIFIED_TIMEZONE 0x07ff + +struct efi_time { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 pad1; + u32 nanosecond; + s16 timezone; + u8 daylight; + u8 pad2; +}; + +struct efi_time_cap { + u32 resolution; + u32 accuracy; + u8 sets_to_zero; +}; + +enum efi_locate_search_type { + all_handles, + by_register_notify, + by_protocol +}; + +struct efi_open_protocol_info_entry { + efi_handle_t agent_handle; + efi_handle_t controller_handle; + u32 attributes; + u32 open_count; +}; + +enum efi_entry_t { + EFIET_END, /* Signals this is the last (empty) entry */ + EFIET_MEMORY_MAP, + + /* Number of entries */ + EFIET_MEMORY_COUNT, +}; + +#define EFI_TABLE_VERSION 1 + +/** + * struct efi_info_hdr - Header for the EFI info table + * + * @version: EFI_TABLE_VERSION + * @hdr_size: Size of this struct in bytes + * @total_size: Total size of this header plus following data + * @spare: Spare space for expansion + */ +struct efi_info_hdr { + u32 version; + u32 hdr_size; + u32 total_size; + u32 spare[5]; +}; + +/** + * struct efi_entry_hdr - Header for a table entry + * + * @type: enum eft_entry_t + * @size size of entry bytes excluding header and padding + * @addr: address of this entry (0 if it follows the header ) + * @link: size of entry including header and padding + * @spare1: Spare space for expansion + * @spare2: Spare space for expansion + * @ + */ +struct efi_entry_hdr { + u32 type; + u32 size; + u64 addr; + u32 link; + u32 spare1; + u64 spare2; +}; + +/** + * struct efi_entry_memmap - a memory map table passed to U-Boot + * + * @version: EFI's memory map table version + * @desc_size: EFI's size of each memory descriptor + * @spare: Spare space for expansion + * @desc: An array of descriptors, each @desc_size bytes apart + */ +struct efi_entry_memmap { + u32 version; + u32 desc_size; + u64 spare; + struct efi_mem_desc desc[]; +}; + +static inline struct efi_mem_desc *efi_get_next_mem_desc( + struct efi_entry_memmap *map, struct efi_mem_desc *desc) +{ + return (struct efi_mem_desc *)((ulong)desc + map->desc_size); +} + +struct efi_priv { + efi_handle_t parent_image; + struct efi_device_path *device_path; + struct efi_system_table *sys_table; + struct efi_boot_services *boot; + struct efi_runtime_services *run; + bool use_pool_for_malloc; + unsigned long ram_base; + unsigned int image_data_type; + struct efi_info_hdr *info; + unsigned int info_size; + void *next_hdr; +}; + +/* Base address of the EFI image */ +extern char image_base[]; + +/** + * efi_get_sys_table() - Get access to the main EFI system table + * + * @return pointer to EFI system table + */ +struct efi_system_table *efi_get_sys_table(void); + +/** + * efi_get_ram_base() - Find the base of RAM + * + * This is used when U-Boot is built as an EFI application. + * + * @return the base of RAM as known to U-Boot + */ +unsigned long efi_get_ram_base(void); + +/** + * efi_init() - Set up ready for use of EFI boot services + * + * @priv: Pointer to our private EFI structure to fill in + * @banner: Banner to display when starting + * @image: The image handle passed to efi_main() + * @sys_table: The EFI system table pointer passed to efi_main() + */ +int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image, + struct efi_system_table *sys_table); + +/** + * efi_malloc() - Allocate some memory from EFI + * + * @priv: Pointer to private EFI structure + * @size: Number of bytes to allocate + * @retp: Return EFI status result + * @return pointer to memory allocated, or NULL on error + */ +void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp); + +/** + * efi_free() - Free memory allocated from EFI + * + * @priv: Pointer to private EFI structure + * @ptr: Pointer to memory to free + */ +void efi_free(struct efi_priv *priv, void *ptr); + +/** + * efi_puts() - Write out a string to the EFI console + * + * @priv: Pointer to private EFI structure + * @str: String to write (note this is a ASCII, not unicode) + */ +void efi_puts(struct efi_priv *priv, const char *str); + +/** + * efi_putc() - Write out a character to the EFI console + * + * @priv: Pointer to private EFI structure + * @ch: Character to write (note this is not unicode) + */ +void efi_putc(struct efi_priv *priv, const char ch); + +/** + * efi_info_get() - get an entry from an EFI table + * + * @type: Entry type to search for + * @datap: Returns pointer to entry data + * @sizep: Returns pointer to entry size + * @return 0 if OK, -ENODATA if there is no table, -ENOENT if there is no entry + * of the requested type, -EPROTONOSUPPORT if the table has the wrong version + */ +int efi_info_get(enum efi_entry_t type, void **datap, int *sizep); + +/** + * efi_build_mem_table() - make a sorted copy of the memory table + * + * @map: Pointer to EFI memory map table + * @size: Size of table in bytes + * @skip_bs: True to skip boot-time memory and merge it with conventional + * memory. This will significantly reduce the number of table + * entries. + * @return pointer to the new table. It should be freed with free() by the + * caller + */ +void *efi_build_mem_table(struct efi_entry_memmap *map, int size, bool skip_bs); + +#endif /* _LINUX_EFI_H */ diff --git a/include/efi_api.h b/include/efi_api.h new file mode 100644 index 0000000..4fd17d6 --- /dev/null +++ b/include/efi_api.h @@ -0,0 +1,244 @@ +/* + * Extensible Firmware Interface + * Based on 'Extensible Firmware Interface Specification' version 0.9, + * April 30, 1999 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond drummond@valinux.com + * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co. + * David Mosberger-Tang davidm@hpl.hp.com + * Stephane Eranian eranian@hpl.hp.com + * + * From include/linux/efi.h in kernel 4.1 with some additions/subtractions + */ + +#ifndef _EFI_API_H +#define _EFI_API_H + +#include <efi.h> + +/* EFI Boot Services table */ +struct efi_boot_services { + struct efi_table_hdr hdr; + void *raise_tpl; + void *restore_tpl; + + efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long, + efi_physical_addr_t *); + efi_status_t (EFIAPI *free_pages)(efi_physical_addr_t, unsigned long); + efi_status_t (EFIAPI *get_memory_map)(unsigned long *memory_map_size, + struct efi_mem_desc *desc, unsigned long *key, + unsigned long *desc_size, u32 *desc_version); + efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **); + efi_status_t (EFIAPI *free_pool)(void *); + + void *create_event; + void *set_timer; + efi_status_t(EFIAPI *wait_for_event)(unsigned long number_of_events, + void *event, unsigned long *index); + void *signal_event; + void *close_event; + void *check_event; + + void *install_protocol_interface; + void *reinstall_protocol_interface; + void *uninstall_protocol_interface; + efi_status_t (EFIAPI *handle_protocol)(efi_handle_t, efi_guid_t *, + void **); + void *reserved; + void *register_protocol_notify; + efi_status_t (EFIAPI *locate_handle)( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *buffer_size, efi_handle_t *buffer); + efi_status_t (EFIAPI *locate_device_path)(efi_guid_t *protocol, + struct efi_device_path **device_path, + efi_handle_t *device); + void *install_configuration_table; + + efi_status_t (EFIAPI *load_image)(bool boot_policiy, + efi_handle_t parent_image, + struct efi_device_path *file_path, void *source_buffer, + unsigned long source_size, efi_handle_t *image); + efi_status_t (EFIAPI *start_image)(efi_handle_t handle, + unsigned long *exitdata_size, + s16 **exitdata); + efi_status_t (EFIAPI *exit)(efi_handle_t handle, + efi_status_t exit_status, + unsigned long exitdata_size, s16 *exitdata); + void *unload_image; + efi_status_t (EFIAPI *exit_boot_services)(efi_handle_t, unsigned long); + + efi_status_t (EFIAPI *get_next_monotonic_count)(u64 *count); + efi_status_t (EFIAPI *stall)(unsigned long usecs); + void *set_watchdog_timer; + efi_status_t(EFIAPI *connect_controller)(efi_handle_t controller_handle, + efi_handle_t *driver_image_handle, + struct efi_device_path *remaining_device_path, + bool recursive); + void *disconnect_controller; +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + efi_status_t (EFIAPI *open_protocol)(efi_handle_t handle, + efi_guid_t *protocol, void **interface, + efi_handle_t agent_handle, + efi_handle_t controller_handle, u32 attributes); + void *close_protocol; + efi_status_t(EFIAPI *open_protocol_information)(efi_handle_t handle, + efi_guid_t *protocol, + struct efi_open_protocol_info_entry **entry_buffer, + unsigned long *entry_count); + efi_status_t (EFIAPI *protocols_per_handle)(efi_handle_t handle, + efi_guid_t ***protocol_buffer, + unsigned long *protocols_buffer_count); + efi_status_t (EFIAPI *locate_handle_buffer) ( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *no_handles, efi_handle_t **buffer); + void *locate_protocol; + void *install_multiple_protocol_interfaces; + void *uninstall_multiple_protocol_interfaces; + void *calculate_crc32; + void *copy_mem; + void *set_mem; + void *create_event_ex; +}; + +/* Types and defines for EFI ResetSystem */ +enum efi_reset_type { + EFI_RESET_COLD = 0, + EFI_RESET_WARM = 1, + EFI_RESET_SHUTDOWN = 2 +}; + +/* EFI Runtime Services table */ +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552ULL +#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 + +struct efi_runtime_services { + struct efi_table_hdr hdr; + void *get_time; + void *set_time; + void *get_wakeup_time; + void *set_wakeup_time; + void *set_virtual_address_map; + void *convert_pointer; + efi_status_t (EFIAPI *get_variable)(s16 *variable_name, + efi_guid_t *vendor, u32 *attributes, + unsigned long *data_size, void *data); + efi_status_t (EFIAPI *get_next_variable)( + unsigned long *variable_name_size, + s16 *variable_name, efi_guid_t *vendor); + efi_status_t (EFIAPI *set_variable)(s16 *variable_name, + efi_guid_t *vendor, u32 attributes, + unsigned long data_size, void *data); + void *get_next_high_mono_count; + void (EFIAPI *reset_system)(enum efi_reset_type reset_type, + efi_status_t reset_status, + unsigned long data_size, void *reset_data); + void *update_capsule; + void *query_capsule_caps; + void *query_variable_info; +}; + +/* EFI Configuration Table and GUID definitions */ +#define NULL_GUID \ + EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + +#define LOADED_IMAGE_PROTOCOL_GUID \ + EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \ + 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + +struct efi_system_table { + struct efi_table_hdr hdr; + unsigned long fw_vendor; /* physical addr of wchar_t vendor string */ + u32 fw_revision; + unsigned long con_in_handle; + struct efi_simple_input_interface *con_in; + unsigned long con_out_handle; + struct efi_simple_text_output_protocol *con_out; + unsigned long stderr_handle; + unsigned long std_err; + struct efi_runtime_services *runtime; + struct efi_boot_services *boottime; + unsigned long nr_tables; + unsigned long tables; +}; + +struct efi_loaded_image { + u32 revision; + void *parent_handle; + struct efi_system_table *system_table; + void *device_handle; + void *file_path; + void *reserved; + u32 load_options_size; + void *load_options; + void *image_base; + aligned_u64 image_size; + unsigned int image_code_type; + unsigned int image_data_type; + unsigned long unload; +}; + +struct efi_device_path { + u8 type; + u8 sub_type; + u16 length; +}; + +struct simple_text_output_mode { + s32 max_mode; + s32 mode; + s32 attribute; + s32 cursor_column; + s32 cursor_row; + bool cursor_visible; +}; + +struct efi_simple_text_output_protocol { + void *reset; + efi_status_t (EFIAPI *output_string)( + struct efi_simple_text_output_protocol *this, + const unsigned short *str); + void *test_string; + + efi_status_t(EFIAPI *query_mode)( + struct efi_simple_text_output_protocol *this, + unsigned long mode_number, unsigned long *columns, + unsigned long *rows); + efi_status_t(EFIAPI *set_mode)( + struct efi_simple_text_output_protocol *this, + unsigned long mode_number); + efi_status_t(EFIAPI *set_attribute)( + struct efi_simple_text_output_protocol *this, + unsigned long attribute); + efi_status_t(EFIAPI *clear_screen) ( + struct efi_simple_text_output_protocol *this); + efi_status_t(EFIAPI *set_cursor_position) ( + struct efi_simple_text_output_protocol *this, + unsigned long column, unsigned long row); + efi_status_t(EFIAPI *enable_cursor)(void *, bool enable); + struct simple_text_output_mode *mode; +}; + +struct efi_input_key { + u16 scan_code; + s16 unicode_char; +}; + +struct efi_simple_input_interface { + efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this, + bool ExtendedVerification); + efi_status_t(EFIAPI *read_key_stroke)( + struct efi_simple_input_interface *this, + struct efi_input_key *key); + void *wait_for_key; +}; + +#endif diff --git a/include/part_efi.h b/include/part_efi.h index d68ef3b..3012b91 100644 --- a/include/part_efi.h +++ b/include/part_efi.h @@ -18,6 +18,8 @@ #ifndef _DISK_PART_EFI_H #define _DISK_PART_EFI_H
+#include <efi.h> + #define MSDOS_MBR_SIGNATURE 0xAA55 #define EFI_PMBR_OSTYPE_EFI 0xEF #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE @@ -29,13 +31,6 @@ #define GPT_ENTRY_NUMBERS 128 #define GPT_ENTRY_SIZE 128
-#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ - ((efi_guid_t) \ - {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ - (b) & 0xff, ((b) >> 8) & 0xff, \ - (c) & 0xff, ((c) >> 8) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) - #define PARTITION_SYSTEM_GUID \ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) diff --git a/lib/Kconfig b/lib/Kconfig index 972ac17..884218a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -98,4 +98,6 @@ config ERRNO_STR - if errno is null or positive number - a pointer to "Success" message - if errno is negative - a pointer to errno related message
+source lib/efi/Kconfig + endmenu diff --git a/lib/Makefile b/lib/Makefile index fd106b9..db7d980 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,6 +7,7 @@
ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_RSA) += rsa/ obj-$(CONFIG_LZMA) += lzma/ obj-$(CONFIG_LZO) += lzo/ diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig new file mode 100644 index 0000000..b23ba5b --- /dev/null +++ b/lib/efi/Kconfig @@ -0,0 +1,33 @@ +config EFI + bool "Support running U-Boot from EFI" + depends on X86 + help + U-Boot can be started from EFI on certain platforms. This allows + EFI to perform most of the system init and then jump to U-Boot for + final system boot. Another option is to run U-Boot as an EFI + application, with U-Boot using EFI's drivers instead of its own. + +choice + prompt "Select EFI mode to use" + depends on X86 && EFI + +config EFI_APP + bool "Support running as an EFI application" + help + Build U-Boot as an application which can be started from EFI. This + is useful for examining a platform in the early stages of porting + U-Boot to it. It allows only very basic functionality, such as a + command prompt and memory and I/O functions. Use 'reset' to return + to EFI. + +config EFI_RAM_SIZE + hex "Amount of EFI RAM for U-Boot" + depends on EFI_APP + default 0x2000000 + help + Set the amount of EFI RAM which is claimed by U-Boot for its own + use. U-Boot allocates this from EFI on start-up (along with a few + other smaller amounts) and it can never be increased after that. + It is used as the RAM size in with U-Boot. + +endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile new file mode 100644 index 0000000..5ee344c --- /dev/null +++ b/lib/efi/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_EFI_APP) += efi_app.o efi.o diff --git a/lib/efi/efi.c b/lib/efi/efi.c new file mode 100644 index 0000000..c6454ea --- /dev/null +++ b/lib/efi/efi.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * Common EFI functions + */ + +#include <common.h> +#include <debug_uart.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/types.h> +#include <efi.h> +#include <efi_api.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Unfortunately we cannot access any code outside what be build especially + * for the stub. lib/string.c is already being built for the U-Boot payload + * so it using the wrong compiler flags. Add our own memset() here. + */ +static void efi_memset(void *ptr, int ch, int size) +{ + char *dest = ptr; + + while (size-- > 0) + *dest++ = ch; +} + +/* + * Since the EFI stub cannot access most of the U-Boot code, add our own + * simple console output functions here. The EFI app will not use these since + * it can use the normal console. + */ +void efi_putc(struct efi_priv *priv, const char ch) +{ + struct efi_simple_text_output_protocol *con = priv->sys_table->con_out; + uint16_t ucode[2]; + + ucode[0] = ch; + ucode[1] = '\0'; + con->output_string(con, ucode); +} + +void efi_puts(struct efi_priv *priv, const char *str) +{ + while (*str) + efi_putc(priv, *str++); +} + +int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image, + struct efi_system_table *sys_table) +{ + efi_guid_t loaded_image_guid = LOADED_IMAGE_PROTOCOL_GUID; + struct efi_boot_services *boot = sys_table->boottime; + struct efi_loaded_image *loaded_image; + int ret; + + efi_memset(priv, '\0', sizeof(*priv)); + priv->sys_table = sys_table; + priv->boot = sys_table->boottime; + priv->parent_image = image; + priv->run = sys_table->runtime; + + efi_puts(priv, "U-Boot EFI "); + efi_puts(priv, banner); + efi_putc(priv, ' '); + + ret = boot->open_protocol(priv->parent_image, &loaded_image_guid, + (void **)&loaded_image, &priv->parent_image, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret) { + efi_puts(priv, "Failed to get loaded image protocol\n"); + return ret; + } + priv->image_data_type = loaded_image->image_data_type; + + return 0; +} + +void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp) +{ + struct efi_boot_services *boot = priv->boot; + void *buf = NULL; + + *retp = boot->allocate_pool(priv->image_data_type, size, &buf); + + return buf; +} + +void efi_free(struct efi_priv *priv, void *ptr) +{ + struct efi_boot_services *boot = priv->boot; + + boot->free_pool(ptr); +} diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c new file mode 100644 index 0000000..452ab5d --- /dev/null +++ b/lib/efi/efi_app.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * This file implements U-Boot running as an EFI application. + */ + +#include <common.h> +#include <debug_uart.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/types.h> +#include <efi.h> +#include <efi_api.h> + +DECLARE_GLOBAL_DATA_PTR; + +static struct efi_priv *global_priv; + +struct efi_system_table *efi_get_sys_table(void) +{ + return global_priv->sys_table; +} + +unsigned long efi_get_ram_base(void) +{ + return global_priv->ram_base; +} + +static efi_status_t setup_memory(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->boot; + efi_physical_addr_t addr; + efi_status_t ret; + int pages; + + /* + * Use global_data_ptr instead of gd since it is an assignment. There + * are very few assignments to global_data in U-Boot and this makes + * it easier to find them. + */ + global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret); + if (!global_data_ptr) + return ret; + memset(gd, '\0', sizeof(*gd)); + + gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_SYS_MALLOC_F_LEN, + &ret); + if (!gd->malloc_base) + return ret; + pages = CONFIG_EFI_RAM_SIZE >> 12; + + /* + * Don't allocate any memory above 4GB. U-Boot is a 32-bit application + * so we want it to load below 4GB. + */ + addr = 1ULL << 32; + ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + priv->image_data_type, pages, &addr); + if (ret) { + printf("(using pool %lx) ", ret); + priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE, + &ret); + if (!priv->ram_base) + return ret; + priv->use_pool_for_malloc = true; + } else { + priv->ram_base = addr; + } + gd->ram_size = pages << 12; + + return 0; +} + +static void free_memory(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->boot; + + if (priv->use_pool_for_malloc) + efi_free(priv, (void *)priv->ram_base); + else + boot->free_pages(priv->ram_base, gd->ram_size >> 12); + + efi_free(priv, (void *)gd->malloc_base); + efi_free(priv, gd); + global_data_ptr = NULL; +} + +/** + * efi_main() - Start an EFI image + * + * This function is called by our EFI start-up code. It handles running + * U-Boot. If it returns, EFI will continue. Another way to get back to EFI + * is via reset_cpu(). + */ +efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) +{ + struct efi_priv local_priv, *priv = &local_priv; + efi_status_t ret; + + /* Set up access to EFI data structures */ + efi_init(priv, "App", image, sys_table); + + global_priv = priv; + + /* + * Set up the EFI debug UART so that printf() works. This is + * implemented in the EFI serial driver, serial_efi.c. The application + * can use printf() freely. + */ + debug_uart_init(); + + ret = setup_memory(priv); + if (ret) { + printf("Failed to set up memory: ret=%lx\n", ret); + return ret; + } + + printf("starting\n"); + + board_init_f(GD_FLG_SKIP_RELOC); + board_init_r(NULL, 0); + free_memory(priv); + + return EFI_SUCCESS; +} + +void reset_cpu(ulong addr) +{ + struct efi_priv *priv = global_priv; + + free_memory(priv); + printf("U-Boot EFI exiting\n"); + priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL); +}

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
When running as an EFI application, U-Boot must request memory from EFI, and provide access to the boot services U-Boot needs.
Add library code to perform these tasks. This includes efi_main() which is the entry point from EFI. U-Boot is built as a shared library.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see nits below.
Changes in v2:
- Add a comment as to why we only allocate pages below 4GB
- Add a comment as to why we use global_data_ptr
- Add comments as to why we need efi_memset(), efi_putc(), efi_puts()
- Avoid useless u64 cast on EFI_RUNTIME_SERVICES_SIGNATURE
- Drop __packed from struct efi_device_path
- Explain in a comment how the debug UART is implemented for the EFI app
- Fix 'command problem' typo - it should say 'command prompt'
- Fix 'withU-Boot.' typo
- Fix a few comment typos
- Fix efi_mem_desc_VERSION typo
- Fix mention of CHAR16 which should be wchar_t
- Fix missing struct comments
- Move the 64-bit payload code to a later patch
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Reword the efi_putc() unicode comment to make more sense
- Use image_base instead of ImageBase
- Use one-line comments when appropriate
- Use reserved instead of __reserved in struct efi_boot_services
arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- include/efi.h | 357 +++++++++++++++++++++++++++++++++++++ include/efi_api.h | 244 +++++++++++++++++++++++++ include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 33 ++++ lib/efi/Makefile | 7 + lib/efi/efi.c | 101 +++++++++++ lib/efi/efi_app.c | 139 +++++++++++++++ 10 files changed, 888 insertions(+), 64 deletions(-) create mode 100644 include/efi.h create mode 100644 include/efi_api.h create mode 100644 lib/efi/Kconfig create mode 100644 lib/efi/Makefile create mode 100644 lib/efi/efi.c create mode 100644 lib/efi/efi_app.c
[snip]
+/**
- struct efi_entry_hdr - Header for a table entry
- @type: enum eft_entry_t
- @size size of entry bytes excluding header and padding
- @addr: address of this entry (0 if it follows the header )
- @link: size of entry including header and padding
- @spare1: Spare space for expansion
- @spare2: Spare space for expansion
- @
Nits: please remove this @
- */
+struct efi_entry_hdr {
u32 type;
u32 size;
u64 addr;
u32 link;
u32 spare1;
u64 spare2;
+};
[snip]
diff --git a/lib/efi/efi.c b/lib/efi/efi.c new file mode 100644 index 0000000..c6454ea --- /dev/null +++ b/lib/efi/efi.c @@ -0,0 +1,101 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- EFI information obtained here:
- Common EFI functions
- */
+#include <common.h> +#include <debug_uart.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/types.h> +#include <efi.h> +#include <efi_api.h>
+DECLARE_GLOBAL_DATA_PTR;
+/*
- Unfortunately we cannot access any code outside what be build especially
Nits: what is built?
- for the stub. lib/string.c is already being built for the U-Boot payload
- so it using the wrong compiler flags. Add our own memset() here.
Nits: using -> uses?
- */
+static void efi_memset(void *ptr, int ch, int size) +{
char *dest = ptr;
while (size-- > 0)
*dest++ = ch;
+}
[snip]
Regards, Bin

On 2 August 2015 at 09:00, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
When running as an EFI application, U-Boot must request memory from EFI, and provide access to the boot services U-Boot needs.
Add library code to perform these tasks. This includes efi_main() which is the entry point from EFI. U-Boot is built as a shared library.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see nits below.
Fixed nits and
Applied to u-boot-x86.
Changes in v2:
- Add a comment as to why we only allocate pages below 4GB
- Add a comment as to why we use global_data_ptr
- Add comments as to why we need efi_memset(), efi_putc(), efi_puts()
- Avoid useless u64 cast on EFI_RUNTIME_SERVICES_SIGNATURE
- Drop __packed from struct efi_device_path
- Explain in a comment how the debug UART is implemented for the EFI app
- Fix 'command problem' typo - it should say 'command prompt'
- Fix 'withU-Boot.' typo
- Fix a few comment typos
- Fix efi_mem_desc_VERSION typo
- Fix mention of CHAR16 which should be wchar_t
- Fix missing struct comments
- Move the 64-bit payload code to a later patch
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Reword the efi_putc() unicode comment to make more sense
- Use image_base instead of ImageBase
- Use one-line comments when appropriate
- Use reserved instead of __reserved in struct efi_boot_services
arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- include/efi.h | 357 +++++++++++++++++++++++++++++++++++++ include/efi_api.h | 244 +++++++++++++++++++++++++ include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 33 ++++ lib/efi/Makefile | 7 + lib/efi/efi.c | 101 +++++++++++ lib/efi/efi_app.c | 139 +++++++++++++++ 10 files changed, 888 insertions(+), 64 deletions(-) create mode 100644 include/efi.h create mode 100644 include/efi_api.h create mode 100644 lib/efi/Kconfig create mode 100644 lib/efi/Makefile create mode 100644 lib/efi/efi.c create mode 100644 lib/efi/efi_app.c

From: Ben Stoltz stoltz@google.com
When U-Boot runs as an EFI application is does not have a definition of CONFIG_SYS_TEXT_BASE. U-Boot is a relocatable application and the relocation is done by EFI. U-Boot can be loaded at any address.
This is similar to how sandbox works. Adjust the early board init to deal with this.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Reorder this patch to after CONFIG_EFI_APP is introduced
common/board_f.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/common/board_f.c b/common/board_f.c index 5e09c5f..c596083 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -144,7 +144,7 @@ static int init_baud_rate(void)
static int display_text_info(void) { -#ifndef CONFIG_SANDBOX +#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP) ulong bss_start, bss_end, text_base;
bss_start = (ulong)&__bss_start; @@ -267,7 +267,7 @@ static int setup_mon_len(void) { #if defined(__ARM__) || defined(__MICROBLAZE__) gd->mon_len = (ulong)&__bss_end - (ulong)_start; -#elif defined(CONFIG_SANDBOX) +#elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP) gd->mon_len = (ulong)&_end - (ulong)_init; #elif defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2) gd->mon_len = CONFIG_SYS_MONITOR_LEN; @@ -975,7 +975,8 @@ void board_init_f(ulong boot_flags) if (initcall_run_list(init_sequence_f)) hang();
-#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) +#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \ + !defined(CONFIG_EFI_APP) /* NOTREACHED - jump_to_copy() does not return */ hang(); #endif

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
When U-Boot runs as an EFI application is does not have a definition of CONFIG_SYS_TEXT_BASE. U-Boot is a relocatable application and the relocation is done by EFI. U-Boot can be loaded at any address.
This is similar to how sandbox works. Adjust the early board init to deal with this.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Reorder this patch to after CONFIG_EFI_APP is introduced
common/board_f.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/common/board_f.c b/common/board_f.c index 5e09c5f..c596083 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -144,7 +144,7 @@ static int init_baud_rate(void)
static int display_text_info(void) { -#ifndef CONFIG_SANDBOX +#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP) ulong bss_start, bss_end, text_base;
bss_start = (ulong)&__bss_start;
@@ -267,7 +267,7 @@ static int setup_mon_len(void) { #if defined(__ARM__) || defined(__MICROBLAZE__) gd->mon_len = (ulong)&__bss_end - (ulong)_start; -#elif defined(CONFIG_SANDBOX) +#elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP) gd->mon_len = (ulong)&_end - (ulong)_init; #elif defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2) gd->mon_len = CONFIG_SYS_MONITOR_LEN; @@ -975,7 +975,8 @@ void board_init_f(ulong boot_flags) if (initcall_run_list(init_sequence_f)) hang();
-#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) +#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!defined(CONFIG_EFI_APP) /* NOTREACHED - jump_to_copy() does not return */ hang();
#endif
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 2 August 2015 at 09:04, Bin Meng bmeng.cn@gmail.com wrote:
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
When U-Boot runs as an EFI application is does not have a definition of CONFIG_SYS_TEXT_BASE. U-Boot is a relocatable application and the relocation is done by EFI. U-Boot can be loaded at any address.
This is similar to how sandbox works. Adjust the early board init to deal with this.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Reorder this patch to after CONFIG_EFI_APP is introduced
common/board_f.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/common/board_f.c b/common/board_f.c index 5e09c5f..c596083 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -144,7 +144,7 @@ static int init_baud_rate(void)
static int display_text_info(void) { -#ifndef CONFIG_SANDBOX +#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP) ulong bss_start, bss_end, text_base;
bss_start = (ulong)&__bss_start;
@@ -267,7 +267,7 @@ static int setup_mon_len(void) { #if defined(__ARM__) || defined(__MICROBLAZE__) gd->mon_len = (ulong)&__bss_end - (ulong)_start; -#elif defined(CONFIG_SANDBOX) +#elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP) gd->mon_len = (ulong)&_end - (ulong)_init; #elif defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2) gd->mon_len = CONFIG_SYS_MONITOR_LEN; @@ -975,7 +975,8 @@ void board_init_f(ulong boot_flags) if (initcall_run_list(init_sequence_f)) hang();
-#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) +#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!defined(CONFIG_EFI_APP) /* NOTREACHED - jump_to_copy() does not return */ hang();
#endif
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Applied to u-boot-x86.

With EFI the start address of U-Boot is specified differently. We could consider just setting GD_FLG_RELOC and then setting up reloc_off. But that flag has other implementations and we are not able to use U-Boot relocation which this flag implies.
Instead, just add a special case for EFI.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Rename ImageBase to image_base
lib/initcall.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/lib/initcall.c b/lib/initcall.c index 7142744..db7c558 100644 --- a/lib/initcall.c +++ b/lib/initcall.c @@ -6,6 +6,7 @@
#include <common.h> #include <initcall.h> +#include <efi.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -19,6 +20,9 @@ int initcall_run_list(const init_fnc_t init_sequence[])
if (gd->flags & GD_FLG_RELOC) reloc_ofs = gd->reloc_off; +#ifdef CONFIG_EFI_APP + reloc_ofs = (unsigned long)image_base; +#endif debug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs); if (gd->flags & GD_FLG_RELOC) debug(" (relocated to %p)\n", (char *)*init_fnc_ptr);

On 31 July 2015 at 09:31, Simon Glass sjg@chromium.org wrote:
With EFI the start address of U-Boot is specified differently. We could consider just setting GD_FLG_RELOC and then setting up reloc_off. But that flag has other implementations and we are not able to use U-Boot relocation which this flag implies.
Instead, just add a special case for EFI.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Rename ImageBase to image_base
lib/initcall.c | 4 ++++ 1 file changed, 4 insertions(+)
Applied to u-boot-x86.

Add a serial driver which makes use of EFI's console in/out service.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a comment about special handling for backspace - Add a comment as to why debug_uart_init() is empty - Drop unused DECLARE_GLOBAL_DATA_PTR - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Rename EFI debug UART to EFI_CONSOLE - Replace serial_s5p with serial_efi
drivers/serial/Kconfig | 9 +++ drivers/serial/Makefile | 1 + drivers/serial/serial_efi.c | 157 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/serial/serial_efi.c
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4829284..bfbf58f 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -44,6 +44,15 @@ config DEBUG_UART_NS16550 will need to provide parameters to make this work. The driver will be available until the real driver model serial is running.
+config DEBUG_EFI_CONSOLE + bool "EFI" + depends on EFI_APP + help + Select this to enable a debug console which calls back to EFI to + output to the console. This can be useful for early debugging of + U-Boot when running on top of EFI (Extensive Firmware Interface). + This is a type of BIOS used by PCs. + endchoice
config DEBUG_UART_BASE diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d183eed..1d1f036 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_DW_SERIAL) += serial_dw.o +obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c new file mode 100644 index 0000000..cf57d89 --- /dev/null +++ b/drivers/serial/serial_efi.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <debug_uart.h> +#include <dm.h> +#include <efi.h> +#include <efi_api.h> +#include <errno.h> +#include <fdtdec.h> +#include <linux/compiler.h> +#include <asm/io.h> +#include <serial.h> + +/* Information about the efi console */ +struct serial_efi_priv { + struct efi_simple_input_interface *con_in; + struct efi_simple_text_output_protocol *con_out; + struct efi_input_key key; + bool have_key; +}; + +int serial_efi_setbrg(struct udevice *dev, int baudrate) +{ + return 0; +} + +static int serial_efi_get_key(struct serial_efi_priv *priv) +{ + int ret; + + if (priv->have_key) + return 0; + ret = priv->con_in->read_key_stroke(priv->con_in, &priv->key); + if (ret == EFI_NOT_READY) + return -EAGAIN; + else if (ret != EFI_SUCCESS) + return -EIO; + + priv->have_key = true; + + return 0; +} + +static int serial_efi_getc(struct udevice *dev) +{ + struct serial_efi_priv *priv = dev_get_priv(dev); + int ret, ch; + + ret = serial_efi_get_key(priv); + if (ret) + return ret; + + priv->have_key = false; + ch = priv->key.unicode_char; + + /* + * Unicode char 8 (for backspace) is never returned. Instead we get a + * key scan code of 8. Handle this so that backspace works correctly + * in the U-Boot command line. + */ + if (!ch && priv->key.scan_code == 8) + ch = 8; + debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code); + + return ch; +} + +static int serial_efi_putc(struct udevice *dev, const char ch) +{ + struct serial_efi_priv *priv = dev_get_priv(dev); + uint16_t ucode[2]; + int ret; + + ucode[0] = ch; + ucode[1] = '\0'; + ret = priv->con_out->output_string(priv->con_out, ucode); + if (ret) + return -EIO; + + return 0; +} + +static int serial_efi_pending(struct udevice *dev, bool input) +{ + struct serial_efi_priv *priv = dev_get_priv(dev); + int ret; + + /* We assume that EFI will stall if its output buffer fills up */ + if (!input) + return 0; + + ret = serial_efi_get_key(priv); + if (ret == -EAGAIN) + return 0; + else if (ret) + return ret; + + return 1; +} + +/* + * There is nothing to init here since the EFI console is already running by + * the time we enter U-Boot. + */ +void debug_uart_init(void) +{ +} + +static inline void _debug_uart_putc(int ch) +{ + struct efi_system_table *sys_table = efi_get_sys_table(); + uint16_t ucode[2]; + + ucode[0] = ch; + ucode[1] = '\0'; + sys_table->con_out->output_string(sys_table->con_out, ucode); +} + +DEBUG_UART_FUNCS + +static int serial_efi_probe(struct udevice *dev) +{ + struct efi_system_table *table = efi_get_sys_table(); + struct serial_efi_priv *priv = dev_get_priv(dev); + + priv->con_in = table->con_in; + priv->con_out = table->con_out; + + return 0; +} + +static const struct dm_serial_ops serial_efi_ops = { + .putc = serial_efi_putc, + .getc = serial_efi_getc, + .pending = serial_efi_pending, + .setbrg = serial_efi_setbrg, +}; + +static const struct udevice_id serial_efi_ids[] = { + { .compatible = "efi,uart" }, + { } +}; + +U_BOOT_DRIVER(serial_efi) = { + .name = "serial_efi", + .id = UCLASS_SERIAL, + .of_match = serial_efi_ids, + .priv_auto_alloc_size = sizeof(struct serial_efi_priv), + .probe = serial_efi_probe, + .ops = &serial_efi_ops, + .flags = DM_FLAG_PRE_RELOC, +};

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add a serial driver which makes use of EFI's console in/out service.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a comment about special handling for backspace
- Add a comment as to why debug_uart_init() is empty
- Drop unused DECLARE_GLOBAL_DATA_PTR
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Rename EFI debug UART to EFI_CONSOLE
- Replace serial_s5p with serial_efi
drivers/serial/Kconfig | 9 +++ drivers/serial/Makefile | 1 + drivers/serial/serial_efi.c | 157 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/serial/serial_efi.c
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4829284..bfbf58f 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -44,6 +44,15 @@ config DEBUG_UART_NS16550 will need to provide parameters to make this work. The driver will be available until the real driver model serial is running.
+config DEBUG_EFI_CONSOLE
bool "EFI"
depends on EFI_APP
help
Select this to enable a debug console which calls back to EFI to
output to the console. This can be useful for early debugging of
U-Boot when running on top of EFI (Extensive Firmware Interface).
This is a type of BIOS used by PCs.
endchoice
config DEBUG_UART_BASE diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d183eed..1d1f036 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_DW_SERIAL) += serial_dw.o +obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c new file mode 100644 index 0000000..cf57d89 --- /dev/null +++ b/drivers/serial/serial_efi.c @@ -0,0 +1,157 @@ +/*
- Copyright (c) 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <debug_uart.h> +#include <dm.h> +#include <efi.h> +#include <efi_api.h> +#include <errno.h> +#include <fdtdec.h> +#include <linux/compiler.h> +#include <asm/io.h> +#include <serial.h>
+/* Information about the efi console */ +struct serial_efi_priv {
struct efi_simple_input_interface *con_in;
struct efi_simple_text_output_protocol *con_out;
struct efi_input_key key;
bool have_key;
+};
+int serial_efi_setbrg(struct udevice *dev, int baudrate) +{
return 0;
+}
+static int serial_efi_get_key(struct serial_efi_priv *priv) +{
int ret;
if (priv->have_key)
return 0;
ret = priv->con_in->read_key_stroke(priv->con_in, &priv->key);
if (ret == EFI_NOT_READY)
return -EAGAIN;
else if (ret != EFI_SUCCESS)
return -EIO;
priv->have_key = true;
return 0;
+}
+static int serial_efi_getc(struct udevice *dev) +{
struct serial_efi_priv *priv = dev_get_priv(dev);
int ret, ch;
ret = serial_efi_get_key(priv);
if (ret)
return ret;
priv->have_key = false;
ch = priv->key.unicode_char;
/*
* Unicode char 8 (for backspace) is never returned. Instead we get a
* key scan code of 8. Handle this so that backspace works correctly
* in the U-Boot command line.
*/
if (!ch && priv->key.scan_code == 8)
ch = 8;
debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
return ch;
+}
+static int serial_efi_putc(struct udevice *dev, const char ch) +{
struct serial_efi_priv *priv = dev_get_priv(dev);
uint16_t ucode[2];
int ret;
ucode[0] = ch;
ucode[1] = '\0';
ret = priv->con_out->output_string(priv->con_out, ucode);
if (ret)
return -EIO;
return 0;
+}
+static int serial_efi_pending(struct udevice *dev, bool input) +{
struct serial_efi_priv *priv = dev_get_priv(dev);
int ret;
/* We assume that EFI will stall if its output buffer fills up */
if (!input)
return 0;
ret = serial_efi_get_key(priv);
if (ret == -EAGAIN)
return 0;
else if (ret)
return ret;
return 1;
+}
+/*
- There is nothing to init here since the EFI console is already running by
- the time we enter U-Boot.
- */
+void debug_uart_init(void) +{ +}
+static inline void _debug_uart_putc(int ch) +{
struct efi_system_table *sys_table = efi_get_sys_table();
uint16_t ucode[2];
ucode[0] = ch;
ucode[1] = '\0';
sys_table->con_out->output_string(sys_table->con_out, ucode);
+}
+DEBUG_UART_FUNCS
+static int serial_efi_probe(struct udevice *dev) +{
struct efi_system_table *table = efi_get_sys_table();
struct serial_efi_priv *priv = dev_get_priv(dev);
priv->con_in = table->con_in;
priv->con_out = table->con_out;
return 0;
+}
+static const struct dm_serial_ops serial_efi_ops = {
.putc = serial_efi_putc,
.getc = serial_efi_getc,
.pending = serial_efi_pending,
.setbrg = serial_efi_setbrg,
+};
+static const struct udevice_id serial_efi_ids[] = {
{ .compatible = "efi,uart" },
{ }
+};
+U_BOOT_DRIVER(serial_efi) = {
.name = "serial_efi",
.id = UCLASS_SERIAL,
.of_match = serial_efi_ids,
.priv_auto_alloc_size = sizeof(struct serial_efi_priv),
.probe = serial_efi_probe,
.ops = &serial_efi_ops,
.flags = DM_FLAG_PRE_RELOC,
+};
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Tested on Intel Crown Bay and QEMU Tested-by: Bin Meng bmeng.cn@gmail.com

From: Ben Stoltz stoltz@google.com
When U-Boot runs as an EFI application is does not have a definition of CONFIG_SYS_TEXT_BASE. U-Boot is a relocatable application and the relocation is done by EFI. U-Boot can be loaded at any address.
Ensure that this CONFIG option is not set in this case.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/Kconfig b/Kconfig index fc69189..05a34f7 100644 --- a/Kconfig +++ b/Kconfig @@ -179,6 +179,7 @@ config SYS_EXTRA_OPTIONS
config SYS_TEXT_BASE depends on SPARC || ARC || X86 || ARCH_UNIPHIER || ARCH_ZYNQMP + depends on !EFI_APP hex "Text Base" help TODO: Move CONFIG_SYS_TEXT_BASE for all the architecture

From: Ben Stoltz stoltz@google.com
Adjust the toolchain flags to build U-Boot as a relocatable shared library, as required by EFI.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a comment as to where LDFLAGS_EFI is used - Drop duplicate OBJCOPYFLAGS_EFI - Drop no-red-zone as it is not needed for i386 - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Use toolchain instead of tool chain
arch/x86/config.mk | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 999143e..a1c0eb2 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -8,19 +8,48 @@ CONFIG_STANDALONE_LOAD_ADDR ?= 0x40000
PLATFORM_CPPFLAGS += -fno-strict-aliasing -PLATFORM_CPPFLAGS += -mregparm=3 PLATFORM_CPPFLAGS += -fomit-frame-pointer PF_CPPFLAGS_X86 := $(call cc-option, -fno-toplevel-reorder, \ $(call cc-option, -fno-unit-at-a-time)) \ $(call cc-option, -mpreferred-stack-boundary=2) + PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_X86) PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm PLATFORM_CPPFLAGS += -march=i386 -m32
PLATFORM_RELFLAGS += -ffunction-sections -fvisibility=hidden
-PLATFORM_LDFLAGS += --emit-relocs -Bsymbolic -Bsymbolic-functions -m elf_i386 +PLATFORM_LDFLAGS += -Bsymbolic -Bsymbolic-functions
-LDFLAGS_FINAL += --gc-sections -pie LDFLAGS_FINAL += --wrap=__divdi3 --wrap=__udivdi3 LDFLAGS_FINAL += --wrap=__moddi3 --wrap=__umoddi3 + +# This is used in the top-level Makefile which does not include +# PLATFORM_LDFLAGS +LDFLAGS_EFI := -Bsymbolic -Bsymbolic-functions -shared --no-undefined + +OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ + -j .rel -j .rela -j .reloc + +CFLAGS_NON_EFI := -mregparm=3 +CFLAGS_EFI := -fpic -fshort-wchar + +EFIARCH=ia32 + +LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH) + +ifeq ($(CONFIG_EFI_APP),y) + +PLATFORM_CPPFLAGS += $(CFLAGS_EFI) +PLATFORM_LDFLAGS += -m elf_i386 +LDFLAGS_FINAL += -znocombreloc -shared +LDSCRIPT := $(LDSCRIPT_EFI) + +else + +PLATFORM_CPPFLAGS += $(CFLAGS_NON_EFI) +PLATFORM_LDFLAGS += --emit-relocs -m elf_i386 +LDFLAGS_FINAL += --gc-sections -pie + +endif

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Adjust the toolchain flags to build U-Boot as a relocatable shared library, as required by EFI.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a comment as to where LDFLAGS_EFI is used
- Drop duplicate OBJCOPYFLAGS_EFI
- Drop no-red-zone as it is not needed for i386
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Use toolchain instead of tool chain
arch/x86/config.mk | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 999143e..a1c0eb2 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -8,19 +8,48 @@ CONFIG_STANDALONE_LOAD_ADDR ?= 0x40000
PLATFORM_CPPFLAGS += -fno-strict-aliasing -PLATFORM_CPPFLAGS += -mregparm=3 PLATFORM_CPPFLAGS += -fomit-frame-pointer PF_CPPFLAGS_X86 := $(call cc-option, -fno-toplevel-reorder, \ $(call cc-option, -fno-unit-at-a-time)) \ $(call cc-option, -mpreferred-stack-boundary=2)
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_X86) PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm PLATFORM_CPPFLAGS += -march=i386 -m32
PLATFORM_RELFLAGS += -ffunction-sections -fvisibility=hidden
-PLATFORM_LDFLAGS += --emit-relocs -Bsymbolic -Bsymbolic-functions -m elf_i386 +PLATFORM_LDFLAGS += -Bsymbolic -Bsymbolic-functions
-LDFLAGS_FINAL += --gc-sections -pie LDFLAGS_FINAL += --wrap=__divdi3 --wrap=__udivdi3 LDFLAGS_FINAL += --wrap=__moddi3 --wrap=__umoddi3
+# This is used in the top-level Makefile which does not include +# PLATFORM_LDFLAGS
I see this is only used by building EFI payload. Can we remove this from this patch and move it into the EFI payload patch? And rename the variable to something like: LDFLAGS_EFIPAYLOAD to reflect this is only used for payload?
+LDFLAGS_EFI := -Bsymbolic -Bsymbolic-functions -shared --no-undefined
+OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
-j .rel -j .rela -j .reloc
+CFLAGS_NON_EFI := -mregparm=3 +CFLAGS_EFI := -fpic -fshort-wchar
+EFIARCH=ia32
Nits: please add space around =
+LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
+ifeq ($(CONFIG_EFI_APP),y)
+PLATFORM_CPPFLAGS += $(CFLAGS_EFI) +PLATFORM_LDFLAGS += -m elf_i386
Nits: '-m elf_i386' is always on for both cases, so we can remove '-m elf_i386' here and just leave it in the original place above
+LDFLAGS_FINAL += -znocombreloc -shared +LDSCRIPT := $(LDSCRIPT_EFI)
+else
+PLATFORM_CPPFLAGS += $(CFLAGS_NON_EFI) +PLATFORM_LDFLAGS += --emit-relocs -m elf_i386 +LDFLAGS_FINAL += --gc-sections -pie
+endif
Regards, Bin

Add support for building U-Boot as an EFI application with a .efi suffix. This can be loaded by EFI provided that EFI has the same bit width (32- or 64-bit) as U-Boot. This unfortunate limitation is imposed by EFI.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
Makefile | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Makefile b/Makefile index 2a3119e..3fb006b 100644 --- a/Makefile +++ b/Makefile @@ -750,6 +750,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf +ALL-$(CONFIG_EFI_APP) += u-boot.efi
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1078,6 +1079,10 @@ u-boot-dtb-tegra.bin: u-boot-nodtb-tegra.bin dts/dt.dtb FORCE endif endif
+OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI) +u-boot.efi: u-boot FORCE + $(call if_changed,zobjcopy) + u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat)

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add support for building U-Boot as an EFI application with a .efi suffix. This can be loaded by EFI provided that EFI has the same bit width (32- or 64-bit) as U-Boot. This unfortunate limitation is imposed by EFI.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
Makefile | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Makefile b/Makefile index 2a3119e..3fb006b 100644 --- a/Makefile +++ b/Makefile @@ -750,6 +750,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf +ALL-$(CONFIG_EFI_APP) += u-boot.efi
u-boot-app.efi?
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1078,6 +1079,10 @@ u-boot-dtb-tegra.bin: u-boot-nodtb-tegra.bin dts/dt.dtb FORCE endif endif
+OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI)
u-boot-app.efi?
+u-boot.efi: u-boot FORCE
u-boot-app.efi?
$(call if_changed,zobjcopy)
u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat)
--
Regards, Bin

Hi Bin,
On 3 August 2015 at 09:51, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add support for building U-Boot as an EFI application with a .efi suffix. This can be loaded by EFI provided that EFI has the same bit width (32- or 64-bit) as U-Boot. This unfortunate limitation is imposed by EFI.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
Makefile | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Makefile b/Makefile index 2a3119e..3fb006b 100644 --- a/Makefile +++ b/Makefile @@ -750,6 +750,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf +ALL-$(CONFIG_EFI_APP) += u-boot.efi
u-boot-app.efi?
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1078,6 +1079,10 @@ u-boot-dtb-tegra.bin: u-boot-nodtb-tegra.bin dts/dt.dtb FORCE endif endif
+OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI)
u-boot-app.efi?
+u-boot.efi: u-boot FORCE
u-boot-app.efi?
$(call if_changed,zobjcopy)
u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat)
--
Ah, that ended up in a different patch. I'll move it.
Regards, Simon

When running as an EFI application we must skip relocation. Add support for this in the x86 relocation code.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Return early in copy_uboot_to_ram() and clear_bbs() when relocation disabled
arch/x86/lib/relocate.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 1a62142..9e748d2 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -28,6 +28,8 @@ int copy_uboot_to_ram(void) { size_t len = (size_t)&__data_end - (size_t)&__text_start;
+ if (gd->flags & GD_FLG_SKIP_RELOC) + return 0; memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
return 0; @@ -38,6 +40,8 @@ int clear_bss(void) ulong dst_addr = (ulong)&__bss_start + gd->reloc_off; size_t len = (size_t)&__bss_end - (size_t)&__bss_start;
+ if (gd->flags & GD_FLG_SKIP_RELOC) + return 0; memset((void *)dst_addr, 0x00, len);
return 0; @@ -58,6 +62,8 @@ int do_elf_reloc_fixups(void) /* The size of the region of u-boot that runs out of RAM. */ uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start;
+ if (gd->flags & GD_FLG_SKIP_RELOC) + return 0; if (re_src == re_end) panic("No relocation data");

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
When running as an EFI application we must skip relocation. Add support for this in the x86 relocation code.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Return early in copy_uboot_to_ram() and clear_bbs() when relocation disabled
arch/x86/lib/relocate.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 1a62142..9e748d2 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -28,6 +28,8 @@ int copy_uboot_to_ram(void) { size_t len = (size_t)&__data_end - (size_t)&__text_start;
if (gd->flags & GD_FLG_SKIP_RELOC)
return 0; memcpy((void *)gd->relocaddr, (void *)&__text_start, len); return 0;
@@ -38,6 +40,8 @@ int clear_bss(void) ulong dst_addr = (ulong)&__bss_start + gd->reloc_off; size_t len = (size_t)&__bss_end - (size_t)&__bss_start;
if (gd->flags & GD_FLG_SKIP_RELOC)
return 0; memset((void *)dst_addr, 0x00, len); return 0;
@@ -58,6 +62,8 @@ int do_elf_reloc_fixups(void) /* The size of the region of u-boot that runs out of RAM. */ uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start;
if (gd->flags & GD_FLG_SKIP_RELOC)
return 0; if (re_src == re_end) panic("No relocation data");
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Bring in this file from Linux 4.1. It supports relocation features specific to x86.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Drop unneeded include of asm/ptrace.h - Fix comment style
arch/x86/include/asm/elf.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 arch/x86/include/asm/elf.h
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h new file mode 100644 index 0000000..3bdcdfe --- /dev/null +++ b/arch/x86/include/asm/elf.h @@ -0,0 +1,46 @@ +/* + * Brought in from Linux 4.1, removed things not useful to U-Boot. + * The definitions perhaps came from the GNU Library which is GPL. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_X86_ELF_H +#define _ASM_X86_ELF_H + +/* ELF register definitions */ +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +/* x86-64 relocation types */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +/* 32 bit signed pc relative offset to GOT */ +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + +#endif

From: Ben Stoltz stoltz@google.com
Add the required x86 glue code. This includes the initial start-up, relocation and jumping to efi_main(). We also need to avoid fiddling with interrupts.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add ALIGN() before .dynamic in the linker script - Add a blank line before return in the _relocate() function - Add a comment as to why .hash has to be first in the linker script - Add a comment as to why interrupt_init() must be skipped for EFI - Drop unused DECLARE_GLOBAL_DATA_INIT - Drop unused board_eth_init() - Drop use of CONFIG_X86_64 since we don't support a 64-bit EFI application yet - Fix spacing around operators - Move 64-bit crt0 to a later patch - Move crt0 and reloc files into arch/x86/lib/efi/ - Remove KEEP in the EFI linker script since garbage collection is not enabled - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Rename ImageBase to image_base - Use SPDX for the EFI start and relocation code - Use u-boot-app.efi instead of u-boot.efi
Makefile | 6 +-- arch/x86/Kconfig | 3 ++ arch/x86/Makefile | 2 + arch/x86/cpu/Makefile | 1 + arch/x86/cpu/efi/Makefile | 8 +++ arch/x86/cpu/efi/efi.c | 42 ++++++++++++++++ arch/x86/cpu/efi/elf_ia32_efi.lds | 94 ++++++++++++++++++++++++++++++++++++ arch/x86/cpu/efi/sdram.c | 29 +++++++++++ arch/x86/cpu/interrupts.c | 6 +++ arch/x86/include/asm/arch-efi/gpio.h | 10 ++++ arch/x86/lib/efi/crt0-efi-ia32.S | 52 ++++++++++++++++++++ arch/x86/lib/efi/reloc_ia32.c | 72 +++++++++++++++++++++++++++ 12 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 arch/x86/cpu/efi/Makefile create mode 100644 arch/x86/cpu/efi/efi.c create mode 100644 arch/x86/cpu/efi/elf_ia32_efi.lds create mode 100644 arch/x86/cpu/efi/sdram.c create mode 100644 arch/x86/include/asm/arch-efi/gpio.h create mode 100644 arch/x86/lib/efi/crt0-efi-ia32.S create mode 100644 arch/x86/lib/efi/reloc_ia32.c
diff --git a/Makefile b/Makefile index 3fb006b..6da9224 100644 --- a/Makefile +++ b/Makefile @@ -750,7 +750,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf -ALL-$(CONFIG_EFI_APP) += u-boot.efi +ALL-$(CONFIG_EFI_APP) += u-boot-app.efi
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1079,8 +1079,8 @@ u-boot-dtb-tegra.bin: u-boot-nodtb-tegra.bin dts/dt.dtb FORCE endif endif
-OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI) -u-boot.efi: u-boot FORCE +OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI) +u-boot-app.efi: u-boot FORCE $(call if_changed,zobjcopy)
u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e8968a7..7e6e89c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -11,6 +11,9 @@ choice config VENDOR_COREBOOT bool "coreboot"
+config VENDOR_EFI + bool "efi" + config VENDOR_EMULATION bool "emulation"
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 36a6018..d104a49 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -2,7 +2,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifeq ($(CONFIG_EFI_APP),) head-y := arch/x86/cpu/start.o +endif ifeq ($(CONFIG_SPL_BUILD),y) head-y += arch/x86/cpu/start16.o head-y += arch/x86/cpu/resetvec.o diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 8a8e63e..5e058c0 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -14,6 +14,7 @@ obj-y += interrupts.o cpu.o cpu_x86.o call64.o
obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ +obj-$(CONFIG_EFI_APP) += efi/ obj-$(CONFIG_QEMU) += qemu/ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ diff --git a/arch/x86/cpu/efi/Makefile b/arch/x86/cpu/efi/Makefile new file mode 100644 index 0000000..e091637 --- /dev/null +++ b/arch/x86/cpu/efi/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (c) 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += efi.o +obj-y += sdram.o diff --git a/arch/x86/cpu/efi/efi.c b/arch/x86/cpu/efi/efi.c new file mode 100644 index 0000000..75ba0d4 --- /dev/null +++ b/arch/x86/cpu/efi/efi.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <netdev.h> + +int arch_cpu_init(void) +{ +#ifdef CONFIG_SYS_X86_TSC_TIMER + timer_set_base(rdtsc()); +#endif + + return 0; +} + +int board_early_init_f(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + return default_print_cpuinfo(); +} + +void board_final_cleanup(void) +{ +} + +int misc_init_r(void) +{ + return 0; +} + +int arch_misc_init(void) +{ + return 0; +} diff --git a/arch/x86/cpu/efi/elf_ia32_efi.lds b/arch/x86/cpu/efi/elf_ia32_efi.lds new file mode 100644 index 0000000..a83ddd0 --- /dev/null +++ b/arch/x86/cpu/efi/elf_ia32_efi.lds @@ -0,0 +1,94 @@ +/* + * U-Boot EFI linker script + * + * SPDX-License-Identifier: bsd-2-clause + * + * Modified from usr/lib32/elf_ia32_efi.lds in gnu-efi + */ + +#include <config.h> + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + image_base = .; + .hash : { *(.hash) } /* this MUST come first, EFI expects it */ + . = ALIGN(4096); + .text : + { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + . = ALIGN(4096); + .sdata : + { + *(.got.plt) + *(.got) + *(.srodata) + *(.sdata) + *(.sbss) + *(.scommon) + } + . = ALIGN(4096); + .data : + { + *(.rodata*) + *(.data) + *(.data1) + *(.data.*) + *(.sdata) + *(.got.plt) + *(.got) + /* + * the EFI loader doesn't seem to like a .bss section, so we + * stick it all into .data: + */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + + /* U-Boot lists and device tree */ + . = ALIGN(8); + *(SORT(.u_boot_list*)); + . = ALIGN(8); + *(.dtb*); + } + + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rel : + { + *(.rel.data) + *(.rel.data.*) + *(.rel.got) + *(.rel.stab) + *(.data.rel.ro.local) + *(.data.rel.local) + *(.data.rel.ro) + *(.data.rel*) + *(.rel.u_boot_list*) + } + . = ALIGN(4096); + .reloc : /* This is the PECOFF .reloc section! */ + { + *(.reloc) + } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + /DISCARD/ : + { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff --git a/arch/x86/cpu/efi/sdram.c b/arch/x86/cpu/efi/sdram.c new file mode 100644 index 0000000..5159944 --- /dev/null +++ b/arch/x86/cpu/efi/sdram.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <efi.h> +#include <asm/u-boot-x86.h> + +DECLARE_GLOBAL_DATA_PTR; + +ulong board_get_usable_ram_top(ulong total_size) +{ + return (ulong)efi_get_ram_base() + gd->ram_size; +} + +int dram_init(void) +{ + /* gd->ram_size is set as part of EFI init */ + + return 0; +} + +void dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = efi_get_ram_base(); + gd->bd->bi_dram[0].size = CONFIG_EFI_RAM_SIZE; +} diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 3a9c2d4..a112938 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -242,6 +242,11 @@ int disable_interrupts(void)
int interrupt_init(void) { + /* + * When running as an EFI application we are not in control of + * interrupts and should leave them alone. + */ +#ifndef CONFIG_EFI_APP /* Just in case... */ disable_interrupts();
@@ -255,6 +260,7 @@ int interrupt_init(void)
/* It is now safe to enable interrupts */ enable_interrupts(); +#endif
return 0; } diff --git a/arch/x86/include/asm/arch-efi/gpio.h b/arch/x86/include/asm/arch-efi/gpio.h new file mode 100644 index 0000000..f044f07 --- /dev/null +++ b/arch/x86/include/asm/arch-efi/gpio.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2015 Google, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _X86_ARCH_GPIO_H_ +#define _X86_ARCH_GPIO_H_ + +#endif /* _X86_ARCH_GPIO_H_ */ diff --git a/arch/x86/lib/efi/crt0-efi-ia32.S b/arch/x86/lib/efi/crt0-efi-ia32.S new file mode 100644 index 0000000..30e5eb0 --- /dev/null +++ b/arch/x86/lib/efi/crt0-efi-ia32.S @@ -0,0 +1,52 @@ +/* + * crt0-efi-ia32.S - x86 EFI startup code. + * + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger davidm@hpl.hp.com. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + .text + .align 4 + + .globl _start +_start: + pushl %ebp + movl %esp,%ebp + + pushl 12(%ebp) # copy "image" argument + pushl 8(%ebp) # copy "systab" argument + + call 0f +0: popl %eax + movl %eax,%ebx + + addl $image_base-0b,%eax # %eax = ldbase + addl $_DYNAMIC-0b,%ebx # %ebx = _DYNAMIC + + pushl %ebx # pass _DYNAMIC as second argument + pushl %eax # pass ldbase as first argument + call _relocate + popl %ebx + popl %ebx + testl %eax,%eax + jne .exit + call efi_main # call app with "image" and "systab" argument + +.exit: leave + ret + + /* + * hand-craft a dummy .reloc section so EFI knows it's a relocatable + * executable: + */ + .data +dummy: .long 0 + +#define IMAGE_REL_ABSOLUTE 0 + .section .reloc + .long dummy /* Page RVA */ + .long 10 /* Block Size (2*4+2) */ + .word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */ diff --git a/arch/x86/lib/efi/reloc_ia32.c b/arch/x86/lib/efi/reloc_ia32.c new file mode 100644 index 0000000..4d68255 --- /dev/null +++ b/arch/x86/lib/efi/reloc_ia32.c @@ -0,0 +1,72 @@ +/* + * reloc_ia32.c - position independent x86 ELF shared object relocator + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger davidm@hpl.hp.com. + * + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common.h> +#include <efi.h> +#include <elf.h> +#include <asm/elf.h> + +efi_status_t _relocate(long ldbase, Elf32_Dyn *dyn, efi_handle_t image, + struct efi_system_table *systab) +{ + long relsz = 0, relent = 0; + Elf32_Rel *rel = 0; + unsigned long *addr; + int i; + + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_REL: + rel = (Elf32_Rel *)((unsigned long)dyn[i].d_un.d_ptr + + ldbase); + break; + + case DT_RELSZ: + relsz = dyn[i].d_un.d_val; + break; + + case DT_RELENT: + relent = dyn[i].d_un.d_val; + break; + + case DT_RELA: + break; + + default: + break; + } + } + + if (!rel && relent == 0) + return EFI_SUCCESS; + + if (!rel || relent == 0) + return EFI_LOAD_ERROR; + + while (relsz > 0) { + /* apply the relocs */ + switch (ELF32_R_TYPE(rel->r_info)) { + case R_386_NONE: + break; + + case R_386_RELATIVE: + addr = (unsigned long *)(ldbase + rel->r_offset); + *addr += ldbase; + break; + + default: + break; + } + rel = (Elf32_Rel *)((char *)rel + relent); + relsz -= relent; + } + + return EFI_SUCCESS; +}

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Add the required x86 glue code. This includes the initial start-up, relocation and jumping to efi_main(). We also need to avoid fiddling with interrupts.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add ALIGN() before .dynamic in the linker script
- Add a blank line before return in the _relocate() function
- Add a comment as to why .hash has to be first in the linker script
- Add a comment as to why interrupt_init() must be skipped for EFI
- Drop unused DECLARE_GLOBAL_DATA_INIT
- Drop unused board_eth_init()
- Drop use of CONFIG_X86_64 since we don't support a 64-bit EFI application yet
- Fix spacing around operators
- Move 64-bit crt0 to a later patch
- Move crt0 and reloc files into arch/x86/lib/efi/
- Remove KEEP in the EFI linker script since garbage collection is not enabled
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Rename ImageBase to image_base
- Use SPDX for the EFI start and relocation code
- Use u-boot-app.efi instead of u-boot.efi
Makefile | 6 +-- arch/x86/Kconfig | 3 ++ arch/x86/Makefile | 2 + arch/x86/cpu/Makefile | 1 + arch/x86/cpu/efi/Makefile | 8 +++ arch/x86/cpu/efi/efi.c | 42 ++++++++++++++++ arch/x86/cpu/efi/elf_ia32_efi.lds | 94 ++++++++++++++++++++++++++++++++++++ arch/x86/cpu/efi/sdram.c | 29 +++++++++++ arch/x86/cpu/interrupts.c | 6 +++ arch/x86/include/asm/arch-efi/gpio.h | 10 ++++ arch/x86/lib/efi/crt0-efi-ia32.S | 52 ++++++++++++++++++++ arch/x86/lib/efi/reloc_ia32.c | 72 +++++++++++++++++++++++++++ 12 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 arch/x86/cpu/efi/Makefile create mode 100644 arch/x86/cpu/efi/efi.c create mode 100644 arch/x86/cpu/efi/elf_ia32_efi.lds create mode 100644 arch/x86/cpu/efi/sdram.c create mode 100644 arch/x86/include/asm/arch-efi/gpio.h create mode 100644 arch/x86/lib/efi/crt0-efi-ia32.S create mode 100644 arch/x86/lib/efi/reloc_ia32.c
diff --git a/Makefile b/Makefile index 3fb006b..6da9224 100644 --- a/Makefile +++ b/Makefile @@ -750,7 +750,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf -ALL-$(CONFIG_EFI_APP) += u-boot.efi +ALL-$(CONFIG_EFI_APP) += u-boot-app.efi
Can we move this change to http://patchwork.ozlabs.org/patch/502642/?
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1079,8 +1079,8 @@ u-boot-dtb-tegra.bin: u-boot-nodtb-tegra.bin dts/dt.dtb FORCE endif endif
-OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI) -u-boot.efi: u-boot FORCE +OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI) +u-boot-app.efi: u-boot FORCE $(call if_changed,zobjcopy)
Ditto.
u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e8968a7..7e6e89c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -11,6 +11,9 @@ choice config VENDOR_COREBOOT bool "coreboot"
+config VENDOR_EFI
bool "efi"
config VENDOR_EMULATION bool "emulation"
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 36a6018..d104a49 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -2,7 +2,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifeq ($(CONFIG_EFI_APP),) head-y := arch/x86/cpu/start.o +endif ifeq ($(CONFIG_SPL_BUILD),y) head-y += arch/x86/cpu/start16.o head-y += arch/x86/cpu/resetvec.o diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 8a8e63e..5e058c0 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -14,6 +14,7 @@ obj-y += interrupts.o cpu.o cpu_x86.o call64.o
obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ +obj-$(CONFIG_EFI_APP) += efi/ obj-$(CONFIG_QEMU) += qemu/ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ diff --git a/arch/x86/cpu/efi/Makefile b/arch/x86/cpu/efi/Makefile new file mode 100644 index 0000000..e091637 --- /dev/null +++ b/arch/x86/cpu/efi/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (c) 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-y += efi.o +obj-y += sdram.o diff --git a/arch/x86/cpu/efi/efi.c b/arch/x86/cpu/efi/efi.c new file mode 100644 index 0000000..75ba0d4 --- /dev/null +++ b/arch/x86/cpu/efi/efi.c @@ -0,0 +1,42 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <netdev.h>
+int arch_cpu_init(void) +{ +#ifdef CONFIG_SYS_X86_TSC_TIMER
timer_set_base(rdtsc());
+#endif
return 0;
+}
+int board_early_init_f(void) +{
return 0;
+}
+int print_cpuinfo(void) +{
return default_print_cpuinfo();
+}
+void board_final_cleanup(void) +{ +}
+int misc_init_r(void) +{
return 0;
+}
+int arch_misc_init(void) +{
return 0;
+} diff --git a/arch/x86/cpu/efi/elf_ia32_efi.lds b/arch/x86/cpu/efi/elf_ia32_efi.lds new file mode 100644 index 0000000..a83ddd0 --- /dev/null +++ b/arch/x86/cpu/efi/elf_ia32_efi.lds @@ -0,0 +1,94 @@ +/*
- U-Boot EFI linker script
- SPDX-License-Identifier: bsd-2-clause
Should be "BSD-2-Clause" (per http://spdx.org/licenses/)
- Modified from usr/lib32/elf_ia32_efi.lds in gnu-efi
- */
+#include <config.h>
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{
image_base = .;
.hash : { *(.hash) } /* this MUST come first, EFI expects it */
. = ALIGN(4096);
.text :
{
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
}
. = ALIGN(4096);
.sdata :
{
*(.got.plt)
*(.got)
*(.srodata)
*(.sdata)
*(.sbss)
*(.scommon)
}
. = ALIGN(4096);
.data :
{
*(.rodata*)
*(.data)
*(.data1)
*(.data.*)
*(.sdata)
*(.got.plt)
*(.got)
/*
* the EFI loader doesn't seem to like a .bss section, so we
* stick it all into .data:
*/
*(.sbss)
*(.scommon)
*(.dynbss)
*(.bss)
*(COMMON)
/* U-Boot lists and device tree */
. = ALIGN(8);
*(SORT(.u_boot_list*));
. = ALIGN(8);
*(.dtb*);
}
. = ALIGN(4096);
.dynamic : { *(.dynamic) }
. = ALIGN(4096);
.rel :
{
*(.rel.data)
*(.rel.data.*)
*(.rel.got)
*(.rel.stab)
*(.data.rel.ro.local)
*(.data.rel.local)
*(.data.rel.ro)
*(.data.rel*)
*(.rel.u_boot_list*)
}
. = ALIGN(4096);
.reloc : /* This is the PECOFF .reloc section! */
{
*(.reloc)
}
. = ALIGN(4096);
.dynsym : { *(.dynsym) }
. = ALIGN(4096);
.dynstr : { *(.dynstr) }
. = ALIGN(4096);
/DISCARD/ :
{
*(.rel.reloc)
*(.eh_frame)
*(.note.GNU-stack)
}
.comment 0 : { *(.comment) }
+} diff --git a/arch/x86/cpu/efi/sdram.c b/arch/x86/cpu/efi/sdram.c new file mode 100644 index 0000000..5159944 --- /dev/null +++ b/arch/x86/cpu/efi/sdram.c @@ -0,0 +1,29 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <efi.h> +#include <asm/u-boot-x86.h>
+DECLARE_GLOBAL_DATA_PTR;
+ulong board_get_usable_ram_top(ulong total_size) +{
return (ulong)efi_get_ram_base() + gd->ram_size;
+}
+int dram_init(void) +{
/* gd->ram_size is set as part of EFI init */
return 0;
+}
+void dram_init_banksize(void) +{
gd->bd->bi_dram[0].start = efi_get_ram_base();
gd->bd->bi_dram[0].size = CONFIG_EFI_RAM_SIZE;
+} diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 3a9c2d4..a112938 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -242,6 +242,11 @@ int disable_interrupts(void)
int interrupt_init(void) {
/*
* When running as an EFI application we are not in control of
* interrupts and should leave them alone.
*/
+#ifndef CONFIG_EFI_APP /* Just in case... */ disable_interrupts();
@@ -255,6 +260,7 @@ int interrupt_init(void)
/* It is now safe to enable interrupts */ enable_interrupts();
+#endif
return 0;
} diff --git a/arch/x86/include/asm/arch-efi/gpio.h b/arch/x86/include/asm/arch-efi/gpio.h new file mode 100644 index 0000000..f044f07 --- /dev/null +++ b/arch/x86/include/asm/arch-efi/gpio.h @@ -0,0 +1,10 @@ +/*
- Copyright (c) 2015 Google, Inc.
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _X86_ARCH_GPIO_H_ +#define _X86_ARCH_GPIO_H_
+#endif /* _X86_ARCH_GPIO_H_ */ diff --git a/arch/x86/lib/efi/crt0-efi-ia32.S b/arch/x86/lib/efi/crt0-efi-ia32.S new file mode 100644 index 0000000..30e5eb0 --- /dev/null +++ b/arch/x86/lib/efi/crt0-efi-ia32.S @@ -0,0 +1,52 @@ +/*
- crt0-efi-ia32.S - x86 EFI startup code.
- Copyright (C) 1999 Hewlett-Packard Co.
- Contributed by David Mosberger davidm@hpl.hp.com.
- All rights reserved.
- SPDX-License-Identifier: BSD-3-Clause
- */
.text
.align 4
.globl _start
+_start:
pushl %ebp
movl %esp,%ebp
pushl 12(%ebp) # copy "image" argument
pushl 8(%ebp) # copy "systab" argument
call 0f
+0: popl %eax
movl %eax,%ebx
addl $image_base-0b,%eax # %eax = ldbase
addl $_DYNAMIC-0b,%ebx # %ebx = _DYNAMIC
pushl %ebx # pass _DYNAMIC as second argument
pushl %eax # pass ldbase as first argument
call _relocate
popl %ebx
popl %ebx
testl %eax,%eax
jne .exit
call efi_main # call app with "image" and "systab" argument
+.exit: leave
ret
/*
* hand-craft a dummy .reloc section so EFI knows it's a relocatable
* executable:
*/
.data
+dummy: .long 0
+#define IMAGE_REL_ABSOLUTE 0
.section .reloc
.long dummy /* Page RVA */
.long 10 /* Block Size (2*4+2) */
.word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */
diff --git a/arch/x86/lib/efi/reloc_ia32.c b/arch/x86/lib/efi/reloc_ia32.c new file mode 100644 index 0000000..4d68255 --- /dev/null +++ b/arch/x86/lib/efi/reloc_ia32.c @@ -0,0 +1,72 @@ +/*
- reloc_ia32.c - position independent x86 ELF shared object relocator
- Copyright (C) 1999 Hewlett-Packard Co.
- Contributed by David Mosberger davidm@hpl.hp.com.
- All rights reserved.
- SPDX-License-Identifier: BSD-3-Clause
- */
+#include <common.h> +#include <efi.h> +#include <elf.h> +#include <asm/elf.h>
+efi_status_t _relocate(long ldbase, Elf32_Dyn *dyn, efi_handle_t image,
struct efi_system_table *systab)
+{
long relsz = 0, relent = 0;
Elf32_Rel *rel = 0;
unsigned long *addr;
int i;
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
switch (dyn[i].d_tag) {
case DT_REL:
rel = (Elf32_Rel *)((unsigned long)dyn[i].d_un.d_ptr +
ldbase);
break;
case DT_RELSZ:
relsz = dyn[i].d_un.d_val;
break;
case DT_RELENT:
relent = dyn[i].d_un.d_val;
break;
case DT_RELA:
break;
default:
break;
}
}
if (!rel && relent == 0)
return EFI_SUCCESS;
if (!rel || relent == 0)
return EFI_LOAD_ERROR;
while (relsz > 0) {
/* apply the relocs */
switch (ELF32_R_TYPE(rel->r_info)) {
case R_386_NONE:
break;
case R_386_RELATIVE:
addr = (unsigned long *)(ldbase + rel->r_offset);
*addr += ldbase;
break;
default:
break;
}
rel = (Elf32_Rel *)((char *)rel + relent);
relsz -= relent;
}
return EFI_SUCCESS;
+}
Regards, Bin

From: Ben Stoltz stoltz@google.com
Add support for the efi-x86 board, which supports running U-Boot as an EFI 32-bit application.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Drop unnecessary SYS_CAR_ADDR/SIZE Kconfig options - Fix text alignment in Kconfig files
arch/x86/Kconfig | 1 + board/efi/Kconfig | 19 +++++++++++++++++++ board/efi/efi-x86/Kconfig | 15 +++++++++++++++ board/efi/efi-x86/MAINTAINERS | 6 ++++++ board/efi/efi-x86/Makefile | 7 +++++++ board/efi/efi-x86/efi.c | 18 ++++++++++++++++++ 6 files changed, 66 insertions(+) create mode 100644 board/efi/Kconfig create mode 100644 board/efi/efi-x86/Kconfig create mode 100644 board/efi/efi-x86/MAINTAINERS create mode 100644 board/efi/efi-x86/Makefile create mode 100644 board/efi/efi-x86/efi.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7e6e89c..f124d58 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -27,6 +27,7 @@ endchoice
# board-specific options below source "board/coreboot/Kconfig" +source "board/efi/Kconfig" source "board/emulation/Kconfig" source "board/google/Kconfig" source "board/intel/Kconfig" diff --git a/board/efi/Kconfig b/board/efi/Kconfig new file mode 100644 index 0000000..6f86a48 --- /dev/null +++ b/board/efi/Kconfig @@ -0,0 +1,19 @@ +if VENDOR_EFI + +choice + prompt "Mainboard model" + optional + +config TARGET_EFI + bool "efi" + help + This target is used for running U-Boot on top of EFI. In + this case EFI does the early initialisation, and U-Boot + takes over once the RAM, video and CPU are fully running. + U-Boot is loaded as an application from EFI. + +endchoice + +source "board/efi/efi-x86/Kconfig" + +endif diff --git a/board/efi/efi-x86/Kconfig b/board/efi/efi-x86/Kconfig new file mode 100644 index 0000000..fa609ba --- /dev/null +++ b/board/efi/efi-x86/Kconfig @@ -0,0 +1,15 @@ +if TARGET_EFI + +config SYS_BOARD + default "efi-x86" + +config SYS_VENDOR + default "efi" + +config SYS_SOC + default "efi" + +config SYS_CONFIG_NAME + default "efi-x86" + +endif diff --git a/board/efi/efi-x86/MAINTAINERS b/board/efi/efi-x86/MAINTAINERS new file mode 100644 index 0000000..a44c7c6 --- /dev/null +++ b/board/efi/efi-x86/MAINTAINERS @@ -0,0 +1,6 @@ +EFI-X86 BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/efi/efi-x86/ +F: include/configs/efi-x86.h +F: configs/efi-x86_defconfig diff --git a/board/efi/efi-x86/Makefile b/board/efi/efi-x86/Makefile new file mode 100644 index 0000000..9b1e0bd --- /dev/null +++ b/board/efi/efi-x86/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (c) 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += efi.o diff --git a/board/efi/efi-x86/efi.c b/board/efi/efi-x86/efi.c new file mode 100644 index 0000000..08958f9 --- /dev/null +++ b/board/efi/efi-x86/efi.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/gpio.h> + +int arch_early_init_r(void) +{ + return 0; +} + +void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio) +{ + return; +}

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Add support for the efi-x86 board, which supports running U-Boot as an EFI 32-bit application.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Drop unnecessary SYS_CAR_ADDR/SIZE Kconfig options
- Fix text alignment in Kconfig files
arch/x86/Kconfig | 1 + board/efi/Kconfig | 19 +++++++++++++++++++ board/efi/efi-x86/Kconfig | 15 +++++++++++++++ board/efi/efi-x86/MAINTAINERS | 6 ++++++ board/efi/efi-x86/Makefile | 7 +++++++ board/efi/efi-x86/efi.c | 18 ++++++++++++++++++ 6 files changed, 66 insertions(+) create mode 100644 board/efi/Kconfig create mode 100644 board/efi/efi-x86/Kconfig create mode 100644 board/efi/efi-x86/MAINTAINERS create mode 100644 board/efi/efi-x86/Makefile create mode 100644 board/efi/efi-x86/efi.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7e6e89c..f124d58 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -27,6 +27,7 @@ endchoice
# board-specific options below source "board/coreboot/Kconfig" +source "board/efi/Kconfig" source "board/emulation/Kconfig" source "board/google/Kconfig" source "board/intel/Kconfig" diff --git a/board/efi/Kconfig b/board/efi/Kconfig new file mode 100644 index 0000000..6f86a48 --- /dev/null +++ b/board/efi/Kconfig @@ -0,0 +1,19 @@ +if VENDOR_EFI
+choice
prompt "Mainboard model"
optional
+config TARGET_EFI
bool "efi"
help
This target is used for running U-Boot on top of EFI. In
this case EFI does the early initialisation, and U-Boot
takes over once the RAM, video and CPU are fully running.
U-Boot is loaded as an application from EFI.
+endchoice
+source "board/efi/efi-x86/Kconfig"
+endif diff --git a/board/efi/efi-x86/Kconfig b/board/efi/efi-x86/Kconfig new file mode 100644 index 0000000..fa609ba --- /dev/null +++ b/board/efi/efi-x86/Kconfig @@ -0,0 +1,15 @@ +if TARGET_EFI
+config SYS_BOARD
default "efi-x86"
+config SYS_VENDOR
default "efi"
+config SYS_SOC
default "efi"
+config SYS_CONFIG_NAME
default "efi-x86"
+endif diff --git a/board/efi/efi-x86/MAINTAINERS b/board/efi/efi-x86/MAINTAINERS new file mode 100644 index 0000000..a44c7c6 --- /dev/null +++ b/board/efi/efi-x86/MAINTAINERS @@ -0,0 +1,6 @@ +EFI-X86 BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/efi/efi-x86/ +F: include/configs/efi-x86.h +F: configs/efi-x86_defconfig diff --git a/board/efi/efi-x86/Makefile b/board/efi/efi-x86/Makefile new file mode 100644 index 0000000..9b1e0bd --- /dev/null +++ b/board/efi/efi-x86/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (c) 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-y += efi.o diff --git a/board/efi/efi-x86/efi.c b/board/efi/efi-x86/efi.c new file mode 100644 index 0000000..08958f9 --- /dev/null +++ b/board/efi/efi-x86/efi.c @@ -0,0 +1,18 @@ +/*
- Copyright (C) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/gpio.h>
+int arch_early_init_r(void) +{
return 0;
+}
+void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio) +{
return;
+}
Reviewed-by: Bin Meng bmeng.cn@gmail.com

This contains just enough to bring up the serial UART.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Remove extraneous '+' in comment - Use "efi,app" instead of "efi,payload" for the compatible string
arch/x86/dts/Makefile | 1 + arch/x86/dts/efi.dts | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 arch/x86/dts/efi.dts
diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile index f86514c..53d0a04 100644 --- a/arch/x86/dts/Makefile +++ b/arch/x86/dts/Makefile @@ -1,6 +1,7 @@ dtb-y += chromebook_link.dtb \ chromebox_panther.dtb \ crownbay.dtb \ + efi.dtb \ galileo.dtb \ minnowmax.dtb \ qemu-x86_i440fx.dtb \ diff --git a/arch/x86/dts/efi.dts b/arch/x86/dts/efi.dts new file mode 100644 index 0000000..1f50428 --- /dev/null +++ b/arch/x86/dts/efi.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/include/ "skeleton.dtsi" + +/ { + model = "EFI"; + compatible = "efi,app"; + + chosen { + stdout-path = &serial; + }; + + serial: serial { + compatible = "efi,uart"; + }; +};

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This contains just enough to bring up the serial UART.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Remove extraneous '+' in comment
- Use "efi,app" instead of "efi,payload" for the compatible string
arch/x86/dts/Makefile | 1 + arch/x86/dts/efi.dts | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 arch/x86/dts/efi.dts
diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile index f86514c..53d0a04 100644 --- a/arch/x86/dts/Makefile +++ b/arch/x86/dts/Makefile @@ -1,6 +1,7 @@ dtb-y += chromebook_link.dtb \ chromebox_panther.dtb \ crownbay.dtb \
efi.dtb \ galileo.dtb \ minnowmax.dtb \ qemu-x86_i440fx.dtb \
diff --git a/arch/x86/dts/efi.dts b/arch/x86/dts/efi.dts new file mode 100644 index 0000000..1f50428 --- /dev/null +++ b/arch/x86/dts/efi.dts @@ -0,0 +1,22 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+/dts-v1/;
+/include/ "skeleton.dtsi"
+/ {
model = "EFI";
compatible = "efi,app";
chosen {
stdout-path = &serial;
};
serial: serial {
compatible = "efi,uart";
};
+};
Reviewed-by: Bin Meng bmeng.cn@gmail.com

This code currently requires CONFIG_SYS_TEXT_BASE but this should be unnecessary. As a first step, remove the build-time limitation and report an error instead.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Set text_base to 0 to avoid possible compiler warning
arch/x86/lib/relocate.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 9e748d2..0d683bf 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -58,6 +58,7 @@ int do_elf_reloc_fixups(void)
Elf32_Addr *offset_ptr_rom, *last_offset = NULL; Elf32_Addr *offset_ptr_ram; + unsigned int text_base = 0;
/* The size of the region of u-boot that runs out of RAM. */ uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start; @@ -67,29 +68,33 @@ int do_elf_reloc_fixups(void) if (re_src == re_end) panic("No relocation data");
+#ifdef CONFIG_SYS_TEXT_BASE + text_base = CONFIG_SYS_TEXT_BASE; +#else + panic("No CONFIG_SYS_TEXT_BASE"); +#endif do { /* Get the location from the relocation entry */ offset_ptr_rom = (Elf32_Addr *)re_src->r_offset;
/* Check that the location of the relocation is in .text */ - if (offset_ptr_rom >= (Elf32_Addr *)CONFIG_SYS_TEXT_BASE && - offset_ptr_rom > last_offset) { + if (offset_ptr_rom >= (Elf32_Addr *)text_base && + offset_ptr_rom > last_offset) {
/* Switch to the in-RAM version */ offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + gd->reloc_off);
/* Check that the target points into .text */ - if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE && - *offset_ptr_ram <= - (CONFIG_SYS_TEXT_BASE + size)) { + if (*offset_ptr_ram >= text_base && + *offset_ptr_ram <= text_base + size) { *offset_ptr_ram += gd->reloc_off; } else { debug(" %p: rom reloc %x, ram %p, value %x," " limit %" PRIXPTR "\n", re_src, re_src->r_offset, offset_ptr_ram, *offset_ptr_ram, - CONFIG_SYS_TEXT_BASE + size); + text_base + size); } } else { debug(" %p: rom reloc %x, last %p\n", re_src,

From: Ben Stoltz stoltz@google.com
Add configuration and Kconfig changes for this board.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Remove CONFIG_SYS_EARLY_PCI_INIT and CONFIG_PCI_PNP - Remove superfluous Kconfig options - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP - Rename CONFIG_DEBUG_UART_EFI to CONFIG_DEBUG_EFI_CONSOLE
configs/efi-x86_defconfig | 16 ++++++++++++++++ include/configs/efi-x86.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 configs/efi-x86_defconfig create mode 100644 include/configs/efi-x86.h
diff --git a/configs/efi-x86_defconfig b/configs/efi-x86_defconfig new file mode 100644 index 0000000..1aa0655 --- /dev/null +++ b/configs/efi-x86_defconfig @@ -0,0 +1,16 @@ +CONFIG_X86=y +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI=y +CONFIG_TSC_CALIBRATION_BYPASS=y +CONFIG_OF_CONTROL=y +CONFIG_OF_EMBED=y +CONFIG_DM_PCI=y +CONFIG_DEFAULT_DEVICE_TREE="efi" +CONFIG_EFI=y +CONFIG_EFI_APP=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_EFI_CONSOLE=y +CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_CLOCK=0 +# CONFIG_CMD_NET is not set +# CONFIG_CMD_BOOTM is not set diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h new file mode 100644 index 0000000..5779cfd --- /dev/null +++ b/include/configs/efi-x86.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <configs/x86-common.h> + +#undef CONFIG_CMD_SF_TEST + +#undef CONFIG_TPM +#undef CONFIG_TPM_TIS_LPC +#undef CONFIG_TPM_TIS_BASE_ADDRESS + +#undef CONFIG_CMD_IMLS + +#undef CONFIG_SYS_NS16550 +#undef CONFIG_X86_SERIAL +#undef CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_IS_NOWHERE +#undef CONFIG_VIDEO +#undef CONFIG_CFB_CONSOLE +#undef CONFIG_SCSI_AHCI +#undef CONFIG_CMD_SCSI +#undef CONFIG_INTEL_ICH6_GPIO + +#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ + "stdout=vga,serial\0" \ + "stderr=vga,serial\0" + +#endif

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Add configuration and Kconfig changes for this board.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see comments/nits below.
Changes in v2:
- Remove CONFIG_SYS_EARLY_PCI_INIT and CONFIG_PCI_PNP
- Remove superfluous Kconfig options
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Rename CONFIG_DEBUG_UART_EFI to CONFIG_DEBUG_EFI_CONSOLE
configs/efi-x86_defconfig | 16 ++++++++++++++++ include/configs/efi-x86.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 configs/efi-x86_defconfig create mode 100644 include/configs/efi-x86.h
diff --git a/configs/efi-x86_defconfig b/configs/efi-x86_defconfig new file mode 100644 index 0000000..1aa0655 --- /dev/null +++ b/configs/efi-x86_defconfig @@ -0,0 +1,16 @@ +CONFIG_X86=y +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI=y +CONFIG_TSC_CALIBRATION_BYPASS=y +CONFIG_OF_CONTROL=y +CONFIG_OF_EMBED=y +CONFIG_DM_PCI=y
Can we remove this DM_PCI too? I don't think it works.
+CONFIG_DEFAULT_DEVICE_TREE="efi" +CONFIG_EFI=y +CONFIG_EFI_APP=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_EFI_CONSOLE=y +CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_CLOCK=0 +# CONFIG_CMD_NET is not set +# CONFIG_CMD_BOOTM is not set diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h new file mode 100644 index 0000000..5779cfd --- /dev/null +++ b/include/configs/efi-x86.h @@ -0,0 +1,34 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __CONFIG_H +#define __CONFIG_H
+#include <configs/x86-common.h>
+#undef CONFIG_CMD_SF_TEST
+#undef CONFIG_TPM +#undef CONFIG_TPM_TIS_LPC +#undef CONFIG_TPM_TIS_BASE_ADDRESS
+#undef CONFIG_CMD_IMLS
+#undef CONFIG_SYS_NS16550 +#undef CONFIG_X86_SERIAL +#undef CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_IS_NOWHERE +#undef CONFIG_VIDEO +#undef CONFIG_CFB_CONSOLE +#undef CONFIG_SCSI_AHCI +#undef CONFIG_CMD_SCSI +#undef CONFIG_INTEL_ICH6_GPIO
+#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \
"stdout=vga,serial\0" \
"stderr=vga,serial\0"
+#endif
Regards, Bin

Hi Bin,
On 3 August 2015 at 23:20, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Add configuration and Kconfig changes for this board.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see comments/nits below.
Changes in v2:
- Remove CONFIG_SYS_EARLY_PCI_INIT and CONFIG_PCI_PNP
- Remove superfluous Kconfig options
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Rename CONFIG_DEBUG_UART_EFI to CONFIG_DEBUG_EFI_CONSOLE
configs/efi-x86_defconfig | 16 ++++++++++++++++ include/configs/efi-x86.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 configs/efi-x86_defconfig create mode 100644 include/configs/efi-x86.h
diff --git a/configs/efi-x86_defconfig b/configs/efi-x86_defconfig new file mode 100644 index 0000000..1aa0655 --- /dev/null +++ b/configs/efi-x86_defconfig @@ -0,0 +1,16 @@ +CONFIG_X86=y +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI=y +CONFIG_TSC_CALIBRATION_BYPASS=y +CONFIG_OF_CONTROL=y +CONFIG_OF_EMBED=y +CONFIG_DM_PCI=y
Can we remove this DM_PCI too? I don't think it works.
Unfortunately not, it breaks the app (it actually crashes the emulator). I'm not really sure why but I suspect that some x86 code requires it at present.
+CONFIG_DEFAULT_DEVICE_TREE="efi" +CONFIG_EFI=y +CONFIG_EFI_APP=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_EFI_CONSOLE=y +CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_CLOCK=0 +# CONFIG_CMD_NET is not set +# CONFIG_CMD_BOOTM is not set diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h new file mode 100644 index 0000000..5779cfd --- /dev/null +++ b/include/configs/efi-x86.h @@ -0,0 +1,34 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __CONFIG_H +#define __CONFIG_H
+#include <configs/x86-common.h>
+#undef CONFIG_CMD_SF_TEST
+#undef CONFIG_TPM +#undef CONFIG_TPM_TIS_LPC +#undef CONFIG_TPM_TIS_BASE_ADDRESS
+#undef CONFIG_CMD_IMLS
+#undef CONFIG_SYS_NS16550 +#undef CONFIG_X86_SERIAL +#undef CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_IS_NOWHERE +#undef CONFIG_VIDEO +#undef CONFIG_CFB_CONSOLE +#undef CONFIG_SCSI_AHCI +#undef CONFIG_CMD_SCSI +#undef CONFIG_INTEL_ICH6_GPIO
+#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \
"stdout=vga,serial\0" \
"stderr=vga,serial\0"
+#endif
Regards, Bin
Regards, Simon

On 4 August 2015 at 12:35, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 3 August 2015 at 23:20, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Add configuration and Kconfig changes for this board.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see comments/nits below.
Changes in v2:
- Remove CONFIG_SYS_EARLY_PCI_INIT and CONFIG_PCI_PNP
- Remove superfluous Kconfig options
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
- Rename CONFIG_DEBUG_UART_EFI to CONFIG_DEBUG_EFI_CONSOLE
configs/efi-x86_defconfig | 16 ++++++++++++++++ include/configs/efi-x86.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 configs/efi-x86_defconfig create mode 100644 include/configs/efi-x86.h
diff --git a/configs/efi-x86_defconfig b/configs/efi-x86_defconfig new file mode 100644 index 0000000..1aa0655 --- /dev/null +++ b/configs/efi-x86_defconfig @@ -0,0 +1,16 @@ +CONFIG_X86=y +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI=y +CONFIG_TSC_CALIBRATION_BYPASS=y +CONFIG_OF_CONTROL=y +CONFIG_OF_EMBED=y +CONFIG_DM_PCI=y
Can we remove this DM_PCI too? I don't think it works.
Unfortunately not, it breaks the app (it actually crashes the emulator). I'm not really sure why but I suspect that some x86 code requires it at present.
[snip]
Applied to u-boot-x86.

Add a linker script and relocation code for building 64-bit EFI applications. This can be used for the EFI stub.
Signed-off-by: Simon Glass sjg@chromium.org Improvements to how the payload is built: Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Add a comment as to why .hash has to be first in the linker script - Change 'link script' to 'linker script' - Drop . = 0x0; - Fix reference to elf_ia32_efi instead of elf_x86_64_efi - Merge in Bin's implementation of adding a U-Boot payload with objcopy - Remove KEEP in the EFI linker script since garbage collection is not enabled - Rename ImageBase to image_base - Update based on the elf.h changes
arch/x86/cpu/efi/elf_x86_64_efi.lds | 83 +++++++++++++++++++++++++++++++++++++ arch/x86/lib/efi/reloc_x86_64.c | 66 +++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 arch/x86/cpu/efi/elf_x86_64_efi.lds create mode 100644 arch/x86/lib/efi/reloc_x86_64.c
diff --git a/arch/x86/cpu/efi/elf_x86_64_efi.lds b/arch/x86/cpu/efi/elf_x86_64_efi.lds new file mode 100644 index 0000000..667fbe2 --- /dev/null +++ b/arch/x86/cpu/efi/elf_x86_64_efi.lds @@ -0,0 +1,83 @@ +/* + * U-Boot EFI linker script + * + * SPDX-License-Identifier: bsd-2-clause + * + * Modified from usr/lib32/elf_x86_64_efi.lds in gnu-efi + */ + +#include <config.h> + +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + image_base = .; + .hash : { *(.hash) } /* this MUST come first, EFI expects it */ + . = ALIGN(4096); + .eh_frame : { + *(.eh_frame) + } + + . = ALIGN(4096); + + .text : { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + + . = ALIGN(4096); + + .reloc : { + *(.reloc) + } + + . = ALIGN(4096); + + .data : { + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + /* the EFI loader doesn't seem to like a .bss section, so we stick + * it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + + /* U-Boot lists and device tree */ + . = ALIGN(8); + *(SORT(.u_boot_list*)); + . = ALIGN(8); + *(.dtb*); + } + + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + + .rela : { + *(.rela.data*) + *(.rela.got) + *(.rela.stab) + } + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .ignored.reloc : { + *(.rela.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + + .comment 0 : { *(.comment) } +} diff --git a/arch/x86/lib/efi/reloc_x86_64.c b/arch/x86/lib/efi/reloc_x86_64.c new file mode 100644 index 0000000..5f71f2a --- /dev/null +++ b/arch/x86/lib/efi/reloc_x86_64.c @@ -0,0 +1,66 @@ +/* + * reloc_x86_64.c - position independent x86_64 ELF shared object relocator + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger davidm@hpl.hp.com. + * Copyright (C) 2005 Intel Co. + * Contributed by Fenghua Yu fenghua.yu@intel.com. + * + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common.h> +#include <efi.h> +#include <elf.h> +#include <asm/elf.h> + +efi_status_t _relocate(long ldbase, Elf64_Dyn *dyn, efi_handle_t image, + struct efi_system_table *systab) +{ + long relsz = 0, relent = 0; + Elf64_Rel *rel = 0; + unsigned long *addr; + int i; + + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_RELA: + rel = (Elf64_Rel *) + ((unsigned long)dyn[i].d_un.d_ptr + ldbase); + break; + case DT_RELASZ: + relsz = dyn[i].d_un.d_val; + break; + case DT_RELAENT: + relent = dyn[i].d_un.d_val; + break; + default: + break; + } + } + + if (!rel && relent == 0) + return EFI_SUCCESS; + + if (!rel || relent == 0) + return EFI_LOAD_ERROR; + + while (relsz > 0) { + /* apply the relocs */ + switch (ELF64_R_TYPE(rel->r_info)) { + case R_X86_64_NONE: + break; + case R_X86_64_RELATIVE: + addr = (unsigned long *)(ldbase + rel->r_offset); + *addr += ldbase; + break; + default: + break; + } + rel = (Elf64_Rel *)((char *)rel + relent); + relsz -= relent; + } + + return EFI_SUCCESS; +}

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add a linker script and relocation code for building 64-bit EFI applications. This can be used for the EFI stub.
Signed-off-by: Simon Glass sjg@chromium.org Improvements to how the payload is built: Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- Add a comment as to why .hash has to be first in the linker script
- Change 'link script' to 'linker script'
- Drop . = 0x0;
- Fix reference to elf_ia32_efi instead of elf_x86_64_efi
- Merge in Bin's implementation of adding a U-Boot payload with objcopy
- Remove KEEP in the EFI linker script since garbage collection is not enabled
- Rename ImageBase to image_base
- Update based on the elf.h changes
arch/x86/cpu/efi/elf_x86_64_efi.lds | 83 +++++++++++++++++++++++++++++++++++++ arch/x86/lib/efi/reloc_x86_64.c | 66 +++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 arch/x86/cpu/efi/elf_x86_64_efi.lds create mode 100644 arch/x86/lib/efi/reloc_x86_64.c
diff --git a/arch/x86/cpu/efi/elf_x86_64_efi.lds b/arch/x86/cpu/efi/elf_x86_64_efi.lds new file mode 100644 index 0000000..667fbe2 --- /dev/null +++ b/arch/x86/cpu/efi/elf_x86_64_efi.lds @@ -0,0 +1,83 @@ +/*
- U-Boot EFI linker script
- SPDX-License-Identifier: bsd-2-clause
- Modified from usr/lib32/elf_x86_64_efi.lds in gnu-efi
- */
+#include <config.h>
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{
image_base = .;
.hash : { *(.hash) } /* this MUST come first, EFI expects it */
. = ALIGN(4096);
.eh_frame : {
*(.eh_frame)
}
. = ALIGN(4096);
.text : {
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
}
. = ALIGN(4096);
.reloc : {
*(.reloc)
}
. = ALIGN(4096);
.data : {
*(.rodata*)
*(.got.plt)
*(.got)
*(.data*)
*(.sdata)
/* the EFI loader doesn't seem to like a .bss section, so we stick
* it all into .data: */
*(.sbss)
*(.scommon)
*(.dynbss)
*(.bss)
*(COMMON)
*(.rel.local)
/* U-Boot lists and device tree */
. = ALIGN(8);
*(SORT(.u_boot_list*));
. = ALIGN(8);
*(.dtb*);
}
. = ALIGN(4096);
.dynamic : { *(.dynamic) }
. = ALIGN(4096);
.rela : {
*(.rela.data*)
*(.rela.got)
*(.rela.stab)
}
. = ALIGN(4096);
.dynsym : { *(.dynsym) }
. = ALIGN(4096);
.dynstr : { *(.dynstr) }
. = ALIGN(4096);
.ignored.reloc : {
*(.rela.reloc)
*(.eh_frame)
*(.note.GNU-stack)
}
.comment 0 : { *(.comment) }
+} diff --git a/arch/x86/lib/efi/reloc_x86_64.c b/arch/x86/lib/efi/reloc_x86_64.c new file mode 100644 index 0000000..5f71f2a --- /dev/null +++ b/arch/x86/lib/efi/reloc_x86_64.c @@ -0,0 +1,66 @@ +/*
- reloc_x86_64.c - position independent x86_64 ELF shared object relocator
- Copyright (C) 1999 Hewlett-Packard Co.
- Contributed by David Mosberger davidm@hpl.hp.com.
- Copyright (C) 2005 Intel Co.
- Contributed by Fenghua Yu fenghua.yu@intel.com.
- All rights reserved.
- SPDX-License-Identifier: BSD-3-Clause
- */
+#include <common.h> +#include <efi.h> +#include <elf.h> +#include <asm/elf.h>
+efi_status_t _relocate(long ldbase, Elf64_Dyn *dyn, efi_handle_t image,
struct efi_system_table *systab)
+{
long relsz = 0, relent = 0;
Elf64_Rel *rel = 0;
unsigned long *addr;
int i;
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
switch (dyn[i].d_tag) {
case DT_RELA:
rel = (Elf64_Rel *)
((unsigned long)dyn[i].d_un.d_ptr + ldbase);
break;
case DT_RELASZ:
relsz = dyn[i].d_un.d_val;
break;
case DT_RELAENT:
relent = dyn[i].d_un.d_val;
break;
default:
break;
}
}
if (!rel && relent == 0)
return EFI_SUCCESS;
if (!rel || relent == 0)
return EFI_LOAD_ERROR;
while (relsz > 0) {
/* apply the relocs */
switch (ELF64_R_TYPE(rel->r_info)) {
case R_X86_64_NONE:
break;
case R_X86_64_RELATIVE:
addr = (unsigned long *)(ldbase + rel->r_offset);
*addr += ldbase;
break;
default:
break;
}
rel = (Elf64_Rel *)((char *)rel + relent);
relsz -= relent;
}
return EFI_SUCCESS;
+}
Reviewed-by: Bin Meng bmeng.cn@gmail.com

It is useful to be able to load U-Boot onto a board even it is it already running EFI. This can allow access to the U-Boot command interface, flexible booting options and easier development.
The easiest way to do this is to build U-Boot as a binary blob and have an EFI stub copy it into RAM. Add support for this feature, targeting 32-bit initially.
Also add a way to detect when U-Boot has been loaded via a stub. This goes in common.h since it needs to be widely available so that we avoid redoing initialisation that should be skipped.
Signed-off-by: Simon Glass sjg@chromium.org Improvements to how the payload is built: Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Add a comment as to why we must call exit_boot_services() twice - Drop \n\t at the end of a one-line asm statement - Merge in Bin's implementation of adding a U-Boot payload with objcopy - Remove comment about reset_cpu() returning to EFI in the stub - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
Makefile | 21 ++++ arch/x86/config.mk | 3 + include/common.h | 7 ++ include/efi.h | 4 + lib/efi/Kconfig | 21 ++++ lib/efi/Makefile | 9 ++ lib/efi/efi_stub.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 364 insertions(+) create mode 100644 lib/efi/efi_stub.c
diff --git a/Makefile b/Makefile index 6da9224..755eec8 100644 --- a/Makefile +++ b/Makefile @@ -751,6 +751,7 @@ ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf ALL-$(CONFIG_EFI_APP) += u-boot-app.efi +ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -786,6 +787,9 @@ cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \ quiet_cmd_zobjcopy = OBJCOPY $@ cmd_zobjcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
+quiet_cmd_efipayload = OBJCOPY $@ +cmd_efipayload = $(OBJCOPY) -I binary -O $(EFIPAYLOAD_BFDTARGET) -B $(EFIPAYLOAD_BFDARCH) $< $@ + quiet_cmd_mkimage = MKIMAGE $@ cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \ $(if $(KBUILD_VERBOSE:1=), >/dev/null) @@ -1083,6 +1087,23 @@ OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI) u-boot-app.efi: u-boot FORCE $(call if_changed,zobjcopy)
+u-boot-dtb.bin.o: u-boot-dtb.bin FORCE + $(call if_changed,efipayload) + +u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE + $(call if_changed_dep,cpp_lds) + +u-boot-payload: u-boot-dtb.bin.o u-boot-payload.lds \ + FORCE + $(LD) $(LDFLAGS_EFI) -o $@ \ + -T u-boot-payload.lds \ + lib/efi/efi.o lib/efi/efi_stub.o u-boot-dtb.bin.o \ + $(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB)) + +OBJCOPYFLAGS_u-boot-payload.efi := $(OBJCOPYFLAGS_EFI) +u-boot-payload.efi: u-boot-payload FORCE + $(call if_changed,zobjcopy) + u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat)
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index a1c0eb2..48eb5f5 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -35,6 +35,9 @@ CFLAGS_NON_EFI := -mregparm=3 CFLAGS_EFI := -fpic -fshort-wchar
EFIARCH=ia32 +EFIPAYLOAD_BFDTARGET = elf32-i386 + +EFIPAYLOAD_BFDARCH = i386
LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH) diff --git a/include/common.h b/include/common.h index 4566bd1..fcc9ae7 100644 --- a/include/common.h +++ b/include/common.h @@ -1021,6 +1021,13 @@ int cpu_release(int nr, int argc, char * const argv[]); offsetof(struct structure, member) == offset, \ "`struct " #structure "` offset for `" #member "` is not " #offset)
+/* Avoid using CONFIG_EFI_STUB directly as we may boot from other loaders */ +#ifdef CONFIG_EFI_STUB +#define ll_boot_init() false +#else +#define ll_boot_init() true +#endif + /* Pull in stuff for the build system */ #ifdef DO_DEPS_ONLY # include <environment.h> diff --git a/include/efi.h b/include/efi.h index 5d80373..34844e4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -269,11 +269,15 @@ struct efi_priv { /* Base address of the EFI image */ extern char image_base[];
+/* Start and end of U-Boot image (for payload) */ +extern char _binary_u_boot_dtb_bin_start[], _binary_u_boot_dtb_bin_end[]; + /** * efi_get_sys_table() - Get access to the main EFI system table * * @return pointer to EFI system table */ + struct efi_system_table *efi_get_sys_table(void);
/** diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index b23ba5b..919e314 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -20,6 +20,11 @@ config EFI_APP command prompt and memory and I/O functions. Use 'reset' to return to EFI.
+config EFI_STUB + bool "Support running as an EFI payload" + +endchoice + config EFI_RAM_SIZE hex "Amount of EFI RAM for U-Boot" depends on EFI_APP @@ -30,4 +35,20 @@ config EFI_RAM_SIZE other smaller amounts) and it can never be increased after that. It is used as the RAM size in with U-Boot.
+choice + prompt "EFI 32/64-bit selection" + depends on EFI_STUB + help + EFI does not support mixing 32-bit and 64-bit modes. This is a + significant problem because it means that you must build a stub with + the correct type for EFI to load it correctly. If you are using + 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do + this may produce no error message - it just won't start! + +config EFI_STUB_32BIT + bool "Produce a stub for running with 32-bit EFI" + +config EFI_STUB_64BIT + bool "Produce a stub for running with 64-bit EFI" + endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 5ee344c..4bc67f0 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,3 +5,12 @@ #
obj-$(CONFIG_EFI_APP) += efi_app.o efi.o + +CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \ + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) +CFLAGS_efi_stub.o := -fpic -fshort-wchar +CFLAGS_REMOVE_efi.o := -mregparm=3 \ + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) +CFLAGS_efi.o := -fpic -fshort-wchar + +extra-$(CONFIG_EFI_STUB) += efi_stub.o efi.o diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c new file mode 100644 index 0000000..7259720 --- /dev/null +++ b/lib/efi/efi_stub.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * Loads a payload (U-Boot) within the EFI environment. This is built as a + * 32-bit EFI application. + */ + +#include <common.h> +#include <debug_uart.h> +#include <efi.h> +#include <efi_api.h> +#include <errno.h> +#include <ns16550.h> +#include <asm/cpu.h> +#include <asm/io.h> +#include <linux/err.h> +#include <linux/types.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_X86 +/* + * Problem areas: + * - putc() uses the ns16550 address directly and assumed I/O access. Many + * platforms will use memory access + * get_codeseg32() is only meaningful on x86 + */ +#error "This file needs to be ported for use on architectures" +#endif + +static struct efi_priv *global_priv; +static bool use_uart; + +struct __packed desctab_info { + uint16_t limit; + uint64_t addr; + uint16_t pad; +}; + +/* + * EFI uses Unicode and we don't. The easiest way to get a sensible output + * function is to use the U-Boot debug UART. We use EFI's console output + * function where available, and assume the built-in UART after that. We rely + * on EFI to set up the UART for us and just bring in the functions here. + * This last bit is a bit icky, but it's only for debugging anyway. We could + * build in ns16550.c with some effort, but this is a payload loader after + * all. + * + * Note: We avoid using printf() so we don't need to bring in lib/vsprintf.c. + * That would require some refactoring since we already build this for U-Boot. + * Building an EFI shared library version would have to be a separate stem. + * That might push us to using the SPL framework to build this stub. However + * that would involve a round of EFI-specific changes in SPL. Worth + * considering if we start needing more U-Boot functionality. Note that we + * could then move get_codeseg32() to arch/x86/cpu/cpu.c. + */ +void debug_uart_init(void) +{ +} + +void putc(const char ch) +{ + if (use_uart) { + NS16550_t com_port = (NS16550_t)0x3f8; + + while ((inb((ulong)&com_port->lsr) & UART_LSR_THRE) == 0) + ; + outb(ch, (ulong)&com_port->thr); + } else { + efi_putc(global_priv, ch); + } + if (ch == '\n') + putc('\r'); +} + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + +static void _debug_uart_putc(int ch) +{ + putc(ch); +} + +DEBUG_UART_FUNCS + +void *memcpy(void *dest, const void *src, size_t size) +{ + unsigned char *dptr = dest; + const unsigned char *ptr = src; + const unsigned char *end = src + size; + + while (ptr < end) + *dptr++ = *ptr++; + + return dest; +} + +void *memset(void *inptr, int ch, size_t size) +{ + char *ptr = inptr; + char *end = ptr + size; + + while (ptr < end) + *ptr++ = ch; + + return ptr; +} + +static void jump_to_uboot(ulong cs32, ulong addr, ulong info) +{ + typedef void (*func_t)(int bist, int unused, ulong info); + +#ifdef CONFIG_EFI_STUB_32BIT + ((func_t)addr)(bist, 0, info); +#else + /* TODO: Implement this */ +#endif +} + +static void get_gdt(struct desctab_info *info) +{ + asm volatile ("sgdt %0" : : "m"(*info) : "memory"); +} + +static inline unsigned long read_cr3(void) +{ + unsigned long val; + + asm volatile("mov %%cr3,%0" : "=r" (val) : : "memory"); + return val; +} + +/** + * get_codeseg32() - Find the code segment to use for 32-bit code + * + * U-Boot only works in 32-bit mode at present, so when booting from 64-bit + * EFI we must first change to 32-bit mode. To do this we need to find the + * correct code segment to use (an entry in the Global Descriptor Table). + * + * @return code segment GDT offset, or 0 for 32-bit EFI, -ENOENT if not found + */ +static int get_codeseg32(void) +{ + int cs32 = 0; + + /* TODO(sjg): Implement this for 64-bit mode */ + return cs32; +} + +static int setup_info_table(struct efi_priv *priv, int size) +{ + struct efi_info_hdr *info; + efi_status_t ret; + + /* Get some memory for our info table */ + priv->info_size = size; + info = efi_malloc(priv, priv->info_size, &ret); + if (ret) { + printhex2(ret); + puts(" No memory for info table: "); + return ret; + } + + memset(info, '\0', sizeof(*info)); + info->version = EFI_TABLE_VERSION; + info->hdr_size = sizeof(*info); + priv->info = info; + priv->next_hdr = (char *)info + info->hdr_size; + + return 0; +} + +static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, + void *ptr1, int size1, void *ptr2, int size2) +{ + struct efi_entry_hdr *hdr = priv->next_hdr; + + hdr->type = type; + hdr->size = size1 + size2; + hdr->addr = 0; + hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16); + priv->next_hdr += hdr->link; + memcpy(hdr + 1, ptr1, size1); + memcpy((void *)(hdr + 1) + size1, ptr2, size2); + priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info; +} + +/** + * efi_main() - Start an EFI image + * + * This function is called by our EFI start-up code. It handles running + * U-Boot. If it returns, EFI will continue. + */ +efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) +{ + struct efi_priv local_priv, *priv = &local_priv; + struct efi_boot_services *boot = sys_table->boottime; + struct efi_mem_desc *desc; + struct efi_entry_memmap map; + ulong key, desc_size, size; + efi_status_t ret; + u32 version; + int cs32; + + ret = efi_init(priv, "Payload", image, sys_table); + if (ret) { + printhex2(ret); puts(" efi_init() failed\n"); + return ret; + } + global_priv = priv; + + cs32 = get_codeseg32(); + if (cs32 < 0) + return EFI_UNSUPPORTED; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); + if (ret != EFI_BUFFER_TOO_SMALL) { + printhex2(BITS_PER_LONG); + printhex2(ret); + puts(" No memory map\n"); + return ret; + } + size += 1024; /* Since doing a malloc() may change the memory map! */ + desc = efi_malloc(priv, size, &ret); + if (!desc) { + printhex2(ret); + puts(" No memory for memory descriptor: "); + return ret; + } + ret = setup_info_table(priv, size + 128); + if (ret) + return ret; + + ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + + ret = boot->exit_boot_services(image, key); + if (ret) { + /* + * Unfortunately it happens that we cannot exit boot services + * the first time. But the second time it work. I don't know + * why but this seems to be a repeatable problem. To get + * around it, just try again. + */ + printhex2(ret); + puts(" Can't exit boot services\n"); + size = sizeof(desc); + ret = boot->get_memory_map(&size, desc, &key, &desc_size, + &version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + ret = boot->exit_boot_services(image, key); + if (ret) { + printhex2(ret); + puts(" Can't exit boot services 2\n"); + return ret; + } + } + + map.version = version; + map.desc_size = desc_size; + add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size); + add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0); + + /* The EFI UART won't work now, switch to a debug one */ + use_uart = true; + + memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_dtb_bin_start, + (ulong)_binary_u_boot_dtb_bin_end - + (ulong)_binary_u_boot_dtb_bin_start); + +#ifdef DEBUG + puts("EFI table at "); + printhex8((ulong)priv->info); + puts(" size "); + printhex8(priv->info->total_size); +#endif + putc('\n'); + jump_to_uboot(cs32, CONFIG_SYS_TEXT_BASE, (ulong)priv->info); + + return EFI_LOAD_ERROR; +}

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
It is useful to be able to load U-Boot onto a board even it is it already
Nits: even it is
running EFI. This can allow access to the U-Boot command interface, flexible booting options and easier development.
The easiest way to do this is to build U-Boot as a binary blob and have an EFI stub copy it into RAM. Add support for this feature, targeting 32-bit initially.
Also add a way to detect when U-Boot has been loaded via a stub. This goes in common.h since it needs to be widely available so that we avoid redoing initialisation that should be skipped.
Signed-off-by: Simon Glass sjg@chromium.org Improvements to how the payload is built: Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- Add a comment as to why we must call exit_boot_services() twice
- Drop \n\t at the end of a one-line asm statement
- Merge in Bin's implementation of adding a U-Boot payload with objcopy
- Remove comment about reset_cpu() returning to EFI in the stub
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
Makefile | 21 ++++ arch/x86/config.mk | 3 + include/common.h | 7 ++ include/efi.h | 4 + lib/efi/Kconfig | 21 ++++ lib/efi/Makefile | 9 ++ lib/efi/efi_stub.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 364 insertions(+) create mode 100644 lib/efi/efi_stub.c
diff --git a/Makefile b/Makefile index 6da9224..755eec8 100644 --- a/Makefile +++ b/Makefile @@ -751,6 +751,7 @@ ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf ALL-$(CONFIG_EFI_APP) += u-boot-app.efi +ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -786,6 +787,9 @@ cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \ quiet_cmd_zobjcopy = OBJCOPY $@ cmd_zobjcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
+quiet_cmd_efipayload = OBJCOPY $@ +cmd_efipayload = $(OBJCOPY) -I binary -O $(EFIPAYLOAD_BFDTARGET) -B $(EFIPAYLOAD_BFDARCH) $< $@
quiet_cmd_mkimage = MKIMAGE $@ cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \ $(if $(KBUILD_VERBOSE:1=), >/dev/null) @@ -1083,6 +1087,23 @@ OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI) u-boot-app.efi: u-boot FORCE $(call if_changed,zobjcopy)
+u-boot-dtb.bin.o: u-boot-dtb.bin FORCE
$(call if_changed,efipayload)
+u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE
$(call if_changed_dep,cpp_lds)
+u-boot-payload: u-boot-dtb.bin.o u-boot-payload.lds \
FORCE
$(LD) $(LDFLAGS_EFI) -o $@ \
-T u-boot-payload.lds \
lib/efi/efi.o lib/efi/efi_stub.o u-boot-dtb.bin.o \
$(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB))
Can we convert this to use quiet_cmd_xxx format so that it won't print anything by default?
+OBJCOPYFLAGS_u-boot-payload.efi := $(OBJCOPYFLAGS_EFI) +u-boot-payload.efi: u-boot-payload FORCE
$(call if_changed,zobjcopy)
u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat)
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index a1c0eb2..48eb5f5 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -35,6 +35,9 @@ CFLAGS_NON_EFI := -mregparm=3 CFLAGS_EFI := -fpic -fshort-wchar
EFIARCH=ia32 +EFIPAYLOAD_BFDTARGET = elf32-i386
+EFIPAYLOAD_BFDARCH = i386
LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH) diff --git a/include/common.h b/include/common.h index 4566bd1..fcc9ae7 100644 --- a/include/common.h +++ b/include/common.h @@ -1021,6 +1021,13 @@ int cpu_release(int nr, int argc, char * const argv[]); offsetof(struct structure, member) == offset, \ "`struct " #structure "` offset for `" #member "` is not " #offset)
+/* Avoid using CONFIG_EFI_STUB directly as we may boot from other loaders */ +#ifdef CONFIG_EFI_STUB +#define ll_boot_init() false +#else +#define ll_boot_init() true +#endif
/* Pull in stuff for the build system */ #ifdef DO_DEPS_ONLY # include <environment.h> diff --git a/include/efi.h b/include/efi.h index 5d80373..34844e4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -269,11 +269,15 @@ struct efi_priv { /* Base address of the EFI image */ extern char image_base[];
+/* Start and end of U-Boot image (for payload) */ +extern char _binary_u_boot_dtb_bin_start[], _binary_u_boot_dtb_bin_end[];
/**
- efi_get_sys_table() - Get access to the main EFI system table
- @return pointer to EFI system table
*/
struct efi_system_table *efi_get_sys_table(void);
/** diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index b23ba5b..919e314 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -20,6 +20,11 @@ config EFI_APP command prompt and memory and I/O functions. Use 'reset' to return to EFI.
+config EFI_STUB
bool "Support running as an EFI payload"
+endchoice
config EFI_RAM_SIZE hex "Amount of EFI RAM for U-Boot" depends on EFI_APP @@ -30,4 +35,20 @@ config EFI_RAM_SIZE other smaller amounts) and it can never be increased after that. It is used as the RAM size in with U-Boot.
+choice
prompt "EFI 32/64-bit selection"
depends on EFI_STUB
help
EFI does not support mixing 32-bit and 64-bit modes. This is a
significant problem because it means that you must build a stub with
the correct type for EFI to load it correctly. If you are using
32-bit EFI, select 32-bit here, else select 64-bit. Failure to do
this may produce no error message - it just won't start!
+config EFI_STUB_32BIT
bool "Produce a stub for running with 32-bit EFI"
+config EFI_STUB_64BIT
bool "Produce a stub for running with 64-bit EFI"
endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 5ee344c..4bc67f0 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,3 +5,12 @@ #
obj-$(CONFIG_EFI_APP) += efi_app.o efi.o
+CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \
$(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32)
+CFLAGS_efi_stub.o := -fpic -fshort-wchar +CFLAGS_REMOVE_efi.o := -mregparm=3 \
$(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32)
+CFLAGS_efi.o := -fpic -fshort-wchar
+extra-$(CONFIG_EFI_STUB) += efi_stub.o efi.o diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c new file mode 100644 index 0000000..7259720 --- /dev/null +++ b/lib/efi/efi_stub.c @@ -0,0 +1,299 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- EFI information obtained here:
- Loads a payload (U-Boot) within the EFI environment. This is built as a
- 32-bit EFI application.
- */
+#include <common.h> +#include <debug_uart.h> +#include <efi.h> +#include <efi_api.h> +#include <errno.h> +#include <ns16550.h> +#include <asm/cpu.h> +#include <asm/io.h> +#include <linux/err.h> +#include <linux/types.h>
+DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_X86 +/*
- Problem areas:
- putc() uses the ns16550 address directly and assumed I/O access. Many
platforms will use memory access
- get_codeseg32() is only meaningful on x86
- */
+#error "This file needs to be ported for use on architectures" +#endif
+static struct efi_priv *global_priv; +static bool use_uart;
+struct __packed desctab_info {
uint16_t limit;
uint64_t addr;
uint16_t pad;
+};
+/*
- EFI uses Unicode and we don't. The easiest way to get a sensible output
- function is to use the U-Boot debug UART. We use EFI's console output
- function where available, and assume the built-in UART after that. We rely
- on EFI to set up the UART for us and just bring in the functions here.
- This last bit is a bit icky, but it's only for debugging anyway. We could
- build in ns16550.c with some effort, but this is a payload loader after
- all.
- Note: We avoid using printf() so we don't need to bring in lib/vsprintf.c.
- That would require some refactoring since we already build this for U-Boot.
- Building an EFI shared library version would have to be a separate stem.
- That might push us to using the SPL framework to build this stub. However
- that would involve a round of EFI-specific changes in SPL. Worth
- considering if we start needing more U-Boot functionality. Note that we
- could then move get_codeseg32() to arch/x86/cpu/cpu.c.
- */
+void debug_uart_init(void) +{ +}
+void putc(const char ch) +{
if (use_uart) {
NS16550_t com_port = (NS16550_t)0x3f8;
while ((inb((ulong)&com_port->lsr) & UART_LSR_THRE) == 0)
;
outb(ch, (ulong)&com_port->thr);
} else {
efi_putc(global_priv, ch);
}
if (ch == '\n')
putc('\r');
+}
+void puts(const char *str) +{
while (*str)
putc(*str++);
+}
+static void _debug_uart_putc(int ch) +{
putc(ch);
+}
+DEBUG_UART_FUNCS
+void *memcpy(void *dest, const void *src, size_t size) +{
unsigned char *dptr = dest;
const unsigned char *ptr = src;
const unsigned char *end = src + size;
while (ptr < end)
*dptr++ = *ptr++;
return dest;
+}
+void *memset(void *inptr, int ch, size_t size) +{
char *ptr = inptr;
char *end = ptr + size;
while (ptr < end)
*ptr++ = ch;
return ptr;
+}
+static void jump_to_uboot(ulong cs32, ulong addr, ulong info) +{
typedef void (*func_t)(int bist, int unused, ulong info);
+#ifdef CONFIG_EFI_STUB_32BIT
((func_t)addr)(bist, 0, info);
+#else
/* TODO: Implement this */
+#endif +}
+static void get_gdt(struct desctab_info *info) +{
asm volatile ("sgdt %0" : : "m"(*info) : "memory");
+}
+static inline unsigned long read_cr3(void) +{
unsigned long val;
asm volatile("mov %%cr3,%0" : "=r" (val) : : "memory");
return val;
+}
+/**
- get_codeseg32() - Find the code segment to use for 32-bit code
- U-Boot only works in 32-bit mode at present, so when booting from 64-bit
- EFI we must first change to 32-bit mode. To do this we need to find the
- correct code segment to use (an entry in the Global Descriptor Table).
- @return code segment GDT offset, or 0 for 32-bit EFI, -ENOENT if not found
- */
+static int get_codeseg32(void) +{
int cs32 = 0;
/* TODO(sjg): Implement this for 64-bit mode */
return cs32;
+}
+static int setup_info_table(struct efi_priv *priv, int size) +{
struct efi_info_hdr *info;
efi_status_t ret;
/* Get some memory for our info table */
priv->info_size = size;
info = efi_malloc(priv, priv->info_size, &ret);
if (ret) {
printhex2(ret);
puts(" No memory for info table: ");
return ret;
}
memset(info, '\0', sizeof(*info));
info->version = EFI_TABLE_VERSION;
info->hdr_size = sizeof(*info);
priv->info = info;
priv->next_hdr = (char *)info + info->hdr_size;
return 0;
+}
+static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type,
void *ptr1, int size1, void *ptr2, int size2)
+{
struct efi_entry_hdr *hdr = priv->next_hdr;
hdr->type = type;
hdr->size = size1 + size2;
hdr->addr = 0;
hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16);
priv->next_hdr += hdr->link;
memcpy(hdr + 1, ptr1, size1);
memcpy((void *)(hdr + 1) + size1, ptr2, size2);
priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info;
+}
+/**
- efi_main() - Start an EFI image
- This function is called by our EFI start-up code. It handles running
- U-Boot. If it returns, EFI will continue.
- */
+efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) +{
struct efi_priv local_priv, *priv = &local_priv;
struct efi_boot_services *boot = sys_table->boottime;
struct efi_mem_desc *desc;
struct efi_entry_memmap map;
ulong key, desc_size, size;
efi_status_t ret;
u32 version;
int cs32;
ret = efi_init(priv, "Payload", image, sys_table);
if (ret) {
printhex2(ret); puts(" efi_init() failed\n");
return ret;
}
global_priv = priv;
cs32 = get_codeseg32();
if (cs32 < 0)
return EFI_UNSUPPORTED;
/* Get the memory map so we can switch off EFI */
size = 0;
ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version);
if (ret != EFI_BUFFER_TOO_SMALL) {
printhex2(BITS_PER_LONG);
printhex2(ret);
puts(" No memory map\n");
return ret;
}
size += 1024; /* Since doing a malloc() may change the memory map! */
desc = efi_malloc(priv, size, &ret);
if (!desc) {
printhex2(ret);
puts(" No memory for memory descriptor: ");
return ret;
}
ret = setup_info_table(priv, size + 128);
if (ret)
return ret;
ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version);
if (ret) {
printhex2(ret);
puts(" Can't get memory map\n");
return ret;
}
ret = boot->exit_boot_services(image, key);
if (ret) {
/*
* Unfortunately it happens that we cannot exit boot services
* the first time. But the second time it work. I don't know
* why but this seems to be a repeatable problem. To get
* around it, just try again.
*/
printhex2(ret);
puts(" Can't exit boot services\n");
size = sizeof(desc);
ret = boot->get_memory_map(&size, desc, &key, &desc_size,
&version);
if (ret) {
printhex2(ret);
puts(" Can't get memory map\n");
return ret;
}
ret = boot->exit_boot_services(image, key);
if (ret) {
printhex2(ret);
puts(" Can't exit boot services 2\n");
return ret;
}
}
map.version = version;
map.desc_size = desc_size;
add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size);
add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0);
/* The EFI UART won't work now, switch to a debug one */
use_uart = true;
memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_dtb_bin_start,
(ulong)_binary_u_boot_dtb_bin_end -
(ulong)_binary_u_boot_dtb_bin_start);
+#ifdef DEBUG
puts("EFI table at ");
printhex8((ulong)priv->info);
puts(" size ");
printhex8(priv->info->total_size);
+#endif
putc('\n');
jump_to_uboot(cs32, CONFIG_SYS_TEXT_BASE, (ulong)priv->info);
return EFI_LOAD_ERROR;
+}
Regards, Bin

Add support for building a 32/64-bit EFI stub for x86. This involves building the startup and relocation code for either i386 or x86_64.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a comment as to why the AFLAGS_REMOVE_.. lines are needed - Move the crt and reloc files into arch/x86/lib/efi/
arch/x86/lib/Makefile | 2 +- arch/x86/lib/efi/Makefile | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 arch/x86/lib/efi/Makefile
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 43489fd..09c236b 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_CMD_ZBOOT) += zimage.o obj-$(CONFIG_HAVE_FSP) += fsp/
-extra-$(CONFIG_USE_PRIVATE_LIBGCC) := lib.a +extra-$(CONFIG_USE_PRIVATE_LIBGCC) += lib.a
NORMAL_LIBGCC = $(shell $(CC) $(PLATFORM_CPPFLAGS) -print-libgcc-file-name) OBJCOPYFLAGS := --prefix-symbols=__normal_ diff --git a/arch/x86/lib/efi/Makefile b/arch/x86/lib/efi/Makefile new file mode 100644 index 0000000..41295d9 --- /dev/null +++ b/arch/x86/lib/efi/Makefile @@ -0,0 +1,24 @@ +# +# (C) Copyright 2002-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_EFI_APP) += crt0-efi-ia32.o reloc_ia32.o + +ifneq ($(CONFIG_EFI_STUB),) + +# When building for 64-bit we must remove the i386-specific flags +CFLAGS_REMOVE_reloc_ia32.o += -mregparm=3 +CFLAGS_reloc_ia32.o += -fpic -fshort-wchar + +CFLAGS_REMOVE_reloc_x86_64.o += -mregparm=3 -march=i386 -m32 +CFLAGS_reloc_x86_64.o += -fpic -fshort-wchar + +AFLAGS_REMOVE_crt0-efi-x86_64.o += -mregparm=3 -march=i386 -m32 +AFLAGS_crt0-efi-x86_64.o += -fpic -fshort-wchar + +extra-$(CONFIG_EFI_STUB_32BIT) += crt0-efi-ia32.o reloc_ia32.o +extra-$(CONFIG_EFI_STUB_64BIT) += crt0-efi-x86_64.o reloc_x86_64.o +endif

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add support for building a 32/64-bit EFI stub for x86. This involves building the startup and relocation code for either i386 or x86_64.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a comment as to why the AFLAGS_REMOVE_.. lines are needed
- Move the crt and reloc files into arch/x86/lib/efi/
arch/x86/lib/Makefile | 2 +- arch/x86/lib/efi/Makefile | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 arch/x86/lib/efi/Makefile
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 43489fd..09c236b 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_CMD_ZBOOT) += zimage.o obj-$(CONFIG_HAVE_FSP) += fsp/
-extra-$(CONFIG_USE_PRIVATE_LIBGCC) := lib.a +extra-$(CONFIG_USE_PRIVATE_LIBGCC) += lib.a
NORMAL_LIBGCC = $(shell $(CC) $(PLATFORM_CPPFLAGS) -print-libgcc-file-name) OBJCOPYFLAGS := --prefix-symbols=__normal_ diff --git a/arch/x86/lib/efi/Makefile b/arch/x86/lib/efi/Makefile new file mode 100644 index 0000000..41295d9 --- /dev/null +++ b/arch/x86/lib/efi/Makefile @@ -0,0 +1,24 @@ +# +# (C) Copyright 2002-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_EFI_APP) += crt0-efi-ia32.o reloc_ia32.o
+ifneq ($(CONFIG_EFI_STUB),)
+# When building for 64-bit we must remove the i386-specific flags
I think this comment should be put before reloc_x86_64 below as 64-bit stub does not build reloc_ia32.c
+CFLAGS_REMOVE_reloc_ia32.o += -mregparm=3 +CFLAGS_reloc_ia32.o += -fpic -fshort-wchar
I don't see AFLAGS_REMOVE_crt0-efi-ia32.o and AFLAGS_crt0-efi-ia32.o.
+CFLAGS_REMOVE_reloc_x86_64.o += -mregparm=3 -march=i386 -m32 +CFLAGS_reloc_x86_64.o += -fpic -fshort-wchar
+AFLAGS_REMOVE_crt0-efi-x86_64.o += -mregparm=3 -march=i386 -m32 +AFLAGS_crt0-efi-x86_64.o += -fpic -fshort-wchar
+extra-$(CONFIG_EFI_STUB_32BIT) += crt0-efi-ia32.o reloc_ia32.o +extra-$(CONFIG_EFI_STUB_64BIT) += crt0-efi-x86_64.o reloc_x86_64.o
+endif
Regards, Bin

Hi Bin,
On 4 August 2015 at 00:54, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Add support for building a 32/64-bit EFI stub for x86. This involves building the startup and relocation code for either i386 or x86_64.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a comment as to why the AFLAGS_REMOVE_.. lines are needed
- Move the crt and reloc files into arch/x86/lib/efi/
arch/x86/lib/Makefile | 2 +- arch/x86/lib/efi/Makefile | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 arch/x86/lib/efi/Makefile
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 43489fd..09c236b 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_CMD_ZBOOT) += zimage.o obj-$(CONFIG_HAVE_FSP) += fsp/
-extra-$(CONFIG_USE_PRIVATE_LIBGCC) := lib.a +extra-$(CONFIG_USE_PRIVATE_LIBGCC) += lib.a
NORMAL_LIBGCC = $(shell $(CC) $(PLATFORM_CPPFLAGS) -print-libgcc-file-name) OBJCOPYFLAGS := --prefix-symbols=__normal_ diff --git a/arch/x86/lib/efi/Makefile b/arch/x86/lib/efi/Makefile new file mode 100644 index 0000000..41295d9 --- /dev/null +++ b/arch/x86/lib/efi/Makefile @@ -0,0 +1,24 @@ +# +# (C) Copyright 2002-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_EFI_APP) += crt0-efi-ia32.o reloc_ia32.o
+ifneq ($(CONFIG_EFI_STUB),)
+# When building for 64-bit we must remove the i386-specific flags
I think this comment should be put before reloc_x86_64 below as 64-bit stub does not build reloc_ia32.c
OK
+CFLAGS_REMOVE_reloc_ia32.o += -mregparm=3 +CFLAGS_reloc_ia32.o += -fpic -fshort-wchar
I don't see AFLAGS_REMOVE_crt0-efi-ia32.o and AFLAGS_crt0-efi-ia32.o.
They should not be needed as we don't need to change the assembler flags in that case.
+CFLAGS_REMOVE_reloc_x86_64.o += -mregparm=3 -march=i386 -m32 +CFLAGS_reloc_x86_64.o += -fpic -fshort-wchar
+AFLAGS_REMOVE_crt0-efi-x86_64.o += -mregparm=3 -march=i386 -m32 +AFLAGS_crt0-efi-x86_64.o += -fpic -fshort-wchar
+extra-$(CONFIG_EFI_STUB_32BIT) += crt0-efi-ia32.o reloc_ia32.o +extra-$(CONFIG_EFI_STUB_64BIT) += crt0-efi-x86_64.o reloc_x86_64.o
+endif
Regards, Simon

Rather than add these as open-coded values, create an enum with the commonly used flags.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add descriptor bits for the base and limit - Rename GDT_4GB to GDT_4KB
arch/x86/include/asm/cpu.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 08284ee..5b89139 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -27,6 +27,24 @@ enum { X86_VENDOR_UNKNOWN = 0xff };
+/* Global descriptor table (GDT) bits */ +enum { + GDT_4KB = 1ULL << 55, + GDT_32BIT = 1ULL << 54, + GDT_LONG = 1ULL << 53, + GDT_PRESENT = 1ULL << 47, + GDT_NOTSYS = 1ULL << 44, + GDT_CODE = 1ULL << 43, + GDT_LIMIT_LOW_SHIFT = 0, + GDT_LIMIT_LOW_MASK = 0xffff, + GDT_LIMIT_HIGH_SHIFT = 48, + GDT_LIMIT_HIGH_MASK = 0xf, + GDT_BASE_LOW_SHIFT = 16, + GDT_BASE_LOW_MASK = 0xffff, + GDT_BASE_HIGH_SHIFT = 56, + GDT_BASE_HIGH_MASK = 0xf, +}; + struct cpuid_result { uint32_t eax; uint32_t ebx;

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Rather than add these as open-coded values, create an enum with the commonly used flags.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add descriptor bits for the base and limit
- Rename GDT_4GB to GDT_4KB
arch/x86/include/asm/cpu.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 08284ee..5b89139 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -27,6 +27,24 @@ enum { X86_VENDOR_UNKNOWN = 0xff };
+/* Global descriptor table (GDT) bits */ +enum {
GDT_4KB = 1ULL << 55,
GDT_32BIT = 1ULL << 54,
GDT_LONG = 1ULL << 53,
GDT_PRESENT = 1ULL << 47,
GDT_NOTSYS = 1ULL << 44,
GDT_CODE = 1ULL << 43,
GDT_LIMIT_LOW_SHIFT = 0,
GDT_LIMIT_LOW_MASK = 0xffff,
GDT_LIMIT_HIGH_SHIFT = 48,
GDT_LIMIT_HIGH_MASK = 0xf,
GDT_BASE_LOW_SHIFT = 16,
GDT_BASE_LOW_MASK = 0xffff,
GDT_BASE_HIGH_SHIFT = 56,
GDT_BASE_HIGH_MASK = 0xf,
+};
struct cpuid_result { uint32_t eax; uint32_t ebx; --
Reviewed-by: Bin Meng bmeng.cn@gmail.com

The procedure to drop from 64-bit mode to 32-bit is a bit messy. Add a function to take care of it. It requires identity-mapped pages and that the calling code is running below 4GB.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a comment about the REX prefix - Drop the REX prefix in 32-bit mode
arch/x86/cpu/Makefile | 6 +++++ arch/x86/cpu/call32.S | 64 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu.h | 9 +++++++ 3 files changed, 79 insertions(+) create mode 100644 arch/x86/cpu/call32.S
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 5e058c0..e797925 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -12,6 +12,12 @@ extra-y = start.o obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o obj-y += interrupts.o cpu.o cpu_x86.o call64.o
+AFLAGS_REMOVE_call32.o := -mregparm=3 \ + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) +AFLAGS_call32.o := -fpic -fshort-wchar + +extra-y += call32.o + obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ obj-$(CONFIG_EFI_APP) += efi/ diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S new file mode 100644 index 0000000..c517e4a --- /dev/null +++ b/arch/x86/cpu/call32.S @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/global_data.h> +#include <asm/msr-index.h> +#include <asm/processor-flags.h> + + /* + * rdi - 32-bit code segment selector + * rsi - target address + * rdx - table address (0 if none) + */ +.code64 +.globl cpu_call32 +cpu_call32: + cli + + /* Save table pointer */ + mov %edx, %ebx + + /* + * Debugging option, this outputs characters to the console UART + * mov $0x3f8,%edx + * mov $'a',%al + * out %al,(%dx) + */ + + pushf + push %rdi /* 32-bit code segment */ + lea compat(%rip), %rax + push %rax + .byte 0x48 /* REX prefix to force 64-bit far return */ + retf +.code32 +compat: + /* + * We are now in compatibility mode with a default operand size of + * 32 bits. First disable paging. + */ + movl %cr0, %eax + andl $~X86_CR0_PG, %eax + movl %eax, %cr0 + + /* Invalidate TLB */ + xorl %eax, %eax + movl %eax, %cr3 + + /* Disable Long mode in EFER (Extended Feature Enable Register) */ + movl $MSR_EFER, %ecx + rdmsr + btr $_EFER_LME, %eax + wrmsr + + /* Set up table pointer for _x86boot_start */ + mov %ebx, %ecx + + /* Jump to the required target */ + pushl %edi /* 32-bit code segment */ + pushl %esi /* 32-bit target address */ + retf diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 5b89139..c70183c 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -230,6 +230,15 @@ char *cpu_get_name(char *name); void cpu_call64(ulong pgtable, ulong setup_base, ulong target);
/** + * cpu_call32() - Jump to a 32-bit entry point + * + * @code_seg32: 32-bit code segment to use (GDT offset, e.g. 0x20) + * @target: Pointer to the start of the 32-bit U-Boot image/entry point + * @table: Pointer to start of info table to pass to U-Boot + */ +void cpu_call32(ulong code_seg32, ulong target, ulong table); + +/** * cpu_jump_to_64bit() - Jump to a 64-bit Linux kernel * * The kernel is uncompressed and the 64-bit entry point is expected to be

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
The procedure to drop from 64-bit mode to 32-bit is a bit messy. Add a function to take care of it. It requires identity-mapped pages and that the calling code is running below 4GB.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a comment about the REX prefix
- Drop the REX prefix in 32-bit mode
arch/x86/cpu/Makefile | 6 +++++ arch/x86/cpu/call32.S | 64 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu.h | 9 +++++++ 3 files changed, 79 insertions(+) create mode 100644 arch/x86/cpu/call32.S
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 5e058c0..e797925 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -12,6 +12,12 @@ extra-y = start.o obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o obj-y += interrupts.o cpu.o cpu_x86.o call64.o
+AFLAGS_REMOVE_call32.o := -mregparm=3 \
$(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32)
+AFLAGS_call32.o := -fpic -fshort-wchar
+extra-y += call32.o
obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ obj-$(CONFIG_EFI_APP) += efi/ diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S new file mode 100644 index 0000000..c517e4a --- /dev/null +++ b/arch/x86/cpu/call32.S @@ -0,0 +1,64 @@ +/*
- (C) Copyright 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <asm/global_data.h> +#include <asm/msr-index.h> +#include <asm/processor-flags.h>
/*
* rdi - 32-bit code segment selector
* rsi - target address
* rdx - table address (0 if none)
*/
+.code64 +.globl cpu_call32 +cpu_call32:
cli
/* Save table pointer */
mov %edx, %ebx
/*
* Debugging option, this outputs characters to the console UART
* mov $0x3f8,%edx
* mov $'a',%al
* out %al,(%dx)
*/
pushf
push %rdi /* 32-bit code segment */
lea compat(%rip), %rax
push %rax
.byte 0x48 /* REX prefix to force 64-bit far return */
retf
+.code32 +compat:
/*
* We are now in compatibility mode with a default operand size of
* 32 bits. First disable paging.
*/
movl %cr0, %eax
andl $~X86_CR0_PG, %eax
movl %eax, %cr0
/* Invalidate TLB */
xorl %eax, %eax
movl %eax, %cr3
/* Disable Long mode in EFER (Extended Feature Enable Register) */
movl $MSR_EFER, %ecx
rdmsr
btr $_EFER_LME, %eax
wrmsr
/* Set up table pointer for _x86boot_start */
mov %ebx, %ecx
/* Jump to the required target */
pushl %edi /* 32-bit code segment */
pushl %esi /* 32-bit target address */
retf
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 5b89139..c70183c 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -230,6 +230,15 @@ char *cpu_get_name(char *name); void cpu_call64(ulong pgtable, ulong setup_base, ulong target);
/**
- cpu_call32() - Jump to a 32-bit entry point
- @code_seg32: 32-bit code segment to use (GDT offset, e.g. 0x20)
- @target: Pointer to the start of the 32-bit U-Boot image/entry point
- @table: Pointer to start of info table to pass to U-Boot
- */
+void cpu_call32(ulong code_seg32, ulong target, ulong table);
+/**
- cpu_jump_to_64bit() - Jump to a 64-bit Linux kernel
- The kernel is uncompressed and the 64-bit entry point is expected to be
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Most EFI implementations use 64-bit. Add a way to build U-Boot as a 64-bit EFI payload. The payload unpacks a (32-bit) U-Boot and starts it. This can be enabled for x86 boards at present.
Signed-off-by: Simon Glass sjg@chromium.org Improvements to how the payload is built: Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Add -no-red-zone for 64-bit only - Check the GDT selector's base and limit against the target address - Drop use of CONFIG_X86_64 since we don't support a 64-bit EFI application yet - Merge in Bin's implementation of adding a U-Boot payload with objcopy - Move the 64-bit crt and reloc code into this patch - Move the 64-bit efi.h additions into this patch - Rename GDT_4GB to GDT_4KB
Makefile | 2 +- arch/x86/config.mk | 10 ++++++ arch/x86/include/asm/types.h | 5 ++- arch/x86/lib/efi/crt0-efi-x86_64.S | 51 ++++++++++++++++++++++++++ include/efi.h | 7 ++++ lib/efi/efi_stub.c | 74 +++++++++++++++++++++++++++++++++++--- 6 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 arch/x86/lib/efi/crt0-efi-x86_64.S
diff --git a/Makefile b/Makefile index 755eec8..e591a6d 100644 --- a/Makefile +++ b/Makefile @@ -1096,7 +1096,7 @@ u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE u-boot-payload: u-boot-dtb.bin.o u-boot-payload.lds \ FORCE $(LD) $(LDFLAGS_EFI) -o $@ \ - -T u-boot-payload.lds \ + -T u-boot-payload.lds arch/x86/cpu/call32.o \ lib/efi/efi.o lib/efi/efi_stub.o u-boot-dtb.bin.o \ $(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB))
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 48eb5f5..83fc424 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -34,14 +34,24 @@ OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ CFLAGS_NON_EFI := -mregparm=3 CFLAGS_EFI := -fpic -fshort-wchar
+ifeq ($(CONFIG_EFI_STUB_64BIT),) +CFLAGS_EFI += $(call cc-option, -mno-red-zone) EFIARCH=ia32 EFIPAYLOAD_BFDTARGET = elf32-i386 +else +EFIARCH=x86_64 +EFIPAYLOAD_BFDTARGET = elf64-x86-64 +endif
EFIPAYLOAD_BFDARCH = i386
LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds +EFISTUB := crt0-efi-$(EFIARCH).o reloc_$(EFIARCH).o OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
+CPPFLAGS_REMOVE_crt0-efi-$(EFIARCH).o += $(CFLAGS_NON_EFI) +CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI) + ifeq ($(CONFIG_EFI_APP),y)
PLATFORM_CPPFLAGS += $(CFLAGS_EFI) diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h index e272c90..766617f 100644 --- a/arch/x86/include/asm/types.h +++ b/arch/x86/include/asm/types.h @@ -44,8 +44,11 @@ typedef __INT64_TYPE__ s64; typedef __UINT64_TYPE__ u64; #endif
+#ifdef CONFIG_EFI_STUB_64BIT +#define BITS_PER_LONG 64 +#else #define BITS_PER_LONG 32 - +#endif /* Dma addresses are 32-bits wide. */
typedef u32 dma_addr_t; diff --git a/arch/x86/lib/efi/crt0-efi-x86_64.S b/arch/x86/lib/efi/crt0-efi-x86_64.S new file mode 100644 index 0000000..c5cbf41 --- /dev/null +++ b/arch/x86/lib/efi/crt0-efi-x86_64.S @@ -0,0 +1,51 @@ +/* + * crt0-efi-x86_64.S - x86_64 EFI startup code. + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger davidm@hpl.hp.com. + * Copyright (C) 2005 Intel Co. + * Contributed by Fenghua Yu fenghua.yu@intel.com. + * + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ + .text + .align 4 + + .globl _start +_start: + subq $8, %rsp + pushq %rcx + pushq %rdx + +0: + lea image_base(%rip), %rdi + lea _DYNAMIC(%rip), %rsi + + popq %rcx + popq %rdx + pushq %rcx + pushq %rdx + call _relocate + + popq %rdi + popq %rsi + + call efi_main + addq $8, %rsp + +.exit: + ret + + /* + * hand-craft a dummy .reloc section so EFI knows it's a relocatable + * executable: + */ + .data +dummy: .long 0 + +#define IMAGE_REL_ABSOLUTE 0 + .section .reloc, "a" +label1: + .long dummy-label1 /* Page RVA */ + .long 10 /* Block Size (2*4+2) */ + .word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */ diff --git a/include/efi.h b/include/efi.h index 34844e4..4932ee1 100644 --- a/include/efi.h +++ b/include/efi.h @@ -18,6 +18,13 @@ #include <linux/string.h> #include <linux/types.h>
+#ifdef CONFIG_EFI_STUB_64BIT +/* EFI uses the Microsoft ABI which is not the default for GCC */ +#define EFIAPI __attribute__((ms_abi)) +#else +#define EFIAPI +#endif + struct efi_device_path;
#define EFI_SUCCESS 0 diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index 7259720..d49804a 100644 --- a/lib/efi/efi_stub.c +++ b/lib/efi/efi_stub.c @@ -6,8 +6,8 @@ * EFI information obtained here: * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES * - * Loads a payload (U-Boot) within the EFI environment. This is built as a - * 32-bit EFI application. + * Loads a payload (U-Boot) within the EFI environment. This is built as an + * EFI application. It can be built either in 32-bit or 64-bit mode. */
#include <common.h> @@ -116,12 +116,12 @@ void *memset(void *inptr, int ch, size_t size)
static void jump_to_uboot(ulong cs32, ulong addr, ulong info) { +#ifdef CONFIG_EFI_STUB_32BIT typedef void (*func_t)(int bist, int unused, ulong info);
-#ifdef CONFIG_EFI_STUB_32BIT ((func_t)addr)(bist, 0, info); #else - /* TODO: Implement this */ + cpu_call32(cs32, CONFIG_SYS_TEXT_BASE, info); #endif }
@@ -151,7 +151,71 @@ static int get_codeseg32(void) { int cs32 = 0;
- /* TODO(sjg): Implement this for 64-bit mode */ +#ifdef CONFIG_EFI_STUB_64BIT + struct desctab_info gdt; + uint64_t *ptr; + int i; + + get_gdt(&gdt); + for (ptr = (uint64_t *)(unsigned long)gdt.addr, i = 0; i < gdt.limit; + i += 8, ptr++) { + uint64_t desc = *ptr; + uint64_t base, limit; + + /* + * Check that the target U-Boot jump address is within the + * selector and that the selector is of the right type. + */ + base = ((desc >> GDT_BASE_LOW_SHIFT) & GDT_BASE_LOW_MASK) | + ((desc >> GDT_BASE_HIGH_SHIFT) & GDT_BASE_HIGH_MASK) + << 16; + limit = ((desc >> GDT_LIMIT_LOW_SHIFT) & GDT_LIMIT_LOW_MASK) | + ((desc >> GDT_LIMIT_HIGH_SHIFT) & GDT_LIMIT_HIGH_MASK) + << 16; + base <<= 12; /* 4KB granularity */ + limit <<= 12; + if ((desc & GDT_PRESENT) && (desc && GDT_NOTSYS) && + !(desc & GDT_LONG) && (desc & GDT_4KB) && + (desc & GDT_32BIT) && (desc & GDT_CODE) && + CONFIG_SYS_TEXT_BASE > base && + CONFIG_SYS_TEXT_BASE + 0x100000 < limit + ) { + cs32 = i; + break; + } + } + +#ifdef DEBUG + puts("\ngdt: "); + printhex8(gdt.limit); + puts(", addr: "); + printhex8(gdt.addr >> 32); + printhex8(gdt.addr); + for (i = 0; i < gdt.limit; i += 8) { + uint32_t *ptr = (uint32_t *)((unsigned long)gdt.addr + i); + + puts("\n"); + printhex2(i); + puts(": "); + printhex8(ptr[1]); + puts(" "); + printhex8(ptr[0]); + } + puts("\n "); + puts("32-bit code segment: "); + printhex2(cs32); + puts("\n "); + + puts("page_table: "); + printhex8(read_cr3()); + puts("\n "); +#endif + if (!cs32) { + puts("Can't find 32-bit code segment\n"); + return -ENOENT; + } +#endif + return cs32; }

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
Most EFI implementations use 64-bit. Add a way to build U-Boot as a 64-bit EFI payload. The payload unpacks a (32-bit) U-Boot and starts it. This can be enabled for x86 boards at present.
Signed-off-by: Simon Glass sjg@chromium.org Improvements to how the payload is built: Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- Add -no-red-zone for 64-bit only
- Check the GDT selector's base and limit against the target address
- Drop use of CONFIG_X86_64 since we don't support a 64-bit EFI application yet
- Merge in Bin's implementation of adding a U-Boot payload with objcopy
- Move the 64-bit crt and reloc code into this patch
- Move the 64-bit efi.h additions into this patch
- Rename GDT_4GB to GDT_4KB
Makefile | 2 +- arch/x86/config.mk | 10 ++++++ arch/x86/include/asm/types.h | 5 ++- arch/x86/lib/efi/crt0-efi-x86_64.S | 51 ++++++++++++++++++++++++++ include/efi.h | 7 ++++ lib/efi/efi_stub.c | 74 +++++++++++++++++++++++++++++++++++--- 6 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 arch/x86/lib/efi/crt0-efi-x86_64.S
diff --git a/Makefile b/Makefile index 755eec8..e591a6d 100644 --- a/Makefile +++ b/Makefile @@ -1096,7 +1096,7 @@ u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE u-boot-payload: u-boot-dtb.bin.o u-boot-payload.lds \ FORCE $(LD) $(LDFLAGS_EFI) -o $@ \
-T u-boot-payload.lds \
-T u-boot-payload.lds arch/x86/cpu/call32.o \ lib/efi/efi.o lib/efi/efi_stub.o u-boot-dtb.bin.o \ $(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB))
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 48eb5f5..83fc424 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -34,14 +34,24 @@ OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ CFLAGS_NON_EFI := -mregparm=3 CFLAGS_EFI := -fpic -fshort-wchar
+ifeq ($(CONFIG_EFI_STUB_64BIT),) +CFLAGS_EFI += $(call cc-option, -mno-red-zone) EFIARCH=ia32 EFIPAYLOAD_BFDTARGET = elf32-i386 +else +EFIARCH=x86_64
Please add space around =
+EFIPAYLOAD_BFDTARGET = elf64-x86-64 +endif
EFIPAYLOAD_BFDARCH = i386
LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds +EFISTUB := crt0-efi-$(EFIARCH).o reloc_$(EFIARCH).o OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
+CPPFLAGS_REMOVE_crt0-efi-$(EFIARCH).o += $(CFLAGS_NON_EFI) +CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI)
ifeq ($(CONFIG_EFI_APP),y)
PLATFORM_CPPFLAGS += $(CFLAGS_EFI) diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h index e272c90..766617f 100644 --- a/arch/x86/include/asm/types.h +++ b/arch/x86/include/asm/types.h @@ -44,8 +44,11 @@ typedef __INT64_TYPE__ s64; typedef __UINT64_TYPE__ u64; #endif
+#ifdef CONFIG_EFI_STUB_64BIT +#define BITS_PER_LONG 64 +#else #define BITS_PER_LONG 32
+#endif /* Dma addresses are 32-bits wide. */
typedef u32 dma_addr_t; diff --git a/arch/x86/lib/efi/crt0-efi-x86_64.S b/arch/x86/lib/efi/crt0-efi-x86_64.S new file mode 100644 index 0000000..c5cbf41 --- /dev/null +++ b/arch/x86/lib/efi/crt0-efi-x86_64.S @@ -0,0 +1,51 @@ +/*
- crt0-efi-x86_64.S - x86_64 EFI startup code.
- Copyright (C) 1999 Hewlett-Packard Co.
- Contributed by David Mosberger davidm@hpl.hp.com.
- Copyright (C) 2005 Intel Co.
- Contributed by Fenghua Yu fenghua.yu@intel.com.
- All rights reserved.
- SPDX-License-Identifier: BSD-3-Clause
- */
.text
.align 4
.globl _start
+_start:
subq $8, %rsp
pushq %rcx
pushq %rdx
+0:
lea image_base(%rip), %rdi
lea _DYNAMIC(%rip), %rsi
popq %rcx
popq %rdx
pushq %rcx
pushq %rdx
call _relocate
popq %rdi
popq %rsi
call efi_main
addq $8, %rsp
+.exit:
ret
/*
* hand-craft a dummy .reloc section so EFI knows it's a relocatable
* executable:
*/
.data
+dummy: .long 0
+#define IMAGE_REL_ABSOLUTE 0
.section .reloc, "a"
+label1:
.long dummy-label1 /* Page RVA */
.long 10 /* Block Size (2*4+2) */
.word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */
diff --git a/include/efi.h b/include/efi.h index 34844e4..4932ee1 100644 --- a/include/efi.h +++ b/include/efi.h @@ -18,6 +18,13 @@ #include <linux/string.h> #include <linux/types.h>
+#ifdef CONFIG_EFI_STUB_64BIT +/* EFI uses the Microsoft ABI which is not the default for GCC */ +#define EFIAPI __attribute__((ms_abi)) +#else +#define EFIAPI +#endif
struct efi_device_path;
#define EFI_SUCCESS 0 diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index 7259720..d49804a 100644 --- a/lib/efi/efi_stub.c +++ b/lib/efi/efi_stub.c @@ -6,8 +6,8 @@
- EFI information obtained here:
- http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
- Loads a payload (U-Boot) within the EFI environment. This is built as a
- 32-bit EFI application.
- Loads a payload (U-Boot) within the EFI environment. This is built as an
*/
- EFI application. It can be built either in 32-bit or 64-bit mode.
#include <common.h> @@ -116,12 +116,12 @@ void *memset(void *inptr, int ch, size_t size)
static void jump_to_uboot(ulong cs32, ulong addr, ulong info) { +#ifdef CONFIG_EFI_STUB_32BIT typedef void (*func_t)(int bist, int unused, ulong info);
-#ifdef CONFIG_EFI_STUB_32BIT ((func_t)addr)(bist, 0, info);
bist is undefined, which causes build error for CONFIG_EFI_STUB_32BIT.
#else
/* TODO: Implement this */
cpu_call32(cs32, CONFIG_SYS_TEXT_BASE, info);
#endif }
@@ -151,7 +151,71 @@ static int get_codeseg32(void) { int cs32 = 0;
/* TODO(sjg): Implement this for 64-bit mode */
+#ifdef CONFIG_EFI_STUB_64BIT
struct desctab_info gdt;
uint64_t *ptr;
int i;
get_gdt(&gdt);
for (ptr = (uint64_t *)(unsigned long)gdt.addr, i = 0; i < gdt.limit;
i += 8, ptr++) {
uint64_t desc = *ptr;
uint64_t base, limit;
/*
* Check that the target U-Boot jump address is within the
* selector and that the selector is of the right type.
*/
base = ((desc >> GDT_BASE_LOW_SHIFT) & GDT_BASE_LOW_MASK) |
((desc >> GDT_BASE_HIGH_SHIFT) & GDT_BASE_HIGH_MASK)
<< 16;
limit = ((desc >> GDT_LIMIT_LOW_SHIFT) & GDT_LIMIT_LOW_MASK) |
((desc >> GDT_LIMIT_HIGH_SHIFT) & GDT_LIMIT_HIGH_MASK)
<< 16;
base <<= 12; /* 4KB granularity */
limit <<= 12;
if ((desc & GDT_PRESENT) && (desc && GDT_NOTSYS) &&
!(desc & GDT_LONG) && (desc & GDT_4KB) &&
(desc & GDT_32BIT) && (desc & GDT_CODE) &&
CONFIG_SYS_TEXT_BASE > base &&
CONFIG_SYS_TEXT_BASE + 0x100000 < limit
What is 0x100000? I think it should be CONFIG_SYS_MONITOR_LEN?
) {
cs32 = i;
break;
}
}
+#ifdef DEBUG
puts("\ngdt: ");
printhex8(gdt.limit);
puts(", addr: ");
printhex8(gdt.addr >> 32);
printhex8(gdt.addr);
for (i = 0; i < gdt.limit; i += 8) {
uint32_t *ptr = (uint32_t *)((unsigned long)gdt.addr + i);
puts("\n");
printhex2(i);
puts(": ");
printhex8(ptr[1]);
puts(" ");
printhex8(ptr[0]);
}
puts("\n ");
puts("32-bit code segment: ");
printhex2(cs32);
puts("\n ");
puts("page_table: ");
printhex8(read_cr3());
puts("\n ");
+#endif
if (!cs32) {
puts("Can't find 32-bit code segment\n");
return -ENOENT;
}
+#endif
return cs32;
}
--
Regards, Bin

The EFI stub provides information to U-Boot in a table. This includes the memory map which is needed to decide where to relocate U-Boot. Collect this information in the early init code and store it in global_data.
Fix up the BIST code at the same time since we don't have it when booting from EFI and can assume it is 0.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Zero BIST when starting from EFI/coreboot
arch/x86/cpu/start.S | 19 ++++++++++++++++++- arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/asm-offsets.c | 1 + 3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 9b2584d..fdef2bb 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -42,6 +42,13 @@ _x86boot_start:
/* Tell 32-bit code it is being entered from an in-RAM copy */ movl $GD_FLG_WARM_BOOT, %ebx + + /* + * Zero the BIST (Built-In Self Test) value since we don't have it. + * It must be 0 or the previous loader would have reported an error. + */ + movl $0, %ebp + jmp 1f
/* Add a way for tools to discover the _start entry point */ @@ -53,9 +60,13 @@ _start: * Set %bx to 0 to indicate this. */ movl $GD_FLG_COLD_BOOT, %ebx -1: + /* Save BIST */ movl %eax, %ebp +1: + + /* Save table pointer */ + movl %ecx, %esi
/* Load the segement registers to match the GDT loaded in start16.S */ movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax @@ -133,7 +144,13 @@ car_init_ret: movl %esi, (%edx)
skip_hob: +#else + /* Store table pointer */ + movl %esp, %edx + addl $GD_TABLE, %edx + movl %esi, (%edx) #endif + /* Setup first parameter to setup_gdt, pointer to global_data */ movl %esp, %eax
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 80ebe3e..f7e3889 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -69,6 +69,7 @@ struct arch_global_data { char *mrc_output; unsigned int mrc_output_len; void *gdt; /* Global descriptor table */ + ulong table; /* Table pointer from previous loader */ };
#endif diff --git a/arch/x86/lib/asm-offsets.c b/arch/x86/lib/asm-offsets.c index 70ccf1b..9da04dd 100644 --- a/arch/x86/lib/asm-offsets.c +++ b/arch/x86/lib/asm-offsets.c @@ -21,5 +21,6 @@ int main(void) #ifdef CONFIG_HAVE_FSP DEFINE(GD_HOB_LIST, offsetof(gd_t, arch.hob_list)); #endif + DEFINE(GD_TABLE, offsetof(gd_t, arch.table)); return 0; }

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
The EFI stub provides information to U-Boot in a table. This includes the memory map which is needed to decide where to relocate U-Boot. Collect this information in the early init code and store it in global_data.
Fix up the BIST code at the same time since we don't have it when booting from EFI and can assume it is 0.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Zero BIST when starting from EFI/coreboot
arch/x86/cpu/start.S | 19 ++++++++++++++++++- arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/asm-offsets.c | 1 + 3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 9b2584d..fdef2bb 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -42,6 +42,13 @@ _x86boot_start:
/* Tell 32-bit code it is being entered from an in-RAM copy */ movl $GD_FLG_WARM_BOOT, %ebx
/*
* Zero the BIST (Built-In Self Test) value since we don't have it.
* It must be 0 or the previous loader would have reported an error.
*/
movl $0, %ebp
jmp 1f /* Add a way for tools to discover the _start entry point */
@@ -53,9 +60,13 @@ _start: * Set %bx to 0 to indicate this. */ movl $GD_FLG_COLD_BOOT, %ebx -1:
/* Save BIST */ movl %eax, %ebp
+1:
/* Save table pointer */
movl %ecx, %esi /* Load the segement registers to match the GDT loaded in start16.S */ movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
@@ -133,7 +144,13 @@ car_init_ret: movl %esi, (%edx)
skip_hob: +#else
/* Store table pointer */
movl %esp, %edx
addl $GD_TABLE, %edx
movl %esi, (%edx)
#endif
/* Setup first parameter to setup_gdt, pointer to global_data */ movl %esp, %eax
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 80ebe3e..f7e3889 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -69,6 +69,7 @@ struct arch_global_data { char *mrc_output; unsigned int mrc_output_len; void *gdt; /* Global descriptor table */
ulong table; /* Table pointer from previous loader */
};
#endif diff --git a/arch/x86/lib/asm-offsets.c b/arch/x86/lib/asm-offsets.c index 70ccf1b..9da04dd 100644 --- a/arch/x86/lib/asm-offsets.c +++ b/arch/x86/lib/asm-offsets.c @@ -21,5 +21,6 @@ int main(void) #ifdef CONFIG_HAVE_FSP DEFINE(GD_HOB_LIST, offsetof(gd_t, arch.hob_list)); #endif
DEFINE(GD_TABLE, offsetof(gd_t, arch.table)); return 0;
}
Reviewed-by: Bin Meng bmeng.cn@gmail.com

The EFI stub can pass a table to U-Boot with information about the memory map Potentially other things will follow. Add a way to access this table.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
lib/efi/Makefile | 1 + lib/efi/efi_info.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 lib/efi/efi_info.c
diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 4bc67f0..e32dc14 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,6 +5,7 @@ #
obj-$(CONFIG_EFI_APP) += efi_app.o efi.o +obj-$(CONFIG_EFI_STUB) += efi_info.o
CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \ $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c new file mode 100644 index 0000000..0cd9a7e --- /dev/null +++ b/lib/efi/efi_info.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Access to the EFI information table + */ + +#include <common.h> +#include <efi.h> +#include <errno.h> +#include <mapmem.h> + +int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) +{ + struct efi_entry_hdr *entry; + struct efi_info_hdr *info; + int ret; + + if (!gd->arch.table) + return -ENODATA; + + info = map_sysmem(gd->arch.table, 0); + if (info->version != EFI_TABLE_VERSION) { + ret = -EPROTONOSUPPORT; + goto err; + } + + entry = (struct efi_entry_hdr *)((ulong)info + info->hdr_size); + while (entry->type != EFIET_END) { + if (entry->type == type) { + if (entry->addr) + *datap = map_sysmem(entry->addr, entry->size); + else + *datap = entry + 1; + *sizep = entry->size; + return 0; + } + entry = (struct efi_entry_hdr *)((ulong)entry + entry->link); + } + + ret = -ENOENT; +err: + unmap_sysmem(info); + + return ret; +}

The EFI memory map is passed from the stub to U-Boot in a table. Add a command to display it in a vaguely readable fashion.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Drop a left-over debug printf() - Fix alignment of region index field in the output - Fix efi_mem_desc_VERSION typo - Output the region index in decimal
common/Makefile | 1 + common/cmd_efi.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 common/cmd_efi.c
diff --git a/common/Makefile b/common/Makefile index d6c1d48..6dc4c89 100644 --- a/common/Makefile +++ b/common/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_CMD_DTT) += cmd_dtt.o obj-$(CONFIG_CMD_ECHO) += cmd_echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o obj-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o +obj-$(CONFIG_EFI_STUB) += cmd_efi.o obj-$(CONFIG_CMD_ELF) += cmd_elf.o obj-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o obj-$(CONFIG_CMD_EXT4) += cmd_ext4.o diff --git a/common/cmd_efi.c b/common/cmd_efi.c new file mode 100644 index 0000000..c76296e --- /dev/null +++ b/common/cmd_efi.c @@ -0,0 +1,257 @@ +/* + * (C) Copyright 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <efi.h> +#include <errno.h> +#include <malloc.h> + +static const char *const type_name[] = { + "reserved", + "loader_code", + "loader_data", + "bs_code", + "bs_data", + "rt_code", + "rt_data", + "conv", + "unusable", + "acpi_reclaim", + "acpi_nvs", + "io", + "io_port", + "pal_code", +}; + +static struct attr_info { + int shift; + const char *name; +} mem_attr[] = { + { EFI_MEMORY_UC_SHIFT, "uncached" }, + { EFI_MEMORY_WC_SHIFT, "write-coalescing" }, + { EFI_MEMORY_WT_SHIFT, "write-through" }, + { EFI_MEMORY_WB_SHIFT, "write-back" }, + { EFI_MEMORY_UCE_SHIFT, "uncached & exported" }, + { EFI_MEMORY_WP_SHIFT, "write-protect" }, + { EFI_MEMORY_RP_SHIFT, "read-protect" }, + { EFI_MEMORY_XP_SHIFT, "execute-protect" }, + { EFI_MEMORY_RUNTIME_SHIFT, "needs runtime mapping" } +}; + +/* Maximum different attribute values we can track */ +#define ATTR_SEEN_MAX 30 + +static inline bool is_boot_services(int type) +{ + return type == EFI_LOADER_CODE || type == EFI_LOADER_DATA || + type == EFI_BOOT_SERVICES_CODE || + type == EFI_BOOT_SERVICES_DATA; +} + +static int h_cmp_entry(const void *v1, const void *v2) +{ + const struct efi_mem_desc *desc1 = v1; + const struct efi_mem_desc *desc2 = v2; + int64_t diff = desc1->physical_start - desc2->physical_start; + + /* + * Manually calculate the difference to avoid sign loss in the 64-bit + * to 32-bit conversion + */ + return diff < 0 ? -1 : diff > 0 ? 1 : 0; +} + +void *efi_build_mem_table(struct efi_entry_memmap *map, int size, bool skip_bs) +{ + struct efi_mem_desc *desc, *end, *base, *dest, *prev; + int count; + u64 addr; + + base = malloc(size + sizeof(*desc)); + if (!base) { + debug("%s: Cannot allocate %#x bytes\n", __func__, size); + return NULL; + } + end = (struct efi_mem_desc *)((ulong)map + size); + count = ((ulong)end - (ulong)map->desc) / map->desc_size; + memcpy(base, map->desc, (ulong)end - (ulong)map->desc); + qsort(base, count, map->desc_size, h_cmp_entry); + prev = NULL; + addr = 0; + dest = base; + end = base + count; + for (desc = base; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + bool merge = true; + int type = desc->type; + + if (skip_bs && is_boot_services(desc->type)) + type = EFI_CONVENTIONAL_MEMORY; + + memcpy(dest, desc, map->desc_size); + dest->type = type; + if (!skip_bs || !prev) + merge = false; + else if (desc->physical_start != addr) + merge = false; + else if (type != EFI_CONVENTIONAL_MEMORY) + merge = false; + else if (prev->type != EFI_CONVENTIONAL_MEMORY) + merge = false; + + if (merge) { + prev->num_pages += desc->num_pages; + } else { + prev = dest; + dest = efi_get_next_mem_desc(map, dest); + } + addr = desc->physical_start + (desc->num_pages << + EFI_PAGE_SHIFT); + } + + /* Mark the end */ + dest->type = EFI_TABLE_END; + + return base; +} + +static void efi_print_mem_table(struct efi_entry_memmap *map, + struct efi_mem_desc *desc, bool skip_bs) +{ + u64 attr_seen[ATTR_SEEN_MAX]; + int attr_seen_count; + int upto, i; + u64 addr; + + printf(" # %-14s %10s %10s %10s %s\n", "Type", "Physical", + "Virtual", "Size", "Attributes"); + + /* Keep track of all the different attributes we have seen */ + attr_seen_count = 0; + addr = 0; + for (upto = 0; desc->type != EFI_TABLE_END; + upto++, desc = efi_get_next_mem_desc(map, desc)) { + const char *name; + u64 size; + + if (skip_bs && is_boot_services(desc->type)) + continue; + if (desc->physical_start != addr) { + printf(" %-14s %010llx %10s %010llx\n", "<gap>", + addr, "", desc->physical_start - addr); + } + size = desc->num_pages << EFI_PAGE_SHIFT; + + name = desc->type < ARRAY_SIZE(type_name) ? + type_name[desc->type] : "<invalid>"; + printf("%2d %x:%-12s %010llx %010llx %010llx ", upto, + desc->type, name, desc->physical_start, + desc->virtual_start, size); + if (desc->attribute & EFI_MEMORY_RUNTIME) + putc('r'); + printf("%llx", desc->attribute & ~EFI_MEMORY_RUNTIME); + putc('\n'); + + for (i = 0; i < attr_seen_count; i++) { + if (attr_seen[i] == desc->attribute) + break; + } + if (i == attr_seen_count && i < ATTR_SEEN_MAX) + attr_seen[attr_seen_count++] = desc->attribute; + addr = desc->physical_start + size; + } + + printf("\nAttributes key:\n"); + for (i = 0; i < attr_seen_count; i++) { + u64 attr = attr_seen[i]; + bool first; + int j; + + printf("%c%llx: ", attr & EFI_MEMORY_RUNTIME ? 'r' : ' ', + attr & ~EFI_MEMORY_RUNTIME); + for (j = 0, first = true; j < ARRAY_SIZE(mem_attr); j++) { + if (attr & (1ULL << mem_attr[j].shift)) { + if (first) + first = false; + else + printf(", "); + printf("%s", mem_attr[j].name); + } + } + putc('\n'); + } + if (skip_bs) + printf("*Some areas are merged (use 'all' to see)\n"); +} + +static int do_efi_mem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct efi_mem_desc *desc; + struct efi_entry_memmap *map; + int size, ret; + bool skip_bs; + + skip_bs = !argc || *argv[0] != 'a'; + ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); + switch (ret) { + case -ENOENT: + printf("No EFI table available\n"); + goto done; + case -EPROTONOSUPPORT: + printf("Incorrect EFI table version\n"); + goto done; + } + printf("EFI table at %lx, memory map %p, size %x, version %x, descr. size %#x\n", + gd->arch.table, map, size, map->version, map->desc_size); + if (map->version != EFI_MEM_DESC_VERSION) { + printf("Incorrect memory map version\n"); + ret = -EPROTONOSUPPORT; + goto done; + } + + desc = efi_build_mem_table(map, size, skip_bs); + if (!desc) { + ret = -ENOMEM; + goto done; + } + + efi_print_mem_table(map, desc, skip_bs); + free(desc); +done: + if (ret) + printf("Error: %d\n", ret); + + return ret ? CMD_RET_FAILURE : 0; +} + +static cmd_tbl_t efi_commands[] = { + U_BOOT_CMD_MKENT(mem, 1, 1, do_efi_mem, "", ""), +}; + +static int do_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cmd_tbl_t *efi_cmd; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + efi_cmd = find_cmd_tbl(argv[1], efi_commands, ARRAY_SIZE(efi_commands)); + argc -= 2; + argv += 2; + if (!efi_cmd || argc > efi_cmd->maxargs) + return CMD_RET_USAGE; + + ret = efi_cmd->cmd(efi_cmd, flag, argc, argv); + + return cmd_process_error(efi_cmd, ret); +} + +U_BOOT_CMD( + efi, 3, 1, do_efi, + "EFI access", + "mem [all] Dump memory information [include boot services]" +);

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
The EFI memory map is passed from the stub to U-Boot in a table. Add a command to display it in a vaguely readable fashion.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Drop a left-over debug printf()
- Fix alignment of region index field in the output
- Fix efi_mem_desc_VERSION typo
- Output the region index in decimal
common/Makefile | 1 + common/cmd_efi.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 common/cmd_efi.c
diff --git a/common/Makefile b/common/Makefile index d6c1d48..6dc4c89 100644 --- a/common/Makefile +++ b/common/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_CMD_DTT) += cmd_dtt.o obj-$(CONFIG_CMD_ECHO) += cmd_echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o obj-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o +obj-$(CONFIG_EFI_STUB) += cmd_efi.o obj-$(CONFIG_CMD_ELF) += cmd_elf.o obj-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o obj-$(CONFIG_CMD_EXT4) += cmd_ext4.o diff --git a/common/cmd_efi.c b/common/cmd_efi.c new file mode 100644 index 0000000..c76296e --- /dev/null +++ b/common/cmd_efi.c @@ -0,0 +1,257 @@ +/*
- (C) Copyright 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <command.h> +#include <efi.h> +#include <errno.h> +#include <malloc.h>
+static const char *const type_name[] = {
"reserved",
"loader_code",
"loader_data",
"bs_code",
"bs_data",
"rt_code",
"rt_data",
"conv",
"unusable",
"acpi_reclaim",
"acpi_nvs",
"io",
"io_port",
"pal_code",
+};
+static struct attr_info {
int shift;
const char *name;
+} mem_attr[] = {
{ EFI_MEMORY_UC_SHIFT, "uncached" },
{ EFI_MEMORY_WC_SHIFT, "write-coalescing" },
{ EFI_MEMORY_WT_SHIFT, "write-through" },
{ EFI_MEMORY_WB_SHIFT, "write-back" },
{ EFI_MEMORY_UCE_SHIFT, "uncached & exported" },
{ EFI_MEMORY_WP_SHIFT, "write-protect" },
{ EFI_MEMORY_RP_SHIFT, "read-protect" },
{ EFI_MEMORY_XP_SHIFT, "execute-protect" },
{ EFI_MEMORY_RUNTIME_SHIFT, "needs runtime mapping" }
+};
+/* Maximum different attribute values we can track */ +#define ATTR_SEEN_MAX 30
+static inline bool is_boot_services(int type) +{
return type == EFI_LOADER_CODE || type == EFI_LOADER_DATA ||
type == EFI_BOOT_SERVICES_CODE ||
type == EFI_BOOT_SERVICES_DATA;
+}
+static int h_cmp_entry(const void *v1, const void *v2) +{
const struct efi_mem_desc *desc1 = v1;
const struct efi_mem_desc *desc2 = v2;
int64_t diff = desc1->physical_start - desc2->physical_start;
/*
* Manually calculate the difference to avoid sign loss in the 64-bit
* to 32-bit conversion
*/
return diff < 0 ? -1 : diff > 0 ? 1 : 0;
+}
+void *efi_build_mem_table(struct efi_entry_memmap *map, int size, bool skip_bs) +{
struct efi_mem_desc *desc, *end, *base, *dest, *prev;
int count;
u64 addr;
base = malloc(size + sizeof(*desc));
if (!base) {
debug("%s: Cannot allocate %#x bytes\n", __func__, size);
return NULL;
}
end = (struct efi_mem_desc *)((ulong)map + size);
count = ((ulong)end - (ulong)map->desc) / map->desc_size;
memcpy(base, map->desc, (ulong)end - (ulong)map->desc);
qsort(base, count, map->desc_size, h_cmp_entry);
prev = NULL;
addr = 0;
dest = base;
end = base + count;
for (desc = base; desc < end; desc = efi_get_next_mem_desc(map, desc)) {
bool merge = true;
int type = desc->type;
if (skip_bs && is_boot_services(desc->type))
type = EFI_CONVENTIONAL_MEMORY;
memcpy(dest, desc, map->desc_size);
dest->type = type;
if (!skip_bs || !prev)
merge = false;
else if (desc->physical_start != addr)
merge = false;
else if (type != EFI_CONVENTIONAL_MEMORY)
merge = false;
else if (prev->type != EFI_CONVENTIONAL_MEMORY)
merge = false;
if (merge) {
prev->num_pages += desc->num_pages;
} else {
prev = dest;
dest = efi_get_next_mem_desc(map, dest);
}
addr = desc->physical_start + (desc->num_pages <<
EFI_PAGE_SHIFT);
}
/* Mark the end */
dest->type = EFI_TABLE_END;
return base;
+}
+static void efi_print_mem_table(struct efi_entry_memmap *map,
struct efi_mem_desc *desc, bool skip_bs)
+{
u64 attr_seen[ATTR_SEEN_MAX];
int attr_seen_count;
int upto, i;
u64 addr;
printf(" # %-14s %10s %10s %10s %s\n", "Type", "Physical",
"Virtual", "Size", "Attributes");
/* Keep track of all the different attributes we have seen */
attr_seen_count = 0;
addr = 0;
for (upto = 0; desc->type != EFI_TABLE_END;
upto++, desc = efi_get_next_mem_desc(map, desc)) {
const char *name;
u64 size;
if (skip_bs && is_boot_services(desc->type))
continue;
if (desc->physical_start != addr) {
printf(" %-14s %010llx %10s %010llx\n", "<gap>",
addr, "", desc->physical_start - addr);
}
size = desc->num_pages << EFI_PAGE_SHIFT;
name = desc->type < ARRAY_SIZE(type_name) ?
type_name[desc->type] : "<invalid>";
printf("%2d %x:%-12s %010llx %010llx %010llx ", upto,
desc->type, name, desc->physical_start,
desc->virtual_start, size);
if (desc->attribute & EFI_MEMORY_RUNTIME)
putc('r');
printf("%llx", desc->attribute & ~EFI_MEMORY_RUNTIME);
putc('\n');
for (i = 0; i < attr_seen_count; i++) {
if (attr_seen[i] == desc->attribute)
break;
}
if (i == attr_seen_count && i < ATTR_SEEN_MAX)
attr_seen[attr_seen_count++] = desc->attribute;
addr = desc->physical_start + size;
}
printf("\nAttributes key:\n");
for (i = 0; i < attr_seen_count; i++) {
u64 attr = attr_seen[i];
bool first;
int j;
printf("%c%llx: ", attr & EFI_MEMORY_RUNTIME ? 'r' : ' ',
attr & ~EFI_MEMORY_RUNTIME);
for (j = 0, first = true; j < ARRAY_SIZE(mem_attr); j++) {
if (attr & (1ULL << mem_attr[j].shift)) {
if (first)
first = false;
else
printf(", ");
printf("%s", mem_attr[j].name);
}
}
putc('\n');
}
if (skip_bs)
printf("*Some areas are merged (use 'all' to see)\n");
+}
+static int do_efi_mem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{
struct efi_mem_desc *desc;
struct efi_entry_memmap *map;
int size, ret;
bool skip_bs;
skip_bs = !argc || *argv[0] != 'a';
ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
switch (ret) {
case -ENOENT:
printf("No EFI table available\n");
goto done;
case -EPROTONOSUPPORT:
printf("Incorrect EFI table version\n");
goto done;
}
printf("EFI table at %lx, memory map %p, size %x, version %x, descr. size %#x\n",
gd->arch.table, map, size, map->version, map->desc_size);
if (map->version != EFI_MEM_DESC_VERSION) {
printf("Incorrect memory map version\n");
ret = -EPROTONOSUPPORT;
goto done;
}
desc = efi_build_mem_table(map, size, skip_bs);
if (!desc) {
ret = -ENOMEM;
goto done;
}
efi_print_mem_table(map, desc, skip_bs);
free(desc);
+done:
if (ret)
printf("Error: %d\n", ret);
return ret ? CMD_RET_FAILURE : 0;
+}
+static cmd_tbl_t efi_commands[] = {
U_BOOT_CMD_MKENT(mem, 1, 1, do_efi_mem, "", ""),
+};
+static int do_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{
cmd_tbl_t *efi_cmd;
int ret;
if (argc < 2)
return CMD_RET_USAGE;
efi_cmd = find_cmd_tbl(argv[1], efi_commands, ARRAY_SIZE(efi_commands));
argc -= 2;
argv += 2;
if (!efi_cmd || argc > efi_cmd->maxargs)
return CMD_RET_USAGE;
ret = efi_cmd->cmd(efi_cmd, flag, argc, argv);
return cmd_process_error(efi_cmd, ret);
+}
+U_BOOT_CMD(
efi, 3, 1, do_efi,
"EFI access",
"mem [all] Dump memory information [include boot services]"
+);
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Tested on QEMU Tested-by: Bin Meng bmeng.cn@gmail.com

When U-Boot runs as an EFI payload it needs to avoid setting up the CPU again. Also U-Boot currently does not handle interrupts for many devices, so run with interrupts disabled.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a note that bootm does not work when running as an EFI app - Move EFI CAR settings to arch/x86/lib/efi/Kconfig - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
arch/x86/Kconfig | 6 ++++++ arch/x86/cpu/cpu.c | 21 +++++++++++++-------- arch/x86/cpu/interrupts.c | 10 ++++++++-- arch/x86/lib/bootm.c | 5 +++++ arch/x86/lib/efi/Kconfig | 11 +++++++++++ 5 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 arch/x86/lib/efi/Kconfig
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f124d58..01ed760 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -194,6 +194,7 @@ config X86_RAMTEST
config HAVE_FSP bool "Add an Firmware Support Package binary" + depends on !EFI help Select this option to add an Firmware Support Package binary to the resulting U-Boot image. It is a binary blob which U-Boot uses @@ -309,6 +310,7 @@ menu "System tables"
config GENERATE_PIRQ_TABLE bool "Generate a PIRQ table" + depends on !EFI default n help Generate a PIRQ routing table for this board. The PIRQ routing table @@ -319,6 +321,7 @@ config GENERATE_PIRQ_TABLE
config GENERATE_SFI_TABLE bool "Generate a SFI (Simple Firmware Interface) table" + depends on !EFI help The Simple Firmware Interface (SFI) provides a lightweight method for platform firmware to pass information to the operating system @@ -333,6 +336,7 @@ config GENERATE_SFI_TABLE
config GENERATE_MP_TABLE bool "Generate an MP (Multi-Processor) table" + depends on !EFI default n help Generate an MP (Multi-Processor) table for this board. The MP table @@ -383,4 +387,6 @@ config PCIE_ECAM_SIZE so a default 0x10000000 size covers all of the 256 buses which is the maximum number of PCI buses as defined by the PCI specification.
+source "arch/x86/lib/efi/Kconfig" + endmenu diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index d233a45..129777c 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -330,13 +330,15 @@ int x86_cpu_init_f(void) const u32 em_rst = ~X86_CR0_EM; const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE;
- /* initialize FPU, reset EM, set MP and NE */ - asm ("fninit\n" \ - "movl %%cr0, %%eax\n" \ - "andl %0, %%eax\n" \ - "orl %1, %%eax\n" \ - "movl %%eax, %%cr0\n" \ - : : "i" (em_rst), "i" (mp_ne_set) : "eax"); + if (ll_boot_init()) { + /* initialize FPU, reset EM, set MP and NE */ + asm ("fninit\n" \ + "movl %%cr0, %%eax\n" \ + "andl %0, %%eax\n" \ + "orl %1, %%eax\n" \ + "movl %%eax, %%cr0\n" \ + : : "i" (em_rst), "i" (mp_ne_set) : "eax"); + }
/* identify CPU via cpuid and store the decoded info into gd->arch */ if (has_cpuid()) { @@ -712,5 +714,8 @@ __weak int x86_init_cpus(void)
int cpu_init_r(void) { - return x86_init_cpus(); + if (ll_boot_init()) + return x86_init_cpus(); + + return 0; } diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index a112938..9217307 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -258,8 +258,14 @@ int interrupt_init(void) /* Initialize core interrupt and exception functionality of CPU */ cpu_init_interrupts();
- /* It is now safe to enable interrupts */ - enable_interrupts(); + /* + * It is now safe to enable interrupts. + * + * TODO(sjg@chromium.org): But we don't handle these correctly when + * booted from EFI. + */ + if (ll_boot_init()) + enable_interrupts(); #endif
return 0; diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 445ee6e..f441c84 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -164,7 +164,11 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * the data segments are 0x18, 4GB flat, and read/write. * U-boot is setting them up that way for itself in * arch/i386/cpu/cpu.c. + * + * Note that we cannot currently boot a kernel while running as + * an EFI application. Please use the payload option for that. */ +#ifndef CONFIG_EFI_APP __asm__ __volatile__ ( "movl $0, %%ebp\n" "cli\n" @@ -173,6 +177,7 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) [boot_params] "S"(setup_base), "b"(0), "D"(0) ); +#endif }
/* We can't get to here */ diff --git a/arch/x86/lib/efi/Kconfig b/arch/x86/lib/efi/Kconfig new file mode 100644 index 0000000..e0975d3 --- /dev/null +++ b/arch/x86/lib/efi/Kconfig @@ -0,0 +1,11 @@ +if EFI + +config SYS_CAR_ADDR + hex + default 0x100000 + +config SYS_CAR_SIZE + hex + default 0x20000 + +endif

On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
When U-Boot runs as an EFI payload it needs to avoid setting up the CPU again. Also U-Boot currently does not handle interrupts for many devices, so run with interrupts disabled.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a note that bootm does not work when running as an EFI app
- Move EFI CAR settings to arch/x86/lib/efi/Kconfig
- Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
arch/x86/Kconfig | 6 ++++++ arch/x86/cpu/cpu.c | 21 +++++++++++++-------- arch/x86/cpu/interrupts.c | 10 ++++++++-- arch/x86/lib/bootm.c | 5 +++++ arch/x86/lib/efi/Kconfig | 11 +++++++++++ 5 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 arch/x86/lib/efi/Kconfig
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f124d58..01ed760 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -194,6 +194,7 @@ config X86_RAMTEST
config HAVE_FSP bool "Add an Firmware Support Package binary"
depends on !EFI help Select this option to add an Firmware Support Package binary to the resulting U-Boot image. It is a binary blob which U-Boot uses
@@ -309,6 +310,7 @@ menu "System tables"
config GENERATE_PIRQ_TABLE bool "Generate a PIRQ table"
depends on !EFI default n help Generate a PIRQ routing table for this board. The PIRQ routing table
@@ -319,6 +321,7 @@ config GENERATE_PIRQ_TABLE
config GENERATE_SFI_TABLE bool "Generate a SFI (Simple Firmware Interface) table"
depends on !EFI help The Simple Firmware Interface (SFI) provides a lightweight method for platform firmware to pass information to the operating system
@@ -333,6 +336,7 @@ config GENERATE_SFI_TABLE
config GENERATE_MP_TABLE bool "Generate an MP (Multi-Processor) table"
depends on !EFI default n help Generate an MP (Multi-Processor) table for this board. The MP table
@@ -383,4 +387,6 @@ config PCIE_ECAM_SIZE so a default 0x10000000 size covers all of the 256 buses which is the maximum number of PCI buses as defined by the PCI specification.
+source "arch/x86/lib/efi/Kconfig"
endmenu diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index d233a45..129777c 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -330,13 +330,15 @@ int x86_cpu_init_f(void) const u32 em_rst = ~X86_CR0_EM; const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE;
/* initialize FPU, reset EM, set MP and NE */
asm ("fninit\n" \
"movl %%cr0, %%eax\n" \
"andl %0, %%eax\n" \
"orl %1, %%eax\n" \
"movl %%eax, %%cr0\n" \
: : "i" (em_rst), "i" (mp_ne_set) : "eax");
if (ll_boot_init()) {
/* initialize FPU, reset EM, set MP and NE */
asm ("fninit\n" \
"movl %%cr0, %%eax\n" \
"andl %0, %%eax\n" \
"orl %1, %%eax\n" \
"movl %%eax, %%cr0\n" \
: : "i" (em_rst), "i" (mp_ne_set) : "eax");
} /* identify CPU via cpuid and store the decoded info into gd->arch */ if (has_cpuid()) {
@@ -712,5 +714,8 @@ __weak int x86_init_cpus(void)
int cpu_init_r(void) {
return x86_init_cpus();
if (ll_boot_init())
return x86_init_cpus();
return 0;
} diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index a112938..9217307 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -258,8 +258,14 @@ int interrupt_init(void) /* Initialize core interrupt and exception functionality of CPU */ cpu_init_interrupts();
/* It is now safe to enable interrupts */
enable_interrupts();
/*
* It is now safe to enable interrupts.
*
* TODO(sjg@chromium.org): But we don't handle these correctly when
* booted from EFI.
*/
if (ll_boot_init())
enable_interrupts();
#endif
return 0;
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 445ee6e..f441c84 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -164,7 +164,11 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * the data segments are 0x18, 4GB flat, and read/write. * U-boot is setting them up that way for itself in * arch/i386/cpu/cpu.c.
*
* Note that we cannot currently boot a kernel while running as
* an EFI application. Please use the payload option for that. */
+#ifndef CONFIG_EFI_APP __asm__ __volatile__ ( "movl $0, %%ebp\n" "cli\n" @@ -173,6 +177,7 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) [boot_params] "S"(setup_base), "b"(0), "D"(0) ); +#endif }
/* We can't get to here */
diff --git a/arch/x86/lib/efi/Kconfig b/arch/x86/lib/efi/Kconfig new file mode 100644 index 0000000..e0975d3 --- /dev/null +++ b/arch/x86/lib/efi/Kconfig @@ -0,0 +1,11 @@ +if EFI
+config SYS_CAR_ADDR
hex
default 0x100000
+config SYS_CAR_SIZE
hex
default 0x20000
+endif
Reviewed-by: Bin Meng bmeng.cn@gmail.com

When U-Boot is running from EFI some of the x86 init is replaced with EFI-specific init. For example, since DRAM has already been set up, we only need to find it, not init it. Add these functions so that boards can easily allow booting from EFI if required.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Drop unnecessary .section .text
arch/x86/lib/Makefile | 1 + arch/x86/lib/efi/Makefile | 3 + arch/x86/lib/efi/car.S | 10 +++ arch/x86/lib/efi/efi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 arch/x86/lib/efi/car.S create mode 100644 arch/x86/lib/efi/efi.c
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 09c236b..dcfe9ee 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -11,6 +11,7 @@ obj-y += bios_interrupts.o obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-y += cmd_boot.o obj-$(CONFIG_HAVE_FSP) += cmd_hob.o +obj-$(CONFIG_EFI) += efi/ obj-y += gcc.o obj-y += init_helpers.o obj-y += interrupts.o diff --git a/arch/x86/lib/efi/Makefile b/arch/x86/lib/efi/Makefile index 41295d9..88d6e58 100644 --- a/arch/x86/lib/efi/Makefile +++ b/arch/x86/lib/efi/Makefile @@ -5,6 +5,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
+obj-$(CONFIG_EFI_STUB) += car.o +obj-$(CONFIG_EFI_STUB) += efi.o + obj-$(CONFIG_EFI_APP) += crt0-efi-ia32.o reloc_ia32.o
ifneq ($(CONFIG_EFI_STUB),) diff --git a/arch/x86/lib/efi/car.S b/arch/x86/lib/efi/car.S new file mode 100644 index 0000000..613af9a --- /dev/null +++ b/arch/x86/lib/efi/car.S @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +.globl car_init +car_init: + jmp car_init_ret diff --git a/arch/x86/lib/efi/efi.c b/arch/x86/lib/efi/efi.c new file mode 100644 index 0000000..ede5d56 --- /dev/null +++ b/arch/x86/lib/efi/efi.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <debug_uart.h> +#include <efi.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/types.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * This function looks for the highest region of memory lower than 4GB which + * has enough space for U-Boot where U-Boot is aligned on a page boundary. + * It overrides the default implementation found elsewhere which simply + * picks the end of ram, wherever that may be. The location of the stack, + * the relocation address, and how far U-Boot is moved by relocation are + * set in the global data structure. + */ +ulong board_get_usable_ram_top(ulong total_size) +{ + struct efi_mem_desc *desc, *end; + struct efi_entry_memmap *map; + int ret, size; + uintptr_t dest_addr = 0; + struct efi_mem_desc *largest = NULL; + + /* + * Find largest area of memory below 4GB. We could + * call efi_build_mem_table() for a more accurate picture since it + * merges areas together where possible. But that function uses more + * pre-relocation memory, and it's not critical that we find the + * absolute largest region. + */ + ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); + if (ret) { + /* We should have stopped in dram_init(), something is wrong */ + debug("%s: Missing memory map\n", __func__); + goto err; + } + + end = (struct efi_mem_desc *)((ulong)map + size); + desc = map->desc; + for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + if (desc->type != EFI_CONVENTIONAL_MEMORY || + desc->physical_start >= 1ULL << 32) + continue; + if (!largest || desc->num_pages > largest->num_pages) + largest = desc; + } + + /* If no suitable area was found, return an error. */ + assert(largest); + if (!largest || (largest->num_pages << EFI_PAGE_SHIFT) < (2 << 20)) + goto err; + + dest_addr = largest->physical_start + (largest->num_pages << + EFI_PAGE_SHIFT); + + return (ulong)dest_addr; +err: + panic("No available memory found for relocation"); + return 0; +} + +int dram_init(void) +{ + struct efi_mem_desc *desc, *end; + struct efi_entry_memmap *map; + int size, ret; + + ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); + if (ret) { + printf("Cannot find EFI memory map tables, ret=%d\n", ret); + + return -ENODEV; + } + + end = (struct efi_mem_desc *)((ulong)map + size); + gd->ram_size = 0; + desc = map->desc; + for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + if (desc->type < EFI_MMAP_IO) + gd->ram_size += desc->num_pages << EFI_PAGE_SHIFT; + } + + return 0; +} + +void dram_init_banksize(void) +{ + struct efi_mem_desc *desc, *end; + struct efi_entry_memmap *map; + int ret, size; + int num_banks; + + ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); + if (ret) { + /* We should have stopped in dram_init(), something is wrong */ + debug("%s: Missing memory map\n", __func__); + return; + } + end = (struct efi_mem_desc *)((ulong)map + size); + desc = map->desc; + for (num_banks = 0; + desc < end && num_banks < CONFIG_NR_DRAM_BANKS; + desc = efi_get_next_mem_desc(map, desc)) { + /* + * We only use conventional memory below 4GB, and ignore + * anything less than 1MB. + */ + if (desc->type != EFI_CONVENTIONAL_MEMORY || + desc->physical_start >= 1ULL << 32 || + (desc->num_pages << EFI_PAGE_SHIFT) < 1 << 20) + continue; + gd->bd->bi_dram[num_banks].start = desc->physical_start; + gd->bd->bi_dram[num_banks].size = desc->num_pages << + EFI_PAGE_SHIFT; + num_banks++; + } +} + +int print_cpuinfo(void) +{ + return default_print_cpuinfo(); +} + +/* Find any available tables and copy them to a safe place */ +int reserve_arch(void) +{ + struct efi_info_hdr *hdr; + + debug("table=%lx\n", gd->arch.table); + if (!gd->arch.table) + return 0; + + hdr = (struct efi_info_hdr *)gd->arch.table; + + gd->start_addr_sp -= hdr->total_size; + memcpy((void *)gd->start_addr_sp, hdr, hdr->total_size); + debug("Stashing EFI table at %lx to %lx, size %x\n", + gd->arch.table, gd->start_addr_sp, hdr->total_size); + gd->arch.table = gd->start_addr_sp; + + return 0; +}

Disable a few things which interfere with the EFI init. This allows the Minnowboard MAX to boot into EFI, load a U-Boot payload then boot to the U-Boot prompt.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Fix indenting in board/intel/minnowmax/Kconfig - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP
arch/x86/cpu/baytrail/Kconfig | 2 +- arch/x86/cpu/baytrail/cpu.c | 2 ++ arch/x86/cpu/baytrail/valleyview.c | 2 ++ board/intel/minnowmax/Kconfig | 5 +++-- 4 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/arch/x86/cpu/baytrail/Kconfig b/arch/x86/cpu/baytrail/Kconfig index e86cc01..407feb2 100644 --- a/arch/x86/cpu/baytrail/Kconfig +++ b/arch/x86/cpu/baytrail/Kconfig @@ -6,4 +6,4 @@
config INTEL_BAYTRAIL bool - select HAVE_FSP + select HAVE_FSP if !EFI diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c index a011730..b1faf8c 100644 --- a/arch/x86/cpu/baytrail/cpu.c +++ b/arch/x86/cpu/baytrail/cpu.c @@ -45,6 +45,8 @@ static void set_max_freq(void)
static int cpu_x86_baytrail_probe(struct udevice *dev) { + if (!ll_boot_init()) + return 0; debug("Init BayTrail core\n");
/* diff --git a/arch/x86/cpu/baytrail/valleyview.c b/arch/x86/cpu/baytrail/valleyview.c index 9915da5..e0652ba 100644 --- a/arch/x86/cpu/baytrail/valleyview.c +++ b/arch/x86/cpu/baytrail/valleyview.c @@ -20,6 +20,7 @@ int cpu_mmc_init(bd_t *bis) ARRAY_SIZE(mmc_supported)); }
+#ifndef CONFIG_EFI_APP int arch_cpu_init(void) { int ret; @@ -35,3 +36,4 @@ int arch_cpu_init(void)
return 0; } +#endif diff --git a/board/intel/minnowmax/Kconfig b/board/intel/minnowmax/Kconfig index f2a0b71..7e975f9 100644 --- a/board/intel/minnowmax/Kconfig +++ b/board/intel/minnowmax/Kconfig @@ -13,11 +13,12 @@ config SYS_CONFIG_NAME default "minnowmax"
config SYS_TEXT_BASE - default 0xfff00000 + default 0xfff00000 if !EFI_STUB + default 0x01110000 if EFI_STUB
config BOARD_SPECIFIC_OPTIONS # dummy def_bool y - select X86_RESET_VECTOR + select X86_RESET_VECTOR if !EFI_STUB select INTEL_BAYTRAIL select BOARD_ROMSIZE_KB_8192

Disable a few things which interfere with the EFI init. This allows QEMU to to boot into EFI, load a U-Boot payload then boot to the U-Boot prompt.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Fix indenting in board/emulation/qemu-x86/Kconfig
arch/x86/cpu/qemu/Makefile | 5 ++++- arch/x86/cpu/qemu/qemu.c | 2 ++ board/emulation/qemu-x86/Kconfig | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index be79723..9a66b16 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -4,5 +4,8 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += car.o dram.o qemu.o +ifndef CONFIG_EFI_STUB +obj-y += car.o dram.o +endif +obj-y += qemu.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 930d2b6..64634a9 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -25,11 +25,13 @@ int arch_cpu_init(void) return 0; }
+#ifndef CONFIG_EFI_STUB int print_cpuinfo(void) { post_code(POST_CPU_INFO); return default_print_cpuinfo(); } +#endif
void reset_cpu(ulong addr) { diff --git a/board/emulation/qemu-x86/Kconfig b/board/emulation/qemu-x86/Kconfig index e777ef4..c9181fc 100644 --- a/board/emulation/qemu-x86/Kconfig +++ b/board/emulation/qemu-x86/Kconfig @@ -13,11 +13,12 @@ config SYS_CONFIG_NAME default "qemu-x86"
config SYS_TEXT_BASE - default 0xfff00000 + default 0xfff00000 if !EFI_STUB + default 0x01110000 if EFI_STUB
config BOARD_SPECIFIC_OPTIONS # dummy def_bool y - select X86_RESET_VECTOR + select X86_RESET_VECTOR if !EFI_STUB select QEMU select BOARD_ROMSIZE_KB_1024

We cannot use this driver when running from EFI as we have no direct hardware access. In fact coreboot uses a different driver which uses tables provided by coreboot. So far it does not seem possible to use a normal video driver when booting from EFI.
Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Anatolij Gustschin agust@denx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Replace 'Coreboot' with 'coreboot'
drivers/video/vesa_fb.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/video/vesa_fb.c b/drivers/video/vesa_fb.c index 909f8e8..4e6d070 100644 --- a/drivers/video/vesa_fb.c +++ b/drivers/video/vesa_fb.c @@ -24,6 +24,14 @@ void *video_hw_init(void) int ret;
printf("Video: "); + if (!ll_boot_init()) { + /* + * If we are running from EFI or coreboot, this driver can't + * work. + */ + printf("Not available (previous bootloader prevents it)\n"); + return NULL; + } if (vbe_get_video_info(gdev)) { dev = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, 0); if (dev == -1) {

Add some documentation on the EFI implementation in U-Boot.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: - Drop patch "Add a link script entry for U-Boot as a payload" - Replace 'Coreboot' with 'coreboot' - Use CONFIG_EFI_APP instead of CONFIG_ARCH_EFI - Use u-boot-app.efi instead of u-boot.efi
doc/README.efi | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 doc/README.efi
diff --git a/doc/README.efi b/doc/README.efi new file mode 100644 index 0000000..7c95579 --- /dev/null +++ b/doc/README.efi @@ -0,0 +1,237 @@ +# +# Copyright (C) 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +U-Boot on EFI +============= +This document provides information about U-Boot running on top of EFI, either +as an application or just as a means of getting U-Boot onto a new platform. + + +In God's Name, Why? +------------------- +This is useful in several situations: + +- You have EFI running on a board but U-Boot does not natively support it +fully yet. You can boot into U-Boot from EFI and use that until U-Boot is +fully ported + +- You need to use an EFI implementation (e.g. UEFI) because your vendor +requires it in order to provide support + +- You plan to use coreboot to boot into U-Boot but coreboot support does +not currently exist for your platform. In the meantime you can use U-Boot +on EFI and then move to U-Boot on coreboot when ready + +- You use EFI but want to experiment with a simpler alternative like U-Boot + + +Status +------ +Only x86 is supported at present. If you are using EFI on another architecture +you may want to reconsider. However, much of the code is generic so could be +ported. + +U-Boot supports running as an EFI application for 32-bit EFI only. This is +not very useful since only a serial port is provided. You can look around at +memory and type 'help' but that is about it. + +More usefully, U-Boot supports building itself as a payload for either 32-bit +or 64-bit EFI. U-Boot is packaged up and loaded in its entirety by EFI. Once +started, U-Boot changes to 32-bit mode (currently) and takes over the +machine. You can use devices, boot a kernel, etc. + + +Build Instructions +------------------ +First choose a board that has EFI support and obtain an EFI implementation +for that board. It will be either 32-bit or 64-bit. + +To build U-Boot as an EFI application (32-bit EFI required), enable +CONFIG_EFI and CONFIG_EFI_APP. The efi-x86 config is set up for this. + +To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), adjust +an existing config to enable CONFIG_EFI, CONFIG_EFI_STUB and either +CONFIG_EFI_STUB_32BIT or CONFIG_EFI_STUB_64BIT. + +Then build U-Boot as normal, e.g. + + make qemu-x86_defconfig + make menuconfig (or make xconfig if you prefer) + # change the settings as above + make + +You will end up with one of these files: + + u-boot-app.efi - U-Boot EFI application + u-boot-payload.efi - U-Boot EFI payload application + + +Trying it out +------------- +Qemu is an emulator and it can emulate an x86 machine. You can run the +payload with something like this: + + mkdir /tmp/efi + cp /path/to/u-boot*.efi /tmp/efi + qemu-system-x86_64 -bios bios.bin -hda fat:/tmp/efi/ + +Add -nographic if you want to use the terminal for output. Once it starts +type 'fs0:u-boot-payload.efi' to run the payload or 'fs0:u-boot-app.efi' to +run the application. 'bios.bin' is the EFI 'BIOS'. + +To try it on real hardware, put u-boot-app.efi on a suitable boot medium, +such as a USB stick. Then you can type something like this to start it: + + fs0:u-boot-payload.efi + +(or fs0:u-boot-app.efi for the application) + +This will start the payload, copy U-Boot into RAM and start U-Boot. Note +that EFI does not support booting a 64-bit application from a 32-bit +EFI (or vice versa). Also it will often fail to print an error message if +you get this wrong. + + +Inner workings +============== +Here follow a few implementation notes for those who want to fiddle with +this and perhaps contribute patches. + +The application and payload approaches sound similar but are in fact +implemented completely differently. + +EFI Application +--------------- +For the application the whole of U-Boot is built as a shared library. The +efi_main() function is in lib/efi/efi_app.c. It sets up some basic EFI +functions with efi_init(), sets up U-Boot global_data, allocates memory for +U-Boot's malloc(), etc. and enters the normal init sequence (board_init_f() +and board_init_r()). + +Since U-Boot limits its memory access to the allocated regions very little +special code is needed. The CONFIG_EFI_APP option controls a few things +that need to change so 'git grep CONFIG_EFI_APP' may be instructive. +The CONFIG_EFI option controls more general EFI adjustments. + +The only available driver is the serial driver. This calls back into EFI +'boot services' to send and receive characters. Although it is implemented +as a serial driver the console device is not necessarilly serial. If you +boot EFI with video output then the 'serial' device will operate on your +target devices's display instead and the device's USB keyboard will also +work if connected. If you have both serial and video output, then both +consoles will be active. Even though U-Boot does the same thing normally, +These are features of EFI, not U-Boot. + +Very little code is involved in implementing the EFI application feature. +U-Boot is highly portable. Most of the difficulty is in modifying the +Makefile settings to pass the right build flags. In particular there is very +little x86-specific code involved - you can find most of it in +arch/x86/cpu. Porting to ARM (which can also use EFI if you are brave +enough) should be straightforward. + +Use the 'reset' command to get back to EFI. + +EFI Payload +----------- +The payload approach is a different kettle of fish. It works by building +U-Boot exactly as normal for your target board, then adding the entire +image (including device tree) into a small EFI stub application responsible +for booting it. The stub application is built as a normal EFI application +except that it has a lot of data attached to it. + +The stub application is implemented in lib/efi/efi_stub.c. The efi_main() +function is called by EFI. It is responsible for copying U-Boot from its +original location into memory, disabling EFI boot services and starting +U-Boot. U-Boot then starts as normal, relocates, starts all drivers, etc. + +The stub application is architecture-dependent. At present it has some +x86-specific code and a comment at the top of efi_stub.c describes this. + +While the stub application does allocate some memory from EFI this is not +used by U-Boot (the payload). In fact when U-Boot starts it has all of the +memory available to it and can operate as it pleases (but see the next +section). + +Tables +------ +The payload can pass information to U-Boot in the form of EFI tables. At +present this feature is used to pass the EFI memory map, an inordinately +large list of memory regions. You can use the 'efi mem all' command to +display this list. U-Boot uses the list to work out where to relocate +itself. + +Although U-Boot can use any memory it likes, EFI marks some memory as used +by 'run-time services', code that hangs around while U-Boot is running and +is even present when Linux is running. This is common on x86 and provides +a way for Linux to call back into the firmware to control things like CPU +fan speed. U-Boot uses only 'conventional' memory, in EFI terminology. It +will relocate itself to the top of the largest block of memory it can find +below 4GB. + +Interrupts +---------- +U-Boot drivers typically don't use interrupts. Since EFI enables interrupts +it is possible that an interrupt will fire that U-Boot cannot handle. This +seems to cause problems. For this reason the U-Boot payload runs with +interrupts disabled at present. + +32/64-bit +--------- +While the EFI application can in principle be built as either 32- or 64-bit, +only 32-bit is currently supported. This means that the application can only +be used with 32-bit EFI. + +The payload stub can be build as either 32- or 64-bits. Only a small amount +of code is built this way (see the extra- line in lib/efi/Makefile). +Everything else is built as a normal U-Boot, so is always 32-bit on x86 at +present. + +Future work +----------- +This work could be extended in a number of ways: + +- Add a generic x86 EFI payload configuration. At present you need to modify +an existing one, but mostly the low-level x86 code is disabled when booting +on EFI anyway, so a generic 'EFI' board could be created with a suitable set +of drivers enabled. + +- Add ARM support + +- Add 64-bit application support + +- Figure out how to solve the interrupt problem + +- Add more drivers to the application side (e.g. video, block devices, USB, +environment access). This would mostly be an academic exercise as a strong +use case is not readily apparent, but it might be fun. + +- Avoid turning off boot services in the stub. Instead allow U-Boot to make +use of boot services in case it wants to. It is unclear what it might want +though. + +Where is the code? +------------------ +lib/efi + payload stub, application, support code. Mostly arch-neutral + +arch/x86/lib/efi + helper functions for the fake DRAM init, etc. These can be used by + any board that runs as a payload. + +arch/x86/cpu/efi + x86 support code for running as an EFI application + +board/efi/efi-x86/efi.c + x86 board code for running as an EFI application + +common/cmd_efi.c + the 'efi' command + + +-- +Ben Stoltz, Simon Glass +Google, Inc +July 2015

Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This series allows U-Boot to be build as an EFI payload so that U-Boot can be started on almost any x86 platform that supports EFI. This is implemented as a stub which EFI can load plus a payload that is copied to RAM. The payload contains a normal U-Boot binary image and device tree.
This allows U-Boot to run on platforms that have EFI support but are not supported natively by U-Boot. It also allows testing and fiddling with the board using U-Boots memory display and other commands.
In addition, U-Boot can be built as an EFI application. This should work regardless of the board type since it only relies on EFI services. However only 32-bit EFI is supported in this case. Again it can be used to snoop around the platform.
A README provides further details of how this series operates.
I've finished the review for the v2 series. Testing shows that EFI application and EFI 64-bit stub works, but EFI 32-bit stub does not.
There are two issues for 32-bit EFI stub. 1). the build issue in jump_to_uboot() in lib/efi/efi_stub.c 2). After fixing the build issue, the 32-bit EFI stub still does not boot. It reports error below.
U-Boot 2015.07-00476-g8771bcb-dirty (Aug 04 2015 - 08:07:09 +0000)
CPU: x86, vendor Intel, device 663h DRAM: Cannot find EFI memory map tables, ret=-93 initcall sequence 0115e954 failed at call 011126fd (err=-19) ### ERROR ### Please RESET the board ###
Regards, Bin

Hi Bin,
On 4 August 2015 at 02:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This series allows U-Boot to be build as an EFI payload so that U-Boot can be started on almost any x86 platform that supports EFI. This is implemented as a stub which EFI can load plus a payload that is copied to RAM. The payload contains a normal U-Boot binary image and device tree.
This allows U-Boot to run on platforms that have EFI support but are not supported natively by U-Boot. It also allows testing and fiddling with the board using U-Boots memory display and other commands.
In addition, U-Boot can be built as an EFI application. This should work regardless of the board type since it only relies on EFI services. However only 32-bit EFI is supported in this case. Again it can be used to snoop around the platform.
A README provides further details of how this series operates.
I've finished the review for the v2 series. Testing shows that EFI application and EFI 64-bit stub works, but EFI 32-bit stub does not.
There are two issues for 32-bit EFI stub. 1). the build issue in jump_to_uboot() in lib/efi/efi_stub.c 2). After fixing the build issue, the 32-bit EFI stub still does not boot. It reports error below.
U-Boot 2015.07-00476-g8771bcb-dirty (Aug 04 2015 - 08:07:09 +0000)
CPU: x86, vendor Intel, device 663h DRAM: Cannot find EFI memory map tables, ret=-93 initcall sequence 0115e954 failed at call 011126fd (err=-19) ### ERROR ### Please RESET the board ###
Do you have any additional patches?
I tested this before sending the series. It works here for me. Did you use u-boot-x86/efi-working?
I've just pushed my tree to u-boot-x86/efi-working again. Unfortunately this has a few v3 changes but there are not too many yet.
Regards, Simon

Hi Bin,
On 4 August 2015 at 06:54, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 4 August 2015 at 02:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This series allows U-Boot to be build as an EFI payload so that U-Boot can be started on almost any x86 platform that supports EFI. This is implemented as a stub which EFI can load plus a payload that is copied to RAM. The payload contains a normal U-Boot binary image and device tree.
This allows U-Boot to run on platforms that have EFI support but are not supported natively by U-Boot. It also allows testing and fiddling with the board using U-Boots memory display and other commands.
In addition, U-Boot can be built as an EFI application. This should work regardless of the board type since it only relies on EFI services. However only 32-bit EFI is supported in this case. Again it can be used to snoop around the platform.
A README provides further details of how this series operates.
I've finished the review for the v2 series. Testing shows that EFI application and EFI 64-bit stub works, but EFI 32-bit stub does not.
There are two issues for 32-bit EFI stub. 1). the build issue in jump_to_uboot() in lib/efi/efi_stub.c 2). After fixing the build issue, the 32-bit EFI stub still does not boot. It reports error below.
U-Boot 2015.07-00476-g8771bcb-dirty (Aug 04 2015 - 08:07:09 +0000)
CPU: x86, vendor Intel, device 663h DRAM: Cannot find EFI memory map tables, ret=-93 initcall sequence 0115e954 failed at call 011126fd (err=-19) ### ERROR ### Please RESET the board ###
Do you have any additional patches?
I tested this before sending the series. It works here for me. Did you use u-boot-x86/efi-working?
I've just pushed my tree to u-boot-x86/efi-working again. Unfortunately this has a few v3 changes but there are not too many yet.
Sorry, I see it. I was testing 64-bit. I'll take another look.
Regards, Simon

Hi Bin,
On 4 August 2015 at 07:45, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 4 August 2015 at 06:54, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 4 August 2015 at 02:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass sjg@chromium.org wrote:
This series allows U-Boot to be build as an EFI payload so that U-Boot can be started on almost any x86 platform that supports EFI. This is implemented as a stub which EFI can load plus a payload that is copied to RAM. The payload contains a normal U-Boot binary image and device tree.
This allows U-Boot to run on platforms that have EFI support but are not supported natively by U-Boot. It also allows testing and fiddling with the board using U-Boots memory display and other commands.
In addition, U-Boot can be built as an EFI application. This should work regardless of the board type since it only relies on EFI services. However only 32-bit EFI is supported in this case. Again it can be used to snoop around the platform.
A README provides further details of how this series operates.
I've finished the review for the v2 series. Testing shows that EFI application and EFI 64-bit stub works, but EFI 32-bit stub does not.
There are two issues for 32-bit EFI stub. 1). the build issue in jump_to_uboot() in lib/efi/efi_stub.c 2). After fixing the build issue, the 32-bit EFI stub still does not boot. It reports error below.
U-Boot 2015.07-00476-g8771bcb-dirty (Aug 04 2015 - 08:07:09 +0000)
CPU: x86, vendor Intel, device 663h DRAM: Cannot find EFI memory map tables, ret=-93 initcall sequence 0115e954 failed at call 011126fd (err=-19) ### ERROR ### Please RESET the board ###
Do you have any additional patches?
I tested this before sending the series. It works here for me. Did you use u-boot-x86/efi-working?
I've just pushed my tree to u-boot-x86/efi-working again. Unfortunately this has a few v3 changes but there are not too many yet.
Sorry, I see it. I was testing 64-bit. I'll take another look.
It's a calling convention problem and it turns out I did not test the 32-bit payload after I added the EFI table. Thanks for picking this up!
Regards, Simon
participants (3)
-
Bin Meng
-
Simon Glass
-
Tom Rini