SHA256
1
0
forked from pool/u-boot
u-boot/efi.patch

5576 lines
159 KiB
Diff
Raw Normal View History

diff --git a/MAINTAINERS b/MAINTAINERS
index 9d447ea..32f97b2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -230,6 +230,13 @@ F: drivers/core/
F: include/dm/
F: test/dm/
+EFI PAYLOAD
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: include/efi_loader.h
+F: lib/efi_loader/
+F: cmd/bootefi.c
+
FLATTENED DEVICE TREE
M: Simon Glass <sjg@chromium.org>
S: Maintained
diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index 8fa57ec..9af6c37 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -122,6 +122,10 @@ ifdef CONFIG_OF_EMBED
OBJCOPYFLAGS += -j .dtb.init.rodata
endif
+ifdef CONFIG_EFI_LOADER
+OBJCOPYFLAGS += -j .efi_runtime -j .efi_runtime_rel
+endif
+
ifneq ($(CONFIG_IMX_CONFIG),)
ifdef CONFIG_SPL
ifndef CONFIG_SPL_BUILD
diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S
index ab8c089..a9f4fec 100644
--- a/arch/arm/cpu/armv8/cache.S
+++ b/arch/arm/cpu/armv8/cache.S
@@ -10,6 +10,7 @@
#include <asm-offsets.h>
#include <config.h>
#include <asm/macro.h>
+#include <asm/system.h>
#include <linux/linkage.h>
/*
@@ -160,3 +161,56 @@ ENTRY(__asm_flush_l3_cache)
ret
ENDPROC(__asm_flush_l3_cache)
.weak __asm_flush_l3_cache
+
+/*
+ * void __asm_switch_ttbr(ulong new_ttbr)
+ *
+ * Safely switches to a new page table.
+ */
+ENTRY(__asm_switch_ttbr)
+ /* x2 = SCTLR (alive throghout the function) */
+ switch_el x4, 3f, 2f, 1f
+3: mrs x2, sctlr_el3
+ b 0f
+2: mrs x2, sctlr_el2
+ b 0f
+1: mrs x2, sctlr_el1
+0:
+
+ /* Unset CR_M | CR_C | CR_I from SCTLR to disable all caches */
+ movn x1, #(CR_M | CR_C | CR_I)
+ and x1, x2, x1
+ switch_el x4, 3f, 2f, 1f
+3: msr sctlr_el3, x1
+ b 0f
+2: msr sctlr_el2, x1
+ b 0f
+1: msr sctlr_el1, x1
+0: isb
+
+ /* This call only clobbers x30 (lr) and x9 (unused) */
+ mov x3, x30
+ bl __asm_invalidate_tlb_all
+
+ /* From here on we're running safely with caches disabled */
+
+ /* Set TTBR to our first argument */
+ switch_el x4, 3f, 2f, 1f
+3: msr ttbr0_el3, x0
+ b 0f
+2: msr ttbr0_el2, x0
+ b 0f
+1: msr ttbr0_el1, x0
+0: isb
+
+ /* Restore original SCTLR and thus enable caches again */
+ switch_el x4, 3f, 2f, 1f
+3: msr sctlr_el3, x2
+ b 0f
+2: msr sctlr_el2, x2
+ b 0f
+1: msr sctlr_el1, x2
+0: isb
+
+ ret x3
+ENDPROC(__asm_switch_ttbr)
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index 71f0020..d1bd06b 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -2,6 +2,9 @@
* (C) Copyright 2013
* David Feng <fenghua@phytium.com.cn>
*
+ * (C) Copyright 2016
+ * Alexander Graf <agraf@suse.de>
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -13,137 +16,388 @@ DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_SYS_DCACHE_OFF
-#ifdef CONFIG_SYS_FULL_VA
-static void set_ptl1_entry(u64 index, u64 ptl2_entry)
+/*
+ * With 4k page granule, a virtual address is split into 4 lookup parts
+ * spanning 9 bits each:
+ *
+ * _______________________________________________
+ * | | | | | | |
+ * | 0 | Lv0 | Lv1 | Lv2 | Lv3 | off |
+ * |_______|_______|_______|_______|_______|_______|
+ * 63-48 47-39 38-30 29-21 20-12 11-00
+ *
+ * mask page size
+ *
+ * Lv0: FF8000000000 --
+ * Lv1: 7FC0000000 1G
+ * Lv2: 3FE00000 2M
+ * Lv3: 1FF000 4K
+ * off: FFF
+ */
+
+static u64 get_tcr(int el, u64 *pips, u64 *pva_bits)
{
- u64 *pgd = (u64 *)gd->arch.tlb_addr;
- u64 value;
+ u64 max_addr = 0;
+ u64 ips, va_bits;
+ u64 tcr;
+ int i;
+
+ /* Find the largest address we need to support */
+ for (i = 0; mem_map[i].size || mem_map[i].attrs; i++)
+ max_addr = max(max_addr, mem_map[i].base + mem_map[i].size);
+
+ /* Calculate the maximum physical (and thus virtual) address */
+ if (max_addr > (1ULL << 44)) {
+ ips = 5;
+ va_bits = 48;
+ } else if (max_addr > (1ULL << 42)) {
+ ips = 4;
+ va_bits = 44;
+ } else if (max_addr > (1ULL << 40)) {
+ ips = 3;
+ va_bits = 42;
+ } else if (max_addr > (1ULL << 36)) {
+ ips = 2;
+ va_bits = 40;
+ } else if (max_addr > (1ULL << 32)) {
+ ips = 1;
+ va_bits = 36;
+ } else {
+ ips = 0;
+ va_bits = 32;
+ }
+
+ if (el == 1) {
+ tcr = TCR_EL1_RSVD | (ips << 32) | TCR_EPD1_DISABLE;
+ } else if (el == 2) {
+ tcr = TCR_EL2_RSVD | (ips << 16);
+ } else {
+ tcr = TCR_EL3_RSVD | (ips << 16);
+ }
- value = ptl2_entry | PTL1_TYPE_TABLE;
- pgd[index] = value;
+ /* PTWs cacheable, inner/outer WBWA and inner shareable */
+ tcr |= TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA;
+ tcr |= TCR_T0SZ(va_bits);
+
+ if (pips)
+ *pips = ips;
+ if (pva_bits)
+ *pva_bits = va_bits;
+
+ return tcr;
}
-static void set_ptl2_block(u64 ptl1, u64 bfn, u64 address, u64 memory_attrs)
+#define MAX_PTE_ENTRIES 512
+
+static int pte_type(u64 *pte)
{
- u64 *pmd = (u64 *)ptl1;
- u64 value;
+ return *pte & PTE_TYPE_MASK;
+}
- value = address | PTL2_TYPE_BLOCK | PTL2_BLOCK_AF;
- value |= memory_attrs;
- pmd[bfn] = value;
+/* Returns the LSB number for a PTE on level <level> */
+static int level2shift(int level)
+{
+ /* Page is 12 bits wide, every level translates 9 bits */
+ return (12 + 9 * (3 - level));
}
-static struct mm_region mem_map[] = CONFIG_SYS_MEM_MAP;
+static u64 *find_pte(u64 addr, int level)
+{
+ int start_level = 0;
+ u64 *pte;
+ u64 idx;
+ u64 va_bits;
+ int i;
+
+ debug("addr=%llx level=%d\n", addr, level);
+
+ get_tcr(0, NULL, &va_bits);
+ if (va_bits < 39)
+ start_level = 1;
+
+ if (level < start_level)
+ return NULL;
+
+ /* Walk through all page table levels to find our PTE */
+ pte = (u64*)gd->arch.tlb_addr;
+ for (i = start_level; i < 4; i++) {
+ idx = (addr >> level2shift(i)) & 0x1FF;
+ pte += idx;
+ debug("idx=%llx PTE %p at level %d: %llx\n", idx, pte, i, *pte);
+
+ /* Found it */
+ if (i == level)
+ return pte;
+ /* PTE is no table (either invalid or block), can't traverse */
+ if (pte_type(pte) != PTE_TYPE_TABLE)
+ return NULL;
+ /* Off to the next level */
+ pte = (u64*)(*pte & 0x0000fffffffff000ULL);
+ }
-#define PTL1_ENTRIES CONFIG_SYS_PTL1_ENTRIES
-#define PTL2_ENTRIES CONFIG_SYS_PTL2_ENTRIES
+ /* Should never reach here */
+ return NULL;
+}
-static void setup_pgtables(void)
+/* Returns and creates a new full table (512 entries) */
+static u64 *create_table(void)
{
- int l1_e, l2_e;
- unsigned long pmd = 0;
- unsigned long address;
-
- /* Setup the PMD pointers */
- for (l1_e = 0; l1_e < CONFIG_SYS_MEM_MAP_SIZE; l1_e++) {
- gd->arch.pmd_addr[l1_e] = gd->arch.tlb_addr +
- PTL1_ENTRIES * sizeof(u64);
- gd->arch.pmd_addr[l1_e] += PTL2_ENTRIES * sizeof(u64) * l1_e;
- gd->arch.pmd_addr[l1_e] = ALIGN(gd->arch.pmd_addr[l1_e],
- 0x10000UL);
+ u64 *new_table = (u64*)gd->arch.tlb_fillptr;
+ u64 pt_len = MAX_PTE_ENTRIES * sizeof(u64);
+
+ /* Allocate MAX_PTE_ENTRIES pte entries */
+ gd->arch.tlb_fillptr += pt_len;
+
+ if (gd->arch.tlb_fillptr - gd->arch.tlb_addr > gd->arch.tlb_size)
+ panic("Insufficient RAM for page table: 0x%lx > 0x%lx. "
+ "Please increase the size in get_page_table_size()",
+ gd->arch.tlb_fillptr - gd->arch.tlb_addr,
+ gd->arch.tlb_size);
+
+ /* Mark all entries as invalid */
+ memset(new_table, 0, pt_len);
+
+ return new_table;
+}
+
+static void set_pte_table(u64 *pte, u64 *table)
+{
+ /* Point *pte to the new table */
+ debug("Setting %p to addr=%p\n", pte, table);
+ *pte = PTE_TYPE_TABLE | (ulong)table;
+}
+
+/* Add one mm_region map entry to the page tables */
+static void add_map(struct mm_region *map)
+{
+ u64 *pte;
+ u64 addr = map->base;
+ u64 size = map->size;
+ u64 attrs = map->attrs | PTE_TYPE_BLOCK | PTE_BLOCK_AF;
+ u64 blocksize;
+ int level;
+ u64 *new_table;
+
+ while (size) {
+ pte = find_pte(addr, 0);
+ if (pte && (pte_type(pte) == PTE_TYPE_FAULT)) {
+ debug("Creating table for addr 0x%llx\n", addr);
+ new_table = create_table();
+ set_pte_table(pte, new_table);
+ }
+
+ for (level = 1; level < 4; level++) {
+ pte = find_pte(addr, level);
+ blocksize = 1ULL << level2shift(level);
+ debug("Checking if pte fits for addr=%llx size=%llx "
+ "blocksize=%llx\n", addr, size, blocksize);
+ if (size >= blocksize && !(addr & (blocksize - 1))) {
+ /* Page fits, create block PTE */
+ debug("Setting PTE %p to block addr=%llx\n",
+ pte, addr);
+ *pte = addr | attrs;
+ addr += blocksize;
+ size -= blocksize;
+ break;
+ } else if ((pte_type(pte) == PTE_TYPE_FAULT)) {
+ /* Page doesn't fit, create subpages */
+ debug("Creating subtable for addr 0x%llx "
+ "blksize=%llx\n", addr, blocksize);
+ new_table = create_table();
+ set_pte_table(pte, new_table);
+ }
+ }
+ }
+}
+
+/* Splits a block PTE into table with subpages spanning the old block */
+static void split_block(u64 *pte, int level)
+{
+ u64 old_pte = *pte;
+ u64 *new_table;
+ u64 i = 0;
+ /* level describes the parent level, we need the child ones */
+ int levelshift = level2shift(level + 1);
+
+ if (pte_type(pte) != PTE_TYPE_BLOCK)
+ panic("PTE %p (%llx) is not a block. Some driver code wants to "
+ "modify dcache settings for an range not covered in "
+ "mem_map.", pte, old_pte);
+
+ new_table = create_table();
+ debug("Splitting pte %p (%llx) into %p\n", pte, old_pte, new_table);
+
+ for (i = 0; i < MAX_PTE_ENTRIES; i++) {
+ new_table[i] = old_pte | (i << levelshift);
+
+ /* Level 3 block PTEs have the table type */
+ if ((level + 1) == 3)
+ new_table[i] |= PTE_TYPE_TABLE;
+
+ debug("Setting new_table[%lld] = %llx\n", i, new_table[i]);
}
- /* Setup the page tables */
- for (l1_e = 0; l1_e < PTL1_ENTRIES; l1_e++) {
- if (mem_map[pmd].base ==
- (uintptr_t)l1_e << PTL2_BITS) {
- set_ptl1_entry(l1_e, gd->arch.pmd_addr[pmd]);
-
- for (l2_e = 0; l2_e < PTL2_ENTRIES; l2_e++) {
- address = mem_map[pmd].base
- + (uintptr_t)l2_e * BLOCK_SIZE;
- set_ptl2_block(gd->arch.pmd_addr[pmd], l2_e,
- address, mem_map[pmd].attrs);
+ /* Set the new table into effect */
+ set_pte_table(pte, new_table);
+}
+
+enum pte_type {
+ PTE_INVAL,
+ PTE_BLOCK,
+ PTE_LEVEL,
+};
+
+/*
+ * This is a recursively called function to count the number of
+ * page tables we need to cover a particular PTE range. If you
+ * call this with level = -1 you basically get the full 48 bit
+ * coverage.
+ */
+static int count_required_pts(u64 addr, int level, u64 maxaddr)
+{
+ int levelshift = level2shift(level);
+ u64 levelsize = 1ULL << levelshift;
+ u64 levelmask = levelsize - 1;
+ u64 levelend = addr + levelsize;
+ int r = 0;
+ int i;
+ enum pte_type pte_type = PTE_INVAL;
+
+ for (i = 0; mem_map[i].size || mem_map[i].attrs; i++) {
+ struct mm_region *map = &mem_map[i];
+ u64 start = map->base;
+ u64 end = start + map->size;
+
+ /* Check if the PTE would overlap with the map */
+ if (max(addr, start) <= min(levelend, end)) {
+ start = max(addr, start);
+ end = min(levelend, end);
+
+ /* We need a sub-pt for this level */
+ if ((start & levelmask) || (end & levelmask)) {
+ pte_type = PTE_LEVEL;
+ break;
}
- pmd++;
- } else {
- set_ptl1_entry(l1_e, 0);
+ /* Lv0 can not do block PTEs, so do levels here too */
+ if (level <= 0) {
+ pte_type = PTE_LEVEL;
+ break;
+ }
+
+ /* PTE is active, but fits into a block */
+ pte_type = PTE_BLOCK;
}
}
+
+ /*
+ * Block PTEs at this level are already covered by the parent page
+ * table, so we only need to count sub page tables.
+ */
+ if (pte_type == PTE_LEVEL) {
+ int sublevel = level + 1;
+ u64 sublevelsize = 1ULL << level2shift(sublevel);
+
+ /* Account for the new sub page table ... */
+ r = 1;
+
+ /* ... and for all child page tables that one might have */
+ for (i = 0; i < MAX_PTE_ENTRIES; i++) {
+ r += count_required_pts(addr, sublevel, maxaddr);
+ addr += sublevelsize;
+
+ if (addr >= maxaddr) {
+ /*
+ * We reached the end of address space, no need
+ * to look any further.
+ */
+ break;
+ }
+ }
+ }
+
+ return r;
}
-#else
+/* Returns the estimated required size of all page tables */
+u64 get_page_table_size(void)
+{
+ u64 one_pt = MAX_PTE_ENTRIES * sizeof(u64);
+ u64 size = 0;
+ u64 va_bits;
+ int start_level = 0;
+
+ get_tcr(0, NULL, &va_bits);
+ if (va_bits < 39)
+ start_level = 1;
+
+ /* Account for all page tables we would need to cover our memory map */
+ size = one_pt * count_required_pts(0, start_level - 1, 1ULL << va_bits);
+
+ /*
+ * We need to duplicate our page table once to have an emergency pt to
+ * resort to when splitting page tables later on
+ */
+ size *= 2;
+
+ /*
+ * We may need to split page tables later on if dcache settings change,
+ * so reserve up to 4 (random pick) page tables for that.
+ */
+ size += one_pt * 4;
+
+ return size;
+}
-inline void set_pgtable_section(u64 *page_table, u64 index, u64 section,
- u64 memory_type, u64 attribute)
+static void setup_pgtables(void)
{
- u64 value;
+ int i;
- value = section | PMD_TYPE_SECT | PMD_SECT_AF;
- value |= PMD_ATTRINDX(memory_type);
- value |= attribute;
- page_table[index] = value;
+ /*
+ * Allocate the first level we're on with invalidate entries.
+ * If the starting level is 0 (va_bits >= 39), then this is our
+ * Lv0 page table, otherwise it's the entry Lv1 page table.
+ */
+ create_table();
+
+ /* Now add all MMU table entries one after another to the table */
+ for (i = 0; mem_map[i].size || mem_map[i].attrs; i++)
+ add_map(&mem_map[i]);
+
+ /* Create the same thing once more for our emergency page table */
+ create_table();
}
-inline void set_pgtable_table(u64 *page_table, u64 index, u64 *table_addr)
+static void setup_all_pgtables(void)
{
- u64 value;
+ u64 tlb_addr = gd->arch.tlb_addr;
+
+ /* Reset the fill ptr */
+ gd->arch.tlb_fillptr = tlb_addr;
- value = (u64)table_addr | PMD_TYPE_TABLE;
- page_table[index] = value;
+ /* Create normal system page tables */
+ setup_pgtables();
+
+ /* Create emergency page tables */
+ gd->arch.tlb_addr = gd->arch.tlb_fillptr;
+ setup_pgtables();
+ gd->arch.tlb_emerg = gd->arch.tlb_addr;
+ gd->arch.tlb_addr = tlb_addr;
}
-#endif
/* to activate the MMU we need to set up virtual memory */
__weak void mmu_setup(void)
{
-#ifndef CONFIG_SYS_FULL_VA
- bd_t *bd = gd->bd;
- u64 *page_table = (u64 *)gd->arch.tlb_addr, i, j;
-#endif
int el;
-#ifdef CONFIG_SYS_FULL_VA
- unsigned long coreid = read_mpidr() & CONFIG_COREID_MASK;
-
- /* Set up page tables only on BSP */
- if (coreid == BSP_COREID)
- setup_pgtables();
-#else
- /* Setup an identity-mapping for all spaces */
- for (i = 0; i < (PGTABLE_SIZE >> 3); i++) {
- set_pgtable_section(page_table, i, i << SECTION_SHIFT,
- MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE);
- }
-
- /* Setup an identity-mapping for all RAM space */
- for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
- ulong start = bd->bi_dram[i].start;
- ulong end = bd->bi_dram[i].start + bd->bi_dram[i].size;
- for (j = start >> SECTION_SHIFT;
- j < end >> SECTION_SHIFT; j++) {
- set_pgtable_section(page_table, j, j << SECTION_SHIFT,
- MT_NORMAL, PMD_SECT_NON_SHARE);
- }
- }
+ /* Set up page tables only once */
+ if (!gd->arch.tlb_fillptr)
+ setup_all_pgtables();
-#endif
- /* load TTBR0 */
el = current_el();
- if (el == 1) {
- set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
- TCR_EL1_RSVD | TCR_FLAGS | TCR_EL1_IPS_BITS,
- MEMORY_ATTRIBUTES);
- } else if (el == 2) {
- set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
- TCR_EL2_RSVD | TCR_FLAGS | TCR_EL2_IPS_BITS,
- MEMORY_ATTRIBUTES);
- } else {
- set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
- TCR_EL3_RSVD | TCR_FLAGS | TCR_EL3_IPS_BITS,
- MEMORY_ATTRIBUTES);
- }
+ set_ttbr_tcr_mair(el, gd->arch.tlb_addr, get_tcr(el, NULL, NULL),
+ MEMORY_ATTRIBUTES);
+
/* enable the mmu */
set_sctlr(get_sctlr() | CR_M);
}
@@ -228,36 +482,99 @@ u64 *__weak arch_get_page_table(void) {
return NULL;
}
-#ifndef CONFIG_SYS_FULL_VA
+static bool is_aligned(u64 addr, u64 size, u64 align)
+{
+ return !(addr & (align - 1)) && !(size & (align - 1));
+}
+
+static u64 set_one_region(u64 start, u64 size, u64 attrs, int level)
+{
+ int levelshift = level2shift(level);
+ u64 levelsize = 1ULL << levelshift;
+ u64 *pte = find_pte(start, level);
+
+ /* Can we can just modify the current level block PTE? */
+ if (is_aligned(start, size, levelsize)) {
+ *pte &= ~PMD_ATTRINDX_MASK;
+ *pte |= attrs;
+ debug("Set attrs=%llx pte=%p level=%d\n", attrs, pte, level);
+
+ return levelsize;
+ }
+
+ /* Unaligned or doesn't fit, maybe split block into table */
+ debug("addr=%llx level=%d pte=%p (%llx)\n", start, level, pte, *pte);
+
+ /* Maybe we need to split the block into a table */
+ if (pte_type(pte) == PTE_TYPE_BLOCK)
+ split_block(pte, level);
+
+ /* And then double-check it became a table or already is one */
+ if (pte_type(pte) != PTE_TYPE_TABLE)
+ panic("PTE %p (%llx) for addr=%llx should be a table",
+ pte, *pte, start);
+
+ /* Roll on to the next page table level */
+ return 0;
+}
+
void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
enum dcache_option option)
{
- u64 *page_table = arch_get_page_table();
- u64 upto, end;
-
- if (page_table == NULL)
- return;
+ u64 attrs = PMD_ATTRINDX(option);
+ u64 real_start = start;
+ u64 real_size = size;
+
+ debug("start=%lx size=%lx\n", (ulong)start, (ulong)size);
+
+ /*
+ * We can not modify page tables that we're currently running on,
+ * so we first need to switch to the "emergency" page tables where
+ * we can safely modify our primary page tables and then switch back
+ */
+ __asm_switch_ttbr(gd->arch.tlb_emerg);
+
+ /*
+ * Loop through the address range until we find a page granule that fits
+ * our alignment constraints, then set it to the new cache attributes
+ */
+ while (size > 0) {
+ int level;
+ u64 r;
+
+ for (level = 1; level < 4; level++) {
+ r = set_one_region(start, size, attrs, level);
+ if (r) {
+ /* PTE successfully replaced */
+ size -= r;
+ start += r;
+ break;
+ }
+ }
- end = ALIGN(start + size, (1 << MMU_SECTION_SHIFT)) >>
- MMU_SECTION_SHIFT;
- start = start >> MMU_SECTION_SHIFT;
- for (upto = start; upto < end; upto++) {
- page_table[upto] &= ~PMD_ATTRINDX_MASK;
- page_table[upto] |= PMD_ATTRINDX(option);
}
- asm volatile("dsb sy");
- __asm_invalidate_tlb_all();
- asm volatile("dsb sy");
- asm volatile("isb");
- start = start << MMU_SECTION_SHIFT;
- end = end << MMU_SECTION_SHIFT;
- flush_dcache_range(start, end);
- asm volatile("dsb sy");
+
+ /* We're done modifying page tables, switch back to our primary ones */
+ __asm_switch_ttbr(gd->arch.tlb_addr);
+
+ /*
+ * Make sure there's nothing stale in dcache for a region that might
+ * have caches off now
+ */
+ flush_dcache_range(real_start, real_start + real_size);
}
-#endif
#else /* CONFIG_SYS_DCACHE_OFF */
+/*
+ * For SPL builds, we may want to not have dcache enabled. Any real U-Boot
+ * running however really wants to have dcache and the MMU active. Check that
+ * everything is sane and give the developer a hint if it isn't.
+ */
+#ifndef CONFIG_SPL_BUILD
+#error Please describe your MMU layout in CONFIG_SYS_MEM_MAP and enable dcache.
+#endif
+
void invalidate_dcache_all(void)
{
}
diff --git a/arch/arm/cpu/armv8/exceptions.S b/arch/arm/cpu/armv8/exceptions.S
index baf9401..4f4f526 100644
--- a/arch/arm/cpu/armv8/exceptions.S
+++ b/arch/arm/cpu/armv8/exceptions.S
@@ -82,31 +82,65 @@ vectors:
_do_bad_sync:
exception_entry
bl do_bad_sync
+ b exception_exit
_do_bad_irq:
exception_entry
bl do_bad_irq
+ b exception_exit
_do_bad_fiq:
exception_entry
bl do_bad_fiq
+ b exception_exit
_do_bad_error:
exception_entry
bl do_bad_error
+ b exception_exit
_do_sync:
exception_entry
bl do_sync
+ b exception_exit
_do_irq:
exception_entry
bl do_irq
+ b exception_exit
_do_fiq:
exception_entry
bl do_fiq
+ b exception_exit
_do_error:
exception_entry
bl do_error
+ b exception_exit
+
+exception_exit:
+ ldp x2, x0, [sp],#16
+ switch_el x11, 3f, 2f, 1f
+3: msr elr_el3, x2
+ b 0f
+2: msr elr_el2, x2
+ b 0f
+1: msr elr_el1, x2
+0:
+ ldp x1, x2, [sp],#16
+ ldp x3, x4, [sp],#16
+ ldp x5, x6, [sp],#16
+ ldp x7, x8, [sp],#16
+ ldp x9, x10, [sp],#16
+ ldp x11, x12, [sp],#16
+ ldp x13, x14, [sp],#16
+ ldp x15, x16, [sp],#16
+ ldp x17, x18, [sp],#16
+ ldp x19, x20, [sp],#16
+ ldp x21, x22, [sp],#16
+ ldp x23, x24, [sp],#16
+ ldp x25, x26, [sp],#16
+ ldp x27, x28, [sp],#16
+ ldp x29, x30, [sp],#16
+ eret
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
index 6ea28ed..7404bd9 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
@@ -26,6 +26,14 @@
DECLARE_GLOBAL_DATA_PTR;
+static struct mm_region layerscape_mem_map[] = {
+ {
+ /* List terminator */
+ 0,
+ }
+};
+struct mm_region *mem_map = layerscape_mem_map;
+
void cpu_name(char *name)
{
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
@@ -48,6 +56,25 @@ void cpu_name(char *name)
}
#ifndef CONFIG_SYS_DCACHE_OFF
+static void set_pgtable_section(u64 *page_table, u64 index, u64 section,
+ u64 memory_type, u64 attribute)
+{
+ u64 value;
+
+ value = section | PTE_TYPE_BLOCK | PTE_BLOCK_AF;
+ value |= PMD_ATTRINDX(memory_type);
+ value |= attribute;
+ page_table[index] = value;
+}
+
+static void set_pgtable_table(u64 *page_table, u64 index, u64 *table_addr)
+{
+ u64 value;
+
+ value = (u64)table_addr | PTE_TYPE_TABLE;
+ page_table[index] = value;
+}
+
/*
* Set the block entries according to the information of the table.
*/
@@ -114,10 +141,10 @@ static int find_table(const struct sys_mmu_table *list,
temp_base -= block_size;
- if ((level_table[index - 1] & PMD_TYPE_MASK) ==
- PMD_TYPE_TABLE) {
+ if ((level_table[index - 1] & PTE_TYPE_MASK) ==
+ PTE_TYPE_TABLE) {
level_table = (u64 *)(level_table[index - 1] &
- ~PMD_TYPE_MASK);
+ ~PTE_TYPE_MASK);
level++;
continue;
} else {
@@ -220,7 +247,7 @@ static inline int final_secure_ddr(u64 *level0_table,
struct table_info table = {};
struct sys_mmu_table ddr_entry = {
0, 0, BLOCK_SIZE_L1, MT_NORMAL,
- PMD_SECT_OUTER_SHARE | PMD_SECT_NS
+ PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS
};
u64 index;
@@ -243,7 +270,7 @@ static inline int final_secure_ddr(u64 *level0_table,
ddr_entry.virt_addr = phys_addr;
ddr_entry.phys_addr = phys_addr;
ddr_entry.size = CONFIG_SYS_MEM_RESERVE_SECURE;
- ddr_entry.attribute = PMD_SECT_OUTER_SHARE;
+ ddr_entry.attribute = PTE_BLOCK_OUTER_SHARE;
ret = find_table(&ddr_entry, &table, level0_table);
if (ret) {
printf("MMU error: could not find secure ddr table\n");
diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds
index 4c12222..fd15ad5 100644
--- a/arch/arm/cpu/armv8/u-boot.lds
+++ b/arch/arm/cpu/armv8/u-boot.lds
@@ -42,6 +42,22 @@ SECTIONS
. = ALIGN(8);
+ .efi_runtime : {
+ __efi_runtime_start = .;
+ *(efi_runtime_text)
+ *(efi_runtime_data)
+ __efi_runtime_stop = .;
+ }
+
+ .efi_runtime_rel : {
+ __efi_runtime_rel_start = .;
+ *(.relaefi_runtime_text)
+ *(.relaefi_runtime_data)
+ __efi_runtime_rel_stop = .;
+ }
+
+ . = ALIGN(8);
+
.image_copy_end :
{
*(.__image_copy_end)
diff --git a/arch/arm/cpu/armv8/zynqmp/cpu.c b/arch/arm/cpu/armv8/zynqmp/cpu.c
index c71f291..5dd3cd8 100644
--- a/arch/arm/cpu/armv8/zynqmp/cpu.c
+++ b/arch/arm/cpu/armv8/zynqmp/cpu.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
+#include <asm/armv8/mmu.h>
#include <asm/io.h>
#define ZYNQ_SILICON_VER_MASK 0xF000
@@ -15,6 +16,53 @@
DECLARE_GLOBAL_DATA_PTR;
+static struct mm_region zynqmp_mem_map[] = {
+ {
+ .base = 0x0UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .base = 0x80000000UL,
+ .size = 0x70000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .base = 0xf8000000UL,
+ .size = 0x07e00000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .base = 0xffe00000UL,
+ .size = 0x00200000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .base = 0x400000000UL,
+ .size = 0x200000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .base = 0x600000000UL,
+ .size = 0x800000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .base = 0xe00000000UL,
+ .size = 0xf200000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+struct mm_region *mem_map = zynqmp_mem_map;
+
static unsigned int zynqmp_get_silicon_version_secure(void)
{
u32 ver;
@@ -44,172 +92,3 @@ unsigned int zynqmp_get_silicon_version(void)
return ZYNQMP_CSU_VERSION_SILICON;
}
-
-#ifndef CONFIG_SYS_DCACHE_OFF
-#include <asm/armv8/mmu.h>
-
-#define SECTION_SHIFT_L1 30UL
-#define SECTION_SHIFT_L2 21UL
-#define BLOCK_SIZE_L0 0x8000000000UL
-#define BLOCK_SIZE_L1 (1 << SECTION_SHIFT_L1)
-#define BLOCK_SIZE_L2 (1 << SECTION_SHIFT_L2)
-
-#define TCR_TG1_4K (1 << 31)
-#define TCR_EPD1_DISABLE (1 << 23)
-#define ZYNQMO_VA_BITS 40
-#define ZYNQMP_TCR TCR_TG1_4K | \
- TCR_EPD1_DISABLE | \
- TCR_SHARED_OUTER | \
- TCR_SHARED_INNER | \
- TCR_IRGN_WBWA | \
- TCR_ORGN_WBWA | \
- TCR_T0SZ(ZYNQMO_VA_BITS)
-
-#define MEMORY_ATTR PMD_SECT_AF | PMD_SECT_INNER_SHARE | \
- PMD_ATTRINDX(MT_NORMAL) | \
- PMD_TYPE_SECT
-#define DEVICE_ATTR PMD_SECT_AF | PMD_SECT_PXN | \
- PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_NGNRNE) | \
- PMD_TYPE_SECT
-
-/* 4K size is required to place 512 entries in each level */
-#define TLB_TABLE_SIZE 0x1000
-
-struct attr_tbl {
- u32 num;
- u64 attr;
-};
-
-static struct attr_tbl attr_tbll1t0[4] = { {16, 0x0},
- {8, DEVICE_ATTR},
- {32, MEMORY_ATTR},
- {456, DEVICE_ATTR}
- };
-static struct attr_tbl attr_tbll2t3[4] = { {0x180, DEVICE_ATTR},
- {0x40, 0x0},
- {0x3F, DEVICE_ATTR},
- {0x1, MEMORY_ATTR}
- };
-
-/*
- * This mmu table looks as below
- * Level 0 table contains two entries to 512GB sizes. One is Level1 Table 0
- * and other Level1 Table1.
- * Level1 Table0 contains entries for each 1GB from 0 to 511GB.
- * Level1 Table1 contains entries for each 1GB from 512GB to 1TB.
- * Level2 Table0, Level2 Table1, Level2 Table2 and Level2 Table3 contains
- * entries for each 2MB starting from 0GB, 1GB, 2GB and 3GB respectively.
- */
-static void zynqmp_mmu_setup(void)
-{
- int el;
- u32 index_attr;
- u64 i, section_l1t0, section_l1t1;
- u64 section_l2t0, section_l2t1, section_l2t2, section_l2t3;
- u64 *level0_table = (u64 *)gd->arch.tlb_addr;
- u64 *level1_table_0 = (u64 *)(gd->arch.tlb_addr + TLB_TABLE_SIZE);
- u64 *level1_table_1 = (u64 *)(gd->arch.tlb_addr + (2 * TLB_TABLE_SIZE));
- u64 *level2_table_0 = (u64 *)(gd->arch.tlb_addr + (3 * TLB_TABLE_SIZE));
- u64 *level2_table_1 = (u64 *)(gd->arch.tlb_addr + (4 * TLB_TABLE_SIZE));
- u64 *level2_table_2 = (u64 *)(gd->arch.tlb_addr + (5 * TLB_TABLE_SIZE));
- u64 *level2_table_3 = (u64 *)(gd->arch.tlb_addr + (6 * TLB_TABLE_SIZE));
-
- level0_table[0] =
- (u64)level1_table_0 | PMD_TYPE_TABLE;
- level0_table[1] =
- (u64)level1_table_1 | PMD_TYPE_TABLE;
-
- /*
- * set level 1 table 0, covering 0 to 512GB
- * set level 1 table 1, covering 512GB to 1TB
- */
- section_l1t0 = 0;
- section_l1t1 = BLOCK_SIZE_L0;
-
- index_attr = 0;
- for (i = 0; i < 512; i++) {
- level1_table_0[i] = section_l1t0;
- level1_table_0[i] |= attr_tbll1t0[index_attr].attr;
- attr_tbll1t0[index_attr].num--;
- if (attr_tbll1t0[index_attr].num == 0)
- index_attr++;
- level1_table_1[i] = section_l1t1;
- level1_table_1[i] |= DEVICE_ATTR;
- section_l1t0 += BLOCK_SIZE_L1;
- section_l1t1 += BLOCK_SIZE_L1;
- }
-
- level1_table_0[0] =
- (u64)level2_table_0 | PMD_TYPE_TABLE;
- level1_table_0[1] =
- (u64)level2_table_1 | PMD_TYPE_TABLE;
- level1_table_0[2] =
- (u64)level2_table_2 | PMD_TYPE_TABLE;
- level1_table_0[3] =
- (u64)level2_table_3 | PMD_TYPE_TABLE;
-
- section_l2t0 = 0;
- section_l2t1 = section_l2t0 + BLOCK_SIZE_L1; /* 1GB */
- section_l2t2 = section_l2t1 + BLOCK_SIZE_L1; /* 2GB */
- section_l2t3 = section_l2t2 + BLOCK_SIZE_L1; /* 3GB */
-
- index_attr = 0;
-
- for (i = 0; i < 512; i++) {
- level2_table_0[i] = section_l2t0 | MEMORY_ATTR;
- level2_table_1[i] = section_l2t1 | MEMORY_ATTR;
- level2_table_2[i] = section_l2t2 | DEVICE_ATTR;
- level2_table_3[i] = section_l2t3 |
- attr_tbll2t3[index_attr].attr;
- attr_tbll2t3[index_attr].num--;
- if (attr_tbll2t3[index_attr].num == 0)
- index_attr++;
- section_l2t0 += BLOCK_SIZE_L2;
- section_l2t1 += BLOCK_SIZE_L2;
- section_l2t2 += BLOCK_SIZE_L2;
- section_l2t3 += BLOCK_SIZE_L2;
- }
-
- /* flush new MMU table */
- flush_dcache_range(gd->arch.tlb_addr,
- gd->arch.tlb_addr + gd->arch.tlb_size);
-
- /* point TTBR to the new table */
- el = current_el();
- set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
- ZYNQMP_TCR, MEMORY_ATTRIBUTES);
-
- set_sctlr(get_sctlr() | CR_M);
-}
-
-int arch_cpu_init(void)
-{
- icache_enable();
- __asm_invalidate_dcache_all();
- __asm_invalidate_tlb_all();
- return 0;
-}
-
-/*
- * This function is called from lib/board.c.
- * It recreates MMU table in main memory. MMU and d-cache are enabled earlier.
- * There is no need to disable d-cache for this operation.
- */
-void enable_caches(void)
-{
- /* The data cache is not active unless the mmu is enabled */
- if (!(get_sctlr() & CR_M)) {
- invalidate_dcache_all();
- __asm_invalidate_tlb_all();
- zynqmp_mmu_setup();
- }
- puts("Enabling Caches...\n");
-
- set_sctlr(get_sctlr() | CR_C);
-}
-
-u64 *arch_get_page_table(void)
-{
- return (u64 *)(gd->arch.tlb_addr + 0x3000);
-}
-#endif
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index e148ab7..13aa4fa 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -90,6 +90,36 @@ SECTIONS
. = ALIGN(4);
+ .__efi_runtime_start : {
+ *(.__efi_runtime_start)
+ }
+
+ .efi_runtime : {
+ *(efi_runtime_text)
+ *(efi_runtime_data)
+ }
+
+ .__efi_runtime_stop : {
+ *(.__efi_runtime_stop)
+ }
+
+ .efi_runtime_rel_start :
+ {
+ *(.__efi_runtime_rel_start)
+ }
+
+ .efi_runtime_rel : {
+ *(.relefi_runtime_text)
+ *(.relefi_runtime_data)
+ }
+
+ .efi_runtime_rel_stop :
+ {
+ *(.__efi_runtime_rel_stop)
+ }
+
+ . = ALIGN(4);
+
.image_copy_end :
{
*(.__image_copy_end)
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h
index 15ade84..93bbda3 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h
@@ -117,48 +117,48 @@ static const struct sys_mmu_table early_mmu_table[] = {
#ifdef CONFIG_FSL_LSCH3
{ CONFIG_SYS_FSL_CCSR_BASE, CONFIG_SYS_FSL_CCSR_BASE,
CONFIG_SYS_FSL_CCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_OCRAM_BASE, CONFIG_SYS_FSL_OCRAM_BASE,
- CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PTE_BLOCK_NON_SHARE },
/* For IFC Region #1, only the first 4MB is cache-enabled */
{ CONFIG_SYS_FSL_IFC_BASE1, CONFIG_SYS_FSL_IFC_BASE1,
- CONFIG_SYS_FSL_IFC_SIZE1_1, MT_NORMAL, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_IFC_SIZE1_1, MT_NORMAL, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_IFC_BASE1 + CONFIG_SYS_FSL_IFC_SIZE1_1,
CONFIG_SYS_FSL_IFC_BASE1 + CONFIG_SYS_FSL_IFC_SIZE1_1,
CONFIG_SYS_FSL_IFC_SIZE1 - CONFIG_SYS_FSL_IFC_SIZE1_1,
- MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
+ MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FSL_IFC_BASE1,
- CONFIG_SYS_FSL_IFC_SIZE1, MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_IFC_SIZE1, MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DRAM_BASE1, CONFIG_SYS_FSL_DRAM_BASE1,
CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL,
- PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
+ PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS },
/* Map IFC region #2 up to CONFIG_SYS_FLASH_BASE for NAND boot */
{ CONFIG_SYS_FSL_IFC_BASE2, CONFIG_SYS_FSL_IFC_BASE2,
CONFIG_SYS_FLASH_BASE - CONFIG_SYS_FSL_IFC_BASE2,
- MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
+ MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DCSR_BASE, CONFIG_SYS_FSL_DCSR_BASE,
CONFIG_SYS_FSL_DCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_DRAM_BASE2, CONFIG_SYS_FSL_DRAM_BASE2,
CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL,
- PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
+ PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS },
#elif defined(CONFIG_FSL_LSCH2)
{ CONFIG_SYS_FSL_CCSR_BASE, CONFIG_SYS_FSL_CCSR_BASE,
CONFIG_SYS_FSL_CCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_OCRAM_BASE, CONFIG_SYS_FSL_OCRAM_BASE,
- CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DCSR_BASE, CONFIG_SYS_FSL_DCSR_BASE,
CONFIG_SYS_FSL_DCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_QSPI_BASE, CONFIG_SYS_FSL_QSPI_BASE,
- CONFIG_SYS_FSL_QSPI_SIZE, MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_QSPI_SIZE, MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_IFC_BASE, CONFIG_SYS_FSL_IFC_BASE,
- CONFIG_SYS_FSL_IFC_SIZE, MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_IFC_SIZE, MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DRAM_BASE1, CONFIG_SYS_FSL_DRAM_BASE1,
- CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+ CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL, PTE_BLOCK_OUTER_SHARE },
{ CONFIG_SYS_FSL_DRAM_BASE2, CONFIG_SYS_FSL_DRAM_BASE2,
- CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+ CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL, PTE_BLOCK_OUTER_SHARE },
#endif
};
@@ -166,96 +166,96 @@ static const struct sys_mmu_table final_mmu_table[] = {
#ifdef CONFIG_FSL_LSCH3
{ CONFIG_SYS_FSL_CCSR_BASE, CONFIG_SYS_FSL_CCSR_BASE,
CONFIG_SYS_FSL_CCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_OCRAM_BASE, CONFIG_SYS_FSL_OCRAM_BASE,
- CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DRAM_BASE1, CONFIG_SYS_FSL_DRAM_BASE1,
CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL,
- PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
+ PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS },
{ CONFIG_SYS_FSL_QSPI_BASE2, CONFIG_SYS_FSL_QSPI_BASE2,
CONFIG_SYS_FSL_QSPI_SIZE2, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_IFC_BASE2, CONFIG_SYS_FSL_IFC_BASE2,
- CONFIG_SYS_FSL_IFC_SIZE2, MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_IFC_SIZE2, MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DCSR_BASE, CONFIG_SYS_FSL_DCSR_BASE,
CONFIG_SYS_FSL_DCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_MC_BASE, CONFIG_SYS_FSL_MC_BASE,
CONFIG_SYS_FSL_MC_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_NI_BASE, CONFIG_SYS_FSL_NI_BASE,
CONFIG_SYS_FSL_NI_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
/* For QBMAN portal, only the first 64MB is cache-enabled */
{ CONFIG_SYS_FSL_QBMAN_BASE, CONFIG_SYS_FSL_QBMAN_BASE,
CONFIG_SYS_FSL_QBMAN_SIZE_1, MT_NORMAL,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN | PMD_SECT_NS },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN | PTE_BLOCK_NS },
{ CONFIG_SYS_FSL_QBMAN_BASE + CONFIG_SYS_FSL_QBMAN_SIZE_1,
CONFIG_SYS_FSL_QBMAN_BASE + CONFIG_SYS_FSL_QBMAN_SIZE_1,
CONFIG_SYS_FSL_QBMAN_SIZE - CONFIG_SYS_FSL_QBMAN_SIZE_1,
- MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_PCIE1_PHYS_ADDR, CONFIG_SYS_PCIE1_PHYS_ADDR,
CONFIG_SYS_PCIE1_PHYS_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_PCIE2_PHYS_ADDR, CONFIG_SYS_PCIE2_PHYS_ADDR,
CONFIG_SYS_PCIE2_PHYS_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_PCIE3_PHYS_ADDR, CONFIG_SYS_PCIE3_PHYS_ADDR,
CONFIG_SYS_PCIE3_PHYS_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
#if defined(CONFIG_LS2080A) || defined(CONFIG_LS2085A)
{ CONFIG_SYS_PCIE4_PHYS_ADDR, CONFIG_SYS_PCIE4_PHYS_ADDR,
CONFIG_SYS_PCIE4_PHYS_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
#endif
{ CONFIG_SYS_FSL_WRIOP1_BASE, CONFIG_SYS_FSL_WRIOP1_BASE,
CONFIG_SYS_FSL_WRIOP1_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_AIOP1_BASE, CONFIG_SYS_FSL_AIOP1_BASE,
CONFIG_SYS_FSL_AIOP1_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_PEBUF_BASE, CONFIG_SYS_FSL_PEBUF_BASE,
CONFIG_SYS_FSL_PEBUF_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_DRAM_BASE2, CONFIG_SYS_FSL_DRAM_BASE2,
CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL,
- PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
+ PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS },
#elif defined(CONFIG_FSL_LSCH2)
{ CONFIG_SYS_FSL_BOOTROM_BASE, CONFIG_SYS_FSL_BOOTROM_BASE,
CONFIG_SYS_FSL_BOOTROM_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_CCSR_BASE, CONFIG_SYS_FSL_CCSR_BASE,
CONFIG_SYS_FSL_CCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_OCRAM_BASE, CONFIG_SYS_FSL_OCRAM_BASE,
- CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DCSR_BASE, CONFIG_SYS_FSL_DCSR_BASE,
CONFIG_SYS_FSL_DCSR_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_QSPI_BASE, CONFIG_SYS_FSL_QSPI_BASE,
CONFIG_SYS_FSL_QSPI_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_IFC_BASE, CONFIG_SYS_FSL_IFC_BASE,
- CONFIG_SYS_FSL_IFC_SIZE, MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
+ CONFIG_SYS_FSL_IFC_SIZE, MT_DEVICE_NGNRNE, PTE_BLOCK_NON_SHARE },
{ CONFIG_SYS_FSL_DRAM_BASE1, CONFIG_SYS_FSL_DRAM_BASE1,
CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL,
- PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
+ PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS },
{ CONFIG_SYS_FSL_QBMAN_BASE, CONFIG_SYS_FSL_QBMAN_BASE,
CONFIG_SYS_FSL_QBMAN_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_DRAM_BASE2, CONFIG_SYS_FSL_DRAM_BASE2,
- CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+ CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL, PTE_BLOCK_OUTER_SHARE },
{ CONFIG_SYS_PCIE1_PHYS_ADDR, CONFIG_SYS_PCIE1_PHYS_ADDR,
CONFIG_SYS_PCIE1_PHYS_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_PCIE2_PHYS_ADDR, CONFIG_SYS_PCIE2_PHYS_ADDR,
CONFIG_SYS_PCIE2_PHYS_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_PCIE3_PHYS_ADDR, CONFIG_SYS_PCIE3_PHYS_ADDR,
CONFIG_SYS_PCIE3_PHYS_SIZE, MT_DEVICE_NGNRNE,
- PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN },
{ CONFIG_SYS_FSL_DRAM_BASE3, CONFIG_SYS_FSL_DRAM_BASE3,
- CONFIG_SYS_FSL_DRAM_SIZE3, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+ CONFIG_SYS_FSL_DRAM_SIZE3, MT_NORMAL, PTE_BLOCK_OUTER_SHARE },
#endif
};
#endif
diff --git a/arch/arm/include/asm/armv8/mmu.h b/arch/arm/include/asm/armv8/mmu.h
index 897f010..0d08ed3 100644
--- a/arch/arm/include/asm/armv8/mmu.h
+++ b/arch/arm/include/asm/armv8/mmu.h
@@ -22,32 +22,19 @@
* calculated specifically.
*/
-#ifndef CONFIG_SYS_FULL_VA
-#define VA_BITS (42) /* 42 bits virtual address */
-#else
#define VA_BITS CONFIG_SYS_VA_BITS
-#define PTL2_BITS CONFIG_SYS_PTL2_BITS
-#endif
+#define PTE_BLOCK_BITS CONFIG_SYS_PTL2_BITS
+
+/*
+ * block/section address mask and size definitions.
+ */
/* PAGE_SHIFT determines the page size */
#undef PAGE_SIZE
-#define PAGE_SHIFT 16
+#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
-/*
- * block/section address mask and size definitions.
- */
-#ifndef CONFIG_SYS_FULL_VA
-#define SECTION_SHIFT 29
-#define SECTION_SIZE (UL(1) << SECTION_SHIFT)
-#define SECTION_MASK (~(SECTION_SIZE-1))
-#else
-#define BLOCK_SHIFT CONFIG_SYS_BLOCK_SHIFT
-#define BLOCK_SIZE (UL(1) << BLOCK_SHIFT)
-#define BLOCK_MASK (~(BLOCK_SIZE-1))
-#endif
-
/***************************************************************/
/*
@@ -70,63 +57,28 @@
*
*/
-#ifdef CONFIG_SYS_FULL_VA
-/*
- * Level 1 descriptor (PGD).
- */
-
-#define PTL1_TYPE_MASK (3 << 0)
-#define PTL1_TYPE_TABLE (3 << 0)
-
-#define PTL1_TABLE_PXN (1UL << 59)
-#define PTL1_TABLE_XN (1UL << 60)
-#define PTL1_TABLE_AP (1UL << 61)
-#define PTL1_TABLE_NS (1UL << 63)
+#define PTE_TYPE_MASK (3 << 0)
+#define PTE_TYPE_FAULT (0 << 0)
+#define PTE_TYPE_TABLE (3 << 0)
+#define PTE_TYPE_BLOCK (1 << 0)
-
-/*
- * Level 2 descriptor (PMD).
- */
-
-#define PTL2_TYPE_MASK (3 << 0)
-#define PTL2_TYPE_FAULT (0 << 0)
-#define PTL2_TYPE_TABLE (3 << 0)
-#define PTL2_TYPE_BLOCK (1 << 0)
+#define PTE_TABLE_PXN (1UL << 59)
+#define PTE_TABLE_XN (1UL << 60)
+#define PTE_TABLE_AP (1UL << 61)
+#define PTE_TABLE_NS (1UL << 63)
/*
* Block
*/
-#define PTL2_MEMTYPE(x) ((x) << 2)
-#define PTL2_BLOCK_NON_SHARE (0 << 8)
-#define PTL2_BLOCK_OUTER_SHARE (2 << 8)
-#define PTL2_BLOCK_INNER_SHARE (3 << 8)
-#define PTL2_BLOCK_AF (1 << 10)
-#define PTL2_BLOCK_NG (1 << 11)
-#define PTL2_BLOCK_PXN (UL(1) << 53)
-#define PTL2_BLOCK_UXN (UL(1) << 54)
-
-#else
-/*
- * Level 2 descriptor (PMD).
- */
-#define PMD_TYPE_MASK (3 << 0)
-#define PMD_TYPE_FAULT (0 << 0)
-#define PMD_TYPE_TABLE (3 << 0)
-#define PMD_TYPE_SECT (1 << 0)
-
-/*
- * Section
- */
-#define PMD_SECT_NS (1 << 5)
-#define PMD_SECT_NON_SHARE (0 << 8)
-#define PMD_SECT_OUTER_SHARE (2 << 8)
-#define PMD_SECT_INNER_SHARE (3 << 8)
-#define PMD_SECT_AF (1 << 10)
-#define PMD_SECT_NG (1 << 11)
-#define PMD_SECT_PXN (UL(1) << 53)
-#define PMD_SECT_UXN (UL(1) << 54)
-
-#endif
+#define PTE_BLOCK_MEMTYPE(x) ((x) << 2)
+#define PTE_BLOCK_NS (1 << 5)
+#define PTE_BLOCK_NON_SHARE (0 << 8)
+#define PTE_BLOCK_OUTER_SHARE (2 << 8)
+#define PTE_BLOCK_INNER_SHARE (3 << 8)
+#define PTE_BLOCK_AF (1 << 10)
+#define PTE_BLOCK_NG (1 << 11)
+#define PTE_BLOCK_PXN (UL(1) << 53)
+#define PTE_BLOCK_UXN (UL(1) << 54)
/*
* AttrIndx[2:0]
@@ -154,38 +106,13 @@
#define TCR_TG0_4K (0 << 14)
#define TCR_TG0_64K (1 << 14)
#define TCR_TG0_16K (2 << 14)
-
-#ifndef CONFIG_SYS_FULL_VA
-#define TCR_EL1_IPS_BITS (UL(3) << 32) /* 42 bits physical address */
-#define TCR_EL2_IPS_BITS (3 << 16) /* 42 bits physical address */
-#define TCR_EL3_IPS_BITS (3 << 16) /* 42 bits physical address */
-#else
-#define TCR_EL1_IPS_BITS CONFIG_SYS_TCR_EL1_IPS_BITS
-#define TCR_EL2_IPS_BITS CONFIG_SYS_TCR_EL2_IPS_BITS
-#define TCR_EL3_IPS_BITS CONFIG_SYS_TCR_EL3_IPS_BITS
-#endif
-
-/* PTWs cacheable, inner/outer WBWA and inner shareable */
-#define TCR_FLAGS (TCR_TG0_64K | \
- TCR_SHARED_INNER | \
- TCR_ORGN_WBWA | \
- TCR_IRGN_WBWA | \
- TCR_T0SZ(VA_BITS))
+#define TCR_EPD1_DISABLE (1 << 23)
#define TCR_EL1_RSVD (1 << 31)
#define TCR_EL2_RSVD (1 << 31 | 1 << 23)
#define TCR_EL3_RSVD (1 << 31 | 1 << 23)
#ifndef __ASSEMBLY__
-#ifndef CONFIG_SYS_FULL_VA
-
-void set_pgtable_section(u64 *page_table, u64 index,
- u64 section, u64 memory_type,
- u64 attribute);
-void set_pgtable_table(u64 *page_table, u64 index,
- u64 *table_addr);
-
-#endif
static inline void set_ttbr_tcr_mair(int el, u64 table, u64 tcr, u64 attr)
{
asm volatile("dsb sy");
@@ -212,6 +139,8 @@ struct mm_region {
u64 size;
u64 attrs;
};
+
+extern struct mm_region *mem_map;
#endif
#endif /* _ASM_ARMV8_MMU_H_ */
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index dcfa098..77d2653 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -38,10 +38,11 @@ struct arch_global_data {
unsigned long long timer_reset_value;
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
unsigned long tlb_addr;
-#if defined(CONFIG_SYS_FULL_VA)
- unsigned long pmd_addr[CONFIG_SYS_PTL1_ENTRIES];
-#endif
unsigned long tlb_size;
+#if defined(CONFIG_ARM64)
+ unsigned long tlb_fillptr;
+ unsigned long tlb_emerg;
+#endif
#endif
#ifdef CONFIG_OMAP_COMMON
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 026e7ef..ac1173d 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -17,18 +17,15 @@
#define CR_WXN (1 << 19) /* Write Permision Imply XN */
#define CR_EE (1 << 25) /* Exception (Big) Endian */
-#ifndef CONFIG_SYS_FULL_VA
-#define PGTABLE_SIZE (0x10000)
-#else
-#define PGTABLE_SIZE CONFIG_SYS_PGTABLE_SIZE
-#endif
+#ifndef __ASSEMBLY__
+
+u64 get_page_table_size(void);
+#define PGTABLE_SIZE get_page_table_size()
/* 2MB granularity */
#define MMU_SECTION_SHIFT 21
#define MMU_SECTION_SIZE (1 << MMU_SECTION_SHIFT)
-#ifndef __ASSEMBLY__
-
enum dcache_option {
DCACHE_OFF = 0x3,
};
@@ -97,6 +94,7 @@ void __asm_flush_dcache_range(u64 start, u64 end);
void __asm_invalidate_tlb_all(void);
void __asm_invalidate_icache_all(void);
int __asm_flush_l3_cache(void);
+void __asm_switch_ttbr(u64 new_ttbr);
void armv8_switch_to_el2(void);
void armv8_switch_to_el1(void);
diff --git a/arch/arm/lib/interrupts_64.c b/arch/arm/lib/interrupts_64.c
index b476722..7c9cfce 100644
--- a/arch/arm/lib/interrupts_64.c
+++ b/arch/arm/lib/interrupts_64.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <linux/compiler.h>
+#include <efi_loader.h>
int interrupt_init(void)
@@ -41,6 +42,7 @@ void show_regs(struct pt_regs *regs)
*/
void do_bad_sync(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("Bad mode in \"Synchronous Abort\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
@@ -51,6 +53,7 @@ void do_bad_sync(struct pt_regs *pt_regs, unsigned int esr)
*/
void do_bad_irq(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("Bad mode in \"Irq\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
@@ -61,6 +64,7 @@ void do_bad_irq(struct pt_regs *pt_regs, unsigned int esr)
*/
void do_bad_fiq(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("Bad mode in \"Fiq\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
@@ -71,6 +75,7 @@ void do_bad_fiq(struct pt_regs *pt_regs, unsigned int esr)
*/
void do_bad_error(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("Bad mode in \"Error\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
@@ -81,6 +86,7 @@ void do_bad_error(struct pt_regs *pt_regs, unsigned int esr)
*/
void do_sync(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("\"Synchronous Abort\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
@@ -91,6 +97,7 @@ void do_sync(struct pt_regs *pt_regs, unsigned int esr)
*/
void do_irq(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("\"Irq\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
@@ -101,6 +108,7 @@ void do_irq(struct pt_regs *pt_regs, unsigned int esr)
*/
void do_fiq(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("\"Fiq\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
@@ -114,6 +122,7 @@ void do_fiq(struct pt_regs *pt_regs, unsigned int esr)
*/
void __weak do_error(struct pt_regs *pt_regs, unsigned int esr)
{
+ efi_restore_gd();
printf("\"Error\" handler, esr 0x%08x\n", esr);
show_regs(pt_regs);
panic("Resetting CPU ...\n");
diff --git a/arch/arm/lib/sections.c b/arch/arm/lib/sections.c
index a1205c3..6a94522 100644
--- a/arch/arm/lib/sections.c
+++ b/arch/arm/lib/sections.c
@@ -27,4 +27,8 @@ char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
char __secure_start[0] __attribute__((section(".__secure_start")));
char __secure_end[0] __attribute__((section(".__secure_end")));
+char __efi_runtime_start[0] __attribute__((section(".__efi_runtime_start")));
+char __efi_runtime_stop[0] __attribute__((section(".__efi_runtime_stop")));
+char __efi_runtime_rel_start[0] __attribute__((section(".__efi_runtime_rel_start")));
+char __efi_runtime_rel_stop[0] __attribute__((section(".__efi_runtime_rel_stop")));
char _end[0] __attribute__((section(".__end")));
diff --git a/arch/arm/mach-tegra/arm64-mmu.c b/arch/arm/mach-tegra/arm64-mmu.c
index c227652..501c4f0 100644
--- a/arch/arm/mach-tegra/arm64-mmu.c
+++ b/arch/arm/mach-tegra/arm64-mmu.c
@@ -12,120 +12,22 @@
#include <asm/system.h>
#include <asm/armv8/mmu.h>
-DECLARE_GLOBAL_DATA_PTR;
-
-#define SECTION_SHIFT_L1 30UL
-#define SECTION_SHIFT_L2 21UL
-#define BLOCK_SIZE_L0 0x8000000000UL
-#define BLOCK_SIZE_L1 (1 << SECTION_SHIFT_L1)
-#define BLOCK_SIZE_L2 (1 << SECTION_SHIFT_L2)
-
-#define TCR_TG1_4K (1 << 31)
-#define TCR_EPD1_DISABLE (1 << 23)
-#define TEGRA_VA_BITS 40
-#define TEGRA_TCR TCR_TG1_4K | \
- TCR_EPD1_DISABLE | \
- TCR_SHARED_OUTER | \
- TCR_SHARED_INNER | \
- TCR_IRGN_WBWA | \
- TCR_ORGN_WBWA | \
- TCR_T0SZ(TEGRA_VA_BITS)
-
-#define MEMORY_ATTR PMD_SECT_AF | PMD_SECT_INNER_SHARE | \
- PMD_ATTRINDX(MT_NORMAL) | \
- PMD_TYPE_SECT
-#define DEVICE_ATTR PMD_SECT_AF | PMD_SECT_PXN | \
- PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_NGNRNE) | \
- PMD_TYPE_SECT
-
-/* 4K size is required to place 512 entries in each level */
-#define TLB_TABLE_SIZE 0x1000
-
-/*
- * This mmu table looks as below
- * Level 0 table contains two entries to 512GB sizes. One is Level1 Table 0
- * and other Level1 Table1.
- * Level1 Table0 contains entries for each 1GB from 0 to 511GB.
- * Level1 Table1 contains entries for each 1GB from 512GB to 1TB.
- * Level2 Table0, Level2 Table1, Level2 Table2 and Level2 Table3 contains
- * entries for each 2MB starting from 0GB, 1GB, 2GB and 3GB respectively.
- */
-void mmu_setup(void)
-{
- int el;
- u64 i, section_l1t0, section_l1t1;
- u64 section_l2t0, section_l2t1, section_l2t2, section_l2t3;
- u64 *level0_table = (u64 *)gd->arch.tlb_addr;
- u64 *level1_table_0 = (u64 *)(gd->arch.tlb_addr + TLB_TABLE_SIZE);
- u64 *level1_table_1 = (u64 *)(gd->arch.tlb_addr + (2 * TLB_TABLE_SIZE));
- u64 *level2_table_0 = (u64 *)(gd->arch.tlb_addr + (3 * TLB_TABLE_SIZE));
- u64 *level2_table_1 = (u64 *)(gd->arch.tlb_addr + (4 * TLB_TABLE_SIZE));
- u64 *level2_table_2 = (u64 *)(gd->arch.tlb_addr + (5 * TLB_TABLE_SIZE));
- u64 *level2_table_3 = (u64 *)(gd->arch.tlb_addr + (6 * TLB_TABLE_SIZE));
-
- /* Invalidate all table entries */
- memset(level0_table, 0, PGTABLE_SIZE);
-
- level0_table[0] =
- (u64)level1_table_0 | PMD_TYPE_TABLE;
- level0_table[1] =
- (u64)level1_table_1 | PMD_TYPE_TABLE;
-
- /*
- * set level 1 table 0, covering 0 to 512GB
- * set level 1 table 1, covering 512GB to 1TB
- */
- section_l1t0 = 0;
- section_l1t1 = BLOCK_SIZE_L0;
-
- for (i = 0; i < 512; i++) {
- level1_table_0[i] = section_l1t0;
- if (i >= 4)
- level1_table_0[i] |= MEMORY_ATTR;
- level1_table_1[i] = section_l1t1;
- level1_table_1[i] |= MEMORY_ATTR;
- section_l1t0 += BLOCK_SIZE_L1;
- section_l1t1 += BLOCK_SIZE_L1;
+static struct mm_region tegra_mem_map[] = {
+ {
+ .base = 0x0UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .base = 0x80000000UL,
+ .size = 0xff80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ /* List terminator */
+ 0,
}
+};
- level1_table_0[0] =
- (u64)level2_table_0 | PMD_TYPE_TABLE;
- level1_table_0[1] =
- (u64)level2_table_1 | PMD_TYPE_TABLE;
- level1_table_0[2] =
- (u64)level2_table_2 | PMD_TYPE_TABLE;
- level1_table_0[3] =
- (u64)level2_table_3 | PMD_TYPE_TABLE;
-
- section_l2t0 = 0;
- section_l2t1 = section_l2t0 + BLOCK_SIZE_L1; /* 1GB */
- section_l2t2 = section_l2t1 + BLOCK_SIZE_L1; /* 2GB */
- section_l2t3 = section_l2t2 + BLOCK_SIZE_L1; /* 3GB */
-
- for (i = 0; i < 512; i++) {
- level2_table_0[i] = section_l2t0 | DEVICE_ATTR;
- level2_table_1[i] = section_l2t1 | DEVICE_ATTR;
- level2_table_2[i] = section_l2t2 | MEMORY_ATTR;
- level2_table_3[i] = section_l2t3 | MEMORY_ATTR;
- section_l2t0 += BLOCK_SIZE_L2;
- section_l2t1 += BLOCK_SIZE_L2;
- section_l2t2 += BLOCK_SIZE_L2;
- section_l2t3 += BLOCK_SIZE_L2;
- }
-
- /* flush new MMU table */
- flush_dcache_range(gd->arch.tlb_addr,
- gd->arch.tlb_addr + gd->arch.tlb_size);
-
- /* point TTBR to the new table */
- el = current_el();
- set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
- TEGRA_TCR, MEMORY_ATTRIBUTES);
-
- set_sctlr(get_sctlr() | CR_M);
-}
-
-u64 *arch_get_page_table(void)
-{
- return (u64 *)(gd->arch.tlb_addr + (3 * TLB_TABLE_SIZE));
-}
+struct mm_region *mem_map = tegra_mem_map;
diff --git a/board/armltd/vexpress64/vexpress64.c b/board/armltd/vexpress64/vexpress64.c
index 6efc8c1..973b579 100644
--- a/board/armltd/vexpress64/vexpress64.c
+++ b/board/armltd/vexpress64/vexpress64.c
@@ -14,6 +14,7 @@
#include <dm/platdata.h>
#include <dm/platform_data/serial_pl01x.h>
#include "pcie.h"
+#include <asm/armv8/mmu.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -28,6 +29,26 @@ U_BOOT_DEVICE(vexpress_serials) = {
.platdata = &serial_platdata,
};
+static struct mm_region vexpress64_mem_map[] = {
+ {
+ .base = 0x0UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .base = 0x80000000UL,
+ .size = 0xff80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = vexpress64_mem_map;
+
/* This function gets replaced by platforms supporting PCIe.
* The replacement function, eg. on Juno, initialises the PCIe bus.
*/
diff --git a/board/cavium/thunderx/thunderx.c b/board/cavium/thunderx/thunderx.c
index b926767..9131a38 100644
--- a/board/cavium/thunderx/thunderx.c
+++ b/board/cavium/thunderx/thunderx.c
@@ -10,6 +10,7 @@
#include <linux/compiler.h>
#include <cavium/atf.h>
+#include <asm/armv8/mmu.h>
#if !CONFIG_IS_ENABLED(OF_CONTROL)
#include <dm/platdata.h>
@@ -42,6 +43,29 @@ U_BOOT_DEVICE(thunderx_serial1) = {
DECLARE_GLOBAL_DATA_PTR;
+static struct mm_region thunderx_mem_map[] = {
+ {
+ .base = 0x000000000000UL,
+ .size = 0x40000000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_NON_SHARE,
+ }, {
+ .base = 0x800000000000UL,
+ .size = 0x40000000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE,
+ }, {
+ .base = 0x840000000000UL,
+ .size = 0x40000000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE,
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = thunderx_mem_map;
+
int board_init(void)
{
return 0;
diff --git a/board/hisilicon/hikey/hikey.c b/board/hisilicon/hikey/hikey.c
index c4ae40b..1edc807 100644
--- a/board/hisilicon/hikey/hikey.c
+++ b/board/hisilicon/hikey/hikey.c
@@ -19,6 +19,7 @@
#include <asm/arch/periph.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/hi6220.h>
+#include <asm/armv8/mmu.h>
/*TODO drop this table in favour of device tree */
static const struct hikey_gpio_platdata hi6220_gpio[] = {
@@ -87,6 +88,26 @@ U_BOOT_DEVICE(hikey_seriala) = {
.platdata = &serial_platdata,
};
+static struct mm_region hikey_mem_map[] = {
+ {
+ .base = 0x0UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .base = 0x80000000UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = hikey_mem_map;
+
#ifdef CONFIG_BOARD_EARLY_INIT_F
int board_uart_init(void)
{
diff --git a/board/ti/am335x/u-boot.lds b/board/ti/am335x/u-boot.lds
index 78f294a..a56cc82 100644
--- a/board/ti/am335x/u-boot.lds
+++ b/board/ti/am335x/u-boot.lds
@@ -59,6 +59,36 @@ SECTIONS
. = ALIGN(4);
+ .__efi_runtime_start : {
+ *(.__efi_runtime_start)
+ }
+
+ .efi_runtime : {
+ *(efi_runtime_text)
+ *(efi_runtime_data)
+ }
+
+ .__efi_runtime_stop : {
+ *(.__efi_runtime_stop)
+ }
+
+ .efi_runtime_rel_start :
+ {
+ *(.__efi_runtime_rel_start)
+ }
+
+ .efi_runtime_rel : {
+ *(.relefi_runtime_text)
+ *(.relefi_runtime_data)
+ }
+
+ .efi_runtime_rel_stop :
+ {
+ *(.__efi_runtime_rel_stop)
+ }
+
+ . = ALIGN(4);
+
.image_copy_end :
{
*(.__image_copy_end)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 2ed0263..7cdff04 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -148,6 +148,13 @@ config CMD_BOOTM
help
Boot an application image from the memory.
+config CMD_BOOTEFI
+ bool "bootefi"
+ depends on EFI_LOADER
+ default y
+ help
+ Boot an EFI image from memory.
+
config CMD_ELF
bool "bootelf, bootvx"
default y
diff --git a/cmd/Makefile b/cmd/Makefile
index 03f7e0a..7604621 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_CMD_SOURCE) += source.o
obj-$(CONFIG_CMD_BDI) += bdinfo.o
obj-$(CONFIG_CMD_BEDBUG) += bedbug.o
obj-$(CONFIG_CMD_BMP) += bmp.o
+obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
obj-$(CONFIG_CMD_BOOTLDR) += bootldr.o
obj-$(CONFIG_CMD_BOOTSTAGE) += bootstage.o
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
new file mode 100644
index 0000000..e3e51d4
--- /dev/null
+++ b/cmd/bootefi.c
@@ -0,0 +1,167 @@
+/*
+ * EFI application loader
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <efi_loader.h>
+#include <errno.h>
+#include <libfdt_env.h>
+
+/*
+ * When booting using the "bootefi" command, we don't know which
+ * physical device the file came from. So we create a pseudo-device
+ * called "bootefi" with the device path /bootefi.
+ *
+ * In addition to the originating device we also declare the file path
+ * of "bootefi" based loads to be /bootefi.
+ */
+static struct efi_device_path_file_path bootefi_dummy_path[] = {
+ {
+ .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
+ .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
+ .dp.length = sizeof(bootefi_dummy_path[0]),
+ .str = { 'b','o','o','t','e','f','i' },
+ }, {
+ .dp.type = DEVICE_PATH_TYPE_END,
+ .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
+ .dp.length = sizeof(bootefi_dummy_path[0]),
+ }
+};
+
+static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ *protocol_interface = bootefi_dummy_path;
+ return EFI_SUCCESS;
+}
+
+/* The EFI loaded_image interface for the image executed via "bootefi" */
+static struct efi_loaded_image loaded_image_info = {
+ .device_handle = bootefi_dummy_path,
+ .file_path = bootefi_dummy_path,
+};
+
+/* The EFI object struct for the image executed via "bootefi" */
+static struct efi_object loaded_image_info_obj = {
+ .handle = &loaded_image_info,
+ .protocols = {
+ {
+ /*
+ * When asking for the loaded_image interface, just
+ * return handle which points to loaded_image_info
+ */
+ .guid = &efi_guid_loaded_image,
+ .open = &efi_return_handle,
+ },
+ {
+ /*
+ * When asking for the device path interface, return
+ * bootefi_dummy_path
+ */
+ .guid = &efi_guid_device_path,
+ .open = &bootefi_open_dp,
+ },
+ },
+};
+
+/* The EFI object struct for the device the "bootefi" image was loaded from */
+static struct efi_object bootefi_device_obj = {
+ .handle = bootefi_dummy_path,
+ .protocols = {
+ {
+ /* When asking for the device path interface, return
+ * bootefi_dummy_path */
+ .guid = &efi_guid_device_path,
+ .open = &bootefi_open_dp,
+ }
+ },
+};
+
+/*
+ * Load an EFI payload into a newly allocated piece of memory, register all
+ * EFI objects it would want to access and jump to it.
+ */
+static unsigned long do_bootefi_exec(void *efi)
+{
+ ulong (*entry)(void *image_handle, struct efi_system_table *st);
+
+ /*
+ * gd lives in a fixed register which may get clobbered while we execute
+ * the payload. So save it here and restore it on every callback entry
+ */
+ efi_save_gd();
+
+ /* Update system table to point to our currently loaded FDT */
+
+ if (working_fdt) {
+ systab.tables[0].guid = EFI_FDT_GUID;
+ systab.tables[0].table = working_fdt;
+ systab.nr_tables = 1;
+ } else {
+ printf("WARNING: No device tree loaded, expect boot to fail\n");
+ systab.nr_tables = 0;
+ }
+
+ /* Load the EFI payload */
+ entry = efi_load_pe(efi, &loaded_image_info);
+ if (!entry)
+ return -ENOENT;
+
+ /* Initialize and populate EFI object list */
+ INIT_LIST_HEAD(&efi_obj_list);
+ list_add_tail(&loaded_image_info_obj.link, &efi_obj_list);
+ list_add_tail(&bootefi_device_obj.link, &efi_obj_list);
+#ifdef CONFIG_PARTITIONS
+ efi_disk_register();
+#endif
+
+ /* Call our payload! */
+#ifdef DEBUG_EFI
+ printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
+#endif
+ return entry(&loaded_image_info, &systab);
+}
+
+
+/* Interpreter command to boot an arbitrary EFI image from memory */
+static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *saddr;
+ unsigned long addr;
+ int r = 0;
+
+ if (argc < 2)
+ return 1;
+ saddr = argv[1];
+
+ addr = simple_strtoul(saddr, NULL, 16);
+
+ printf("## Starting EFI application at 0x%08lx ...\n", addr);
+ r = do_bootefi_exec((void *)addr);
+ printf("## Application terminated, r = %d\n", r);
+
+ if (r != 0)
+ r = 1;
+
+ return r;
+}
+
+static char bootefi_help_text[] =
+ "<image address>\n"
+ " - boot EFI payload stored at address <image address>\n"
+ "\n"
+ "Since most EFI payloads want to have a device tree provided, please\n"
+ "make sure you load a device tree using the fdt addr command before\n"
+ "executing bootefi.\n";
+
+U_BOOT_CMD(
+ bootefi, 2, 0, do_bootefi,
+ "Boots an EFI payload from memory\n",
+ bootefi_help_text
+);
diff --git a/common/board_r.c b/common/board_r.c
index 6c23865..63837e9 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -64,6 +64,7 @@
#ifdef CONFIG_AVR32
#include <asm/arch/mmu.h>
#endif
+#include <efi_loader.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -176,6 +177,9 @@ static int initr_reloc_global_data(void)
*/
gd->fdt_blob += gd->reloc_off;
#endif
+#ifdef CONFIG_EFI_LOADER
+ efi_runtime_relocate(gd->relocaddr, NULL);
+#endif
return 0;
}
@@ -781,6 +785,9 @@ init_fnc_t init_sequence_r[] = {
#ifdef CONFIG_CLOCKS
set_cpu_clk_info, /* Setup clock information */
#endif
+#ifdef CONFIG_EFI_LOADER
+ efi_memory_init,
+#endif
stdio_init_tables,
initr_serial,
initr_announce,
diff --git a/disk/part.c b/disk/part.c
index 1935b28..d265c2b 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -20,13 +20,8 @@
#define PRINTF(fmt,args...)
#endif
-struct block_drvr {
- char *name;
- block_dev_desc_t* (*get_dev)(int dev);
- int (*select_hwpart)(int dev_num, int hwpart);
-};
-static const struct block_drvr block_drvr[] = {
+const struct block_drvr block_drvr[] = {
#if defined(CONFIG_CMD_IDE)
{ .name = "ide", .get_dev = ide_get_dev, },
#endif
diff --git a/doc/README.arm64 b/doc/README.arm64
index de669cb..f658fa2 100644
--- a/doc/README.arm64
+++ b/doc/README.arm64
@@ -36,26 +36,6 @@ Notes
6. CONFIG_ARM64 instead of CONFIG_ARMV8 is used to distinguish aarch64 and
aarch32 specific codes.
-7. CONFIG_SYS_FULL_VA is used to enable 2-level page tables. For cores
- supporting 64k pages it allows usage of full 48+ virtual/physical addresses
-
- Enabling this option requires the following ones to be defined:
- - CONFIG_SYS_MEM_MAP - an array of 'struct mm_region' describing the
- system memory map (start, length, attributes)
- - CONFIG_SYS_MEM_MAP_SIZE - number of entries in CONFIG_SYS_MEM_MAP
- - CONFIG_SYS_PTL1_ENTRIES - number of 1st level page table entries
- - CONFIG_SYS_PTL2_ENTRIES - number of 1nd level page table entries
- for the largest CONFIG_SYS_MEM_MAP entry
- - CONFIG_COREID_MASK - the mask value used to get the core from the
- MPIDR_EL1 register
- - CONFIG_SYS_PTL2_BITS - number of bits addressed by the 2nd level
- page tables
- - CONFIG_SYS_BLOCK_SHIFT - number of bits addressed by a single block
- entry from L2 page tables
- - CONFIG_SYS_PGTABLE_SIZE - total size of the page table
- - CONFIG_SYS_TCR_EL{1,2,3}_IPS_BITS - the IPS field of the TCR_EL{1,2,3}
-
-
Contributor
diff --git a/doc/README.efi b/doc/README.efi
index 23a3cdd..1fd3f00 100644
--- a/doc/README.efi
+++ b/doc/README.efi
@@ -4,6 +4,28 @@
# SPDX-License-Identifier: GPL-2.0+
#
+=========== Table of Contents ===========
+
+ 1 U-Boot on EFI
+ 1.1 In God's Name, Why?
+ 1.2 Status
+ 1.3 Build Instructions
+ 1.4 Trying it out
+ 1.5 Inner workings
+ 1.6 EFI Application
+ 1.7 EFI Payload
+ 1.8 Tables
+ 1.9 Interrupts
+ 1.10 32/64-bit
+ 1.11 Future work
+ 1.12 Where is the code?
+
+ 2 EFI on U-Boot
+ 2.1 In God's Name, Why?
+ 2.2 How do I get it?
+ 2.3 Status
+ 2.4 Future work
+
U-Boot on EFI
=============
This document provides information about U-Boot running on top of EFI, either
@@ -234,7 +256,6 @@ board/efi/efi-x86/efi.c
common/cmd_efi.c
the 'efi' command
-
--
Ben Stoltz, Simon Glass
Google, Inc
@@ -242,3 +263,63 @@ July 2015
[1] http://www.qemu.org
[2] http://www.tianocore.org/ovmf/
+
+-------------------------------------------------------------------------------
+
+EFI on U-Boot
+=============
+
+In addition to support for running U-Boot as a UEFI application, U-Boot itself
+can also expose the UEFI interfaces and thus allow UEFI payloads to run under
+it.
+
+In God's Name, Why?
+-------------------
+
+With this support in place, you can run any UEFI payload (such as the Linux
+kernel, grub2 or gummiboot) on U-Boot. This dramatically simplifies boot loader
+configuration, as U-Boot based systems now look and feel (almost) the same way
+as TianoCore based systems.
+
+How do I get it?
+----------------
+
+EFI support for 32bit ARM and AArch64 is already included in U-Boot. All you
+need to do is enable
+
+ CONFIG_CMD_BOOTEFI=y
+ CONFIG_EFI_LOADER=y
+
+in your .config file and you will automatically get a bootefi command to run
+an efi application as well as snippet in the default distro boot script that
+scans for removable media efi binaries as fallback.
+
+Status
+------
+
+I am successfully able to run grub2 and Linux EFI binaries with this code on
+ARMv7 as well as AArch64 systems.
+
+When enabled, the resulting U-Boot binary only grows by ~10KB, so it's very
+light weight.
+
+All storage devices are directly accessible from the uEFI payload
+
+Removable media booting (search for /efi/boot/boota{a64,arm}.efi) is supported.
+
+Simple use cases like "Plug this SD card into my ARM device and it just
+boots into grub which boots into Linux", work very well.
+
+Future work
+-----------
+
+Of course, there are still a few things one could do on top:
+
+ - Improve disk media detection (don't scan, use what information we
+have)
+ - Add EFI variable support using NVRAM
+ - Add GFX support
+ - Make EFI Shell work
+ - Network device support
+ - Support for payload exit
+ - Payload Watchdog support
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 909e3ca..7329f40 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -189,7 +189,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
data ? DIV_ROUND_UP(data->blocks, 8) : 0);
int ret = 0, flags = 0, i;
unsigned int timeout = 100000;
- u32 retry = 10000;
+ u32 retry = 100000;
u32 mask, ctrl;
ulong start = get_timer(0);
struct bounce_buffer bbstate;
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index 37c6b43..c19f1b0 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -90,6 +90,48 @@
BOOT_TARGET_DEVICES_references_UBIFS_without_CONFIG_CMD_UBIFS
#endif
+#ifdef CONFIG_EFI_LOADER
+#if defined(CONFIG_ARM64)
+#define BOOTEFI_NAME "bootaa64.efi"
+#elif defined(CONFIG_ARM)
+#define BOOTEFI_NAME "bootarm.efi"
+#endif
+#endif
+
+#ifdef BOOTEFI_NAME
+#define BOOTENV_SHARED_EFI \
+ "boot_efi_binary=" \
+ "load ${devtype} ${devnum}:${distro_bootpart} " \
+ "${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; " \
+ "bootefi ${kernel_addr_r}\0" \
+ \
+ "load_efi_dtb=" \
+ "load ${devtype} ${devnum}:${distro_bootpart} " \
+ "${fdt_addr_r} ${prefix}${fdt_name}; " \
+ "fdt addr ${fdt_addr_r}\0" \
+ \
+ "efi_dtb_prefixes=/ /dtb/ /dtb/current/\0" \
+ "scan_dev_for_efi=" \
+ "for prefix in ${efi_dtb_prefixes}; do " \
+ "if test -e ${devtype} " \
+ "${devnum}:${distro_bootpart} " \
+ "${prefix}${fdt_name}; then " \
+ "run load_efi_dtb; " \
+ "fi;" \
+ "done;" \
+ "if test -e ${devtype} ${devnum}:${distro_bootpart} " \
+ "efi/boot/"BOOTEFI_NAME"; then " \
+ "echo Found EFI removable media binary " \
+ "efi/boot/"BOOTEFI_NAME"; " \
+ "run boot_efi_binary; " \
+ "echo EFI LOAD FAILED: continuing...; " \
+ "fi; "
+#define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
+#else
+#define BOOTENV_SHARED_EFI
+#define SCAN_DEV_FOR_EFI
+#endif
+
#ifdef CONFIG_CMD_SATA
#define BOOTENV_SHARED_SATA BOOTENV_SHARED_BLKDEV(sata)
#define BOOTENV_DEV_SATA BOOTENV_DEV_BLKDEV
@@ -217,6 +259,7 @@
BOOTENV_SHARED_SCSI \
BOOTENV_SHARED_IDE \
BOOTENV_SHARED_UBIFS \
+ BOOTENV_SHARED_EFI \
"boot_prefixes=/ /boot/\0" \
"boot_scripts=boot.scr.uimg boot.scr\0" \
"boot_script_dhcp=boot.scr.uimg\0" \
@@ -258,7 +301,9 @@
"for prefix in ${boot_prefixes}; do " \
"run scan_dev_for_extlinux; " \
"run scan_dev_for_scripts; " \
- "done\0" \
+ "done;" \
+ SCAN_DEV_FOR_EFI \
+ "\0" \
\
"scan_dev_for_boot_part=" \
"part list ${devtype} ${devnum} -bootable devplist; " \
diff --git a/include/configs/hikey.h b/include/configs/hikey.h
index 796861e..2d9ace9 100644
--- a/include/configs/hikey.h
+++ b/include/configs/hikey.h
@@ -21,8 +21,8 @@
#define CONFIG_SUPPORT_RAW_INITRD
-/* Cache Definitions */
-#define CONFIG_SYS_DCACHE_OFF
+/* MMU Definitions */
+#define CONFIG_SYS_CACHELINE_SIZE 64
#define CONFIG_IDENT_STRING "hikey"
diff --git a/include/configs/thunderx_88xx.h b/include/configs/thunderx_88xx.h
index cece4dd..736d0a5 100644
--- a/include/configs/thunderx_88xx.h
+++ b/include/configs/thunderx_88xx.h
@@ -22,38 +22,8 @@
#define MEM_BASE 0x00500000
-#define CONFIG_COREID_MASK 0xffffff
-
-#define CONFIG_SYS_FULL_VA
-
#define CONFIG_SYS_LOWMEM_BASE MEM_BASE
-#define CONFIG_SYS_MEM_MAP {{0x000000000000UL, 0x40000000000UL, \
- PTL2_MEMTYPE(MT_NORMAL) | \
- PTL2_BLOCK_NON_SHARE}, \
- {0x800000000000UL, 0x40000000000UL, \
- PTL2_MEMTYPE(MT_DEVICE_NGNRNE) | \
- PTL2_BLOCK_NON_SHARE}, \
- {0x840000000000UL, 0x40000000000UL, \
- PTL2_MEMTYPE(MT_DEVICE_NGNRNE) | \
- PTL2_BLOCK_NON_SHARE}, \
- }
-
-#define CONFIG_SYS_MEM_MAP_SIZE 3
-
-#define CONFIG_SYS_VA_BITS 48
-#define CONFIG_SYS_PTL2_BITS 42
-#define CONFIG_SYS_BLOCK_SHIFT 29
-#define CONFIG_SYS_PTL1_ENTRIES 64
-#define CONFIG_SYS_PTL2_ENTRIES 8192
-
-#define CONFIG_SYS_PGTABLE_SIZE \
- ((CONFIG_SYS_PTL1_ENTRIES + \
- CONFIG_SYS_MEM_MAP_SIZE * CONFIG_SYS_PTL2_ENTRIES) * 8)
-#define CONFIG_SYS_TCR_EL1_IPS_BITS (5UL << 32)
-#define CONFIG_SYS_TCR_EL2_IPS_BITS (5 << 16)
-#define CONFIG_SYS_TCR_EL3_IPS_BITS (5 << 16)
-
/* Link Definitions */
#define CONFIG_SYS_TEXT_BASE 0x00500000
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
diff --git a/include/configs/vexpress_aemv8a.h b/include/configs/vexpress_aemv8a.h
index 133041b..2949170 100644
--- a/include/configs/vexpress_aemv8a.h
+++ b/include/configs/vexpress_aemv8a.h
@@ -19,9 +19,8 @@
#define CONFIG_SUPPORT_RAW_INITRD
-/* Cache Definitions */
-#define CONFIG_SYS_DCACHE_OFF
-#define CONFIG_SYS_ICACHE_OFF
+/* MMU Definitions */
+#define CONFIG_SYS_CACHELINE_SIZE 64
#define CONFIG_IDENT_STRING " vexpress_aemv8a"
#define CONFIG_BOOTP_VCI_STRING "U-Boot.armv8.vexpress_aemv8a"
diff --git a/include/efi.h b/include/efi.h
index fcafda0..1dbc3b7 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -38,6 +38,7 @@ struct efi_device_path;
#define EFI_WRITE_PROTECTED (8 | (1UL << (BITS_PER_LONG - 1)))
#define EFI_OUT_OF_RESOURCES (9 | (1UL << (BITS_PER_LONG - 1)))
#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG - 1)))
+#define EFI_ACCESS_DENIED (15 | (1UL << (BITS_PER_LONG - 1)))
#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG - 1)))
typedef unsigned long efi_status_t;
@@ -139,6 +140,7 @@ enum {
#define EFI_PAGE_SHIFT 12
#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
+#define EFI_PAGE_MASK (EFI_PAGE_SIZE - 1)
struct efi_mem_desc {
u32 type;
diff --git a/include/efi_api.h b/include/efi_api.h
index 4fd17d6..03f6687 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -17,11 +17,18 @@
#include <efi.h>
+/* Types and defines for EFI CreateEvent */
+enum efi_event_type {
+ EFI_TIMER_STOP = 0,
+ EFI_TIMER_PERIODIC = 1,
+ EFI_TIMER_RELATIVE = 2
+};
+
/* EFI Boot Services table */
struct efi_boot_services {
struct efi_table_hdr hdr;
- void *raise_tpl;
- void *restore_tpl;
+ efi_status_t (EFIAPI *raise_tpl)(unsigned long new_tpl);
+ void (EFIAPI *restore_tpl)(unsigned long old_tpl);
efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long,
efi_physical_addr_t *);
@@ -32,21 +39,33 @@ struct efi_boot_services {
efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **);
efi_status_t (EFIAPI *free_pool)(void *);
- void *create_event;
- void *set_timer;
- efi_status_t(EFIAPI *wait_for_event)(unsigned long number_of_events,
- void *event, unsigned long *index);
- void *signal_event;
- void *close_event;
- void *check_event;
-
- void *install_protocol_interface;
- void *reinstall_protocol_interface;
- void *uninstall_protocol_interface;
+ efi_status_t (EFIAPI *create_event)(enum efi_event_type type,
+ unsigned long notify_tpl,
+ void (EFIAPI *notify_function) (void *event,
+ void *context),
+ void *notify_context, void **event);
+ efi_status_t (EFIAPI *set_timer)(void *event, int type,
+ uint64_t trigger_time);
+ efi_status_t (EFIAPI *wait_for_event)(unsigned long number_of_events,
+ void *event, unsigned long *index);
+ efi_status_t (EFIAPI *signal_event)(void *event);
+ efi_status_t (EFIAPI *close_event)(void *event);
+ efi_status_t (EFIAPI *check_event)(void *event);
+
+ efi_status_t (EFIAPI *install_protocol_interface)(
+ void **handle, efi_guid_t *protocol,
+ int protocol_interface_type, void *protocol_interface);
+ efi_status_t (EFIAPI *reinstall_protocol_interface)(
+ void *handle, efi_guid_t *protocol,
+ void *old_interface, void *new_interface);
+ efi_status_t (EFIAPI *uninstall_protocol_interface)(void *handle,
+ efi_guid_t *protocol, void *protocol_interface);
efi_status_t (EFIAPI *handle_protocol)(efi_handle_t, efi_guid_t *,
void **);
void *reserved;
- void *register_protocol_notify;
+ efi_status_t (EFIAPI *register_protocol_notify)(
+ efi_guid_t *protocol, void *event,
+ void **registration);
efi_status_t (EFIAPI *locate_handle)(
enum efi_locate_search_type search_type,
efi_guid_t *protocol, void *search_key,
@@ -54,7 +73,8 @@ struct efi_boot_services {
efi_status_t (EFIAPI *locate_device_path)(efi_guid_t *protocol,
struct efi_device_path **device_path,
efi_handle_t *device);
- void *install_configuration_table;
+ efi_status_t (EFIAPI *install_configuration_table)(
+ efi_guid_t *guid, void *table);
efi_status_t (EFIAPI *load_image)(bool boot_policiy,
efi_handle_t parent_image,
@@ -66,17 +86,20 @@ struct efi_boot_services {
efi_status_t (EFIAPI *exit)(efi_handle_t handle,
efi_status_t exit_status,
unsigned long exitdata_size, s16 *exitdata);
- void *unload_image;
+ efi_status_t (EFIAPI *unload_image)(void *image_handle);
efi_status_t (EFIAPI *exit_boot_services)(efi_handle_t, unsigned long);
efi_status_t (EFIAPI *get_next_monotonic_count)(u64 *count);
efi_status_t (EFIAPI *stall)(unsigned long usecs);
- void *set_watchdog_timer;
+ efi_status_t (EFIAPI *set_watchdog_timer)(unsigned long timeout,
+ uint64_t watchdog_code, unsigned long data_size,
+ uint16_t *watchdog_data);
efi_status_t(EFIAPI *connect_controller)(efi_handle_t controller_handle,
efi_handle_t *driver_image_handle,
struct efi_device_path *remaining_device_path,
bool recursive);
- void *disconnect_controller;
+ efi_status_t (EFIAPI *disconnect_controller)(void *controller_handle,
+ void *driver_image_handle, void *child_handle);
#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002
#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004
@@ -87,7 +110,9 @@ struct efi_boot_services {
efi_guid_t *protocol, void **interface,
efi_handle_t agent_handle,
efi_handle_t controller_handle, u32 attributes);
- void *close_protocol;
+ efi_status_t (EFIAPI *close_protocol)(void *handle,
+ efi_guid_t *protocol, void *agent_handle,
+ void *controller_handle);
efi_status_t(EFIAPI *open_protocol_information)(efi_handle_t handle,
efi_guid_t *protocol,
struct efi_open_protocol_info_entry **entry_buffer,
@@ -99,12 +124,18 @@ struct efi_boot_services {
enum efi_locate_search_type search_type,
efi_guid_t *protocol, void *search_key,
unsigned long *no_handles, efi_handle_t **buffer);
- void *locate_protocol;
- void *install_multiple_protocol_interfaces;
- void *uninstall_multiple_protocol_interfaces;
- void *calculate_crc32;
- void *copy_mem;
- void *set_mem;
+ efi_status_t (EFIAPI *locate_protocol)(efi_guid_t *protocol,
+ void *registration, void **protocol_interface);
+ efi_status_t (EFIAPI *install_multiple_protocol_interfaces)(
+ void **handle, ...);
+ efi_status_t (EFIAPI *uninstall_multiple_protocol_interfaces)(
+ void *handle, ...);
+ efi_status_t (EFIAPI *calculate_crc32)(void *data,
+ unsigned long data_size, uint32_t *crc32);
+ void (EFIAPI *copy_mem)(void *destination, void *source,
+ unsigned long length);
+ void (EFIAPI *set_mem)(void *buffer, unsigned long size,
+ uint8_t value);
void *create_event_ex;
};
@@ -121,12 +152,19 @@ enum efi_reset_type {
struct efi_runtime_services {
struct efi_table_hdr hdr;
- void *get_time;
- void *set_time;
- void *get_wakeup_time;
- void *set_wakeup_time;
- void *set_virtual_address_map;
- void *convert_pointer;
+ efi_status_t (EFIAPI *get_time)(struct efi_time *time,
+ struct efi_time_cap *capabilities);
+ efi_status_t (EFIAPI *set_time)(struct efi_time *time);
+ efi_status_t (EFIAPI *get_wakeup_time)(char *enabled, char *pending,
+ struct efi_time *time);
+ efi_status_t (EFIAPI *set_wakeup_time)(char enabled,
+ struct efi_time *time);
+ efi_status_t (EFIAPI *set_virtual_address_map)(
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ uint32_t descriptor_version,
+ struct efi_mem_desc *virtmap);
+ efi_status_t (*convert_pointer)(unsigned long dbg, void **address);
efi_status_t (EFIAPI *get_variable)(s16 *variable_name,
efi_guid_t *vendor, u32 *attributes,
unsigned long *data_size, void *data);
@@ -136,7 +174,8 @@ struct efi_runtime_services {
efi_status_t (EFIAPI *set_variable)(s16 *variable_name,
efi_guid_t *vendor, u32 attributes,
unsigned long data_size, void *data);
- void *get_next_high_mono_count;
+ efi_status_t (EFIAPI *get_next_high_mono_count)(
+ uint32_t *high_count);
void (EFIAPI *reset_system)(enum efi_reset_type reset_type,
efi_status_t reset_status,
unsigned long data_size, void *reset_data);
@@ -154,6 +193,18 @@ struct efi_runtime_services {
EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \
0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_FDT_GUID \
+ EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \
+ 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
+
+struct efi_configuration_table
+{
+ efi_guid_t guid;
+ void *table;
+};
+
+#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
+
struct efi_system_table {
struct efi_table_hdr hdr;
unsigned long fw_vendor; /* physical addr of wchar_t vendor string */
@@ -163,13 +214,17 @@ struct efi_system_table {
unsigned long con_out_handle;
struct efi_simple_text_output_protocol *con_out;
unsigned long stderr_handle;
- unsigned long std_err;
+ struct efi_simple_text_output_protocol *std_err;
struct efi_runtime_services *runtime;
struct efi_boot_services *boottime;
unsigned long nr_tables;
- unsigned long tables;
+ struct efi_configuration_table *tables;
};
+#define LOADED_IMAGE_GUID \
+ EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \
+ 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
struct efi_loaded_image {
u32 revision;
void *parent_handle;
@@ -186,12 +241,60 @@ struct efi_loaded_image {
unsigned long unload;
};
+#define DEVICE_PATH_GUID \
+ EFI_GUID(0x09576e91, 0x6d3f, 0x11d2, \
+ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
+#define DEVICE_PATH_TYPE_END 0x7f
+# define DEVICE_PATH_SUB_TYPE_END 0xff
+
struct efi_device_path {
u8 type;
u8 sub_type;
u16 length;
};
+#define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04
+# define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04
+
+struct efi_device_path_file_path {
+ struct efi_device_path dp;
+ u16 str[16];
+};
+
+#define BLOCK_IO_GUID \
+ EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \
+ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
+struct efi_block_io_media
+{
+ u32 media_id;
+ char removable_media;
+ char media_present;
+ char logical_partition;
+ char read_only;
+ char write_caching;
+ u8 pad[3];
+ u32 block_size;
+ u32 io_align;
+ u8 pad2[4];
+ u64 last_block;
+};
+
+struct efi_block_io {
+ u64 revision;
+ struct efi_block_io_media *media;
+ efi_status_t (EFIAPI *reset)(struct efi_block_io *this,
+ char extended_verification);
+ efi_status_t (EFIAPI *read_blocks)(struct efi_block_io *this,
+ u32 media_id, u64 lba, unsigned long buffer_size,
+ void *buffer);
+ efi_status_t (EFIAPI *write_blocks)(struct efi_block_io *this,
+ u32 media_id, u64 lba, unsigned long buffer_size,
+ void *buffer);
+ efi_status_t (EFIAPI *flush_blocks)(struct efi_block_io *this);
+};
+
struct simple_text_output_mode {
s32 max_mode;
s32 mode;
@@ -206,8 +309,9 @@ struct efi_simple_text_output_protocol {
efi_status_t (EFIAPI *output_string)(
struct efi_simple_text_output_protocol *this,
const unsigned short *str);
- void *test_string;
-
+ efi_status_t (EFIAPI *test_string)(
+ struct efi_simple_text_output_protocol *this,
+ const unsigned short *str);
efi_status_t(EFIAPI *query_mode)(
struct efi_simple_text_output_protocol *this,
unsigned long mode_number, unsigned long *columns,
@@ -223,7 +327,9 @@ struct efi_simple_text_output_protocol {
efi_status_t(EFIAPI *set_cursor_position) (
struct efi_simple_text_output_protocol *this,
unsigned long column, unsigned long row);
- efi_status_t(EFIAPI *enable_cursor)(void *, bool enable);
+ efi_status_t(EFIAPI *enable_cursor)(
+ struct efi_simple_text_output_protocol *this,
+ bool enable);
struct simple_text_output_mode *mode;
};
@@ -241,4 +347,22 @@ struct efi_simple_input_interface {
void *wait_for_key;
};
+#define CONSOLE_CONTROL_GUID \
+ EFI_GUID(0xf42f7782, 0x12e, 0x4c12, \
+ 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21)
+#define EFI_CONSOLE_MODE_TEXT 0
+#define EFI_CONSOLE_MODE_GFX 1
+
+struct efi_console_control_protocol
+{
+ efi_status_t (EFIAPI *get_mode)(
+ struct efi_console_control_protocol *this, int *mode,
+ char *uga_exists, char *std_in_locked);
+ efi_status_t (EFIAPI *set_mode)(
+ struct efi_console_control_protocol *this, int mode);
+ efi_status_t (EFIAPI *lock_std_in)(
+ struct efi_console_control_protocol *this,
+ uint16_t *password);
+};
+
#endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
new file mode 100644
index 0000000..e344566
--- /dev/null
+++ b/include/efi_loader.h
@@ -0,0 +1,147 @@
+/*
+ * EFI application loader
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <part_efi.h>
+#include <efi_api.h>
+
+#ifdef CONFIG_EFI_LOADER
+
+#include <linux/list.h>
+
+/* #define DEBUG_EFI */
+
+#ifdef DEBUG_EFI
+#define EFI_ENTRY(format, ...) do { \
+ efi_restore_gd(); \
+ printf("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \
+ } while(0)
+#else
+#define EFI_ENTRY(format, ...) do { \
+ efi_restore_gd(); \
+ } while(0)
+#endif
+
+#define EFI_EXIT(ret) efi_exit_func(ret);
+
+extern struct efi_runtime_services efi_runtime_services;
+extern struct efi_system_table systab;
+
+extern const struct efi_simple_text_output_protocol efi_con_out;
+extern const struct efi_simple_input_interface efi_con_in;
+extern const struct efi_console_control_protocol efi_console_control;
+
+extern const efi_guid_t efi_guid_console_control;
+extern const efi_guid_t efi_guid_device_path;
+extern const efi_guid_t efi_guid_loaded_image;
+
+extern unsigned int __efi_runtime_start, __efi_runtime_stop;
+extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
+
+/*
+ * While UEFI objects can have callbacks, you can also call functions on
+ * protocols (classes) themselves. This struct maps a protocol GUID to its
+ * interface (usually a struct with callback functions).
+ */
+struct efi_class_map {
+ const efi_guid_t *guid;
+ const void *interface;
+};
+
+/*
+ * When the UEFI payload wants to open a protocol on an object to get its
+ * interface (usually a struct with callback functions), this struct maps the
+ * protocol GUID to the respective protocol handler open function for that
+ * object protocol combination.
+ */
+struct efi_handler {
+ const efi_guid_t *guid;
+ efi_status_t (EFIAPI *open)(void *handle,
+ efi_guid_t *protocol, void **protocol_interface,
+ void *agent_handle, void *controller_handle,
+ uint32_t attributes);
+};
+
+/*
+ * UEFI has a poor man's OO model where one "object" can be polymorphic and have
+ * multiple different protocols (classes) attached to it.
+ *
+ * This struct is the parent struct for all of our actual implementation objects
+ * that can include it to make themselves an EFI object
+ */
+struct efi_object {
+ /* Every UEFI object is part of a global object list */
+ struct list_head link;
+ /* We support up to 4 "protocols" an object can be accessed through */
+ struct efi_handler protocols[4];
+ /* The object spawner can either use this for data or as identifier */
+ void *handle;
+};
+
+/* This list contains all UEFI objects we know of */
+extern struct list_head efi_obj_list;
+
+/* Called by bootefi to make all disk storage accessible as EFI objects */
+int efi_disk_register(void);
+/*
+ * Stub implementation for a protocol opener that just returns the handle as
+ * interface
+ */
+efi_status_t efi_return_handle(void *handle,
+ efi_guid_t *protocol, void **protocol_interface,
+ void *agent_handle, void *controller_handle,
+ uint32_t attributes);
+/* Called from places to check whether a timer expired */
+void efi_timer_check(void);
+/* PE loader implementation */
+void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
+/* Called once to store the pristine gd pointer */
+void efi_save_gd(void);
+/* Called from EFI_ENTRY on callback entry to put gd into the gd register */
+void efi_restore_gd(void);
+/* Called from EFI_EXIT on callback exit to restore the gd register */
+efi_status_t efi_exit_func(efi_status_t ret);
+/* Call this to relocate the runtime section to an address space */
+void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
+
+/* Generic EFI memory allocator, call this to get memory */
+void *efi_alloc(uint64_t len, int memory_type);
+/* More specific EFI memory allocator, called by EFI payloads */
+efi_status_t efi_allocate_pages(int type, int memory_type, unsigned long pages,
+ uint64_t *memory);
+/* EFI memory free function. Not implemented today */
+efi_status_t efi_free_pages(uint64_t memory, unsigned long pages);
+/* Returns the EFI memory map */
+efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
+ struct efi_mem_desc *memory_map,
+ unsigned long *map_key,
+ unsigned long *descriptor_size,
+ uint32_t *descriptor_version);
+/* Adds a range into the EFI memory map */
+uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
+ bool overlap_only_ram);
+/* Called by board init to initialize the EFI memory map */
+int efi_memory_init(void);
+
+/*
+ * Use these to indicate that your code / data should go into the EFI runtime
+ * section and thus still be available when the OS is running
+ */
+#define EFI_RUNTIME_DATA __attribute__ ((section ("efi_runtime_data")))
+#define EFI_RUNTIME_TEXT __attribute__ ((section ("efi_runtime_text")))
+
+#else /* defined(EFI_LOADER) */
+
+/* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
+#define EFI_RUNTIME_DATA
+#define EFI_RUNTIME_TEXT
+
+/* No loader configured, stub out EFI_ENTRY */
+static inline void efi_restore_gd(void) { }
+
+#endif
diff --git a/include/part.h b/include/part.h
index dc23949..6e6205b 100644
--- a/include/part.h
+++ b/include/part.h
@@ -42,6 +42,12 @@ struct block_dev_desc {
void *priv; /* driver private struct pointer */
};
+struct block_drvr {
+ char *name;
+ block_dev_desc_t* (*get_dev)(int dev);
+ int (*select_hwpart)(int dev_num, int hwpart);
+};
+
#define BLOCK_CNT(size, block_dev_desc) (PAD_COUNT(size, block_dev_desc->blksz))
#define PAD_TO_BLOCKSIZE(size, block_dev_desc) \
(PAD_SIZE(size, block_dev_desc->blksz))
@@ -123,6 +129,8 @@ int get_device(const char *ifname, const char *dev_str,
int get_device_and_partition(const char *ifname, const char *dev_part_str,
block_dev_desc_t **dev_desc,
disk_partition_t *info, int allow_whole_dev);
+
+extern const struct block_drvr block_drvr[];
#else
static inline block_dev_desc_t *get_dev(const char *ifname, int dev)
{ return NULL; }
diff --git a/include/pe.h b/include/pe.h
new file mode 100644
index 0000000..deb35a0
--- /dev/null
+++ b/include/pe.h
@@ -0,0 +1,263 @@
+/*
+ * Portable Executable binary format structures
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * Based on wine code
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _PE_H
+#define _PE_H
+
+typedef struct _IMAGE_DOS_HEADER {
+ uint16_t e_magic; /* 00: MZ Header signature */
+ uint16_t e_cblp; /* 02: Bytes on last page of file */
+ uint16_t e_cp; /* 04: Pages in file */
+ uint16_t e_crlc; /* 06: Relocations */
+ uint16_t e_cparhdr; /* 08: Size of header in paragraphs */
+ uint16_t e_minalloc; /* 0a: Minimum extra paragraphs needed */
+ uint16_t e_maxalloc; /* 0c: Maximum extra paragraphs needed */
+ uint16_t e_ss; /* 0e: Initial (relative) SS value */
+ uint16_t e_sp; /* 10: Initial SP value */
+ uint16_t e_csum; /* 12: Checksum */
+ uint16_t e_ip; /* 14: Initial IP value */
+ uint16_t e_cs; /* 16: Initial (relative) CS value */
+ uint16_t e_lfarlc; /* 18: File address of relocation table */
+ uint16_t e_ovno; /* 1a: Overlay number */
+ uint16_t e_res[4]; /* 1c: Reserved words */
+ uint16_t e_oemid; /* 24: OEM identifier (for e_oeminfo) */
+ uint16_t e_oeminfo; /* 26: OEM information; e_oemid specific */
+ uint16_t e_res2[10]; /* 28: Reserved words */
+ uint32_t e_lfanew; /* 3c: Offset to extended header */
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
+#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
+
+#define IMAGE_FILE_MACHINE_ARM 0x01c0
+#define IMAGE_FILE_MACHINE_THUMB 0x01c2
+#define IMAGE_FILE_MACHINE_ARMNT 0x01c4
+#define IMAGE_FILE_MACHINE_AMD64 0x8664
+#define IMAGE_FILE_MACHINE_ARM64 0xaa64
+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+
+typedef struct _IMAGE_FILE_HEADER {
+ uint16_t Machine;
+ uint16_t NumberOfSections;
+ uint32_t TimeDateStamp;
+ uint32_t PointerToSymbolTable;
+ uint32_t NumberOfSymbols;
+ uint16_t SizeOfOptionalHeader;
+ uint16_t Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+ uint32_t VirtualAddress;
+ uint32_t Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+
+typedef struct _IMAGE_OPTIONAL_HEADER64 {
+ uint16_t Magic; /* 0x20b */
+ uint8_t MajorLinkerVersion;
+ uint8_t MinorLinkerVersion;
+ uint32_t SizeOfCode;
+ uint32_t SizeOfInitializedData;
+ uint32_t SizeOfUninitializedData;
+ uint32_t AddressOfEntryPoint;
+ uint32_t BaseOfCode;
+ uint64_t ImageBase;
+ uint32_t SectionAlignment;
+ uint32_t FileAlignment;
+ uint16_t MajorOperatingSystemVersion;
+ uint16_t MinorOperatingSystemVersion;
+ uint16_t MajorImageVersion;
+ uint16_t MinorImageVersion;
+ uint16_t MajorSubsystemVersion;
+ uint16_t MinorSubsystemVersion;
+ uint32_t Win32VersionValue;
+ uint32_t SizeOfImage;
+ uint32_t SizeOfHeaders;
+ uint32_t CheckSum;
+ uint16_t Subsystem;
+ uint16_t DllCharacteristics;
+ uint64_t SizeOfStackReserve;
+ uint64_t SizeOfStackCommit;
+ uint64_t SizeOfHeapReserve;
+ uint64_t SizeOfHeapCommit;
+ uint32_t LoaderFlags;
+ uint32_t NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
+
+typedef struct _IMAGE_NT_HEADERS64 {
+ uint32_t Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+
+ /* Standard fields */
+
+ uint16_t Magic; /* 0x10b or 0x107 */ /* 0x00 */
+ uint8_t MajorLinkerVersion;
+ uint8_t MinorLinkerVersion;
+ uint32_t SizeOfCode;
+ uint32_t SizeOfInitializedData;
+ uint32_t SizeOfUninitializedData;
+ uint32_t AddressOfEntryPoint; /* 0x10 */
+ uint32_t BaseOfCode;
+ uint32_t BaseOfData;
+
+ /* NT additional fields */
+
+ uint32_t ImageBase;
+ uint32_t SectionAlignment; /* 0x20 */
+ uint32_t FileAlignment;
+ uint16_t MajorOperatingSystemVersion;
+ uint16_t MinorOperatingSystemVersion;
+ uint16_t MajorImageVersion;
+ uint16_t MinorImageVersion;
+ uint16_t MajorSubsystemVersion; /* 0x30 */
+ uint16_t MinorSubsystemVersion;
+ uint32_t Win32VersionValue;
+ uint32_t SizeOfImage;
+ uint32_t SizeOfHeaders;
+ uint32_t CheckSum; /* 0x40 */
+ uint16_t Subsystem;
+ uint16_t DllCharacteristics;
+ uint32_t SizeOfStackReserve;
+ uint32_t SizeOfStackCommit;
+ uint32_t SizeOfHeapReserve; /* 0x50 */
+ uint32_t SizeOfHeapCommit;
+ uint32_t LoaderFlags;
+ uint32_t NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */
+ /* 0xE0 */
+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
+
+typedef struct _IMAGE_NT_HEADERS {
+ uint32_t Signature; /* "PE"\0\0 */ /* 0x00 */
+ IMAGE_FILE_HEADER FileHeader; /* 0x04 */
+ IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */
+} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
+
+#define IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct _IMAGE_SECTION_HEADER {
+ uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ uint32_t PhysicalAddress;
+ uint32_t VirtualSize;
+ } Misc;
+ uint32_t VirtualAddress;
+ uint32_t SizeOfRawData;
+ uint32_t PointerToRawData;
+ uint32_t PointerToRelocations;
+ uint32_t PointerToLinenumbers;
+ uint16_t NumberOfRelocations;
+ uint16_t NumberOfLinenumbers;
+ uint32_t Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
+
+typedef struct _IMAGE_BASE_RELOCATION
+{
+ uint32_t VirtualAddress;
+ uint32_t SizeOfBlock;
+ /* WORD TypeOffset[1]; */
+} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
+
+typedef struct _IMAGE_RELOCATION
+{
+ union {
+ uint32_t VirtualAddress;
+ uint32_t RelocCount;
+ } DUMMYUNIONNAME;
+ uint32_t SymbolTableIndex;
+ uint16_t Type;
+} IMAGE_RELOCATION, *PIMAGE_RELOCATION;
+
+#define IMAGE_SIZEOF_RELOCATION 10
+
+/* generic relocation types */
+#define IMAGE_REL_BASED_ABSOLUTE 0
+#define IMAGE_REL_BASED_HIGH 1
+#define IMAGE_REL_BASED_LOW 2
+#define IMAGE_REL_BASED_HIGHLOW 3
+#define IMAGE_REL_BASED_HIGHADJ 4
+#define IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define IMAGE_REL_BASED_ARM_MOV32A 5 /* yes, 5 too */
+#define IMAGE_REL_BASED_ARM_MOV32 5 /* yes, 5 too */
+#define IMAGE_REL_BASED_SECTION 6
+#define IMAGE_REL_BASED_REL 7
+#define IMAGE_REL_BASED_ARM_MOV32T 7 /* yes, 7 too */
+#define IMAGE_REL_BASED_THUMB_MOV32 7 /* yes, 7 too */
+#define IMAGE_REL_BASED_MIPS_JMPADDR16 9
+#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */
+#define IMAGE_REL_BASED_DIR64 10
+#define IMAGE_REL_BASED_HIGH3ADJ 11
+
+/* ARM relocation types */
+#define IMAGE_REL_ARM_ABSOLUTE 0x0000
+#define IMAGE_REL_ARM_ADDR 0x0001
+#define IMAGE_REL_ARM_ADDR32NB 0x0002
+#define IMAGE_REL_ARM_BRANCH24 0x0003
+#define IMAGE_REL_ARM_BRANCH11 0x0004
+#define IMAGE_REL_ARM_TOKEN 0x0005
+#define IMAGE_REL_ARM_GPREL12 0x0006
+#define IMAGE_REL_ARM_GPREL7 0x0007
+#define IMAGE_REL_ARM_BLX24 0x0008
+#define IMAGE_REL_ARM_BLX11 0x0009
+#define IMAGE_REL_ARM_SECTION 0x000E
+#define IMAGE_REL_ARM_SECREL 0x000F
+#define IMAGE_REL_ARM_MOV32A 0x0010
+#define IMAGE_REL_ARM_MOV32T 0x0011
+#define IMAGE_REL_ARM_BRANCH20T 0x0012
+#define IMAGE_REL_ARM_BRANCH24T 0x0014
+#define IMAGE_REL_ARM_BLX23T 0x0015
+
+/* ARM64 relocation types */
+#define IMAGE_REL_ARM64_ABSOLUTE 0x0000
+#define IMAGE_REL_ARM64_ADDR32 0x0001
+#define IMAGE_REL_ARM64_ADDR32NB 0x0002
+#define IMAGE_REL_ARM64_BRANCH26 0x0003
+#define IMAGE_REL_ARM64_PAGEBASE_REL21 0x0004
+#define IMAGE_REL_ARM64_REL21 0x0005
+#define IMAGE_REL_ARM64_PAGEOFFSET_12A 0x0006
+#define IMAGE_REL_ARM64_PAGEOFFSET_12L 0x0007
+#define IMAGE_REL_ARM64_SECREL 0x0008
+#define IMAGE_REL_ARM64_SECREL_LOW12A 0x0009
+#define IMAGE_REL_ARM64_SECREL_HIGH12A 0x000A
+#define IMAGE_REL_ARM64_SECREL_LOW12L 0x000B
+#define IMAGE_REL_ARM64_TOKEN 0x000C
+#define IMAGE_REL_ARM64_SECTION 0x000D
+#define IMAGE_REL_ARM64_ADDR64 0x000E
+
+/* AMD64 relocation types */
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001
+#define IMAGE_REL_AMD64_ADDR32 0x0002
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+#endif /* _PE_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index c7eab46..a67df3c 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -129,5 +129,6 @@ config ERRNO_STR
- if errno is negative - a pointer to errno related message
source lib/efi/Kconfig
+source lib/efi_loader/Kconfig
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 1e21bcc..4aaa2ea 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,6 +8,7 @@
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_EFI) += efi/
+obj-$(CONFIG_EFI_LOADER) += efi_loader/
obj-$(CONFIG_RSA) += rsa/
obj-$(CONFIG_LZMA) += lzma/
obj-$(CONFIG_LZO) += lzo/
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
new file mode 100644
index 0000000..6da1c7f
--- /dev/null
+++ b/lib/efi_loader/Kconfig
@@ -0,0 +1,9 @@
+config EFI_LOADER
+ bool "Support running EFI Applications in U-Boot"
+ depends on ARM64 || ARM
+ default y
+ help
+ Select this option if you want to run EFI applications (like grub2)
+ on top of U-Boot. If this option is enabled, U-Boot will expose EFI
+ interfaces to a loaded EFI application, enabling it to reuse U-Boot's
+ device drivers.
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
new file mode 100644
index 0000000..28725a2
--- /dev/null
+++ b/lib/efi_loader/Makefile
@@ -0,0 +1,12 @@
+#
+# (C) Copyright 2016 Alexander Graf
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+# This file only gets included with CONFIG_EFI_LOADER set, so all
+# object inclusion implicitly depends on it
+
+obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
+obj-y += efi_memory.o
+obj-$(CONFIG_PARTITIONS) += efi_disk.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
new file mode 100644
index 0000000..87400de
--- /dev/null
+++ b/lib/efi_loader/efi_boottime.c
@@ -0,0 +1,781 @@
+/*
+ * EFI application boot time services
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* #define DEBUG_EFI */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <libfdt_env.h>
+#include <u-boot/crc.h>
+#include <bootm.h>
+#include <inttypes.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* This list contains all the EFI objects our payload has access to */
+LIST_HEAD(efi_obj_list);
+
+/*
+ * If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
+ * we need to do trickery with caches. Since we don't want to break the EFI
+ * aware boot path, only apply hacks when loading exiting directly (breaking
+ * direct Linux EFI booting along the way - oh well).
+ */
+static bool efi_is_direct_boot = true;
+
+/*
+ * EFI can pass arbitrary additional "tables" containing vendor specific
+ * information to the payload. One such table is the FDT table which contains
+ * a pointer to a flattened device tree blob.
+ *
+ * In most cases we want to pass an FDT to the payload, so reserve one slot of
+ * config table space for it. The pointer gets populated by do_bootefi_exec().
+ */
+static struct efi_configuration_table EFI_RUNTIME_DATA efi_conf_table[1];
+
+/*
+ * The "gd" pointer lives in a register on ARM and AArch64 that we declare
+ * fixed when compiling U-Boot. However, the payload does not know about that
+ * restriction so we need to manually swap its and our view of that register on
+ * EFI callback entry/exit.
+ */
+static volatile void *efi_gd, *app_gd;
+
+/* Called from do_bootefi_exec() */
+void efi_save_gd(void)
+{
+ efi_gd = gd;
+}
+
+/* Called on every callback entry */
+void efi_restore_gd(void)
+{
+ /* Only restore if we're already in EFI context */
+ if (!efi_gd)
+ return;
+
+ if (gd != efi_gd)
+ app_gd = gd;
+ gd = efi_gd;
+}
+
+/* Called on every callback exit */
+efi_status_t efi_exit_func(efi_status_t ret)
+{
+ gd = app_gd;
+ return ret;
+}
+
+static efi_status_t efi_unsupported(const char *funcname)
+{
+#ifdef DEBUG_EFI
+ printf("EFI: App called into unimplemented function %s\n", funcname);
+#endif
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2)
+{
+ return memcmp(g1, g2, sizeof(efi_guid_t));
+}
+
+static unsigned long EFIAPI efi_raise_tpl(unsigned long new_tpl)
+{
+ EFI_ENTRY("0x%lx", new_tpl);
+ return EFI_EXIT(0);
+}
+
+static void EFIAPI efi_restore_tpl(unsigned long old_tpl)
+{
+ EFI_ENTRY("0x%lx", old_tpl);
+ EFI_EXIT(efi_unsupported(__func__));
+}
+
+efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type,
+ unsigned long pages,
+ uint64_t *memory)
+{
+ efi_status_t r;
+
+ EFI_ENTRY("%d, %d, 0x%lx, %p", type, memory_type, pages, memory);
+ r = efi_allocate_pages(type, memory_type, pages, memory);
+ return EFI_EXIT(r);
+}
+
+efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, unsigned long pages)
+{
+ efi_status_t r;
+
+ EFI_ENTRY("%"PRIx64", 0x%lx", memory, pages);
+ r = efi_free_pages(memory, pages);
+ return EFI_EXIT(r);
+}
+
+efi_status_t EFIAPI efi_get_memory_map_ext(unsigned long *memory_map_size,
+ struct efi_mem_desc *memory_map,
+ unsigned long *map_key,
+ unsigned long *descriptor_size,
+ uint32_t *descriptor_version)
+{
+ efi_status_t r;
+
+ EFI_ENTRY("%p, %p, %p, %p, %p", memory_map_size, memory_map,
+ map_key, descriptor_size, descriptor_version);
+ r = efi_get_memory_map(memory_map_size, memory_map, map_key,
+ descriptor_size, descriptor_version);
+ return EFI_EXIT(r);
+}
+
+static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size,
+ void **buffer)
+{
+ return efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer);
+}
+
+static efi_status_t EFIAPI efi_free_pool(void *buffer)
+{
+ return efi_free_pages((ulong)buffer, 0);
+}
+
+/*
+ * Our event capabilities are very limited. Only support a single
+ * event to exist, so we don't need to maintain lists.
+ */
+static struct {
+ enum efi_event_type type;
+ u32 trigger_type;
+ u32 trigger_time;
+ u64 trigger_next;
+ unsigned long notify_tpl;
+ void (*notify_function) (void *event, void *context);
+ void *notify_context;
+} efi_event = {
+ /* Disable timers on bootup */
+ .trigger_next = -1ULL,
+};
+
+static efi_status_t EFIAPI efi_create_event(
+ enum efi_event_type type, ulong notify_tpl,
+ void (*notify_function) (void *event, void *context),
+ void *notify_context, void **event)
+{
+ EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function,
+ notify_context);
+ if (efi_event.notify_function) {
+ /* We only support one event at a time */
+ return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+ }
+
+ efi_event.type = type;
+ efi_event.notify_tpl = notify_tpl;
+ efi_event.notify_function = notify_function;
+ efi_event.notify_context = notify_context;
+ *event = &efi_event;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+/*
+ * Our timers have to work without interrupts, so we check whenever keyboard
+ * input or disk accesses happen if enough time elapsed for it to fire.
+ */
+void efi_timer_check(void)
+{
+ u64 now = timer_get_us();
+
+ if (now >= efi_event.trigger_next) {
+ /* Triggering! */
+ if (efi_event.trigger_type == EFI_TIMER_PERIODIC)
+ efi_event.trigger_next += efi_event.trigger_time / 10;
+ efi_event.notify_function(&efi_event, efi_event.notify_context);
+ }
+
+ WATCHDOG_RESET();
+}
+
+static efi_status_t EFIAPI efi_set_timer(void *event, int type,
+ uint64_t trigger_time)
+{
+ /* We don't have 64bit division available everywhere, so limit timer
+ * distances to 32bit bits. */
+ u32 trigger32 = trigger_time;
+
+ EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time);
+
+ if (trigger32 < trigger_time) {
+ printf("WARNING: Truncating timer from %"PRIx64" to %x\n",
+ trigger_time, trigger32);
+ }
+
+ if (event != &efi_event) {
+ /* We only support one event at a time */
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+ }
+
+ switch (type) {
+ case EFI_TIMER_STOP:
+ efi_event.trigger_next = -1ULL;
+ break;
+ case EFI_TIMER_PERIODIC:
+ case EFI_TIMER_RELATIVE:
+ efi_event.trigger_next = timer_get_us() + (trigger32 / 10);
+ break;
+ default:
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+ }
+ efi_event.trigger_type = type;
+ efi_event.trigger_time = trigger_time;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
+ void *event, unsigned long *index)
+{
+ u64 now;
+
+ EFI_ENTRY("%ld, %p, %p", num_events, event, index);
+
+ now = timer_get_us();
+ while (now < efi_event.trigger_next) { }
+ efi_timer_check();
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_signal_event(void *event)
+{
+ EFI_ENTRY("%p", event);
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_close_event(void *event)
+{
+ EFI_ENTRY("%p", event);
+ efi_event.trigger_next = -1ULL;
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_check_event(void *event)
+{
+ EFI_ENTRY("%p", event);
+ return EFI_EXIT(EFI_NOT_READY);
+}
+
+static efi_status_t EFIAPI efi_install_protocol_interface(void **handle,
+ efi_guid_t *protocol, int protocol_interface_type,
+ void *protocol_interface)
+{
+ EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type,
+ protocol_interface);
+ return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle,
+ efi_guid_t *protocol, void *old_interface,
+ void *new_interface)
+{
+ EFI_ENTRY("%p, %p, %p, %p", handle, protocol, old_interface,
+ new_interface);
+ return EFI_EXIT(EFI_ACCESS_DENIED);
+}
+
+static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle,
+ efi_guid_t *protocol, void *protocol_interface)
+{
+ EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface);
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol,
+ void *event,
+ void **registration)
+{
+ EFI_ENTRY("%p, %p, %p", protocol, event, registration);
+ return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static int efi_search(enum efi_locate_search_type search_type,
+ efi_guid_t *protocol, void *search_key,
+ struct efi_object *efiobj)
+{
+ int i;
+
+ switch (search_type) {
+ case all_handles:
+ return 0;
+ case by_register_notify:
+ return -1;
+ case by_protocol:
+ for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
+ const efi_guid_t *guid = efiobj->protocols[i].guid;
+ if (guid && !guidcmp(guid, protocol))
+ return 0;
+ }
+ return -1;
+ }
+
+ return -1;
+}
+
+static efi_status_t EFIAPI efi_locate_handle(
+ enum efi_locate_search_type search_type,
+ efi_guid_t *protocol, void *search_key,
+ unsigned long *buffer_size, efi_handle_t *buffer)
+{
+ struct list_head *lhandle;
+ unsigned long size = 0;
+
+ EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key,
+ buffer_size, buffer);
+
+ /* Count how much space we need */
+ list_for_each(lhandle, &efi_obj_list) {
+ struct efi_object *efiobj;
+ efiobj = list_entry(lhandle, struct efi_object, link);
+ if (!efi_search(search_type, protocol, search_key, efiobj)) {
+ size += sizeof(void*);
+ }
+ }
+
+ if (*buffer_size < size) {
+ *buffer_size = size;
+ return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+ }
+
+ /* Then fill the array */
+ list_for_each(lhandle, &efi_obj_list) {
+ struct efi_object *efiobj;
+ efiobj = list_entry(lhandle, struct efi_object, link);
+ if (!efi_search(search_type, protocol, search_key, efiobj)) {
+ *(buffer++) = efiobj->handle;
+ }
+ }
+
+ *buffer_size = size;
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol,
+ struct efi_device_path **device_path,
+ efi_handle_t *device)
+{
+ EFI_ENTRY("%p, %p, %p", protocol, device_path, device);
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI efi_install_configuration_table(efi_guid_t *guid,
+ void *table)
+{
+ int i;
+
+ EFI_ENTRY("%p, %p", guid, table);
+
+ /* Check for guid override */
+ for (i = 0; i < systab.nr_tables; i++) {
+ if (!guidcmp(guid, &efi_conf_table[i].guid)) {
+ efi_conf_table[i].table = table;
+ return EFI_EXIT(EFI_SUCCESS);
+ }
+ }
+
+ /* No override, check for overflow */
+ if (i >= ARRAY_SIZE(efi_conf_table))
+ return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+
+ /* Add a new entry */
+ memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid));
+ efi_conf_table[i].table = table;
+ systab.nr_tables = i;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_load_image(bool boot_policy,
+ efi_handle_t parent_image,
+ struct efi_device_path *file_path,
+ void *source_buffer,
+ unsigned long source_size,
+ efi_handle_t *image_handle)
+{
+ static struct efi_object loaded_image_info_obj = {
+ .protocols = {
+ {
+ .guid = &efi_guid_loaded_image,
+ .open = &efi_return_handle,
+ },
+ },
+ };
+ struct efi_loaded_image *info;
+ struct efi_object *obj;
+
+ EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
+ file_path, source_buffer, source_size, image_handle);
+ info = malloc(sizeof(*info));
+ obj = malloc(sizeof(loaded_image_info_obj));
+ memset(info, 0, sizeof(*info));
+ memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj));
+ obj->handle = info;
+ info->file_path = file_path;
+ info->reserved = efi_load_pe(source_buffer, info);
+ if (!info->reserved) {
+ free(info);
+ free(obj);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+ }
+
+ *image_handle = info;
+ list_add_tail(&obj->link, &efi_obj_list);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
+ unsigned long *exit_data_size,
+ s16 **exit_data)
+{
+ ulong (*entry)(void *image_handle, struct efi_system_table *st);
+ struct efi_loaded_image *info = image_handle;
+
+ EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
+ entry = info->reserved;
+
+ efi_is_direct_boot = false;
+
+ /* call the image! */
+ entry(image_handle, &systab);
+
+ /* Should usually never get here */
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_exit(void *image_handle, long exit_status,
+ unsigned long exit_data_size,
+ uint16_t *exit_data)
+{
+ EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
+ exit_data_size, exit_data);
+ return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static struct efi_object *efi_search_obj(void *handle)
+{
+ struct list_head *lhandle;
+
+ list_for_each(lhandle, &efi_obj_list) {
+ struct efi_object *efiobj;
+ efiobj = list_entry(lhandle, struct efi_object, link);
+ if (efiobj->handle == handle)
+ return efiobj;
+ }
+
+ return NULL;
+}
+
+static efi_status_t EFIAPI efi_unload_image(void *image_handle)
+{
+ struct efi_object *efiobj;
+
+ EFI_ENTRY("%p", image_handle);
+ efiobj = efi_search_obj(image_handle);
+ if (efiobj)
+ list_del(&efiobj->link);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static void efi_exit_caches(void)
+{
+#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
+ /*
+ * Grub on 32bit ARM needs to have caches disabled before jumping into
+ * a zImage, but does not know of all cache layers. Give it a hand.
+ */
+ if (efi_is_direct_boot)
+ cleanup_before_linux();
+#endif
+}
+
+static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
+ unsigned long map_key)
+{
+ EFI_ENTRY("%p, %ld", image_handle, map_key);
+
+ /* Fix up caches for EFI payloads if necessary */
+ efi_exit_caches();
+
+ /* This stops all lingering devices */
+ bootm_disable_interrupts();
+
+ /* Give the payload some time to boot */
+ WATCHDOG_RESET();
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count)
+{
+ static uint64_t mono = 0;
+ EFI_ENTRY("%p", count);
+ *count = mono++;
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_stall(unsigned long microseconds)
+{
+ EFI_ENTRY("%ld", microseconds);
+ udelay(microseconds);
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
+ uint64_t watchdog_code,
+ unsigned long data_size,
+ uint16_t *watchdog_data)
+{
+ EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code,
+ data_size, watchdog_data);
+ return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t EFIAPI efi_connect_controller(
+ efi_handle_t controller_handle,
+ efi_handle_t *driver_image_handle,
+ struct efi_device_path *remain_device_path,
+ bool recursive)
+{
+ EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
+ remain_device_path, recursive);
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI efi_disconnect_controller(void *controller_handle,
+ void *driver_image_handle,
+ void *child_handle)
+{
+ EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
+ child_handle);
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_close_protocol(void *handle,
+ efi_guid_t *protocol,
+ void *agent_handle,
+ void *controller_handle)
+{
+ EFI_ENTRY("%p, %p, %p, %p", handle, protocol, agent_handle,
+ controller_handle);
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle,
+ efi_guid_t *protocol,
+ struct efi_open_protocol_info_entry **entry_buffer,
+ unsigned long *entry_count)
+{
+ EFI_ENTRY("%p, %p, %p, %p", handle, protocol, entry_buffer,
+ entry_count);
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI efi_protocols_per_handle(void *handle,
+ efi_guid_t ***protocol_buffer,
+ unsigned long *protocol_buffer_count)
+{
+ EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
+ protocol_buffer_count);
+ return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI efi_locate_handle_buffer(
+ enum efi_locate_search_type search_type,
+ efi_guid_t *protocol, void *search_key,
+ unsigned long *no_handles, efi_handle_t **buffer)
+{
+ EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key,
+ no_handles, buffer);
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static struct efi_class_map efi_class_maps[] = {
+ {
+ .guid = &efi_guid_console_control,
+ .interface = &efi_console_control
+ },
+};
+
+static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol,
+ void *registration,
+ void **protocol_interface)
+{
+ int i;
+
+ EFI_ENTRY("%p, %p, %p", protocol, registration, protocol_interface);
+ for (i = 0; i < ARRAY_SIZE(efi_class_maps); i++) {
+ struct efi_class_map *curmap = &efi_class_maps[i];
+ if (!guidcmp(protocol, curmap->guid)) {
+ *protocol_interface = (void*)curmap->interface;
+ return EFI_EXIT(EFI_SUCCESS);
+ }
+ }
+
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
+ void **handle, ...)
+{
+ EFI_ENTRY("%p", handle);
+ return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
+ void *handle, ...)
+{
+ EFI_ENTRY("%p", handle);
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+static efi_status_t EFIAPI efi_calculate_crc32(void *data,
+ unsigned long data_size,
+ uint32_t *crc32_p)
+{
+ EFI_ENTRY("%p, %ld", data, data_size);
+ *crc32_p = crc32(0, data, data_size);
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static void EFIAPI efi_copy_mem(void *destination, void *source,
+ unsigned long length)
+{
+ EFI_ENTRY("%p, %p, %ld", destination, source, length);
+ memcpy(destination, source, length);
+}
+
+static void EFIAPI efi_set_mem(void *buffer, unsigned long size, uint8_t value)
+{
+ EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value);
+ memset(buffer, value, size);
+}
+
+static efi_status_t EFIAPI efi_open_protocol(
+ void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct list_head *lhandle;
+ int i;
+ efi_status_t r = EFI_UNSUPPORTED;
+
+ EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol,
+ protocol_interface, agent_handle, controller_handle,
+ attributes);
+ list_for_each(lhandle, &efi_obj_list) {
+ struct efi_object *efiobj;
+ efiobj = list_entry(lhandle, struct efi_object, link);
+
+ if (efiobj->handle != handle)
+ continue;
+
+ for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
+ struct efi_handler *handler = &efiobj->protocols[i];
+ const efi_guid_t *hprotocol = handler->guid;
+ if (!hprotocol)
+ break;
+ if (!guidcmp(hprotocol, protocol)) {
+ r = handler->open(handle, protocol,
+ protocol_interface, agent_handle,
+ controller_handle, attributes);
+ goto out;
+ }
+ }
+ }
+
+out:
+ return EFI_EXIT(r);
+}
+
+static efi_status_t EFIAPI efi_handle_protocol(void *handle,
+ efi_guid_t *protocol,
+ void **protocol_interface)
+{
+ EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface);
+ return efi_open_protocol(handle, protocol, protocol_interface,
+ NULL, NULL, 0);
+}
+
+static const struct efi_boot_services efi_boot_services = {
+ .hdr = {
+ .headersize = sizeof(struct efi_table_hdr),
+ },
+ .raise_tpl = efi_raise_tpl,
+ .restore_tpl = efi_restore_tpl,
+ .allocate_pages = efi_allocate_pages_ext,
+ .free_pages = efi_free_pages_ext,
+ .get_memory_map = efi_get_memory_map_ext,
+ .allocate_pool = efi_allocate_pool,
+ .free_pool = efi_free_pool,
+ .create_event = efi_create_event,
+ .set_timer = efi_set_timer,
+ .wait_for_event = efi_wait_for_event,
+ .signal_event = efi_signal_event,
+ .close_event = efi_close_event,
+ .check_event = efi_check_event,
+ .install_protocol_interface = efi_install_protocol_interface,
+ .reinstall_protocol_interface = efi_reinstall_protocol_interface,
+ .uninstall_protocol_interface = efi_uninstall_protocol_interface,
+ .handle_protocol = efi_handle_protocol,
+ .reserved = NULL,
+ .register_protocol_notify = efi_register_protocol_notify,
+ .locate_handle = efi_locate_handle,
+ .locate_device_path = efi_locate_device_path,
+ .install_configuration_table = efi_install_configuration_table,
+ .load_image = efi_load_image,
+ .start_image = efi_start_image,
+ .exit = (void*)efi_exit,
+ .unload_image = efi_unload_image,
+ .exit_boot_services = efi_exit_boot_services,
+ .get_next_monotonic_count = efi_get_next_monotonic_count,
+ .stall = efi_stall,
+ .set_watchdog_timer = efi_set_watchdog_timer,
+ .connect_controller = efi_connect_controller,
+ .disconnect_controller = efi_disconnect_controller,
+ .open_protocol = efi_open_protocol,
+ .close_protocol = efi_close_protocol,
+ .open_protocol_information = efi_open_protocol_information,
+ .protocols_per_handle = efi_protocols_per_handle,
+ .locate_handle_buffer = efi_locate_handle_buffer,
+ .locate_protocol = efi_locate_protocol,
+ .install_multiple_protocol_interfaces = efi_install_multiple_protocol_interfaces,
+ .uninstall_multiple_protocol_interfaces = efi_uninstall_multiple_protocol_interfaces,
+ .calculate_crc32 = efi_calculate_crc32,
+ .copy_mem = efi_copy_mem,
+ .set_mem = efi_set_mem,
+};
+
+
+static uint16_t EFI_RUNTIME_DATA firmware_vendor[] =
+ { 'D','a','s',' ','U','-','b','o','o','t',0 };
+
+struct efi_system_table EFI_RUNTIME_DATA systab = {
+ .hdr = {
+ .signature = EFI_SYSTEM_TABLE_SIGNATURE,
+ .revision = 0x20005, /* 2.5 */
+ .headersize = sizeof(struct efi_table_hdr),
+ },
+ .fw_vendor = (long)firmware_vendor,
+ .con_in = (void*)&efi_con_in,
+ .con_out = (void*)&efi_con_out,
+ .std_err = (void*)&efi_con_out,
+ .runtime = (void*)&efi_runtime_services,
+ .boottime = (void*)&efi_boot_services,
+ .nr_tables = 0,
+ .tables = (void*)efi_conf_table,
+};
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
new file mode 100644
index 0000000..2e0228c
--- /dev/null
+++ b/lib/efi_loader/efi_console.c
@@ -0,0 +1,360 @@
+/*
+ * EFI application console interface
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+/* If we can't determine the console size, default to 80x24 */
+static int console_columns = 80;
+static int console_rows = 24;
+static bool console_size_queried;
+
+const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
+
+#define cESC '\x1b'
+#define ESC "\x1b"
+
+static efi_status_t EFIAPI efi_cin_get_mode(
+ struct efi_console_control_protocol *this,
+ int *mode, char *uga_exists, char *std_in_locked)
+{
+ EFI_ENTRY("%p, %p, %p, %p", this, mode, uga_exists, std_in_locked);
+
+ if (mode)
+ *mode = EFI_CONSOLE_MODE_TEXT;
+ if (uga_exists)
+ *uga_exists = 0;
+ if (std_in_locked)
+ *std_in_locked = 0;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cin_set_mode(
+ struct efi_console_control_protocol *this, int mode)
+{
+ EFI_ENTRY("%p, %d", this, mode);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cin_lock_std_in(
+ struct efi_console_control_protocol *this,
+ uint16_t *password)
+{
+ EFI_ENTRY("%p, %p", this, password);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+const struct efi_console_control_protocol efi_console_control = {
+ .get_mode = efi_cin_get_mode,
+ .set_mode = efi_cin_set_mode,
+ .lock_std_in = efi_cin_lock_std_in,
+};
+
+static struct simple_text_output_mode efi_con_mode = {
+ .max_mode = 0,
+ .mode = 0,
+ .attribute = 0,
+ .cursor_column = 0,
+ .cursor_row = 0,
+ .cursor_visible = 1,
+};
+
+static int term_read_reply(int *n, int maxnum, char end_char)
+{
+ char c;
+ int i = 0;
+
+ c = getc();
+ if (c != cESC)
+ return -1;
+ c = getc();
+ if (c != '[')
+ return -1;
+
+ n[0] = 0;
+ while (1) {
+ c = getc();
+ if (c == ';') {
+ i++;
+ if (i >= maxnum)
+ return -1;
+ n[i] = 0;
+ continue;
+ } else if (c == end_char) {
+ break;
+ } else if (c > '9' || c < '0') {
+ return -1;
+ }
+
+ /* Read one more decimal position */
+ n[i] *= 10;
+ n[i] += c - '0';
+ }
+
+ return 0;
+}
+
+static efi_status_t EFIAPI efi_cout_reset(
+ struct efi_simple_text_output_protocol *this,
+ char extended_verification)
+{
+ EFI_ENTRY("%p, %d", this, extended_verification);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static void print_unicode_in_utf8(u16 c)
+{
+ char utf8[4] = { 0 };
+ char *b = utf8;
+
+ if (c < 0x80) {
+ *(b++) = c;
+ } else if (c < 0x800) {
+ *(b++) = 192 + c / 64;
+ *(b++) = 128 + c % 64;
+ } else {
+ *(b++) = 224 + c / 4096;
+ *(b++) = 128 + c / 64 % 64;
+ *(b++) = 128 + c % 64;
+ }
+
+ puts(utf8);
+}
+
+static efi_status_t EFIAPI efi_cout_output_string(
+ struct efi_simple_text_output_protocol *this,
+ const unsigned short *string)
+{
+ u16 ch;
+
+ EFI_ENTRY("%p, %p", this, string);
+ for (;(ch = *string); string++) {
+ print_unicode_in_utf8(ch);
+ efi_con_mode.cursor_column++;
+ if (ch == '\n') {
+ efi_con_mode.cursor_column = 1;
+ efi_con_mode.cursor_row++;
+ } else if (efi_con_mode.cursor_column > console_columns) {
+ efi_con_mode.cursor_column = 1;
+ efi_con_mode.cursor_row++;
+ }
+ if (efi_con_mode.cursor_row > console_rows) {
+ efi_con_mode.cursor_row = console_rows;
+ }
+ }
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_test_string(
+ struct efi_simple_text_output_protocol *this,
+ const unsigned short *string)
+{
+ EFI_ENTRY("%p, %p", this, string);
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_query_mode(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long mode_number, unsigned long *columns,
+ unsigned long *rows)
+{
+ EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
+
+ if (!console_size_queried) {
+ /* Ask the terminal about its size */
+ int n[3];
+ u64 timeout;
+
+ console_size_queried = true;
+
+ /* Empty input buffer */
+ while (tstc())
+ getc();
+
+ printf(ESC"[18t");
+
+ /* Check if we have a terminal that understands */
+ timeout = timer_get_us() + 1000000;
+ while (!tstc())
+ if (timer_get_us() > timeout)
+ goto out;
+
+ /* Read {depth,rows,cols} */
+ if (term_read_reply(n, 3, 't')) {
+ goto out;
+ }
+
+ console_columns = n[2];
+ console_rows = n[1];
+ }
+
+out:
+ if (columns)
+ *columns = console_columns;
+ if (rows)
+ *rows = console_rows;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_set_mode(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long mode_number)
+{
+ EFI_ENTRY("%p, %ld", this, mode_number);
+
+ /* We only support text output for now */
+ if (mode_number == EFI_CONSOLE_MODE_TEXT)
+ return EFI_EXIT(EFI_SUCCESS);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cout_set_attribute(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long attribute)
+{
+ EFI_ENTRY("%p, %lx", this, attribute);
+
+ /* Just ignore attributes (colors) for now */
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cout_clear_screen(
+ struct efi_simple_text_output_protocol *this)
+{
+ EFI_ENTRY("%p", this);
+
+ printf(ESC"[2J");
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_set_cursor_position(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long column, unsigned long row)
+{
+ EFI_ENTRY("%p, %ld, %ld", this, column, row);
+
+ printf(ESC"[%d;%df", (int)row, (int)column);
+ efi_con_mode.cursor_column = column;
+ efi_con_mode.cursor_row = row;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_enable_cursor(
+ struct efi_simple_text_output_protocol *this,
+ bool enable)
+{
+ EFI_ENTRY("%p, %d", this, enable);
+
+ printf(ESC"[?25%c", enable ? 'h' : 'l');
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+const struct efi_simple_text_output_protocol efi_con_out = {
+ .reset = efi_cout_reset,
+ .output_string = efi_cout_output_string,
+ .test_string = efi_cout_test_string,
+ .query_mode = efi_cout_query_mode,
+ .set_mode = efi_cout_set_mode,
+ .set_attribute = efi_cout_set_attribute,
+ .clear_screen = efi_cout_clear_screen,
+ .set_cursor_position = efi_cout_set_cursor_position,
+ .enable_cursor = efi_cout_enable_cursor,
+ .mode = (void*)&efi_con_mode,
+};
+
+static efi_status_t EFIAPI efi_cin_reset(
+ struct efi_simple_input_interface *this,
+ bool extended_verification)
+{
+ EFI_ENTRY("%p, %d", this, extended_verification);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cin_read_key_stroke(
+ struct efi_simple_input_interface *this,
+ struct efi_input_key *key)
+{
+ struct efi_input_key pressed_key = {
+ .scan_code = 0,
+ .unicode_char = 0,
+ };
+ char ch;
+
+ EFI_ENTRY("%p, %p", this, key);
+
+ /* We don't do interrupts, so check for timers cooperatively */
+ efi_timer_check();
+
+ if (!tstc()) {
+ /* No key pressed */
+ return EFI_EXIT(EFI_NOT_READY);
+ }
+
+ ch = getc();
+ if (ch == cESC) {
+ /* Escape Sequence */
+ ch = getc();
+ switch (ch) {
+ case cESC: /* ESC */
+ pressed_key.scan_code = 23;
+ break;
+ case 'O': /* F1 - F4 */
+ pressed_key.scan_code = getc() - 'P' + 11;
+ break;
+ case 'a'...'z':
+ ch = ch - 'a';
+ break;
+ case '[':
+ ch = getc();
+ switch (ch) {
+ case 'A'...'D': /* up, down right, left */
+ pressed_key.scan_code = ch - 'A' + 1;
+ break;
+ case 'F': /* End */
+ pressed_key.scan_code = 6;
+ break;
+ case 'H': /* Home */
+ pressed_key.scan_code = 5;
+ break;
+ case '1': /* F5 - F8 */
+ pressed_key.scan_code = getc() - '0' + 11;
+ getc();
+ break;
+ case '2': /* F9 - F12 */
+ pressed_key.scan_code = getc() - '0' + 19;
+ getc();
+ break;
+ case '3': /* DEL */
+ pressed_key.scan_code = 8;
+ getc();
+ break;
+ }
+ break;
+ }
+ } else if (ch == 0x7f) {
+ /* Backspace */
+ ch = 0x08;
+ }
+ pressed_key.unicode_char = ch;
+ *key = pressed_key;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+const struct efi_simple_input_interface efi_con_in = {
+ .reset = efi_cin_reset,
+ .read_key_stroke = efi_cin_read_key_stroke,
+ .wait_for_key = NULL,
+};
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
new file mode 100644
index 0000000..f93fcb2
--- /dev/null
+++ b/lib/efi_loader/efi_disk.c
@@ -0,0 +1,218 @@
+/*
+ * EFI application disk support
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <inttypes.h>
+#include <part.h>
+#include <malloc.h>
+
+static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
+
+struct efi_disk_obj {
+ /* Generic EFI object parent class data */
+ struct efi_object parent;
+ /* EFI Interface callback struct for block I/O */
+ struct efi_block_io ops;
+ /* U-Boot ifname for block device */
+ const char *ifname;
+ /* U-Boot dev_index for block device */
+ int dev_index;
+ /* EFI Interface Media descriptor struct, referenced by ops */
+ struct efi_block_io_media media;
+ /* EFI device path to this block device */
+ struct efi_device_path_file_path *dp;
+};
+
+static void ascii2unicode(u16 *unicode, char *ascii)
+{
+ while (*ascii)
+ *(unicode++) = *(ascii++);
+}
+
+static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct efi_disk_obj *diskobj = handle;
+
+ *protocol_interface = &diskobj->ops;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct efi_disk_obj *diskobj = handle;
+
+ *protocol_interface = diskobj->dp;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
+ char extended_verification)
+{
+ EFI_ENTRY("%p, %x", this, extended_verification);
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+}
+
+enum efi_disk_direction {
+ EFI_DISK_READ,
+ EFI_DISK_WRITE,
+};
+
+static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this,
+ u32 media_id, u64 lba, unsigned long buffer_size,
+ void *buffer, enum efi_disk_direction direction)
+{
+ struct efi_disk_obj *diskobj;
+ struct block_dev_desc *desc;
+ int blksz;
+ int blocks;
+ unsigned long n;
+
+ EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
+ buffer_size, buffer);
+
+ diskobj = container_of(this, struct efi_disk_obj, ops);
+ if (!(desc = get_dev(diskobj->ifname, diskobj->dev_index)))
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+ blksz = desc->blksz;
+ blocks = buffer_size / blksz;
+
+#ifdef DEBUG_EFI
+ printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__,
+ __LINE__, blocks, lba, blksz, direction);
+#endif
+
+ /* We only support full block access */
+ if (buffer_size & (blksz - 1))
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+
+ if (direction == EFI_DISK_READ)
+ n = desc->block_read(desc, lba, blocks, buffer);
+ else
+ n = desc->block_write(desc, lba, blocks, buffer);
+
+ /* We don't do interrupts, so check for timers cooperatively */
+ efi_timer_check();
+
+#ifdef DEBUG_EFI
+ printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
+#endif
+ if (n != blocks)
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
+ u32 media_id, u64 lba, unsigned long buffer_size,
+ void *buffer)
+{
+ return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
+ EFI_DISK_READ);
+}
+
+static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
+ u32 media_id, u64 lba, unsigned long buffer_size,
+ void *buffer)
+{
+ return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
+ EFI_DISK_WRITE);
+}
+
+static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
+{
+ /* We always write synchronously */
+ EFI_ENTRY("%p", this);
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static const struct efi_block_io block_io_disk_template = {
+ .reset = &efi_disk_reset,
+ .read_blocks = &efi_disk_read_blocks,
+ .write_blocks = &efi_disk_write_blocks,
+ .flush_blocks = &efi_disk_flush_blocks,
+};
+
+/*
+ * U-Boot doesn't have a list of all online disk devices. So when running our
+ * EFI payload, we scan through all of the potentially available ones and
+ * store them in our object pool.
+ *
+ * This gets called from do_bootefi_exec().
+ */
+int efi_disk_register(void)
+{
+ const struct block_drvr *cur_drvr;
+ int i;
+ int disks = 0;
+
+ /* Search for all available disk devices */
+ for (cur_drvr = block_drvr; cur_drvr->name; cur_drvr++) {
+ printf("Scanning disks on %s...\n", cur_drvr->name);
+ for (i = 0; i < 4; i++) {
+ block_dev_desc_t *desc;
+ struct efi_disk_obj *diskobj;
+ struct efi_device_path_file_path *dp;
+ int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2);
+ char devname[16] = { 0 }; /* dp->str is u16[16] long */
+
+ desc = get_dev(cur_drvr->name, i);
+ if (!desc)
+ continue;
+ if (desc->type == DEV_TYPE_UNKNOWN)
+ continue;
+
+ diskobj = calloc(1, objlen);
+
+ /* Fill in object data */
+ diskobj->parent.protocols[0].guid = &efi_block_io_guid;
+ diskobj->parent.protocols[0].open = efi_disk_open_block;
+ diskobj->parent.protocols[1].guid = &efi_guid_device_path;
+ diskobj->parent.protocols[1].open = efi_disk_open_dp;
+ diskobj->parent.handle = diskobj;
+ diskobj->ops = block_io_disk_template;
+ diskobj->ifname = cur_drvr->name;
+ diskobj->dev_index = i;
+
+ /* Fill in EFI IO Media info (for read/write callbacks) */
+ diskobj->media.removable_media = desc->removable;
+ diskobj->media.media_present = 1;
+ diskobj->media.block_size = desc->blksz;
+ diskobj->media.io_align = desc->blksz;
+ diskobj->media.last_block = desc->lba;
+ diskobj->ops.media = &diskobj->media;
+
+ /* Fill in device path */
+ dp = (void*)&diskobj[1];
+ diskobj->dp = dp;
+ dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
+ dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
+ dp[0].dp.length = sizeof(*dp);
+ snprintf(devname, sizeof(devname), "%s%d",
+ cur_drvr->name, i);
+ ascii2unicode(dp[0].str, devname);
+
+ dp[1].dp.type = DEVICE_PATH_TYPE_END;
+ dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END;
+ dp[1].dp.length = sizeof(*dp);
+
+ /* Hook up to the device list */
+ list_add_tail(&diskobj->parent.link, &efi_obj_list);
+ disks++;
+ }
+ }
+ printf("Found %d disks\n", disks);
+
+ return 0;
+}
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
new file mode 100644
index 0000000..4479726
--- /dev/null
+++ b/lib/efi_loader/efi_image_loader.c
@@ -0,0 +1,183 @@
+/*
+ * EFI image loader
+ *
+ * based partly on wine code
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <pe.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
+const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
+
+efi_status_t EFIAPI efi_return_handle(void *handle, efi_guid_t *protocol,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol,
+ protocol_interface, agent_handle, controller_handle,
+ attributes);
+ *protocol_interface = handle;
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static void efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
+ unsigned long rel_size, void *efi_reloc)
+{
+ const IMAGE_BASE_RELOCATION *end;
+ int i;
+
+ end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
+ while (rel < end - 1 && rel->SizeOfBlock) {
+ const uint16_t *relocs = (const uint16_t *)(rel + 1);
+ i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
+ while (i--) {
+ uint16_t offset = (*relocs & 0xfff) +
+ rel->VirtualAddress;
+ int type = *relocs >> EFI_PAGE_SHIFT;
+ unsigned long delta = (unsigned long)efi_reloc;
+ uint64_t *x64 = efi_reloc + offset;
+ uint32_t *x32 = efi_reloc + offset;
+ uint16_t *x16 = efi_reloc + offset;
+
+ switch (type) {
+ case IMAGE_REL_BASED_ABSOLUTE:
+ break;
+ case IMAGE_REL_BASED_HIGH:
+ *x16 += ((uint32_t)delta) >> 16;
+ break;
+ case IMAGE_REL_BASED_LOW:
+ *x16 += (uint16_t)delta;
+ break;
+ case IMAGE_REL_BASED_HIGHLOW:
+ *x32 += (uint32_t)delta;
+ break;
+ case IMAGE_REL_BASED_DIR64:
+ *x64 += (uint64_t)delta;
+ break;
+ default:
+ printf("Unknown Relocation off %x type %x\n",
+ offset, type);
+ }
+ relocs++;
+ }
+ rel = (const IMAGE_BASE_RELOCATION *)relocs;
+ }
+}
+
+/*
+ * This function loads all sections from a PE binary into a newly reserved
+ * piece of memory. On successful load it then returns the entry point for
+ * the binary. Otherwise NULL.
+ */
+void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
+{
+ IMAGE_NT_HEADERS32 *nt;
+ IMAGE_DOS_HEADER *dos;
+ IMAGE_SECTION_HEADER *sections;
+ int num_sections;
+ void *efi_reloc;
+ int i;
+ const IMAGE_BASE_RELOCATION *rel;
+ unsigned long rel_size;
+ int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
+ void *entry;
+ uint64_t image_size;
+ unsigned long virt_size = 0;
+ bool can_run_nt64 = true;
+ bool can_run_nt32 = true;
+
+#if defined(CONFIG_ARM64)
+ can_run_nt32 = false;
+#elif defined(CONFIG_ARM)
+ can_run_nt64 = false;
+#endif
+
+ dos = efi;
+ if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
+ printf("%s: Invalid DOS Signature\n", __func__);
+ return NULL;
+ }
+
+ nt = (void *) ((char *)efi + dos->e_lfanew);
+ if (nt->Signature != IMAGE_NT_SIGNATURE) {
+ printf("%s: Invalid NT Signature\n", __func__);
+ return NULL;
+ }
+
+ /* Calculate upper virtual address boundary */
+ num_sections = nt->FileHeader.NumberOfSections;
+ sections = (void *)&nt->OptionalHeader +
+ nt->FileHeader.SizeOfOptionalHeader;
+
+ for (i = num_sections - 1; i >= 0; i--) {
+ IMAGE_SECTION_HEADER *sec = &sections[i];
+ virt_size = max_t(unsigned long, virt_size,
+ sec->VirtualAddress + sec->Misc.VirtualSize);
+ }
+
+ /* Read 32/64bit specific header bits */
+ if (can_run_nt64 &&
+ (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
+ IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
+ IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
+ image_size = opt->SizeOfImage;
+ efi_reloc = efi_alloc(virt_size, EFI_LOADER_DATA);
+ if (!efi_reloc) {
+ printf("%s: Could not allocate %ld bytes\n",
+ __func__, virt_size);
+ return NULL;
+ }
+ entry = efi_reloc + opt->AddressOfEntryPoint;
+ rel_size = opt->DataDirectory[rel_idx].Size;
+ rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
+ } else if (can_run_nt32 &&
+ (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
+ IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
+ image_size = opt->SizeOfImage;
+ efi_reloc = efi_alloc(virt_size, EFI_LOADER_DATA);
+ if (!efi_reloc) {
+ printf("%s: Could not allocate %ld bytes\n",
+ __func__, virt_size);
+ return NULL;
+ }
+ entry = efi_reloc + opt->AddressOfEntryPoint;
+ rel_size = opt->DataDirectory[rel_idx].Size;
+ rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
+ } else {
+ printf("%s: Invalid optional header magic %x\n", __func__,
+ nt->OptionalHeader.Magic);
+ return NULL;
+ }
+
+ /* Load sections into RAM */
+ for (i = num_sections - 1; i >= 0; i--) {
+ IMAGE_SECTION_HEADER *sec = &sections[i];
+ memset(efi_reloc + sec->VirtualAddress, 0,
+ sec->Misc.VirtualSize);
+ memcpy(efi_reloc + sec->VirtualAddress,
+ efi + sec->PointerToRawData,
+ sec->SizeOfRawData);
+ }
+
+ /* Run through relocations */
+ efi_loader_relocate(rel, rel_size, efi_reloc);
+
+ /* Flush cache */
+ flush_cache((ulong)efi_reloc, virt_size);
+ invalidate_icache_all();
+
+ /* Populate the loaded image interface bits */
+ loaded_image_info->image_base = efi;
+ loaded_image_info->image_size = image_size;
+
+ return entry;
+}
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
new file mode 100644
index 0000000..c82b53f
--- /dev/null
+++ b/lib/efi_loader/efi_memory.c
@@ -0,0 +1,319 @@
+/*
+ * EFI application memory management
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* #define DEBUG_EFI */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <libfdt_env.h>
+#include <inttypes.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct efi_mem_list {
+ struct list_head link;
+ struct efi_mem_desc desc;
+};
+
+/* This list contains all memory map items */
+LIST_HEAD(efi_mem);
+
+/*
+ * Unmaps all memory occupied by the carve_desc region from the
+ * list entry pointed to by map.
+ *
+ * Returns 1 if carving was performed or 0 if the regions don't overlap.
+ * Returns -1 if it would affect non-RAM regions but overlap_only_ram is set.
+ * Carving is only guaranteed to complete when all regions return 0.
+ */
+static int efi_mem_carve_out(struct efi_mem_list *map,
+ struct efi_mem_desc *carve_desc,
+ bool overlap_only_ram)
+{
+ struct efi_mem_list *newmap;
+ struct efi_mem_desc *map_desc = &map->desc;
+ uint64_t map_start = map_desc->physical_start;
+ uint64_t map_end = map_start + (map_desc->num_pages << EFI_PAGE_SHIFT);
+ uint64_t carve_start = carve_desc->physical_start;
+ uint64_t carve_end = carve_start +
+ (carve_desc->num_pages << EFI_PAGE_SHIFT);
+
+ /* check whether we're overlapping */
+ if ((carve_end <= map_start) || (carve_start >= map_end))
+ return 0;
+
+ /* We're overlapping with non-RAM, warn the caller if desired */
+ if (overlap_only_ram && (map_desc->type != EFI_CONVENTIONAL_MEMORY))
+ return -1;
+
+ /* Sanitize carve_start and carve_end to lie within our bounds */
+ carve_start = max(carve_start, map_start);
+ carve_end = min(carve_end, map_end);
+
+ /* Carving at the beginning of our map? Just move it! */
+ if (carve_start == map_start) {
+ if (map_end == carve_end) {
+ /* Full overlap, just remove map */
+ list_del(&map->link);
+ }
+
+ map_desc->physical_start = carve_end;
+ map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT;
+ return 1;
+ }
+
+ /*
+ * Overlapping maps, just split the list map at carve_start,
+ * it will get moved or removed in the next iteration.
+ *
+ * [ map_desc |__carve_start__| newmap ]
+ */
+
+ /* Create a new map from [ carve_start ... map_end ] */
+ newmap = calloc(1, sizeof(*newmap));
+ newmap->desc = map->desc;
+ newmap->desc.physical_start = carve_start;
+ newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT;
+ list_add_tail(&newmap->link, &efi_mem);
+
+ /* Shrink the map to [ map_start ... carve_start ] */
+ map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT;
+
+ return 1;
+}
+
+uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
+ bool overlap_only_ram)
+{
+ struct list_head *lhandle;
+ struct efi_mem_list *newlist;
+ bool do_carving;
+
+ if (!pages)
+ return start;
+
+ newlist = calloc(1, sizeof(*newlist));
+ newlist->desc.type = memory_type;
+ newlist->desc.physical_start = start;
+ newlist->desc.virtual_start = start;
+ newlist->desc.num_pages = pages;
+
+ switch (memory_type) {
+ case EFI_RUNTIME_SERVICES_CODE:
+ case EFI_RUNTIME_SERVICES_DATA:
+ newlist->desc.attribute = (1 << EFI_MEMORY_WB_SHIFT) |
+ (1ULL << EFI_MEMORY_RUNTIME_SHIFT);
+ break;
+ case EFI_MMAP_IO:
+ newlist->desc.attribute = 1ULL << EFI_MEMORY_RUNTIME_SHIFT;
+ break;
+ default:
+ newlist->desc.attribute = 1 << EFI_MEMORY_WB_SHIFT;
+ break;
+ }
+
+ /* Add our new map */
+ do {
+ do_carving = false;
+ list_for_each(lhandle, &efi_mem) {
+ struct efi_mem_list *lmem;
+ int r;
+
+ lmem = list_entry(lhandle, struct efi_mem_list, link);
+ r = efi_mem_carve_out(lmem, &newlist->desc,
+ overlap_only_ram);
+ if (r < 0) {
+ return 0;
+ } else if (r) {
+ do_carving = true;
+ break;
+ }
+ }
+ } while (do_carving);
+
+ /* Add our new map */
+ list_add_tail(&newlist->link, &efi_mem);
+
+ return start;
+}
+
+static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr)
+{
+ struct list_head *lhandle;
+
+ list_for_each(lhandle, &efi_mem) {
+ struct efi_mem_list *lmem = list_entry(lhandle,
+ struct efi_mem_list, link);
+ struct efi_mem_desc *desc = &lmem->desc;
+ uint64_t desc_len = desc->num_pages << EFI_PAGE_SHIFT;
+ uint64_t desc_end = desc->physical_start + desc_len;
+ uint64_t curmax = min(max_addr, desc_end);
+ uint64_t ret = curmax - len;
+
+ /* We only take memory from free RAM */
+ if (desc->type != EFI_CONVENTIONAL_MEMORY)
+ continue;
+
+ /* Out of bounds for max_addr */
+ if ((ret + len) > max_addr)
+ continue;
+
+ /* Out of bounds for upper map limit */
+ if ((ret + len) > desc_end)
+ continue;
+
+ /* Out of bounds for lower map limit */
+ if (ret < desc->physical_start)
+ continue;
+
+ /* Return the highest address in this map within bounds */
+ return ret;
+ }
+
+ return 0;
+}
+
+efi_status_t efi_allocate_pages(int type, int memory_type,
+ unsigned long pages, uint64_t *memory)
+{
+ u64 len = pages << EFI_PAGE_SHIFT;
+ efi_status_t r = EFI_SUCCESS;
+ uint64_t addr;
+
+ switch (type) {
+ case 0:
+ /* Any page */
+ addr = efi_find_free_memory(len, gd->ram_top);
+ if (!addr) {
+ r = EFI_NOT_FOUND;
+ break;
+ }
+ break;
+ case 1:
+ /* Max address */
+ addr = efi_find_free_memory(len, *memory);
+ if (!addr) {
+ r = EFI_NOT_FOUND;
+ break;
+ }
+ break;
+ case 2:
+ /* Exact address, reserve it. The addr is already in *memory. */
+ addr = *memory;
+ break;
+ default:
+ /* UEFI doesn't specify other allocation types */
+ r = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (r == EFI_SUCCESS) {
+ uint64_t ret;
+
+ /* Reserve that map in our memory maps */
+ ret = efi_add_memory_map(addr, pages, memory_type, true);
+ if (ret == addr) {
+ *memory = addr;
+ } else {
+ /* Map would overlap, bail out */
+ r = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return r;
+}
+
+void *efi_alloc(uint64_t len, int memory_type)
+{
+ uint64_t ret = 0;
+ uint64_t pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+ efi_status_t r;
+
+ r = efi_allocate_pages(0, memory_type, pages, &ret);
+ if (r == EFI_SUCCESS)
+ return (void*)(uintptr_t)ret;
+
+ return NULL;
+}
+
+efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
+{
+ /* We don't free, let's cross our fingers we have plenty RAM */
+ return EFI_SUCCESS;
+}
+
+efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
+ struct efi_mem_desc *memory_map,
+ unsigned long *map_key,
+ unsigned long *descriptor_size,
+ uint32_t *descriptor_version)
+{
+ ulong map_size = 0;
+ struct list_head *lhandle;
+
+ list_for_each(lhandle, &efi_mem)
+ map_size += sizeof(struct efi_mem_desc);
+
+ *memory_map_size = map_size;
+
+ if (descriptor_size)
+ *descriptor_size = sizeof(struct efi_mem_desc);
+
+ if (*memory_map_size < map_size)
+ return EFI_BUFFER_TOO_SMALL;
+
+ /* Copy list into array */
+ if (memory_map) {
+ list_for_each(lhandle, &efi_mem) {
+ struct efi_mem_list *lmem;
+
+ lmem = list_entry(lhandle, struct efi_mem_list, link);
+ *memory_map = lmem->desc;
+ memory_map++;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+int efi_memory_init(void)
+{
+ uint64_t runtime_start, runtime_end, runtime_pages;
+ uint64_t uboot_start, uboot_pages;
+ uint64_t uboot_stack_size = 16 * 1024 * 1024;
+ int i;
+
+ /* Add RAM */
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ u64 ram_start = gd->bd->bi_dram[i].start;
+ u64 ram_size = gd->bd->bi_dram[i].size;
+ u64 start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+ u64 pages = (ram_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+
+ efi_add_memory_map(start, pages, EFI_CONVENTIONAL_MEMORY,
+ false);
+ }
+
+ /* Add U-Boot */
+ uboot_start = (gd->start_addr_sp - uboot_stack_size) & ~EFI_PAGE_MASK;
+ uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT;
+ efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false);
+
+ /* Add Runtime Services */
+ runtime_start = (ulong)&__efi_runtime_start & ~EFI_PAGE_MASK;
+ runtime_end = (ulong)&__efi_runtime_stop;
+ runtime_end = (runtime_end + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+ runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT;
+ efi_add_memory_map(runtime_start, runtime_pages,
+ EFI_RUNTIME_SERVICES_CODE, false);
+
+ return 0;
+}
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
new file mode 100644
index 0000000..22bcd08
--- /dev/null
+++ b/lib/efi_loader/efi_runtime.c
@@ -0,0 +1,290 @@
+/*
+ * EFI application runtime services
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <rtc.h>
+#include <asm/global_data.h>
+
+/* For manual relocation support */
+DECLARE_GLOBAL_DATA_PTR;
+
+static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void);
+static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void);
+static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void);
+
+#if defined(CONFIG_ARM64)
+#define R_RELATIVE 1027
+#define R_MASK 0xffffffffULL
+#define IS_RELA 1
+#elif defined(CONFIG_ARM)
+#define R_RELATIVE 23
+#define R_MASK 0xffULL
+#else
+#error Need to add relocation awareness
+#endif
+
+struct elf_rel {
+ ulong *offset;
+ ulong info;
+};
+
+struct elf_rela {
+ ulong *offset;
+ ulong info;
+ long addend;
+};
+
+/*
+ * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI
+ * payload are running concurrently at the same time. In this mode, we can
+ * handle a good number of runtime callbacks
+ */
+
+static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
+ efi_status_t reset_status,
+ unsigned long data_size, void *reset_data)
+{
+ EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
+ reset_data);
+
+ switch (reset_type) {
+ case EFI_RESET_COLD:
+ case EFI_RESET_WARM:
+ do_reset(NULL, 0, 0, NULL);
+ break;
+ case EFI_RESET_SHUTDOWN:
+ /* We don't have anything to map this to */
+ break;
+ }
+
+ EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
+ struct efi_time_cap *capabilities)
+{
+#if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
+ struct rtc_time tm;
+ int r;
+ struct udevice *dev;
+
+ EFI_ENTRY("%p %p", time, capabilities);
+
+ r = uclass_get_device(UCLASS_RTC, 0, &dev);
+ if (r)
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+
+ r = dm_rtc_get(dev, &tm);
+ if (r)
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+
+ memset(time, 0, sizeof(*time));
+ time->year = tm.tm_year;
+ time->month = tm.tm_mon;
+ time->day = tm.tm_mday;
+ time->hour = tm.tm_hour;
+ time->minute = tm.tm_min;
+ time->daylight = tm.tm_isdst;
+
+ return EFI_EXIT(EFI_SUCCESS);
+#else
+ return EFI_DEVICE_ERROR;
+#endif
+}
+
+struct efi_runtime_detach_list_struct {
+ void *ptr;
+ void *patchto;
+};
+
+static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
+ {
+ /* do_reset is gone */
+ .ptr = &efi_runtime_services.reset_system,
+ .patchto = NULL,
+ }, {
+ /* invalidate_*cache_all are gone */
+ .ptr = &efi_runtime_services.set_virtual_address_map,
+ .patchto = &efi_invalid_parameter,
+ }, {
+ /* RTC accessors are gone */
+ .ptr = &efi_runtime_services.get_time,
+ .patchto = &efi_device_error,
+ },
+};
+
+static bool efi_runtime_tobedetached(void *p)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++)
+ if (efi_runtime_detach_list[i].ptr == p)
+ return true;
+
+ return false;
+}
+
+static void efi_runtime_detach(ulong offset)
+{
+ int i;
+ ulong patchoff = offset - (ulong)gd->relocaddr;
+
+ for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) {
+ ulong patchto = (ulong)efi_runtime_detach_list[i].patchto;
+ ulong *p = efi_runtime_detach_list[i].ptr;
+ ulong newaddr = patchto ? (patchto + patchoff) : 0;
+
+#ifdef DEBUG_EFI
+ printf("%s: Setting %p to %lx\n", __func__, p, newaddr);
+#endif
+ *p = newaddr;
+ }
+}
+
+/* Relocate EFI runtime to uboot_reloc_base = offset */
+void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
+{
+#ifdef IS_RELA
+ struct elf_rela *rel = (void*)&__efi_runtime_rel_start;
+#else
+ struct elf_rel *rel = (void*)&__efi_runtime_rel_start;
+ static ulong lastoff = CONFIG_SYS_TEXT_BASE;
+#endif
+
+#ifdef DEBUG_EFI
+ printf("%s: Relocating to offset=%lx\n", __func__, offset);
+#endif
+
+ for (; (ulong)rel < (ulong)&__efi_runtime_rel_stop; rel++) {
+ ulong base = CONFIG_SYS_TEXT_BASE;
+ ulong *p;
+ ulong newaddr;
+
+ p = (void*)((ulong)rel->offset - base) + gd->relocaddr;
+
+ if ((rel->info & R_MASK) != R_RELATIVE) {
+ continue;
+ }
+
+#ifdef IS_RELA
+ newaddr = rel->addend + offset - CONFIG_SYS_TEXT_BASE;
+#else
+ newaddr = *p - lastoff + offset;
+#endif
+
+ /* Check if the relocation is inside bounds */
+ if (map && ((newaddr < map->virtual_start) ||
+ newaddr > (map->virtual_start + (map->num_pages << 12)))) {
+ if (!efi_runtime_tobedetached(p))
+ printf("U-Boot EFI: Relocation at %p is out of "
+ "range (%lx)\n", p, newaddr);
+ continue;
+ }
+
+#ifdef DEBUG_EFI
+ printf("%s: Setting %p to %lx\n", __func__, p, newaddr);
+#endif
+
+ *p = newaddr;
+ flush_dcache_range((ulong)p, (ulong)&p[1]);
+ }
+
+#ifndef IS_RELA
+ lastoff = offset;
+#endif
+
+ invalidate_icache_all();
+}
+
+static efi_status_t EFIAPI efi_set_virtual_address_map(
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ uint32_t descriptor_version,
+ struct efi_mem_desc *virtmap)
+{
+ ulong runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL;
+ int n = memory_map_size / descriptor_size;
+ int i;
+
+ EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
+ descriptor_version, virtmap);
+
+ for (i = 0; i < n; i++) {
+ struct efi_mem_desc *map;
+
+ map = (void*)virtmap + (descriptor_size * i);
+ if (map->type == EFI_RUNTIME_SERVICES_CODE) {
+ ulong new_offset = map->virtual_start - (runtime_start - gd->relocaddr);
+
+ efi_runtime_relocate(new_offset, map);
+ /* Once we're virtual, we can no longer handle
+ complex callbacks */
+ efi_runtime_detach(new_offset);
+ return EFI_EXIT(EFI_SUCCESS);
+ }
+ }
+
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+/*
+ * In the second stage, U-Boot has disappeared. To isolate our runtime code
+ * that at this point still exists from the rest, we put it into a special
+ * section.
+ *
+ * !!WARNING!!
+ *
+ * This means that we can not rely on any code outside of this file in any
+ * function or variable below this line.
+ *
+ * Please keep everything fully self-contained and annotated with
+ * EFI_RUNTIME_TEXT and EFI_RUNTIME_DATA markers.
+ */
+
+/*
+ * Relocate the EFI runtime stub to a different place. We need to call this
+ * the first time we expose the runtime interface to a user and on set virtual
+ * address map calls.
+ */
+
+static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void)
+{
+ return EFI_UNSUPPORTED;
+}
+
+static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void)
+{
+ return EFI_DEVICE_ERROR;
+}
+
+static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void)
+{
+ return EFI_INVALID_PARAMETER;
+}
+
+struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = {
+ .hdr = {
+ .signature = EFI_RUNTIME_SERVICES_SIGNATURE,
+ .revision = EFI_RUNTIME_SERVICES_REVISION,
+ .headersize = sizeof(struct efi_table_hdr),
+ },
+ .get_time = &efi_get_time,
+ .set_time = (void *)&efi_device_error,
+ .get_wakeup_time = (void *)&efi_unimplemented,
+ .set_wakeup_time = (void *)&efi_unimplemented,
+ .set_virtual_address_map = &efi_set_virtual_address_map,
+ .convert_pointer = (void *)&efi_invalid_parameter,
+ .get_variable = (void *)&efi_device_error,
+ .get_next_variable = (void *)&efi_device_error,
+ .set_variable = (void *)&efi_device_error,
+ .get_next_high_mono_count = (void *)&efi_device_error,
+ .reset_system = &efi_reset_system,
+};