forked from pool/u-boot
cad836ad68
Sorry for the supersede, this fixes a small issue with beaglebone where grub2 would overwrite the initrd while patching the device tree because it's missing boundary checks. - EFI: Map fdt as reserved * efi-map-fdt-as-reserved.patch - Fix OMAP3 boards to load u-boot from raw sector offset * omap3-Use-raw-SPL-by-default-for-mmc1.patch - Allow grub2 to find its config * efi_loader-Pass-proper-device-path-in-on-boot.patch - Fix Raspberry Pi 1 build * efi_loader-Provide-icache-flush-stub.patch - Move omap3 to distro bootcmd (to enable efi boot on beagle-xm) * omap3-Move-to-distro-bootcmd.patch - Add EFI patch to support FDT fixups (patches in RAM size) * efi_loader-Call-fdt-preparation-functions.patch - Patch the default u-boot env to search for dtb in /boot at part 2 * efi-default-env.patch - Use $fdtfile rather than $fdt_name everywhere: * efi2.patch - Add EFI support about to move upstream: * efi.patch - EFI: Map fdt as reserved * efi-map-fdt-as-reserved.patch - Fix OMAP3 boards to load u-boot from raw sector offset * omap3-Use-raw-SPL-by-default-for-mmc1.patch (forwarded request 365802 from algraf) OBS-URL: https://build.opensuse.org/request/show/366093 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/u-boot?expand=0&rev=68
5576 lines
159 KiB
Diff
5576 lines
159 KiB
Diff
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 = §ions[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 = §ions[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,
|
||
+};
|