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