x86: Add support for U-Boot as an EFI application
authorBen Stoltz <stoltz@google.com>
Tue, 4 Aug 2015 18:33:46 +0000 (12:33 -0600)
committerSimon Glass <sjg@chromium.org>
Wed, 5 Aug 2015 14:44:06 +0000 (08:44 -0600)
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>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/cpu/Makefile
arch/x86/cpu/efi/Makefile [new file with mode: 0644]
arch/x86/cpu/efi/efi.c [new file with mode: 0644]
arch/x86/cpu/efi/elf_ia32_efi.lds [new file with mode: 0644]
arch/x86/cpu/efi/sdram.c [new file with mode: 0644]
arch/x86/cpu/interrupts.c
arch/x86/include/asm/arch-efi/gpio.h [new file with mode: 0644]
arch/x86/lib/efi/crt0-efi-ia32.S [new file with mode: 0644]
arch/x86/lib/efi/reloc_ia32.c [new file with mode: 0644]

index e8968a7182bbcbc0b64722b4667b97fcc7c00ac4..7e6e89c23176b1e10cbcfbece6bb9581adc2afc0 100644 (file)
@@ -11,6 +11,9 @@ choice
 config VENDOR_COREBOOT
        bool "coreboot"
 
+config VENDOR_EFI
+       bool "efi"
+
 config VENDOR_EMULATION
        bool "emulation"
 
index 36a601822a204c476be6f129e2c810498763c765..d104a497301dd3e41b828a03beda6178e40fbae8 100644 (file)
@@ -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
index 8a8e63e1d3d1c270ec39aa592a9eaac86eb28df9..5e058c0c097849a001b23dfc42479cfc2486c35b 100644 (file)
@@ -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 (file)
index 0000000..e091637
--- /dev/null
@@ -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 (file)
index 0000000..75ba0d4
--- /dev/null
@@ -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 (file)
index 0000000..cd3b0a9
--- /dev/null
@@ -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 (file)
index 0000000..5159944
--- /dev/null
@@ -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;
+}
index 3a9c2d478363c697bd0f0babdd1593f4027d9b6a..a1129384e2e31809d797cb9bb7bf4d2d9a5b1835 100644 (file)
@@ -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 (file)
index 0000000..f044f07
--- /dev/null
@@ -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 (file)
index 0000000..30e5eb0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * crt0-efi-ia32.S - x86 EFI startup code.
+ *
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:    BSD-3-Clause
+ */
+
+       .text
+       .align 4
+
+       .globl _start
+_start:
+       pushl %ebp
+       movl %esp,%ebp
+
+       pushl 12(%ebp)                  # copy "image" argument
+       pushl  8(%ebp)                  # copy "systab" argument
+
+       call 0f
+0:     popl %eax
+       movl %eax,%ebx
+
+       addl $image_base-0b,%eax        # %eax = ldbase
+       addl $_DYNAMIC-0b,%ebx          # %ebx = _DYNAMIC
+
+       pushl %ebx                      # pass _DYNAMIC as second argument
+       pushl %eax                      # pass ldbase as first argument
+       call _relocate
+       popl %ebx
+       popl %ebx
+       testl %eax,%eax
+       jne .exit
+       call efi_main           # call app with "image" and "systab" argument
+
+.exit: leave
+       ret
+
+       /*
+        * hand-craft a dummy .reloc section so EFI knows it's a relocatable
+        * executable:
+        */
+       .data
+dummy: .long   0
+
+#define IMAGE_REL_ABSOLUTE     0
+       .section .reloc
+       .long   dummy                                   /* Page RVA */
+       .long   10                                      /* Block Size (2*4+2) */
+       .word   (IMAGE_REL_ABSOLUTE << 12) +  0         /* reloc for dummy */
diff --git a/arch/x86/lib/efi/reloc_ia32.c b/arch/x86/lib/efi/reloc_ia32.c
new file mode 100644 (file)
index 0000000..4d68255
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * reloc_ia32.c - position independent x86 ELF shared object relocator
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ *
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:    BSD-3-Clause
+ */
+
+#include <common.h>
+#include <efi.h>
+#include <elf.h>
+#include <asm/elf.h>
+
+efi_status_t _relocate(long ldbase, Elf32_Dyn *dyn, efi_handle_t image,
+                      struct efi_system_table *systab)
+{
+       long relsz = 0, relent = 0;
+       Elf32_Rel *rel = 0;
+       unsigned long *addr;
+       int i;
+
+       for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
+               switch (dyn[i].d_tag) {
+               case DT_REL:
+                       rel = (Elf32_Rel *)((unsigned long)dyn[i].d_un.d_ptr +
+                                                               ldbase);
+                       break;
+
+               case DT_RELSZ:
+                       relsz = dyn[i].d_un.d_val;
+                       break;
+
+               case DT_RELENT:
+                       relent = dyn[i].d_un.d_val;
+                       break;
+
+               case DT_RELA:
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       if (!rel && relent == 0)
+               return EFI_SUCCESS;
+
+       if (!rel || relent == 0)
+               return EFI_LOAD_ERROR;
+
+       while (relsz > 0) {
+               /* apply the relocs */
+               switch (ELF32_R_TYPE(rel->r_info)) {
+               case R_386_NONE:
+                       break;
+
+               case R_386_RELATIVE:
+                       addr = (unsigned long *)(ldbase + rel->r_offset);
+                       *addr += ldbase;
+                       break;
+
+               default:
+                       break;
+               }
+               rel = (Elf32_Rel *)((char *)rel + relent);
+               relsz -= relent;
+       }
+
+       return EFI_SUCCESS;
+}