summaryrefslogtreecommitdiff
path: root/arch/x86/lib/efi
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/lib/efi')
-rw-r--r--arch/x86/lib/efi/Kconfig11
-rw-r--r--arch/x86/lib/efi/Makefile27
-rw-r--r--arch/x86/lib/efi/car.S10
-rw-r--r--arch/x86/lib/efi/crt0-efi-ia32.S52
-rw-r--r--arch/x86/lib/efi/crt0-efi-x86_64.S51
-rw-r--r--arch/x86/lib/efi/efi.c151
-rw-r--r--arch/x86/lib/efi/reloc_ia32.c72
-rw-r--r--arch/x86/lib/efi/reloc_x86_64.c66
8 files changed, 440 insertions, 0 deletions
diff --git a/arch/x86/lib/efi/Kconfig b/arch/x86/lib/efi/Kconfig
new file mode 100644
index 0000000000..e0975d34d3
--- /dev/null
+++ b/arch/x86/lib/efi/Kconfig
@@ -0,0 +1,11 @@
+if EFI
+
+config SYS_CAR_ADDR
+ hex
+ default 0x100000
+
+config SYS_CAR_SIZE
+ hex
+ default 0x20000
+
+endif
diff --git a/arch/x86/lib/efi/Makefile b/arch/x86/lib/efi/Makefile
new file mode 100644
index 0000000000..af4503e1c2
--- /dev/null
+++ b/arch/x86/lib/efi/Makefile
@@ -0,0 +1,27 @@
+#
+# (C) Copyright 2002-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_EFI_STUB) += car.o
+obj-$(CONFIG_EFI_STUB) += efi.o
+
+obj-$(CONFIG_EFI_APP) += crt0-efi-ia32.o reloc_ia32.o
+
+ifneq ($(CONFIG_EFI_STUB),)
+
+CFLAGS_REMOVE_reloc_ia32.o += -mregparm=3
+CFLAGS_reloc_ia32.o += -fpic -fshort-wchar
+
+# When building for 64-bit we must remove the i386-specific flags
+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
diff --git a/arch/x86/lib/efi/car.S b/arch/x86/lib/efi/car.S
new file mode 100644
index 0000000000..613af9ac8a
--- /dev/null
+++ b/arch/x86/lib/efi/car.S
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+.globl car_init
+car_init:
+ jmp car_init_ret
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 0000000000..30e5eb0c1a
--- /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@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/crt0-efi-x86_64.S b/arch/x86/lib/efi/crt0-efi-x86_64.S
new file mode 100644
index 0000000000..c5cbf4108b
--- /dev/null
+++ b/arch/x86/lib/efi/crt0-efi-x86_64.S
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ .text
+ .align 4
+
+ .globl _start
+_start:
+ subq $8, %rsp
+ pushq %rcx
+ pushq %rdx
+
+0:
+ lea image_base(%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/efi/efi.c b/arch/x86/lib/efi/efi.c
new file mode 100644
index 0000000000..ede5d5676b
--- /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;
+}
diff --git a/arch/x86/lib/efi/reloc_ia32.c b/arch/x86/lib/efi/reloc_ia32.c
new file mode 100644
index 0000000000..4d6825515d
--- /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@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;
+}
diff --git a/arch/x86/lib/efi/reloc_x86_64.c b/arch/x86/lib/efi/reloc_x86_64.c
new file mode 100644
index 0000000000..5f71f2ac8a
--- /dev/null
+++ b/arch/x86/lib/efi/reloc_x86_64.c
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ *
+ * 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, Elf64_Dyn *dyn, efi_handle_t image,
+ struct efi_system_table *systab)
+{
+ long relsz = 0, relent = 0;
+ 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 = (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 = (Elf64_Rel *)((char *)rel + relent);
+ relsz -= relent;
+ }
+
+ return EFI_SUCCESS;
+}