[U-Boot] [PATCH v3 08/28] x86: Add support for U-Boot as an EFI application

Bin Meng bmeng.cn at gmail.com
Wed Aug 5 09:42:20 CEST 2015


On Wed, Aug 5, 2015 at 2:33 AM, Simon Glass <sjg at chromium.org> wrote:
> 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 v3:
> - Move u-boot-app.efi Makefile change to the earlier patch
> - Use "BSD-2-Clause" for the SPDX license
>
> 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
>
>  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 +++++++++++++++++++++++++++
>  11 files changed, 319 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/efi/crt0-efi-ia32.S
>  create mode 100644 arch/x86/lib/efi/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..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..cd3b0a9
> --- /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;
> +}
> --

Reviewed-by: Bin Meng <bmeng.cn at gmail.com>


More information about the U-Boot mailing list