Commit 3dcdd17b43c5cfd3a216169948dfd08d6741c631
Committed by
Simon Glass
1 parent
ed3b4d3736
Exists in
v2017.01-smarct4x
and in
33 other branches
x86: Add support for U-Boot as an EFI application
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>
Showing 11 changed files with 319 additions and 0 deletions Side-by-side Diff
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/cpu/Makefile
| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | |
| 15 | 15 | obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ |
| 16 | 16 | obj-$(CONFIG_SYS_COREBOOT) += coreboot/ |
| 17 | +obj-$(CONFIG_EFI_APP) += efi/ | |
| 17 | 18 | obj-$(CONFIG_QEMU) += qemu/ |
| 18 | 19 | obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ |
| 19 | 20 | obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ |
arch/x86/cpu/efi/Makefile
arch/x86/cpu/efi/efi.c
| 1 | +/* | |
| 2 | + * Copyright (c) 2015 Google, Inc | |
| 3 | + * | |
| 4 | + * SPDX-License-Identifier: GPL-2.0+ | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include <common.h> | |
| 8 | +#include <fdtdec.h> | |
| 9 | +#include <netdev.h> | |
| 10 | + | |
| 11 | +int arch_cpu_init(void) | |
| 12 | +{ | |
| 13 | +#ifdef CONFIG_SYS_X86_TSC_TIMER | |
| 14 | + timer_set_base(rdtsc()); | |
| 15 | +#endif | |
| 16 | + | |
| 17 | + return 0; | |
| 18 | +} | |
| 19 | + | |
| 20 | +int board_early_init_f(void) | |
| 21 | +{ | |
| 22 | + return 0; | |
| 23 | +} | |
| 24 | + | |
| 25 | +int print_cpuinfo(void) | |
| 26 | +{ | |
| 27 | + return default_print_cpuinfo(); | |
| 28 | +} | |
| 29 | + | |
| 30 | +void board_final_cleanup(void) | |
| 31 | +{ | |
| 32 | +} | |
| 33 | + | |
| 34 | +int misc_init_r(void) | |
| 35 | +{ | |
| 36 | + return 0; | |
| 37 | +} | |
| 38 | + | |
| 39 | +int arch_misc_init(void) | |
| 40 | +{ | |
| 41 | + return 0; | |
| 42 | +} |
arch/x86/cpu/efi/elf_ia32_efi.lds
| 1 | +/* | |
| 2 | + * U-Boot EFI linker script | |
| 3 | + * | |
| 4 | + * SPDX-License-Identifier: BSD-2-Clause | |
| 5 | + * | |
| 6 | + * Modified from usr/lib32/elf_ia32_efi.lds in gnu-efi | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <config.h> | |
| 10 | + | |
| 11 | +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") | |
| 12 | +OUTPUT_ARCH(i386) | |
| 13 | +ENTRY(_start) | |
| 14 | +SECTIONS | |
| 15 | +{ | |
| 16 | + image_base = .; | |
| 17 | + .hash : { *(.hash) } /* this MUST come first, EFI expects it */ | |
| 18 | + . = ALIGN(4096); | |
| 19 | + .text : | |
| 20 | + { | |
| 21 | + *(.text) | |
| 22 | + *(.text.*) | |
| 23 | + *(.gnu.linkonce.t.*) | |
| 24 | + } | |
| 25 | + . = ALIGN(4096); | |
| 26 | + .sdata : | |
| 27 | + { | |
| 28 | + *(.got.plt) | |
| 29 | + *(.got) | |
| 30 | + *(.srodata) | |
| 31 | + *(.sdata) | |
| 32 | + *(.sbss) | |
| 33 | + *(.scommon) | |
| 34 | + } | |
| 35 | + . = ALIGN(4096); | |
| 36 | + .data : | |
| 37 | + { | |
| 38 | + *(.rodata*) | |
| 39 | + *(.data) | |
| 40 | + *(.data1) | |
| 41 | + *(.data.*) | |
| 42 | + *(.sdata) | |
| 43 | + *(.got.plt) | |
| 44 | + *(.got) | |
| 45 | + /* | |
| 46 | + * the EFI loader doesn't seem to like a .bss section, so we | |
| 47 | + * stick it all into .data: | |
| 48 | + */ | |
| 49 | + *(.sbss) | |
| 50 | + *(.scommon) | |
| 51 | + *(.dynbss) | |
| 52 | + *(.bss) | |
| 53 | + *(COMMON) | |
| 54 | + | |
| 55 | + /* U-Boot lists and device tree */ | |
| 56 | + . = ALIGN(8); | |
| 57 | + *(SORT(.u_boot_list*)); | |
| 58 | + . = ALIGN(8); | |
| 59 | + *(.dtb*); | |
| 60 | + } | |
| 61 | + | |
| 62 | + . = ALIGN(4096); | |
| 63 | + .dynamic : { *(.dynamic) } | |
| 64 | + . = ALIGN(4096); | |
| 65 | + .rel : | |
| 66 | + { | |
| 67 | + *(.rel.data) | |
| 68 | + *(.rel.data.*) | |
| 69 | + *(.rel.got) | |
| 70 | + *(.rel.stab) | |
| 71 | + *(.data.rel.ro.local) | |
| 72 | + *(.data.rel.local) | |
| 73 | + *(.data.rel.ro) | |
| 74 | + *(.data.rel*) | |
| 75 | + *(.rel.u_boot_list*) | |
| 76 | + } | |
| 77 | + . = ALIGN(4096); | |
| 78 | + .reloc : /* This is the PECOFF .reloc section! */ | |
| 79 | + { | |
| 80 | + *(.reloc) | |
| 81 | + } | |
| 82 | + . = ALIGN(4096); | |
| 83 | + .dynsym : { *(.dynsym) } | |
| 84 | + . = ALIGN(4096); | |
| 85 | + .dynstr : { *(.dynstr) } | |
| 86 | + . = ALIGN(4096); | |
| 87 | + /DISCARD/ : | |
| 88 | + { | |
| 89 | + *(.rel.reloc) | |
| 90 | + *(.eh_frame) | |
| 91 | + *(.note.GNU-stack) | |
| 92 | + } | |
| 93 | + .comment 0 : { *(.comment) } | |
| 94 | +} |
arch/x86/cpu/efi/sdram.c
| 1 | +/* | |
| 2 | + * Copyright (c) 2015 Google, Inc | |
| 3 | + * | |
| 4 | + * SPDX-License-Identifier: GPL-2.0+ | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include <common.h> | |
| 8 | +#include <efi.h> | |
| 9 | +#include <asm/u-boot-x86.h> | |
| 10 | + | |
| 11 | +DECLARE_GLOBAL_DATA_PTR; | |
| 12 | + | |
| 13 | +ulong board_get_usable_ram_top(ulong total_size) | |
| 14 | +{ | |
| 15 | + return (ulong)efi_get_ram_base() + gd->ram_size; | |
| 16 | +} | |
| 17 | + | |
| 18 | +int dram_init(void) | |
| 19 | +{ | |
| 20 | + /* gd->ram_size is set as part of EFI init */ | |
| 21 | + | |
| 22 | + return 0; | |
| 23 | +} | |
| 24 | + | |
| 25 | +void dram_init_banksize(void) | |
| 26 | +{ | |
| 27 | + gd->bd->bi_dram[0].start = efi_get_ram_base(); | |
| 28 | + gd->bd->bi_dram[0].size = CONFIG_EFI_RAM_SIZE; | |
| 29 | +} |
arch/x86/cpu/interrupts.c
| ... | ... | @@ -242,6 +242,11 @@ |
| 242 | 242 | |
| 243 | 243 | int interrupt_init(void) |
| 244 | 244 | { |
| 245 | + /* | |
| 246 | + * When running as an EFI application we are not in control of | |
| 247 | + * interrupts and should leave them alone. | |
| 248 | + */ | |
| 249 | +#ifndef CONFIG_EFI_APP | |
| 245 | 250 | /* Just in case... */ |
| 246 | 251 | disable_interrupts(); |
| 247 | 252 | |
| ... | ... | @@ -255,6 +260,7 @@ |
| 255 | 260 | |
| 256 | 261 | /* It is now safe to enable interrupts */ |
| 257 | 262 | enable_interrupts(); |
| 263 | +#endif | |
| 258 | 264 | |
| 259 | 265 | return 0; |
| 260 | 266 | } |
arch/x86/include/asm/arch-efi/gpio.h
arch/x86/lib/efi/crt0-efi-ia32.S
| 1 | +/* | |
| 2 | + * crt0-efi-ia32.S - x86 EFI startup code. | |
| 3 | + * | |
| 4 | + * Copyright (C) 1999 Hewlett-Packard Co. | |
| 5 | + * Contributed by David Mosberger <davidm@hpl.hp.com>. | |
| 6 | + * All rights reserved. | |
| 7 | + * | |
| 8 | + * SPDX-License-Identifier: BSD-3-Clause | |
| 9 | + */ | |
| 10 | + | |
| 11 | + .text | |
| 12 | + .align 4 | |
| 13 | + | |
| 14 | + .globl _start | |
| 15 | +_start: | |
| 16 | + pushl %ebp | |
| 17 | + movl %esp,%ebp | |
| 18 | + | |
| 19 | + pushl 12(%ebp) # copy "image" argument | |
| 20 | + pushl 8(%ebp) # copy "systab" argument | |
| 21 | + | |
| 22 | + call 0f | |
| 23 | +0: popl %eax | |
| 24 | + movl %eax,%ebx | |
| 25 | + | |
| 26 | + addl $image_base-0b,%eax # %eax = ldbase | |
| 27 | + addl $_DYNAMIC-0b,%ebx # %ebx = _DYNAMIC | |
| 28 | + | |
| 29 | + pushl %ebx # pass _DYNAMIC as second argument | |
| 30 | + pushl %eax # pass ldbase as first argument | |
| 31 | + call _relocate | |
| 32 | + popl %ebx | |
| 33 | + popl %ebx | |
| 34 | + testl %eax,%eax | |
| 35 | + jne .exit | |
| 36 | + call efi_main # call app with "image" and "systab" argument | |
| 37 | + | |
| 38 | +.exit: leave | |
| 39 | + ret | |
| 40 | + | |
| 41 | + /* | |
| 42 | + * hand-craft a dummy .reloc section so EFI knows it's a relocatable | |
| 43 | + * executable: | |
| 44 | + */ | |
| 45 | + .data | |
| 46 | +dummy: .long 0 | |
| 47 | + | |
| 48 | +#define IMAGE_REL_ABSOLUTE 0 | |
| 49 | + .section .reloc | |
| 50 | + .long dummy /* Page RVA */ | |
| 51 | + .long 10 /* Block Size (2*4+2) */ | |
| 52 | + .word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */ |
arch/x86/lib/efi/reloc_ia32.c
| 1 | +/* | |
| 2 | + * reloc_ia32.c - position independent x86 ELF shared object relocator | |
| 3 | + * Copyright (C) 1999 Hewlett-Packard Co. | |
| 4 | + * Contributed by David Mosberger <davidm@hpl.hp.com>. | |
| 5 | + * | |
| 6 | + * All rights reserved. | |
| 7 | + * | |
| 8 | + * SPDX-License-Identifier: BSD-3-Clause | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#include <common.h> | |
| 12 | +#include <efi.h> | |
| 13 | +#include <elf.h> | |
| 14 | +#include <asm/elf.h> | |
| 15 | + | |
| 16 | +efi_status_t _relocate(long ldbase, Elf32_Dyn *dyn, efi_handle_t image, | |
| 17 | + struct efi_system_table *systab) | |
| 18 | +{ | |
| 19 | + long relsz = 0, relent = 0; | |
| 20 | + Elf32_Rel *rel = 0; | |
| 21 | + unsigned long *addr; | |
| 22 | + int i; | |
| 23 | + | |
| 24 | + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { | |
| 25 | + switch (dyn[i].d_tag) { | |
| 26 | + case DT_REL: | |
| 27 | + rel = (Elf32_Rel *)((unsigned long)dyn[i].d_un.d_ptr + | |
| 28 | + ldbase); | |
| 29 | + break; | |
| 30 | + | |
| 31 | + case DT_RELSZ: | |
| 32 | + relsz = dyn[i].d_un.d_val; | |
| 33 | + break; | |
| 34 | + | |
| 35 | + case DT_RELENT: | |
| 36 | + relent = dyn[i].d_un.d_val; | |
| 37 | + break; | |
| 38 | + | |
| 39 | + case DT_RELA: | |
| 40 | + break; | |
| 41 | + | |
| 42 | + default: | |
| 43 | + break; | |
| 44 | + } | |
| 45 | + } | |
| 46 | + | |
| 47 | + if (!rel && relent == 0) | |
| 48 | + return EFI_SUCCESS; | |
| 49 | + | |
| 50 | + if (!rel || relent == 0) | |
| 51 | + return EFI_LOAD_ERROR; | |
| 52 | + | |
| 53 | + while (relsz > 0) { | |
| 54 | + /* apply the relocs */ | |
| 55 | + switch (ELF32_R_TYPE(rel->r_info)) { | |
| 56 | + case R_386_NONE: | |
| 57 | + break; | |
| 58 | + | |
| 59 | + case R_386_RELATIVE: | |
| 60 | + addr = (unsigned long *)(ldbase + rel->r_offset); | |
| 61 | + *addr += ldbase; | |
| 62 | + break; | |
| 63 | + | |
| 64 | + default: | |
| 65 | + break; | |
| 66 | + } | |
| 67 | + rel = (Elf32_Rel *)((char *)rel + relent); | |
| 68 | + relsz -= relent; | |
| 69 | + } | |
| 70 | + | |
| 71 | + return EFI_SUCCESS; | |
| 72 | +} |