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

This series allows U-Boot to be built 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.
Ben Stoltz (6): efi: Avoid using non-existent text base efi: Drop CONFIG_SYS_TEXT_BASE for EFI x86: Add support for U-Boot as an EFI application x86: Add EFI board code x86: Set up tool chain flags for running as EFI application x86: Add definitions for the x86-efi board and plumb it in
Simon Glass (42): 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 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 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 use of global_data with EFI x86: Allow relocation code to build without text base x86: Add a link script entry for U-Boot as a payload 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 Makefile settings for EFI build 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 | 45 ++++- arch/x86/Kconfig | 20 ++ arch/x86/Makefile | 2 + arch/x86/config.mk | 46 ++++- 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 | 65 +++++++ arch/x86/cpu/call64.S | 4 +- arch/x86/cpu/cpu.c | 23 ++- arch/x86/cpu/efi/Makefile | 8 + arch/x86/cpu/efi/efi.c | 49 +++++ arch/x86/cpu/efi/elf_ia32_efi.lds | 95 +++++++++ arch/x86/cpu/efi/elf_x86_64_efi.lds | 87 +++++++++ arch/x86/cpu/efi/sdram.c | 29 +++ arch/x86/cpu/interrupts.c | 21 +- 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 | 55 ++++-- 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 | 19 ++ arch/x86/include/asm/elf.h | 50 +++++ 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 | 23 ++- arch/x86/lib/asm-offsets.c | 1 + arch/x86/lib/bootm.c | 4 + arch/x86/lib/crt0-efi-ia32.S | 77 ++++++++ arch/x86/lib/crt0-efi-x86_64.S | 77 ++++++++ arch/x86/lib/efi/Makefile | 9 + arch/x86/lib/efi/car.S | 12 ++ arch/x86/lib/efi/efi.c | 151 +++++++++++++++ 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/reloc_ia32.c | 96 ++++++++++ arch/x86/lib/reloc_x86_64.c | 90 +++++++++ arch/x86/lib/relocate.c | 43 ++--- board/efi/Kconfig | 19 ++ board/efi/efi-x86/Kconfig | 27 +++ 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 | 258 +++++++++++++++++++++++++ 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 | 8 + drivers/serial/Makefile | 1 + drivers/serial/serial-uclass.c | 2 +- drivers/serial/serial_efi.c | 149 +++++++++++++++ drivers/video/vesa_fb.c | 8 + include/asm-generic/global_data.h | 1 + include/common.h | 7 + include/configs/efi-x86.h | 37 ++++ include/efi.h | 360 +++++++++++++++++++++++++++++++++++ include/efi_api.h | 252 ++++++++++++++++++++++++ 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 | 91 +++++++++ lib/efi/efi_app.c | 125 ++++++++++++ lib/efi/efi_info.c | 47 +++++ lib/efi/efi_stub.c | 341 +++++++++++++++++++++++++++++++++ lib/initcall.c | 4 + scripts/Makefile.build | 8 + scripts/Makefile.lib | 3 +- 85 files changed, 3395 insertions(+), 179 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/crt0-efi-ia32.S create mode 100644 arch/x86/lib/crt0-efi-x86_64.S create mode 100644 arch/x86/lib/efi/Makefile create mode 100644 arch/x86/lib/efi/car.S create mode 100644 arch/x86/lib/efi/efi.c create mode 100644 arch/x86/lib/reloc_ia32.c create mode 100644 arch/x86/lib/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 ---
scripts/Makefile.lib | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 8731fc6..3d5c872 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 Wed, Jul 22, 2015 at 11:48 PM, Simon Glass sjg@chromium.org 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
scripts/Makefile.lib | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 8731fc6..3d5c872 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))
#
Reviewed-by: Bin Meng bmeng.cn@gmail.com

This function needs to check the list has entries before traversing it. Fix this bug.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/uclass.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 7de8173..a930c30 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 0;
list_for_each_entry(dev, &uc->dev_head, uclass_node) { if (!index--) {

On Wed, Jul 22, 2015 at 11:48 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
drivers/core/uclass.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 7de8173..a930c30 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 0; list_for_each_entry(dev, &uc->dev_head, uclass_node) { if (!index--) {
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

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 ---
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 Wed, Jul 22, 2015 at 11:48 PM, 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
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; }
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Provide the types necessary to relocate 64-bit images.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/elf.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/include/elf.h b/include/elf.h index 63d9341..1936ef6 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 __u64 Elf64_Addr; +typedef __u16 Elf64_Half; +typedef __s16 Elf64_SHalf; +typedef __u64 Elf64_Off; +typedef __s32 Elf64_Sword; +typedef __u32 Elf64_Word; +typedef __u64 Elf64_Xword; +typedef __s64 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;
+struct elf64_rel { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +}; + /* 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 */

Hi Simon,
On Wed, Jul 22, 2015 at 11:48 PM, Simon Glass sjg@chromium.org wrote:
Provide the types necessary to relocate 64-bit images.
Signed-off-by: Simon Glass sjg@chromium.org
include/elf.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/include/elf.h b/include/elf.h index 63d9341..1936ef6 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 __u64 Elf64_Addr; +typedef __u16 Elf64_Half; +typedef __s16 Elf64_SHalf; +typedef __u64 Elf64_Off; +typedef __s32 Elf64_Sword; +typedef __u32 Elf64_Word; +typedef __u64 Elf64_Xword; +typedef __s64 Elf64_Sxword;
Can we use uint64_t, uint32_t, uint16_t etc. to define these? To keep consistent wit the Elf32_xxx types.
/* 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;
+struct elf64_rel {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
+};
Again, to be consistent with the elf32 one, can we use?
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 */
Regards, Bin

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 ---
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 db0550b..086ee96 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -116,5 +116,6 @@ typedef struct global_data { #define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */ #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_SKIP_RELOC 0x00400 /* Don't relocate */
#endif /* __ASM_GENERIC_GBL_DATA_H */

Hi Simon,
On Wed, Jul 22, 2015 at 11:48 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
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 db0550b..086ee96 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -116,5 +116,6 @@ typedef struct global_data { #define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */ #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_SKIP_RELOC 0x00400 /* Don't relocate */
#endif /* __ASM_GENERIC_GBL_DATA_H */
What about reloc_fdt() and do_elf_reloc_fixups()?
Regards, Bin

Hi Bin,
On 22 July 2015 at 21:41, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:48 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
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 db0550b..086ee96 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -116,5 +116,6 @@ typedef struct global_data { #define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */ #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_SKIP_RELOC 0x00400 /* Don't relocate */
#endif /* __ASM_GENERIC_GBL_DATA_H */
What about reloc_fdt() and do_elf_reloc_fixups()?
I'll add the first one. The second one is not called and I have a patch to remove it.
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 ---
Makefile | 8 +++++++- config.mk | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile index b6f83a5..e0218b3 100644 --- a/Makefile +++ b/Makefile @@ -778,8 +778,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 Wed, Jul 22, 2015 at 11:48 PM, 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
Makefile | 8 +++++++- config.mk | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile index b6f83a5..e0218b3 100644 --- a/Makefile +++ b/Makefile @@ -778,8 +778,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
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

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 ---
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..255967f 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 {

Hi Simon,
On Wed, Jul 22, 2015 at 11:48 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
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..255967f 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)
The above two should be __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 {
Regards, Bin

Fix a typo, improve some comments and add a little more detail in some cases.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 Wed, Jul 22, 2015 at 11:49 PM, 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
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 */
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

We should use these constants where possible.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
We should use these constants where possible.
Signed-off-by: Simon Glass sjg@chromium.org
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 */
Reviewed-by: Bin Meng bmeng.cn@gmail.com

These flags now overlap some global ones. Adjust the x86-specific flags to avoid this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/global_data.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4d9eac6..abd70b9 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 0x1000 /* Cold Boot */ +#define GD_FLG_WARM_BOOT 0x2000 /* Warm Boot */
#endif /* __ASM_GBL_DATA_H */

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
These flags now overlap some global ones. Adjust the x86-specific flags to avoid this.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/global_data.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4d9eac6..abd70b9 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 0x1000 /* Cold Boot */ +#define GD_FLG_WARM_BOOT 0x2000 /* Warm Boot */
To avoid future conflicts, can we define flags high 16-bits as architecture-specific flags while leaving low 16-bits as the generic ones?
#endif /* __ASM_GBL_DATA_H */
Regards, Bin

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 ---
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 Wed, Jul 22, 2015 at 11:49 PM, 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
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; --
Reviewed-by: Bin Meng bmeng.cn@gmail.com

The GDT works but technically the length is incorrect. Fix this and add a comment.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 Wed, Jul 22, 2015 at 11:49 PM, 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
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 */
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Some files use global_data but don't declare it. Fix this.
Signed-off-by: Simon Glass sjg@chromium.org ---
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 Wed, Jul 22, 2015 at 11:49 PM, 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
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 {
Reviewed-by: Bin Meng bmeng.cn@gmail.com

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 ---
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 Wed, Jul 22, 2015 at 11:49 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
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

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 ---
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 Wed 2015-07-22 09:49:07, Simon Glass 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

On Wed, Jul 22, 2015 at 11:49 PM, 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
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,
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

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 ---
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,

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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.
It looks like CONFIG_PCI_ENUM_ONLY does similar things as CONFIG_PCI_PNP. Can we just use CONFIG_PCI_PNP?
Signed-off-by: Simon Glass sjg@chromium.org
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,
--
Regards, Bin

Hi Bin,
On 23 July 2015 at 00:46, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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.
It looks like CONFIG_PCI_ENUM_ONLY does similar things as CONFIG_PCI_PNP. Can we just use CONFIG_PCI_PNP?
My understanding is that:
- CONFIG_PCI_PNP enables auto-configuration of devices - CONFIG_PCI_ENUM_ONLY changes the auto-config code to just scan and print out what is there, not change it
So I believe both are useful, even if the current code structure could be improved...
Signed-off-by: Simon Glass sjg@chromium.org
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,
--
Regards, Bin
Regards, Simon

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 ---
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..ad5500f 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_ARCH_EFI) 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_ARCH_EFI) 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_ARCH_EFI) /* NOTREACHED - jump_to_copy() does not return */ hang(); #endif

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
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..ad5500f 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_ARCH_EFI)
I think this patch should come after CONFIG_ARCH_EFI is introduced. And per your commit message, I think here CONFIG_ARCH_EFI means EFI application. ARCH_xxx is confusing. Can we use the name 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_ARCH_EFI) 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_ARCH_EFI) /* NOTREACHED - jump_to_copy() does not return */ hang();
#endif
Regards, Bin

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 ---
arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- include/efi.h | 356 +++++++++++++++++++++++++++++++++++++ include/efi_api.h | 252 ++++++++++++++++++++++++++ include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 33 ++++ lib/efi/Makefile | 7 + lib/efi/efi.c | 91 ++++++++++ lib/efi/efi_app.c | 125 +++++++++++++ 10 files changed, 871 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..66ef6c3 --- /dev/null +++ b/include/efi.h @@ -0,0 +1,356 @@ +/* + * 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> + +#ifdef CONFIG_EFI_STUB_64BIT +#define EFIAPI __attribute__((ms_abi)) +#else +#define EFIAPI +#endif + +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, + + 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 + */ +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 + * @ + */ +struct efi_entry_hdr { + u32 type; + u32 size; + u64 addr; + u32 link; + u32 spare1; + u64 spare22; +}; + +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 ImageBase[]; + +/** + * 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 know 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 resuilt + * @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 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 ASCII, 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..d4528f6 --- /dev/null +++ b/include/efi_api.h @@ -0,0 +1,252 @@ +/* + * 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 ((u64)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 CHAR16 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 __packed 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 c98d399..4c8d38e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -96,4 +96,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 97ed398..4821779 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..2b3dbd4 --- /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 ARCH_EFI + bool "Support running U-Boot from EFI" + 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 problem 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 ARCH_EFI + 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 withU-Boot. + +endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile new file mode 100644 index 0000000..137d2f9 --- /dev/null +++ b/lib/efi/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_ARCH_EFI) += efi_app.o efi.o diff --git a/lib/efi/efi.c b/lib/efi/efi.c new file mode 100644 index 0000000..acd276c --- /dev/null +++ b/lib/efi/efi.c @@ -0,0 +1,91 @@ +/* + * 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; + +static void efi_memset(void *ptr, int ch, int size) +{ + char *dest = ptr; + + while (size-- > 0) + *dest++ = ch; +} + +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..b71669c --- /dev/null +++ b/lib/efi/efi_app.c @@ -0,0 +1,125 @@ +/* + * 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; + + 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; + 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 */ + 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 Wed, Jul 22, 2015 at 11:49 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
arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- include/efi.h | 356 +++++++++++++++++++++++++++++++++++++ include/efi_api.h | 252 ++++++++++++++++++++++++++ include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 33 ++++ lib/efi/Makefile | 7 + lib/efi/efi.c | 91 ++++++++++ lib/efi/efi_app.c | 125 +++++++++++++ 10 files changed, 871 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..66ef6c3 --- /dev/null +++ b/include/efi.h @@ -0,0 +1,356 @@ +/*
- 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>
+#ifdef CONFIG_EFI_STUB_64BIT
I believe this CONFIG_EFI_STUB_64BIT is introduced in later patches, can we remove this to later patch where you add this CONFIG_EFI_STUB_64BIT?
+#define EFIAPI __attribute__((ms_abi))
This is worth a comment block to describe the fact that EFI 64-bit is using M$ ABI which is different from ours.
+#else +#define EFIAPI +#endif
+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)))
Can we also remove those duplicated defines in arch/x86/include/asm/fsp/fsp_types.h so that FSP codes can use the one in efi.h?
+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
- */
Please use one-line comment.
+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,
What is efi_mem_desc_VERSION? The name should be all capital letters.
+};
+#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.
- */
Please use one-line comment.
+#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
- */
Please use one-line comment.
+#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,
Please remove this blank line.
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
Missing description for total_size and spare[5]
- */
+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
- @
Missing description for spare1 and spare2.
- */
+struct efi_entry_hdr {
u32 type;
u32 size;
u64 addr;
u32 link;
u32 spare1;
u64 spare22;
Why 22? Should it be spare2?
+};
+struct efi_entry_memmap {
Can we add comment block for this structure too?
u32 version;
u32 desc_size;
u64 spare;
struct efi_mem_desc desc[];
Nits: should it be "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 ImageBase[];
Can we avoid CamelCase?
+/**
- 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 know to U-Boot
as 'known'?
- */
+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 resuilt
Typo of '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 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 ASCII, not unicode)
A character can only be ASCII.
- */
+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..d4528f6 --- /dev/null +++ b/include/efi_api.h @@ -0,0 +1,252 @@ +/*
- 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
- */
Please use one-line comment.
+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;
Can it be just '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
Can we move these to efi.h?
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
- */
Please use one-line comment.
+enum efi_reset_type {
EFI_RESET_COLD = 0,
EFI_RESET_WARM = 1,
EFI_RESET_SHUTDOWN = 2
+};
Nits: can we move this to efi.h?
+/*
- EFI Runtime Services table
- */
Please use one-line comment.
+#define EFI_RUNTIME_SERVICES_SIGNATURE ((u64)0x5652453544e5552ULL)
Is the (u64) cast necessary?
+#define EFI_RUNTIME_SERVICES_REVISION 0x00010000
Nits: can we move the above two to efi.h?
+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
- */
Please use one-line comment.
+#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)
Nits: can we move the above two to efi.h?
+struct efi_system_table {
struct efi_table_hdr hdr;
unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */
What's CHAR16? Is it wchar_t?
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 __packed efi_device_path {
__packed is not needed here.
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 c98d399..4c8d38e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -96,4 +96,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 97ed398..4821779 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..2b3dbd4 --- /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 ARCH_EFI
Can we change this to EFI_APP?
bool "Support running U-Boot from EFI"
Nits: better to be "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 problem and memory and I/O functions. Use 'reset' to return
I don't understand what is 'a command problem'.
to EFI.
+config EFI_RAM_SIZE
hex "Amount of EFI RAM for U-Boot"
depends on ARCH_EFI
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 withU-Boot.
Missing space between 'with' and 'U-Boot'
+endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile new file mode 100644 index 0000000..137d2f9 --- /dev/null +++ b/lib/efi/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_ARCH_EFI) += efi_app.o efi.o diff --git a/lib/efi/efi.c b/lib/efi/efi.c new file mode 100644 index 0000000..acd276c --- /dev/null +++ b/lib/efi/efi.c @@ -0,0 +1,91 @@ +/*
- 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;
+static void efi_memset(void *ptr, int ch, int size) +{
char *dest = ptr;
while (size-- > 0)
*dest++ = ch;
+}
Why do we need this? Can we use memset() here?
+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..b71669c --- /dev/null +++ b/lib/efi/efi_app.c @@ -0,0 +1,125 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- EFI information obtained here:
- 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;
global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret);
Where is this global_data_ptr defined? I guess this is introduced in later patches. The introduction of global_data_ptr should be moved to this patch.
if (!global_data_ptr)
return ret;
memset(gd, '\0', sizeof(*gd));
And gd here? If gd == global_data_ptr, why no just use gd without adding global_data_ptr?
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;
addr = 1ULL << 32;
Please add a comment to describe what we are trying to do here, eg: addr points to 4GiB, that means the allocated address should not exceed that.
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 */
debug_uart_init();
Where is this implemented for efi app?
ret = setup_memory(priv);
if (ret) {
printf("Failed to set up memory: ret=%lx\n", ret);
Is printf usable here? If yes, why do we create efi_puts() and efi_putc()?
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);
+}
Regards, Bin

Hi Bin,
On 23 July 2015 at 02:09, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- include/efi.h | 356 +++++++++++++++++++++++++++++++++++++ include/efi_api.h | 252 ++++++++++++++++++++++++++ include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 33 ++++ lib/efi/Makefile | 7 + lib/efi/efi.c | 91 ++++++++++ lib/efi/efi_app.c | 125 +++++++++++++ 10 files changed, 871 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..66ef6c3 --- /dev/null +++ b/include/efi.h @@ -0,0 +1,356 @@ +/*
- 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>
+#ifdef CONFIG_EFI_STUB_64BIT
I believe this CONFIG_EFI_STUB_64BIT is introduced in later patches, can we remove this to later patch where you add this CONFIG_EFI_STUB_64BIT?
+#define EFIAPI __attribute__((ms_abi))
This is worth a comment block to describe the fact that EFI 64-bit is using M$ ABI which is different from ours.
+#else +#define EFIAPI +#endif
+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)))
Can we also remove those duplicated defines in arch/x86/include/asm/fsp/fsp_types.h so that FSP codes can use the one in efi.h?
But these have an FSP prefix, right? If you are sure about this, I'll do it as a separate clean-up patch.
+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
- */
Please use one-line comment.
+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,
What is efi_mem_desc_VERSION? The name should be all capital letters.
+};
+#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.
- */
Please use one-line comment.
+#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
- */
Please use one-line comment.
+#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,
Please remove this blank line.
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
Missing description for total_size and spare[5]
- */
+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
- @
Missing description for spare1 and spare2.
- */
+struct efi_entry_hdr {
u32 type;
u32 size;
u64 addr;
u32 link;
u32 spare1;
u64 spare22;
Why 22? Should it be spare2?
+};
+struct efi_entry_memmap {
Can we add comment block for this structure too?
u32 version;
u32 desc_size;
u64 spare;
struct efi_mem_desc desc[];
Nits: should it be "struct efi_mem_desc *desc"?
No, the data follows immediately here.
+};
+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 ImageBase[];
Can we avoid CamelCase?
+/**
- 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 know to U-Boot
as 'known'?
- */
+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 resuilt
Typo of '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 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 ASCII, not unicode)
A character can only be ASCII.
- */
+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..d4528f6 --- /dev/null +++ b/include/efi_api.h @@ -0,0 +1,252 @@ +/*
- 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
- */
Please use one-line comment.
+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;
Can it be just '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
Can we move these to efi.h?
Well they relate to a specific API method so I think they are better here.
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
- */
Please use one-line comment.
+enum efi_reset_type {
EFI_RESET_COLD = 0,
EFI_RESET_WARM = 1,
EFI_RESET_SHUTDOWN = 2
+};
Nits: can we move this to efi.h?
I think it relates to the reset API so is best here. What do you think?
+/*
- EFI Runtime Services table
- */
Please use one-line comment.
+#define EFI_RUNTIME_SERVICES_SIGNATURE ((u64)0x5652453544e5552ULL)
Is the (u64) cast necessary?
+#define EFI_RUNTIME_SERVICES_REVISION 0x00010000
Nits: can we move the above two to efi.h?
Again I think this is API-related.
+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
- */
Please use one-line comment.
+#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)
Nits: can we move the above two to efi.h?
+struct efi_system_table {
struct efi_table_hdr hdr;
unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */
What's CHAR16? Is it wchar_t?
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 __packed efi_device_path {
__packed is not needed here.
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 c98d399..4c8d38e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -96,4 +96,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 97ed398..4821779 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..2b3dbd4 --- /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 ARCH_EFI
Can we change this to EFI_APP?
bool "Support running U-Boot from EFI"
Nits: better to be "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 problem and memory and I/O functions. Use 'reset' to return
I don't understand what is 'a command problem'.
to EFI.
+config EFI_RAM_SIZE
hex "Amount of EFI RAM for U-Boot"
depends on ARCH_EFI
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 withU-Boot.
Missing space between 'with' and 'U-Boot'
+endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile new file mode 100644 index 0000000..137d2f9 --- /dev/null +++ b/lib/efi/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_ARCH_EFI) += efi_app.o efi.o diff --git a/lib/efi/efi.c b/lib/efi/efi.c new file mode 100644 index 0000000..acd276c --- /dev/null +++ b/lib/efi/efi.c @@ -0,0 +1,91 @@ +/*
- 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;
+static void efi_memset(void *ptr, int ch, int size) +{
char *dest = ptr;
while (size-- > 0)
*dest++ = ch;
+}
Why do we need this? Can we use memset() here?
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.
+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..b71669c --- /dev/null +++ b/lib/efi/efi_app.c @@ -0,0 +1,125 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- EFI information obtained here:
- 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;
global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret);
Where is this global_data_ptr defined? I guess this is introduced in later patches. The introduction of global_data_ptr should be moved to this patch.
if (!global_data_ptr)
return ret;
memset(gd, '\0', sizeof(*gd));
And gd here? If gd == global_data_ptr, why no just use gd without adding global_data_ptr?
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;
addr = 1ULL << 32;
Please add a comment to describe what we are trying to do here, eg: addr points to 4GiB, that means the allocated address should not exceed that.
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 */
debug_uart_init();
Where is this implemented for efi app?
ret = setup_memory(priv);
if (ret) {
printf("Failed to set up memory: ret=%lx\n", ret);
Is printf usable here? If yes, why do we create efi_puts() and efi_putc()?
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);
+}
Regards, Bin
Regards, Simon

Hi Simon,
On Fri, Jul 31, 2015 at 11:45 PM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 23 July 2015 at 02:09, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
[snip]
+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)))
Can we also remove those duplicated defines in arch/x86/include/asm/fsp/fsp_types.h so that FSP codes can use the one in efi.h?
But these have an FSP prefix, right? If you are sure about this, I'll do it as a separate clean-up patch.
According to FSP spec, FSP is using EFI status codes, so they are compatible. We can do it as a separate clean-up patch later.
[snip]
Regards, Bin

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 ---
lib/initcall.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/lib/initcall.c b/lib/initcall.c index 7142744..1931655 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_ARCH_EFI + reloc_ofs = (unsigned long)ImageBase; +#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);

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, 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
Please check previous review comments regarding to CONFIG_ARCH_EFI and ImageBase, otherwise:
Reviewed-by: Bin Meng bmeng.cn@gmail.com
lib/initcall.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/lib/initcall.c b/lib/initcall.c index 7142744..1931655 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_ARCH_EFI
reloc_ofs = (unsigned long)ImageBase;
+#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); --
Regards, Bin

Add a serial driver which makes use of EFI's console in/out service.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/Kconfig | 8 +++ drivers/serial/Makefile | 1 + drivers/serial/serial_efi.c | 149 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 drivers/serial/serial_efi.c
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4829284..f874837 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -44,6 +44,14 @@ 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_UART_EFI + bool "EFI" + help + Select this to enable a debug UART 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..92c3808 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_ARCH_EFI) += 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..15e541b --- /dev/null +++ b/drivers/serial/serial_efi.c @@ -0,0 +1,149 @@ +/* + * 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> + +DECLARE_GLOBAL_DATA_PTR; + +/* 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; + 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; +} + +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_s5p) = { + .name = "serial_s5p", + .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, +};

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
drivers/serial/Kconfig | 8 +++ drivers/serial/Makefile | 1 + drivers/serial/serial_efi.c | 149 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 drivers/serial/serial_efi.c
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4829284..f874837 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -44,6 +44,14 @@ 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_UART_EFI
This driver looks like a normal serial driver, except one debug uart api _debug_uart_putc(). Also it can not only support UART, but also support any console input/output devices that EFI supports. Should we rename it to: EFI_CONSOLE?
bool "EFI"
depends on EFI_APP?
help
Select this to enable a debug UART 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..92c3808 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_ARCH_EFI) += 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..15e541b --- /dev/null +++ b/drivers/serial/serial_efi.c @@ -0,0 +1,149 @@ +/*
- 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>
+DECLARE_GLOBAL_DATA_PTR;
Is this needed? I don't see gd is referenced.
+/* 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;
What is 8 here? Can we add a comment here?
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;
+}
+void debug_uart_init(void) +{ +}
Can we add come comments here to mention nothing needs to be done here for EFI?
+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_s5p) = {
Should be serial_efi.
.name = "serial_s5p",
The same here.
.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,
+};
Regards, Bin

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 ---
Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/Kconfig b/Kconfig index 15e15af..c1e7d22 100644 --- a/Kconfig +++ b/Kconfig @@ -179,6 +179,7 @@ config SYS_EXTRA_OPTIONS
config SYS_TEXT_BASE depends on SPARC || ARC || X86 || ARCH_UNIPHIER + depends on !ARCH_EFI hex "Text Base" help TODO: Move CONFIG_SYS_TEXT_BASE for all the architecture

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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.
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
Except the name of ARCH_EFI per my previous comments:
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/Kconfig b/Kconfig index 15e15af..c1e7d22 100644 --- a/Kconfig +++ b/Kconfig @@ -179,6 +179,7 @@ config SYS_EXTRA_OPTIONS
config SYS_TEXT_BASE depends on SPARC || ARC || X86 || ARCH_UNIPHIER
depends on !ARCH_EFI hex "Text Base" help TODO: Move CONFIG_SYS_TEXT_BASE for all the architecture
--
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 ---
Makefile | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Makefile b/Makefile index e0218b3..91ebc2e 100644 --- a/Makefile +++ b/Makefile @@ -752,6 +752,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf +ALL-$(CONFIG_ARCH_EFI) += u-boot.efi
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1080,6 +1081,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 Wed, Jul 22, 2015 at 11:49 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
Makefile | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Makefile b/Makefile index e0218b3..91ebc2e 100644 --- a/Makefile +++ b/Makefile @@ -752,6 +752,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf +ALL-$(CONFIG_ARCH_EFI) += u-boot.efi
Can we use u-boot-app.efi?
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1080,6 +1081,10 @@ u-boot-dtb-tegra.bin: u-boot-nodtb-tegra.bin dts/dt.dtb FORCE endif endif
+OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI)
Where is OBJCOPYFLAGS_EFI introduced? Can we move that into this patch?
+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)
--
Regards, Bin

Hi Bin,
On 23 July 2015 at 02:46, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
Makefile | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Makefile b/Makefile index e0218b3..91ebc2e 100644 --- a/Makefile +++ b/Makefile @@ -752,6 +752,7 @@ ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf +ALL-$(CONFIG_ARCH_EFI) += u-boot.efi
Can we use u-boot-app.efi?
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1080,6 +1081,10 @@ u-boot-dtb-tegra.bin: u-boot-nodtb-tegra.bin dts/dt.dtb FORCE endif endif
+OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI)
Where is OBJCOPYFLAGS_EFI introduced? Can we move that into this patch?
It's in the x86 patch - I don't want to mix generic code with arch-specific code, so have kept it separate.
+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)
--
Regards, Bin
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 ---
arch/x86/lib/relocate.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 1a62142..0839f59 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -28,7 +28,8 @@ int copy_uboot_to_ram(void) { size_t len = (size_t)&__data_end - (size_t)&__text_start;
- memcpy((void *)gd->relocaddr, (void *)&__text_start, len); + if (!(gd->flags & GD_FLG_SKIP_RELOC)) + memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
return 0; } @@ -38,7 +39,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;
- memset((void *)dst_addr, 0x00, len); + if (!(gd->flags & GD_FLG_SKIP_RELOC)) + memset((void *)dst_addr, 0x00, len);
return 0; } @@ -58,6 +60,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");

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
Can we squash this patch into previous patch#5?
[U-Boot,05/48] Add a way to skip relocation http://patchwork.ozlabs.org/patch/498649/
arch/x86/lib/relocate.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 1a62142..0839f59 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -28,7 +28,8 @@ int copy_uboot_to_ram(void) { size_t len = (size_t)&__data_end - (size_t)&__text_start;
memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
if (!(gd->flags & GD_FLG_SKIP_RELOC))
memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
Can we just do in the function beginning, like in patch#5:
if (gd->flags & GD_FLG_SKIP_RELOC) return 0;
return 0;
} @@ -38,7 +39,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;
memset((void *)dst_addr, 0x00, len);
if (!(gd->flags & GD_FLG_SKIP_RELOC))
memset((void *)dst_addr, 0x00, len);
Ditto.
return 0;
} @@ -58,6 +60,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");
--
Regards, Bin

Hi Bin,
On 23 July 2015 at 02:51, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
Can we squash this patch into previous patch#5?
That's generic code though so I would rather that the arch-specific implementations are in separate patches.
[U-Boot,05/48] Add a way to skip relocation http://patchwork.ozlabs.org/patch/498649/
arch/x86/lib/relocate.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 1a62142..0839f59 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -28,7 +28,8 @@ int copy_uboot_to_ram(void) { size_t len = (size_t)&__data_end - (size_t)&__text_start;
memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
if (!(gd->flags & GD_FLG_SKIP_RELOC))
memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
Can we just do in the function beginning, like in patch#5:
if (gd->flags & GD_FLG_SKIP_RELOC) return 0;
return 0;
} @@ -38,7 +39,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;
memset((void *)dst_addr, 0x00, len);
if (!(gd->flags & GD_FLG_SKIP_RELOC))
memset((void *)dst_addr, 0x00, len);
Ditto.
return 0;
} @@ -58,6 +60,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");
--
Regards, Bin
Regards, Simon

Bring in this file from Linux 4.1. It supports relocation features specific to x86.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/elf.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 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..d6eff0e --- /dev/null +++ b/arch/x86/include/asm/elf.h @@ -0,0 +1,50 @@ +/* + * 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.. + */ +#include <asm/ptrace.h> + +#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 */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#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 /* _ASM_X86_ELF_H */

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
But please find nits below.
arch/x86/include/asm/elf.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 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..d6eff0e --- /dev/null +++ b/arch/x86/include/asm/elf.h @@ -0,0 +1,50 @@ +/*
- 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..
- */
Please use one-line comment.
+#include <asm/ptrace.h>
Is this <ptrace.h> needed for ELF relocation? If not, please remove.
+#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 */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative
offset to GOT */
+#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 /* _ASM_X86_ELF_H */
Regards, Bin

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 ---
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 | 49 ++++++++++++++++++ arch/x86/cpu/efi/elf_ia32_efi.lds | 92 ++++++++++++++++++++++++++++++++++ arch/x86/cpu/efi/sdram.c | 29 +++++++++++ arch/x86/cpu/interrupts.c | 2 + arch/x86/include/asm/arch-efi/gpio.h | 10 ++++ arch/x86/lib/Makefile | 6 +++ arch/x86/lib/crt0-efi-ia32.S | 77 +++++++++++++++++++++++++++++ arch/x86/lib/crt0-efi-x86_64.S | 77 +++++++++++++++++++++++++++++ arch/x86/lib/reloc_ia32.c | 96 ++++++++++++++++++++++++++++++++++++ 13 files changed, 452 insertions(+) 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/crt0-efi-ia32.S create mode 100644 arch/x86/lib/crt0-efi-x86_64.S create mode 100644 arch/x86/lib/reloc_ia32.c
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..e842015 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -2,7 +2,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifeq ($(CONFIG_ARCH_EFI),) 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..9678976 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_ARCH_EFI) += 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..0b1c54e --- /dev/null +++ b/arch/x86/cpu/efi/efi.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <netdev.h> + +DECLARE_GLOBAL_DATA_PTR; + +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(); +} + +int board_eth_init(bd_t *bis) +{ + return pci_eth_init(bis); +} + +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..fca008b --- /dev/null +++ b/arch/x86/cpu/efi/elf_ia32_efi.lds @@ -0,0 +1,92 @@ +/* + * U-Boot EFI link 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 +{ + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = 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); + KEEP(*(SORT(.u_boot_list*))); + . = ALIGN(8); + KEEP(*(.dtb*)); + } + .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..a86c673 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -242,6 +242,7 @@ int disable_interrupts(void)
int interrupt_init(void) { +#ifndef CONFIG_ARCH_EFI /* Just in case... */ disable_interrupts();
@@ -255,6 +256,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/Makefile b/arch/x86/lib/Makefile index 43489fd..77bba16 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -5,6 +5,12 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifeq ($(CONFIG_X86_64),) +obj-$(CONFIG_ARCH_EFI) += crt0-efi-ia32.o reloc_ia32.o +else +obj-$(CONFIG_ARCH_EFI) += crt0-efi-ia64.o reloc_ia64.o +endif + obj-y += bios.o obj-y += bios_asm.o obj-y += bios_interrupts.o diff --git a/arch/x86/lib/crt0-efi-ia32.S b/arch/x86/lib/crt0-efi-ia32.S new file mode 100644 index 0000000..a5aebda --- /dev/null +++ b/arch/x86/lib/crt0-efi-ia32.S @@ -0,0 +1,77 @@ +/* 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. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of Hewlett-Packard Co. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + + .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 $ImageBase-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/crt0-efi-x86_64.S b/arch/x86/lib/crt0-efi-x86_64.S new file mode 100644 index 0000000..65a2795 --- /dev/null +++ b/arch/x86/lib/crt0-efi-x86_64.S @@ -0,0 +1,77 @@ +/* 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. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of Hewlett-Packard Co. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + .text + .align 4 + + .globl _start +_start: + subq $8, %rsp + pushq %rcx + pushq %rdx + +0: + lea ImageBase(%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/arch/x86/lib/reloc_ia32.c b/arch/x86/lib/reloc_ia32.c new file mode 100644 index 0000000..45c6654 --- /dev/null +++ b/arch/x86/lib/reloc_ia32.c @@ -0,0 +1,96 @@ +/* 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. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of Hewlett-Packard Co. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#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 Wed, Jul 22, 2015 at 11:49 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
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 | 49 ++++++++++++++++++ arch/x86/cpu/efi/elf_ia32_efi.lds | 92 ++++++++++++++++++++++++++++++++++ arch/x86/cpu/efi/sdram.c | 29 +++++++++++ arch/x86/cpu/interrupts.c | 2 + arch/x86/include/asm/arch-efi/gpio.h | 10 ++++ arch/x86/lib/Makefile | 6 +++ arch/x86/lib/crt0-efi-ia32.S | 77 +++++++++++++++++++++++++++++ arch/x86/lib/crt0-efi-x86_64.S | 77 +++++++++++++++++++++++++++++ arch/x86/lib/reloc_ia32.c | 96 ++++++++++++++++++++++++++++++++++++ 13 files changed, 452 insertions(+) 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/crt0-efi-ia32.S create mode 100644 arch/x86/lib/crt0-efi-x86_64.S create mode 100644 arch/x86/lib/reloc_ia32.c
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..e842015 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -2,7 +2,9 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifeq ($(CONFIG_ARCH_EFI),) 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..9678976 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_ARCH_EFI) += 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..0b1c54e --- /dev/null +++ b/arch/x86/cpu/efi/efi.c @@ -0,0 +1,49 @@ +/*
- Copyright (c) 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <netdev.h>
+DECLARE_GLOBAL_DATA_PTR;
This is not needed.
+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();
+}
+int board_eth_init(bd_t *bis) +{
return pci_eth_init(bis);
I don't think this works. Remove?
+}
+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..fca008b --- /dev/null +++ b/arch/x86/cpu/efi/elf_ia32_efi.lds @@ -0,0 +1,92 @@ +/*
- U-Boot EFI link script
Nits: 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 +{
ImageBase = .;
CamelCase
.hash : { *(.hash) } /* this MUST come first! */
Why? Please add a comment on this.
. = 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);
KEEP(*(SORT(.u_boot_list*)));
I doubt KEEP is needed as this is in the .data section anyway.
. = ALIGN(8);
KEEP(*(.dtb*));
}
The original gnuefi codes have a ". = ALIGN(4096)" here. Is it intended to drop this?
.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..a86c673 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -242,6 +242,7 @@ int disable_interrupts(void)
int interrupt_init(void) { +#ifndef CONFIG_ARCH_EFI
Can we add a comment block above to explain why EFI APP cannot call interrupt_init()?
/* Just in case... */ disable_interrupts();
@@ -255,6 +256,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/Makefile b/arch/x86/lib/Makefile index 43489fd..77bba16 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -5,6 +5,12 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifeq ($(CONFIG_X86_64),)
Where is CONFIG_X86_64 introduced?
+obj-$(CONFIG_ARCH_EFI) += crt0-efi-ia32.o reloc_ia32.o +else +obj-$(CONFIG_ARCH_EFI) += crt0-efi-ia64.o reloc_ia64.o +endif
obj-y += bios.o obj-y += bios_asm.o obj-y += bios_interrupts.o diff --git a/arch/x86/lib/crt0-efi-ia32.S b/arch/x86/lib/crt0-efi-ia32.S
Can we put this file to arch/x86/lib/efi instead given it is only used for efi?
new file mode 100644 index 0000000..a5aebda --- /dev/null +++ b/arch/x86/lib/crt0-efi-ia32.S @@ -0,0 +1,77 @@ +/* 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.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
- Neither the name of Hewlett-Packard Co. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
Can we replace the above license with simplified SPDX version?
+*/
.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 $ImageBase-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 */
Nits: space around <<
diff --git a/arch/x86/lib/crt0-efi-x86_64.S b/arch/x86/lib/crt0-efi-x86_64.S
I believe this file needs to be introduced in later patches, as we only handle 32-bit so far.
new file mode 100644 index 0000000..65a2795 --- /dev/null +++ b/arch/x86/lib/crt0-efi-x86_64.S @@ -0,0 +1,77 @@ +/* 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.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
- Neither the name of Hewlett-Packard Co. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
Can we replace the above license with simplified SPDX version?
+*/
.text
.align 4
.globl _start
+_start:
subq $8, %rsp
pushq %rcx
pushq %rdx
+0:
lea ImageBase(%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 */
Nits: space around <<
diff --git a/arch/x86/lib/reloc_ia32.c b/arch/x86/lib/reloc_ia32.c new file mode 100644 index 0000000..45c6654 --- /dev/null +++ b/arch/x86/lib/reloc_ia32.c @@ -0,0 +1,96 @@ +/* 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.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
- Neither the name of Hewlett-Packard Co. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
Can we replace the above license with simplified SPDX version?
+*/
+#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;
}
Nits: need a blank line
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 ---
arch/x86/Kconfig | 1 + board/efi/Kconfig | 19 +++++++++++++++++++ board/efi/efi-x86/Kconfig | 27 +++++++++++++++++++++++++++ board/efi/efi-x86/MAINTAINERS | 6 ++++++ board/efi/efi-x86/Makefile | 7 +++++++ board/efi/efi-x86/efi.c | 18 ++++++++++++++++++ 6 files changed, 78 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..330eb65 --- /dev/null +++ b/board/efi/efi-x86/Kconfig @@ -0,0 +1,27 @@ +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" + +config SYS_CAR_ADDR + hex "Board specific Cache-As-RAM (CAR) address" + default 0x01920000 + help + This option specifies the board specific Cache-As-RAM (CAR) address. + +config SYS_CAR_SIZE + hex "Board specific Cache-As-RAM (CAR) size" + default 0x4000 + help + This option specifies the board specific Cache-As-RAM (CAR) size. + +endif diff --git a/board/efi/efi-x86/MAINTAINERS b/board/efi/efi-x86/MAINTAINERS new file mode 100644 index 0000000..755247c --- /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; +}

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/Kconfig | 1 + board/efi/Kconfig | 19 +++++++++++++++++++ board/efi/efi-x86/Kconfig | 27 +++++++++++++++++++++++++++ board/efi/efi-x86/MAINTAINERS | 6 ++++++ board/efi/efi-x86/Makefile | 7 +++++++ board/efi/efi-x86/efi.c | 18 ++++++++++++++++++ 6 files changed, 78 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..330eb65 --- /dev/null +++ b/board/efi/efi-x86/Kconfig @@ -0,0 +1,27 @@ +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"
'default' is not aligned/indented correctly with others
+config SYS_CAR_ADDR
hex "Board specific Cache-As-RAM (CAR) address"
default 0x01920000
help
This option specifies the board specific Cache-As-RAM (CAR) address.
+config SYS_CAR_SIZE
hex "Board specific Cache-As-RAM (CAR) size"
default 0x4000
help
This option specifies the board specific Cache-As-RAM (CAR) size.
I don't think the above two options are needed for EFI APP.
+endif diff --git a/board/efi/efi-x86/MAINTAINERS b/board/efi/efi-x86/MAINTAINERS new file mode 100644 index 0000000..755247c --- /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
'include..' is not aligned/indented corretly with other lines.
+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;
+}
Regards, Bin

This contains just enough to bring up the serial UART.
Signed-off-by: Simon Glass sjg@chromium.org ---
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..a6a5d38 --- /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,payload"; + + chosen { + stdout-path = &serial; + }; + + serial: serial { + compatible = "efi,uart"; + }; +};

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
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..a6a5d38 --- /dev/null +++ b/arch/x86/dts/efi.dts @@ -0,0 +1,22 @@ +/* ++ * Copyright (c) 2015 Google, Inc
Please remove the leading +
- SPDX-License-Identifier: GPL-2.0+
- */
+/dts-v1/;
+/include/ "skeleton.dtsi"
+/ {
model = "EFI";
compatible = "efi,payload";
Shouldn't it be "efi,app"?
chosen {
stdout-path = &serial;
};
serial: serial {
compatible = "efi,uart";
};
+};
Regards, Bin

On x86 the global_data pointer is provided through a somewhat-bizarre and x86-specific mechanism: the frame segment 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 ---
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 abd70b9..6df6a78 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_ARCH_EFI + +#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 Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
On x86 the global_data pointer is provided through a somewhat-bizarre and x86-specific mechanism: the frame segment is set to a pointer to the start
frame segment? I don't think F stands for frame.
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
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 abd70b9..6df6a78 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_ARCH_EFI
+#define gd global_data_ptr
OK, I got you here :) See comments in patch#18 @ http://patchwork.ozlabs.org/patch/498657/
I think this patch should come before patch#18. Please adjust the order.
+#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

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 ---
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 0839f59..79c1af3 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -56,6 +56,7 @@ int do_elf_reloc_fixups(void)
Elf32_Addr *offset_ptr_rom, *last_offset = NULL; Elf32_Addr *offset_ptr_ram; + unsigned int text_base;
/* The size of the region of u-boot that runs out of RAM. */ uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start; @@ -65,29 +66,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,

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
But please see nits below.
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 0839f59..79c1af3 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -56,6 +56,7 @@ int do_elf_reloc_fixups(void)
Elf32_Addr *offset_ptr_rom, *last_offset = NULL; Elf32_Addr *offset_ptr_ram;
unsigned int text_base;
Should we initialize text_base to 0? I suspect there will be warnings for uninitialized variable when CONFIG_SYS_TEXT_BASE is not defined.
/* The size of the region of u-boot that runs out of RAM. */ uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start;
@@ -65,29 +66,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,
--
Regards, Bin

From: Ben Stoltz stoltz@google.com
Adjust the tool chain 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 ---
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..bb0b254 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 + +LDFLAGS_EFI := -Bsymbolic -Bsymbolic-functions -znocombreloc -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 $(call cc-option, -mno-red-zone) + +EFIARCH=ia32 + +LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH) + +ifeq ($(CONFIG_ARCH_EFI),y) + +PLATFORM_CPPFLAGS += $(CFLAGS_EFI) +PLATFORM_LDFLAGS += -m elf_i386 +LDFLAGS_FINAL += -znocombreloc -shared +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH) +LDSCRIPT := $(LDSCRIPT_EFI) + +else + +PLATFORM_CPPFLAGS += $(CFLAGS_NON_EFI) +PLATFORM_LDFLAGS += --emit-relocs -m elf_i386 +LDFLAGS_FINAL += --gc-sections -pie + +endif

Hi Simon,
I think this patch should come before patch#22 in which it refers to OBJCOPYFLAGS_EFI defined in this patch. More comments below.
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Adjust the tool chain flags to build U-Boot as a relocatable shared library,
Nits: toolchain
as required by EFI.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
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..bb0b254 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
+LDFLAGS_EFI := -Bsymbolic -Bsymbolic-functions -znocombreloc -shared \
--no-undefined
- Where is this referenced? - It has duplicated options like '-Bsymbolic -Bsymbolic-functions' which are already in PLATFORM_LDFLAGS. - Is 'znocombreloc' a must for U-Boot? It is not in the original gnu-efi codes.
+OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
-j .rel -j .rela -j .reloc
Should we add wildcard section names as well, like the original gnu-efi codes?
+CFLAGS_NON_EFI := -mregparm=3 +CFLAGS_EFI := -fpic -fshort-wchar $(call cc-option, -mno-red-zone)
no-red-zone is only needed for x86_64. The cc-option only tests if compiler supports this, but it does not know if it is compiled against x86 or x64 codes.
+EFIARCH=ia32
+LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
+ifeq ($(CONFIG_ARCH_EFI),y)
+PLATFORM_CPPFLAGS += $(CFLAGS_EFI) +PLATFORM_LDFLAGS += -m elf_i386 +LDFLAGS_FINAL += -znocombreloc -shared +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
Duplicated. Already has this in above lines.
+LDSCRIPT := $(LDSCRIPT_EFI)
+else
+PLATFORM_CPPFLAGS += $(CFLAGS_NON_EFI) +PLATFORM_LDFLAGS += --emit-relocs -m elf_i386 +LDFLAGS_FINAL += --gc-sections -pie
+endif
Regards, Bin

Hi Bin,
On 23 July 2015 at 05:07, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
I think this patch should come before patch#22 in which it refers to OBJCOPYFLAGS_EFI defined in this patch. More comments below.
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
From: Ben Stoltz stoltz@google.com
Adjust the tool chain flags to build U-Boot as a relocatable shared library,
Nits: toolchain
as required by EFI.
Signed-off-by: Ben Stoltz stoltz@google.com Signed-off-by: Simon Glass sjg@chromium.org
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..bb0b254 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
+LDFLAGS_EFI := -Bsymbolic -Bsymbolic-functions -znocombreloc -shared \
--no-undefined
- Where is this referenced?
- It has duplicated options like '-Bsymbolic -Bsymbolic-functions'
which are already in PLATFORM_LDFLAGS.
I'll add a comment - it is used in the top-level Makefile.
- Is 'znocombreloc' a must for U-Boot? It is not in the original gnu-efi codes.
+OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
-j .rel -j .rela -j .reloc
Should we add wildcard section names as well, like the original gnu-efi codes?
By the time we do the objcopy these have been removed by the previous link step. I don't think we need them.
+CFLAGS_NON_EFI := -mregparm=3 +CFLAGS_EFI := -fpic -fshort-wchar $(call cc-option, -mno-red-zone)
no-red-zone is only needed for x86_64. The cc-option only tests if compiler supports this, but it does not know if it is compiled against x86 or x64 codes.
+EFIARCH=ia32
+LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
+ifeq ($(CONFIG_ARCH_EFI),y)
+PLATFORM_CPPFLAGS += $(CFLAGS_EFI) +PLATFORM_LDFLAGS += -m elf_i386 +LDFLAGS_FINAL += -znocombreloc -shared +OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
Duplicated. Already has this in above lines.
+LDSCRIPT := $(LDSCRIPT_EFI)
+else
+PLATFORM_CPPFLAGS += $(CFLAGS_NON_EFI) +PLATFORM_LDFLAGS += --emit-relocs -m elf_i386 +LDFLAGS_FINAL += --gc-sections -pie
+endif
Regards, Bin
Regards, Simon

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 ---
configs/efi-x86_defconfig | 16 ++++++++++++++++ include/configs/efi-x86.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 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..f07305c --- /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_ARCH_EFI=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_EFI=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..9ffc2ea --- /dev/null +++ b/include/configs/efi-x86.h @@ -0,0 +1,37 @@ +/* + * 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 + +#define CONFIG_SYS_EARLY_PCI_INIT +#define CONFIG_PCI_PNP + +#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 Wed, Jul 22, 2015 at 11:49 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
configs/efi-x86_defconfig | 16 ++++++++++++++++ include/configs/efi-x86.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 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..f07305c --- /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
I don't think DM_CPI works..
+CONFIG_DEFAULT_DEVICE_TREE="efi" +CONFIG_EFI=y +CONFIG_ARCH_EFI=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_EFI=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..9ffc2ea --- /dev/null +++ b/include/configs/efi-x86.h @@ -0,0 +1,37 @@ +/*
- 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
+#define CONFIG_SYS_EARLY_PCI_INIT +#define CONFIG_PCI_PNP
I guess these two should be turned off for now as pci is not supported.
+#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

Allow U-Boot to be packaged into the image as a binary payload.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/efi/elf_ia32_efi.lds | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/x86/cpu/efi/elf_ia32_efi.lds b/arch/x86/cpu/efi/elf_ia32_efi.lds index fca008b..87ddb4d 100644 --- a/arch/x86/cpu/efi/elf_ia32_efi.lds +++ b/arch/x86/cpu/efi/elf_ia32_efi.lds @@ -57,6 +57,9 @@ SECTIONS KEEP(*(SORT(.u_boot_list*))); . = ALIGN(8); KEEP(*(.dtb*)); + /* Keep U-Boot payload */ + . = ALIGN(8); + KEEP(*(.u_boot_bin.*)); } .dynamic : { *(.dynamic) } . = ALIGN(4096);

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
Allow U-Boot to be packaged into the image as a binary payload.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please check comments below.
arch/x86/cpu/efi/elf_ia32_efi.lds | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/x86/cpu/efi/elf_ia32_efi.lds b/arch/x86/cpu/efi/elf_ia32_efi.lds index fca008b..87ddb4d 100644 --- a/arch/x86/cpu/efi/elf_ia32_efi.lds +++ b/arch/x86/cpu/efi/elf_ia32_efi.lds @@ -57,6 +57,9 @@ SECTIONS KEEP(*(SORT(.u_boot_list*))); . = ALIGN(8); KEEP(*(.dtb*));
/* Keep U-Boot payload */
. = ALIGN(8);
KEEP(*(.u_boot_bin.*));
I don't see section .u_boot_bin defined so far. Assume it is introduced in later patches, so please consider the patch order.
} .dynamic : { *(.dynamic) } . = ALIGN(4096);
--
Regards, Bin

Add a link 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 ---
arch/x86/cpu/efi/elf_x86_64_efi.lds | 87 +++++++++++++++++++++++++++++++++++ arch/x86/lib/reloc_x86_64.c | 90 +++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 arch/x86/cpu/efi/elf_x86_64_efi.lds create mode 100644 arch/x86/lib/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..369f146 --- /dev/null +++ b/arch/x86/cpu/efi/elf_x86_64_efi.lds @@ -0,0 +1,87 @@ +/* + * U-Boot EFI link script + * + * SPDX-License-Identifier: bsd-2-clause + * + * Modified from usr/lib32/elf_ia32_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 +{ + . = 0x0; + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = 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); + KEEP(*(SORT(.u_boot_list*))); + . = ALIGN(8); + KEEP(*(.dtb*)); + /* Keep U-Boot payload */ + . = ALIGN(8); + KEEP(*(.u_boot_bin.*)); + } + + . = 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/reloc_x86_64.c b/arch/x86/lib/reloc_x86_64.c new file mode 100644 index 0000000..70a2b2a --- /dev/null +++ b/arch/x86/lib/reloc_x86_64.c @@ -0,0 +1,90 @@ +/* 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. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of Hewlett-Packard Co. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#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; + struct 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 = (struct 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 = (struct elf64_rel *)((char *)rel + relent); + relsz -= relent; + } + return EFI_SUCCESS; +}

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
Add a link script and relocation code for building 64-bit EFI applications.
Nits: linker script
This can be used for the EFI stub.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/efi/elf_x86_64_efi.lds | 87 +++++++++++++++++++++++++++++++++++ arch/x86/lib/reloc_x86_64.c | 90 +++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 arch/x86/cpu/efi/elf_x86_64_efi.lds create mode 100644 arch/x86/lib/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..369f146 --- /dev/null +++ b/arch/x86/cpu/efi/elf_x86_64_efi.lds @@ -0,0 +1,87 @@ +/*
- U-Boot EFI link script
Ditto.
- SPDX-License-Identifier: bsd-2-clause
- Modified from usr/lib32/elf_ia32_efi.lds in gnu-efi
I guess you want to say: usr/lib32/elf_x86_64_efi.lds
- */
+#include <config.h>
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{
. = 0x0;
We don't have this line in the elf_ia32_efi.lds. Can this be removed. Or we need add the same in the 32-bit lds. (BTW: I checked gnu-efi, it has this line)
ImageBase = .;
CamelCase
.hash : { *(.hash) } /* this MUST come first! */
. = 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);
KEEP(*(SORT(.u_boot_list*)));
. = ALIGN(8);
KEEP(*(.dtb*));
/* Keep U-Boot payload */
. = ALIGN(8);
KEEP(*(.u_boot_bin.*));
}
. = 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/reloc_x86_64.c b/arch/x86/lib/reloc_x86_64.c new file mode 100644 index 0000000..70a2b2a --- /dev/null +++ b/arch/x86/lib/reloc_x86_64.c @@ -0,0 +1,90 @@ +/* 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.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
- Neither the name of Hewlett-Packard Co. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
Please replace this with SPDX version.
+*/
+#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;
struct 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 = (struct 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 = (struct elf64_rel *)((char *)rel + relent);
relsz -= relent;
}
Nits: blank line
return EFI_SUCCESS;
+}
Regards, Bin

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 ---
Makefile | 32 ++++++ include/common.h | 7 ++ include/efi.h | 4 + lib/efi/Kconfig | 21 ++++ lib/efi/Makefile | 9 ++ lib/efi/efi_stub.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 366 insertions(+) create mode 100644 lib/efi/efi_stub.c
diff --git a/Makefile b/Makefile index 91ebc2e..9f863e1 100644 --- a/Makefile +++ b/Makefile @@ -753,6 +753,7 @@ ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf ALL-$(CONFIG_ARCH_EFI) += u-boot.efi +ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1085,6 +1086,37 @@ OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI) u-boot.efi: u-boot FORCE $(call if_changed,zobjcopy)
+# Generate an assembly file to wrap a binary file +quiet_cmd_bin_S = BIN $@ +cmd_bin_S = \ +( \ + echo '.section .u_boot_bin.init.rodata,"a"'; \ + echo '.balign 16'; \ + echo '.global __u_boot_bin_begin'; \ + echo '__u_boot_bin_begin:'; \ + echo '.incbin "$<" '; \ + echo '__u_boot_bin_end:'; \ + echo '.global __u_boot_bin_end'; \ + echo '.balign 16'; \ +) > $@ + +u-boot-dtb.bin.S: u-boot-dtb.bin FORCE + $(call if_changed,bin_S) + +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/,$(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/include/common.h b/include/common.h index 8f4b2ec..406fb33 100644 --- a/include/common.h +++ b/include/common.h @@ -1010,6 +1010,13 @@ int cpu_release(int nr, int argc, char * const argv[]); #define DEFINE_CACHE_ALIGN_BUFFER(type, name, size) \ DEFINE_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
+/* 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 66ef6c3..edc8cd9 100644 --- a/include/efi.h +++ b/include/efi.h @@ -268,11 +268,15 @@ struct efi_priv { /* Base address of the EFI image */ extern char ImageBase[];
+/* Start and end of U-Boot image (for payload) */ +extern char __u_boot_bin_begin[], __u_boot_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 2b3dbd4..f1a8873 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -20,6 +20,11 @@ config ARCH_EFI command problem 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 ARCH_EFI @@ -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 withU-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 137d2f9..ba2824e 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,3 +5,12 @@ #
obj-$(CONFIG_ARCH_EFI) += 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..e3b7cdb --- /dev/null +++ b/lib/efi/efi_stub.c @@ -0,0 +1,293 @@ +/* + * 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\n\t" : "=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. 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; + 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) { + 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, __u_boot_bin_begin, + (ulong)__u_boot_bin_end - (ulong)__u_boot_bin_begin); + +#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 Wed, Jul 22, 2015 at 11:49 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 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
Makefile | 32 ++++++ include/common.h | 7 ++ include/efi.h | 4 + lib/efi/Kconfig | 21 ++++ lib/efi/Makefile | 9 ++ lib/efi/efi_stub.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 366 insertions(+) create mode 100644 lib/efi/efi_stub.c
diff --git a/Makefile b/Makefile index 91ebc2e..9f863e1 100644 --- a/Makefile +++ b/Makefile @@ -753,6 +753,7 @@ ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf ALL-$(CONFIG_ARCH_EFI) += u-boot.efi +ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi
ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -1085,6 +1086,37 @@ OBJCOPYFLAGS_u-boot.efi := $(OBJCOPYFLAGS_EFI) u-boot.efi: u-boot FORCE $(call if_changed,zobjcopy)
+# Generate an assembly file to wrap a binary file +quiet_cmd_bin_S = BIN $@ +cmd_bin_S = \ +( \
echo '.section .u_boot_bin.init.rodata,"a"'; \
echo '.balign 16'; \
echo '.global __u_boot_bin_begin'; \
echo '__u_boot_bin_begin:'; \
echo '.incbin "$<" '; \
echo '__u_boot_bin_end:'; \
echo '.global __u_boot_bin_end'; \
echo '.balign 16'; \
+) > $@
Please check another approach @ http://patchwork.ozlabs.org/patch/499458/
+u-boot-dtb.bin.S: u-boot-dtb.bin FORCE
$(call if_changed,bin_S)
+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/,$(EFISTUB))
Please change to use cmd_xxx to avoid putting compiler message to the console.
+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/include/common.h b/include/common.h index 8f4b2ec..406fb33 100644 --- a/include/common.h +++ b/include/common.h @@ -1010,6 +1010,13 @@ int cpu_release(int nr, int argc, char * const argv[]); #define DEFINE_CACHE_ALIGN_BUFFER(type, name, size) \ DEFINE_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
+/* 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 66ef6c3..edc8cd9 100644 --- a/include/efi.h +++ b/include/efi.h @@ -268,11 +268,15 @@ struct efi_priv { /* Base address of the EFI image */ extern char ImageBase[];
+/* Start and end of U-Boot image (for payload) */ +extern char __u_boot_bin_begin[], __u_boot_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 2b3dbd4..f1a8873 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -20,6 +20,11 @@ config ARCH_EFI command problem 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 ARCH_EFI @@ -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 withU-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 137d2f9..ba2824e 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,3 +5,12 @@ #
obj-$(CONFIG_ARCH_EFI) += 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..e3b7cdb --- /dev/null +++ b/lib/efi/efi_stub.c @@ -0,0 +1,293 @@ +/*
- 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\n\t" : "=r" (val) : : "memory");
Please remove the "\n\t"
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. Another way to get back to EFI
- is via reset_cpu().
- */
reset_cpu() in the EFI_STUB case does not return back to EFI.
+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) {
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);
Why do we need call exit_boot_services() twice? Please add a comment on this.
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, __u_boot_bin_begin,
(ulong)__u_boot_bin_end - (ulong)__u_boot_bin_begin);
+#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 ---
arch/x86/lib/Makefile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 77bba16..fb4a73c 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -11,6 +11,20 @@ else obj-$(CONFIG_ARCH_EFI) += crt0-efi-ia64.o reloc_ia64.o endif
+ifneq ($(CONFIG_EFI_STUB),) +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 + obj-y += bios.o obj-y += bios_asm.o obj-y += bios_interrupts.o @@ -40,7 +54,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_

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/lib/Makefile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 77bba16..fb4a73c 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -11,6 +11,20 @@ else obj-$(CONFIG_ARCH_EFI) += crt0-efi-ia64.o reloc_ia64.o endif
+ifneq ($(CONFIG_EFI_STUB),) +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
I don't see AFLAGS_REMOVE_crt0-efi-ia32.o and AFLAGS_crt0-efi-ia32.o. Are they not needed?
+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
obj-y += bios.o obj-y += bios_asm.o obj-y += bios_interrupts.o @@ -40,7 +54,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_ --
Regards, Bin

Rather than add these as open-coded values, create an enum with the commonly used flags.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/cpu.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 08284ee..b96513d 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -27,6 +27,16 @@ enum { X86_VENDOR_UNKNOWN = 0xff };
+/* Global descriptor table (GDT) bits */ +enum { + GDT_4GB = 1ULL << 55, + GDT_32BIT = 1ULL << 54, + GDT_LONG = 1ULL << 53, + GDT_PRESENT = 1ULL << 47, + GDT_NOTSYS = 1ULL << 44, + GDT_CODE = 1ULL << 43, +}; + struct cpuid_result { uint32_t eax; uint32_t ebx;

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/include/asm/cpu.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 08284ee..b96513d 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -27,6 +27,16 @@ enum { X86_VENDOR_UNKNOWN = 0xff };
+/* Global descriptor table (GDT) bits */ +enum {
GDT_4GB = 1ULL << 55,
I think it should be GDT_4KB
GDT_32BIT = 1ULL << 54,
GDT_LONG = 1ULL << 53,
GDT_PRESENT = 1ULL << 47,
GDT_NOTSYS = 1ULL << 44,
GDT_CODE = 1ULL << 43,
+};
struct cpuid_result { uint32_t eax; uint32_t ebx; --
Regards, Bin

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 ---
arch/x86/cpu/Makefile | 6 +++++ arch/x86/cpu/call32.S | 65 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu.h | 9 +++++++ 3 files changed, 80 insertions(+) create mode 100644 arch/x86/cpu/call32.S
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 9678976..eb993ec 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_ARCH_EFI) += efi/ diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S new file mode 100644 index 0000000..3fe010e --- /dev/null +++ b/arch/x86/cpu/call32.S @@ -0,0 +1,65 @@ +/* + * (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 + 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 */ + .byte 0x48 + retf diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index b96513d..e977045 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -222,6 +222,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

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/cpu/Makefile | 6 +++++ arch/x86/cpu/call32.S | 65 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu.h | 9 +++++++ 3 files changed, 80 insertions(+) create mode 100644 arch/x86/cpu/call32.S
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 9678976..eb993ec 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_ARCH_EFI) += efi/ diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S new file mode 100644 index 0000000..3fe010e --- /dev/null +++ b/arch/x86/cpu/call32.S @@ -0,0 +1,65 @@ +/*
- (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
I think this is a REX prefix. Is there any compiler macro we can use? We can put some comments here for better understanding. BTW: is this a must? I believe retf will operate on 64-bit by operand in 64-bit by default?
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 */
.byte 0x48
retf
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index b96513d..e977045 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -222,6 +222,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
--
Regards, Bin

Hi Bin,
On 24 July 2015 at 01:25, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/cpu/Makefile | 6 +++++ arch/x86/cpu/call32.S | 65 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu.h | 9 +++++++ 3 files changed, 80 insertions(+) create mode 100644 arch/x86/cpu/call32.S
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 9678976..eb993ec 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_ARCH_EFI) += efi/ diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S new file mode 100644 index 0000000..3fe010e --- /dev/null +++ b/arch/x86/cpu/call32.S @@ -0,0 +1,65 @@ +/*
- (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
I think this is a REX prefix. Is there any compiler macro we can use? We can put some comments here for better understanding. BTW: is this a must? I believe retf will operate on 64-bit by operand in 64-bit by default?
I'll add a comment. In fact this problem took me ages to figure out as the documentation seems unclear. But neither qemu nor real hardware seem to work without this prefix.
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 */
.byte 0x48
I'll drop this one though.
retf
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index b96513d..e977045 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -222,6 +222,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
--
Regards, Bin
Regards, Simon

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 ---
Makefile | 2 +- arch/x86/config.mk | 11 +++++++++ arch/x86/include/asm/types.h | 5 +++- lib/efi/efi_stub.c | 58 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 69 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile index 9f863e1..6e3edb4 100644 --- a/Makefile +++ b/Makefile @@ -1109,7 +1109,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/,$(EFISTUB))
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index bb0b254..5107b43 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -15,7 +15,10 @@ PF_CPPFLAGS_X86 := $(call cc-option, -fno-toplevel-reorder, \
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_X86) PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm + +ifeq ($(CONFIG_X86_64),) PLATFORM_CPPFLAGS += -march=i386 -m32 +endif
PLATFORM_RELFLAGS += -ffunction-sections -fvisibility=hidden
@@ -33,11 +36,19 @@ OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ CFLAGS_NON_EFI := -mregparm=3 CFLAGS_EFI := -fpic -fshort-wchar $(call cc-option, -mno-red-zone)
+ifeq ($(CONFIG_X86_64)$(CONFIG_EFI_STUB_64BIT),) EFIARCH=ia32 +else +EFIARCH=x86_64 +endif
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_ARCH_EFI),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/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index e3b7cdb..36f14ff 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,55 @@ 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; + + if ((desc & GDT_PRESENT) && (desc && GDT_NOTSYS) && + !(desc & GDT_LONG) && (desc & GDT_4GB) && + (desc & GDT_32BIT) && (desc & GDT_CODE)) { + 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 Wed, Jul 22, 2015 at 11:49 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
Makefile | 2 +- arch/x86/config.mk | 11 +++++++++ arch/x86/include/asm/types.h | 5 +++- lib/efi/efi_stub.c | 58 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 69 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile index 9f863e1..6e3edb4 100644 --- a/Makefile +++ b/Makefile @@ -1109,7 +1109,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/,$(EFISTUB))
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index bb0b254..5107b43 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -15,7 +15,10 @@ PF_CPPFLAGS_X86 := $(call cc-option, -fno-toplevel-reorder, \
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_X86) PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm
+ifeq ($(CONFIG_X86_64),)
Again I don't see CONFIG_X86_64 is introduced anywhere so far.
PLATFORM_CPPFLAGS += -march=i386 -m32 +endif
PLATFORM_RELFLAGS += -ffunction-sections -fvisibility=hidden
@@ -33,11 +36,19 @@ OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ CFLAGS_NON_EFI := -mregparm=3 CFLAGS_EFI := -fpic -fshort-wchar $(call cc-option, -mno-red-zone)
+ifeq ($(CONFIG_X86_64)$(CONFIG_EFI_STUB_64BIT),) EFIARCH=ia32 +else +EFIARCH=x86_64 +endif
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_ARCH_EFI),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/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index e3b7cdb..36f14ff 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,55 @@ 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;
if ((desc & GDT_PRESENT) && (desc && GDT_NOTSYS) &&
!(desc & GDT_LONG) && (desc & GDT_4GB) &&
(desc & GDT_32BIT) && (desc & GDT_CODE)) {
I think only checking GDT_4KB is not enough. We should check segment limit to make sure CONFIG_SYS_TEXT_BASE is within the range.
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

This is not in a good place. I'm hoping that Masahiro can help figure this one out.
Signed-off-by: Simon Glass sjg@chromium.org ---
scripts/Makefile.build | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index ac0554e..9a7d28d 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -294,6 +294,14 @@ $(obj)/%.lst: $(src)/%.c FORCE # Compile assembler sources (.S) # ---------------------------------------------------------------------------
+# TODO(sjg@chromium.org): Move this to a sensible place. It does not seem to +# work if placed in arch/x86/config.mk, etc. It is placed here so that +# we use the correct flags when assembling u-boot-dtb.bin.S. +ifdef CONFIG_X86 +AFLAGS_REMOVE_u-boot-dtb.bin.o += -mregparm=3 -march=i386 -m32 +AFLAGS_u-boot-dtb.bin.o += -fpic -fshort-wchar +endif + modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)
$(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
This is not in a good place. I'm hoping that Masahiro can help figure this one out.
Please check my approach without the need to change this file.
http://patchwork.ozlabs.org/patch/499458/
Signed-off-by: Simon Glass sjg@chromium.org
scripts/Makefile.build | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index ac0554e..9a7d28d 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -294,6 +294,14 @@ $(obj)/%.lst: $(src)/%.c FORCE # Compile assembler sources (.S) # ---------------------------------------------------------------------------
+# TODO(sjg@chromium.org): Move this to a sensible place. It does not seem to +# work if placed in arch/x86/config.mk, etc. It is placed here so that +# we use the correct flags when assembling u-boot-dtb.bin.S. +ifdef CONFIG_X86 +AFLAGS_REMOVE_u-boot-dtb.bin.o += -mregparm=3 -march=i386 -m32 +AFLAGS_u-boot-dtb.bin.o += -fpic -fshort-wchar +endif
modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)
$(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
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.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/start.S | 9 +++++++++ arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/asm-offsets.c | 1 + 3 files changed, 11 insertions(+)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 7ef8b88..356c1a5 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -53,6 +53,9 @@ _start: /* Save BIST */ movl %eax, %ebp
+ /* 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 movw %ax, %fs @@ -129,7 +132,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 6df6a78..ca32046 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; }

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/start.S | 9 +++++++++ arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/asm-offsets.c | 1 + 3 files changed, 11 insertions(+)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 7ef8b88..356c1a5 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -53,6 +53,9 @@ _start: /* Save BIST */ movl %eax, %ebp
What about the %eax in the EFI_STUB case? %eax already gets corrupted before.
/* 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 movw %ax, %fs
@@ -129,7 +132,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 6df6a78..ca32046 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;
}
Regards, Bin

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 ---
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 ba2824e..84bc5e3 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,6 +5,7 @@ #
obj-$(CONFIG_ARCH_EFI) += 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; +}

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
But please see nits below.
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 ba2824e..84bc5e3 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,6 +5,7 @@ #
obj-$(CONFIG_ARCH_EFI) += 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);
Is map_sysmem() necessary? I think it only matters for sandbox. If not, please remove.
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;
+}
Regards, Bin

Hi Bin,
On 24 July 2015 at 02:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
But please see nits below.
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 ba2824e..84bc5e3 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,6 +5,7 @@ #
obj-$(CONFIG_ARCH_EFI) += 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);
Is map_sysmem() necessary? I think it only matters for sandbox. If not, please remove.
That's true but I think it is good practice to use it most of the time. It avoids a cast and I suspect we may consider adding a sandbox EFI implementation in future.
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;
+}
Regards, Bin
Regards, Simon

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 ---
common/Makefile | 1 + common/cmd_efi.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 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..cc8758b --- /dev/null +++ b/common/cmd_efi.c @@ -0,0 +1,258 @@ +/* + * (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("%2x %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; + + printf("%d %s\n", argc, *argv); + 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]" +);

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
common/Makefile | 1 + common/cmd_efi.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 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..cc8758b --- /dev/null +++ b/common/cmd_efi.c @@ -0,0 +1,258 @@ +/*
- (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("%2x %x:%-12s %010llx %010llx %010llx ", upto,
%2x makes the entry number right aligned, however the # is left aligned (see above). Also can we print the decimal numbers?
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;
printf("%d %s\n", argc, *argv);
I believe this is a debug code.
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]"
+);
Regards, Bin

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 ---
arch/x86/Kconfig | 16 ++++++++++++++++ arch/x86/cpu/cpu.c | 21 +++++++++++++-------- arch/x86/cpu/interrupts.c | 10 ++++++++-- arch/x86/lib/bootm.c | 2 ++ 4 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f124d58..c64c626 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,16 @@ 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.
+if EFI + +config SYS_CAR_ADDR + hex + default 0x100000 + +config SYS_CAR_SIZE + hex + default 0x20000 + +endif + 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 a86c673..7df50bd 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -254,8 +254,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..3ad941f 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -165,6 +165,7 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * U-boot is setting them up that way for itself in * arch/i386/cpu/cpu.c. */ +#ifndef CONFIG_ARCH_EFI __asm__ __volatile__ ( "movl $0, %%ebp\n" "cli\n" @@ -173,6 +174,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 */

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/Kconfig | 16 ++++++++++++++++ arch/x86/cpu/cpu.c | 21 +++++++++++++-------- arch/x86/cpu/interrupts.c | 10 ++++++++-- arch/x86/lib/bootm.c | 2 ++ 4 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f124d58..c64c626 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,16 @@ 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.
+if EFI
+config SYS_CAR_ADDR
hex
default 0x100000
+config SYS_CAR_SIZE
hex
default 0x20000
+endif
Can we move this to arch/x86/cpu/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 a86c673..7df50bd 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -254,8 +254,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..3ad941f 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -165,6 +165,7 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * U-boot is setting them up that way for itself in * arch/i386/cpu/cpu.c. */ +#ifndef CONFIG_ARCH_EFI
Does this mean EFI application cannot load a Linux kernel?
__asm__ __volatile__ ( "movl $0, %%ebp\n" "cli\n"
@@ -173,6 +174,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 */
--
Regards, Bin

Hi Bin,
On 24 July 2015 at 02:58, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 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
arch/x86/Kconfig | 16 ++++++++++++++++ arch/x86/cpu/cpu.c | 21 +++++++++++++-------- arch/x86/cpu/interrupts.c | 10 ++++++++-- arch/x86/lib/bootm.c | 2 ++ 4 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f124d58..c64c626 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,16 @@ 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.
+if EFI
+config SYS_CAR_ADDR
hex
default 0x100000
+config SYS_CAR_SIZE
hex
default 0x20000
+endif
Can we move this to arch/x86/cpu/efi/Kconfig?
That's for the application (i.e. the 'cpu' is EFI). These options are actually needed for the payload. I'll move them to arch/x86/lib/efi/Kconfig since it is reasonable to include that for all x86 boards.
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 a86c673..7df50bd 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -254,8 +254,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..3ad941f 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -165,6 +165,7 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * U-boot is setting them up that way for itself in * arch/i386/cpu/cpu.c. */ +#ifndef CONFIG_ARCH_EFI
Does this mean EFI application cannot load a Linux kernel?
Yes. I'll add a comment. It would actually be possible to implement this, but it is not done yet.
__asm__ __volatile__ ( "movl $0, %%ebp\n" "cli\n"
@@ -173,6 +174,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 */
--
Regards, Bin
Regards, Simon

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 ---
arch/x86/lib/Makefile | 1 + arch/x86/lib/efi/Makefile | 9 +++ arch/x86/lib/efi/car.S | 12 ++++ arch/x86/lib/efi/efi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 arch/x86/lib/efi/Makefile 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 fb4a73c..3db373c 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,6 +31,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_STUB) += 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 new file mode 100644 index 0000000..a308a0e --- /dev/null +++ b/arch/x86/lib/efi/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2002-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += car.o +obj-y += efi.o diff --git a/arch/x86/lib/efi/car.S b/arch/x86/lib/efi/car.S new file mode 100644 index 0000000..6dda058 --- /dev/null +++ b/arch/x86/lib/efi/car.S @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +.section .text + +.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; +}

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
arch/x86/lib/Makefile | 1 + arch/x86/lib/efi/Makefile | 9 +++ arch/x86/lib/efi/car.S | 12 ++++ arch/x86/lib/efi/efi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 arch/x86/lib/efi/Makefile 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 fb4a73c..3db373c 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,6 +31,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_STUB) += 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 new file mode 100644 index 0000000..a308a0e --- /dev/null +++ b/arch/x86/lib/efi/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2002-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-y += car.o +obj-y += efi.o diff --git a/arch/x86/lib/efi/car.S b/arch/x86/lib/efi/car.S new file mode 100644 index 0000000..6dda058 --- /dev/null +++ b/arch/x86/lib/efi/car.S @@ -0,0 +1,12 @@ +/*
- Copyright (c) 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SPDX-License-Identifier: GPL-2.0+
- */
+.section .text
This is not needed.
+.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;
+}
Regards, Bin

On Fri, Jul 24, 2015 at 5:03 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
arch/x86/lib/Makefile | 1 + arch/x86/lib/efi/Makefile | 9 +++ arch/x86/lib/efi/car.S | 12 ++++ arch/x86/lib/efi/efi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 arch/x86/lib/efi/Makefile 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 fb4a73c..3db373c 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,6 +31,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_STUB) += 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 new file mode 100644 index 0000000..a308a0e --- /dev/null +++ b/arch/x86/lib/efi/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2002-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-y += car.o +obj-y += efi.o diff --git a/arch/x86/lib/efi/car.S b/arch/x86/lib/efi/car.S new file mode 100644 index 0000000..6dda058 --- /dev/null +++ b/arch/x86/lib/efi/car.S @@ -0,0 +1,12 @@ +/*
- Copyright (c) 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SPDX-License-Identifier: GPL-2.0+
- */
+.section .text
This is not needed.
Except this nits,
Reviewed-by: Bin Meng bmeng.cn@gmail.com
[snip]
Regards, Bin

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 ---
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..f1c3578 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_ARCH_EFI 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..2052c52 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

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
But please see nits below.
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..f1c3578 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_ARCH_EFI 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..2052c52 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
The above two lines are not indented correctly.
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
--
Regards, Bin

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 ---
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..930eeb8 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

Hi Simon,
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
But please see nits below.
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..930eeb8 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
The above line is not indented correctly.
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
--
Regards, Bin

We cannot use this driver when running from EFI as we have no direct hardware access. 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 ---
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..7a93443 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) {

Hi Simon,
On Wed, 22 Jul 2015 09:49:39 -0600 Simon Glass sjg@chromium.org wrote:
We cannot use this driver when running from EFI as we have no direct hardware access. 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

Hi Simon,
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please see nits below.
On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
We cannot use this driver when running from EFI as we have no direct hardware access. Coreboot uses a different driver which uses tables provided by
coreboot. I don't see any official name with a capital C.
Coreboot. So far it does not seem possible to use a normal video driver when
coreboot
booting from EFI.
Signed-off-by: Simon Glass sjg@chromium.org
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..7a93443 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
coreboot
* 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) {
--
Regards, Bin

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 ---
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..4706602 --- /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_ARCH_EFI. 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.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.efi' to run +the application. 'bios.bin' is the EFI 'BIOS'. + +To try it on real hardware, put u-boot.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.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_ARCH_EFI option controls a few things +that need to change so 'git grep CONFIG_ARCH_EFI' 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

On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass sjg@chromium.org wrote:
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
Well written doc!
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But please check nits below.
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..4706602 --- /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
coreboot
+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
coreboot
+- 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
Can we move 'architecture' one line above, or will it exceed the 80 char limitation?
+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_ARCH_EFI. The efi-x86 config is set up for this.
CONFIG_ARCH_EFI, see my previous comments.
+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.efi - U-Boot EFI application
u-boot-app.efi, see my previous comments.
- 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.efi' to run +the application. 'bios.bin' is the EFI 'BIOS'.
+To try it on real hardware, put u-boot.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.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_ARCH_EFI option controls a few things +that need to change so 'git grep CONFIG_ARCH_EFI' 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
Regards, Bin

Hi Simon,
On Wed, Jul 22, 2015 at 11:48 PM, Simon Glass sjg@chromium.org wrote:
This series allows U-Boot to be built 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.
This is really great work! Thank you.
So far I've finished reviewing the first 33 patch in the series, which covers the u-boot efi application support. After I started to look at the efi payload support whening review patch#34, I came up with another solution[1] to create efi payload which is different from yours. My version does not touch ASFLAGS_REMOVE for u-boot-dtb.o hence I believe it can be easily portable to ARM.
I've tested u-boot.efi on Intel Crown Bay and QEMU, and u-boot-payload.efi on QEMU 64-bit. They work like a charm. It's amazing work!
I will continue reviewing the remaining patches tomorrow.
[1]: http://patchwork.ozlabs.org/patch/499458/
[snip]
Regards, Bin

[trimming the list - wow a lot of people!]
Hi Bin,
On 23 July 2015 at 10:05, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Jul 22, 2015 at 11:48 PM, Simon Glass sjg@chromium.org wrote:
This series allows U-Boot to be built 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.
This is really great work! Thank you.
So far I've finished reviewing the first 33 patch in the series, which covers the u-boot efi application support. After I started to look at the efi payload support whening review patch#34, I came up with another solution[1] to create efi payload which is different from yours. My version does not touch ASFLAGS_REMOVE for u-boot-dtb.o hence I believe it can be easily portable to ARM.
I've tested u-boot.efi on Intel Crown Bay and QEMU, and u-boot-payload.efi on QEMU 64-bit. They work like a charm. It's amazing work!
I will continue reviewing the remaining patches tomorrow.
Thanks very much! I'm pleased you think it is useful. The implementation certainly has opportunities for improvement but I think it's a good solid start.
Also thanks for your reviews, very much appreciated. I know it is a lot of work to go through such a large series, but it will produce a better result with fewer patches!
[snip]
Regards, Bin
Regards, Simon
participants (4)
-
Anatolij Gustschin
-
Bin Meng
-
Pavel Machek
-
Simon Glass