aboutsummaryrefslogtreecommitdiffstats
path: root/meta-seattle/recipes-kernel/linux/files/01-arm64-boot-BE-kernels-from-UEFI.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-seattle/recipes-kernel/linux/files/01-arm64-boot-BE-kernels-from-UEFI.patch')
-rw-r--r--meta-seattle/recipes-kernel/linux/files/01-arm64-boot-BE-kernels-from-UEFI.patch999
1 files changed, 999 insertions, 0 deletions
diff --git a/meta-seattle/recipes-kernel/linux/files/01-arm64-boot-BE-kernels-from-UEFI.patch b/meta-seattle/recipes-kernel/linux/files/01-arm64-boot-BE-kernels-from-UEFI.patch
new file mode 100644
index 00000000..35b25249
--- /dev/null
+++ b/meta-seattle/recipes-kernel/linux/files/01-arm64-boot-BE-kernels-from-UEFI.patch
@@ -0,0 +1,999 @@
+From c55fa726d3e67da11a7ccd16ca367e9094265e4e Mon Sep 17 00:00:00 2001
+From: Adrian Calianu <adrian.calianu@enea.com>
+Date: Mon, 16 Feb 2015 13:56:36 +0100
+Subject: [PATCH 1/1] arm64: boot BE kernels from UEFI
+
+Adds support for booting BE kernels from UEFI. As UEFI is defined to
+be strictly little endian, some workarounds are required to combine a little
+endian EFI stub with a big endian kernel. Also, runtime services need to be
+wrapped so they can be executed in little endian mode.
+
+Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+This patch is the resulting of porting on 3.19 kernel of a patch set
+([RFC PATCH 00/10] arm64: boot BE kernels from UEFI) provided by
+Ard Biesheuvel ard.biesheuvel at linaro.org for 3.17 kernel.
+
+http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/274208.html
+
+Upstream-Status: Pending
+
+Signed-off-by: Adrian Calianu <adrian.calianu@enea.com>
+---
+ arch/arm64/Kconfig | 10 ++-
+ arch/arm64/include/asm/assembler.h | 18 +++++
+ arch/arm64/include/asm/efi.h | 2 +
+ arch/arm64/kernel/Makefile | 7 +-
+ arch/arm64/kernel/efi-be-call.S | 55 +++++++++++++++
+ arch/arm64/kernel/efi-be-runtime.c | 104 ++++++++++++++++++++++++++++
+ arch/arm64/kernel/efi-entry.S | 43 +++++++++---
+ arch/arm64/kernel/efi-stub.c | 10 +--
+ arch/arm64/kernel/efi.c | 64 ++++++++++-------
+ arch/arm64/kernel/efistub-le/Makefile | 52 ++++++++++++++
+ arch/arm64/kernel/efistub-le/efi-le-entry.S | 12 ++++
+ arch/arm64/kernel/efistub-le/efistub-le.lds | 35 ++++++++++
+ arch/arm64/kernel/efistub-le/le.h | 12 ++++
+ arch/arm64/kernel/efistub-le/strstr.c | 20 ++++++
+ arch/arm64/kernel/head.S | 48 +++++++------
+ arch/arm64/kernel/image.h | 16 ++++-
+ drivers/firmware/efi/efi.c | 26 ++++---
+ drivers/firmware/efi/efivars.c | 2 +-
+ drivers/firmware/efi/libstub/fdt.c | 4 ++
+ 19 files changed, 459 insertions(+), 81 deletions(-)
+ create mode 100644 arch/arm64/kernel/efi-be-call.S
+ create mode 100644 arch/arm64/kernel/efi-be-runtime.c
+ create mode 100644 arch/arm64/kernel/efistub-le/Makefile
+ create mode 100644 arch/arm64/kernel/efistub-le/efi-le-entry.S
+ create mode 100644 arch/arm64/kernel/efistub-le/efistub-le.lds
+ create mode 100644 arch/arm64/kernel/efistub-le/le.h
+ create mode 100644 arch/arm64/kernel/efistub-le/strstr.c
+
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index 3f08727..d35a06c 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -573,16 +573,20 @@ config CMDLINE_FORCE
+ config EFI_STUB
+ bool
+
++config EFI_LE_STUB
++ bool
++
+ config EFI
+ bool "UEFI runtime support"
+- depends on OF && !CPU_BIG_ENDIAN
++ depends on OF
+ select LIBFDT
+ select UCS2_STRING
+ select EFI_PARAMS_FROM_FDT
+ select EFI_RUNTIME_WRAPPERS
+- select EFI_STUB
++ select EFI_STUB if !CPU_BIG_ENDIAN
++ select EFI_LE_STUB if CPU_BIG_ENDIAN
+ select EFI_ARMSTUB
+- default y
++ default y if !CPU_BIG_ENDIAN
+ help
+ This option provides support for runtime services provided
+ by UEFI firmware (such as non-volatile variables, realtime
+diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
+index 5901480..ad3aa92 100644
+--- a/arch/arm64/include/asm/assembler.h
++++ b/arch/arm64/include/asm/assembler.h
+@@ -155,3 +155,21 @@ lr .req x30 // link register
+ #endif
+ orr \rd, \lbits, \hbits, lsl #32
+ .endm
++
++ /*
++ * Define LE constants
++ */
++ .macro le16, x
++ .byte \x & 0xff
++ .byte (\x >> 8) & 0xff
++ .endm
++
++ .macro le32, x
++ le16 \x
++ le16 \x >> 16
++ .endm
++
++ .macro le64, x
++ le32 \x
++ le32 \x >> 32
++ .endm
+diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
+index a34fd3b..44e642b 100644
+--- a/arch/arm64/include/asm/efi.h
++++ b/arch/arm64/include/asm/efi.h
+@@ -44,4 +44,6 @@ extern void efi_idmap_init(void);
+
+ #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
+
++extern void efi_be_runtime_setup(void);
++
+ #endif /* _ASM_EFI_H */
+diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
+index 79bdd3b..1ab3ff4 100644
+--- a/arch/arm64/kernel/Makefile
++++ b/arch/arm64/kernel/Makefile
+@@ -32,7 +32,12 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
+ arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+ arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+ arm64-obj-$(CONFIG_KGDB) += kgdb.o
+-arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
++arm64-efi-obj-y := efi.o
++arm64-efi-obj-$(CONFIG_EFI_STUB) += efi-stub.o efi-entry.o
++arm64-efi-obj-$(CONFIG_EFI_LE_STUB) += efistub-le/
++arm64-efi-obj-$(CONFIG_CPU_BIG_ENDIAN) += efi-be-runtime.o efi-be-call.o
++arm64-obj-$(CONFIG_EFI) += $(arm64-efi-obj-y)
++
+ arm64-obj-$(CONFIG_PCI) += pci.o
+ arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
+ arm64-obj-$(CONFIG_ACPI) += acpi.o
+diff --git a/arch/arm64/kernel/efi-be-call.S b/arch/arm64/kernel/efi-be-call.S
+new file mode 100644
+index 0000000..b395c8c
+--- /dev/null
++++ b/arch/arm64/kernel/efi-be-call.S
+@@ -0,0 +1,55 @@
++
++#include <linux/linkage.h>
++
++ .text
++ .align 3
++ENTRY(efi_be_phys_call)
++ /*
++ * Entered at physical address with 1:1 mapping enabled.
++ */
++ stp x29, x30, [sp, #-96]!
++ mov x29, sp
++ str x27, [sp, #16]
++
++ ldr x8, =efi_be_phys_call // virt address of this function
++ adr x9, efi_be_phys_call // phys address of this function
++ sub x9, x8, x9 // calculate virt to phys offset in x9
++
++ /* preserve all inputs */
++ stp x0, x1, [sp, #32]
++ stp x2, x3, [sp, #48]
++ stp x4, x5, [sp, #64]
++ stp x6, x7, [sp, #80]
++
++ /* get phys address of stack */
++ sub sp, sp, x9
++
++ /* switch to LE, disable MMU and D-cache but leave I-cache enabled */
++ mrs x27, sctlr_el1
++ bic x8, x27, #1 << 2 // clear SCTLR.C
++ msr sctlr_el1, x8
++
++ bl flush_cache_all
++
++ /* restore inputs but rotated by 1 register */
++ ldp x7, x0, [sp, #32]
++ ldp x1, x2, [sp, #48]
++ ldp x3, x4, [sp, #64]
++ ldp x5, x6, [sp, #80]
++
++ bic x8, x27, #1 << 2 // clear SCTLR.C
++ bic x8, x8, #1 << 0 // clear SCTLR.M
++ bic x8, x8, #1 << 25 // clear SCTLR.EE
++ msr sctlr_el1, x8
++ isb
++
++ blr x7
++
++ /* switch back to BE and reenable MMU and D-cache */
++ msr sctlr_el1, x27
++
++ mov sp, x29
++ ldr x27, [sp, #16]
++ ldp x29, x30, [sp], #96
++ ret
++ENDPROC(efi_be_phys_call)
+diff --git a/arch/arm64/kernel/efi-be-runtime.c b/arch/arm64/kernel/efi-be-runtime.c
+new file mode 100644
+index 0000000..28d7406
+--- /dev/null
++++ b/arch/arm64/kernel/efi-be-runtime.c
+@@ -0,0 +1,104 @@
++
++#include <linux/efi.h>
++#include <linux/spinlock.h>
++#include <asm/efi.h>
++#include <asm/neon.h>
++#include <asm/tlbflush.h>
++
++static efi_runtime_services_t *runtime;
++static efi_status_t (*efi_be_call)(phys_addr_t func, ...);
++
++static DEFINE_SPINLOCK(efi_be_rt_lock);
++
++static unsigned long efi_be_call_pre(void)
++{
++ unsigned long flags;
++
++ kernel_neon_begin();
++ spin_lock_irqsave(&efi_be_rt_lock, flags);
++ cpu_switch_mm(idmap_pg_dir, &init_mm);
++ flush_tlb_all();
++ return flags;
++}
++
++static void efi_be_call_post(unsigned long flags)
++{
++ cpu_switch_mm(current, current->active_mm);
++ flush_tlb_all();
++ spin_unlock_irqrestore(&efi_be_rt_lock, flags);
++ kernel_neon_end();
++}
++
++static efi_status_t efi_be_get_variable(efi_char16_t *name,
++ efi_guid_t *vendor,
++ u32 *attr,
++ unsigned long *data_size,
++ void *data)
++{
++ unsigned long flags;
++ efi_status_t status;
++
++ *data_size = cpu_to_le64(*data_size);
++ flags = efi_be_call_pre();
++ status = efi_be_call(le64_to_cpu(runtime->get_variable),
++ virt_to_phys(name), virt_to_phys(vendor),
++ virt_to_phys(attr), virt_to_phys(data_size),
++ virt_to_phys(data));
++ efi_be_call_post(flags);
++ *attr = le32_to_cpu(*attr);
++ *data_size = le64_to_cpu(*data_size);
++ return status;
++}
++
++static efi_status_t efi_be_get_next_variable(unsigned long *name_size,
++ efi_char16_t *name,
++ efi_guid_t *vendor)
++{
++ unsigned long flags;
++ efi_status_t status;
++
++ *name_size = cpu_to_le64(*name_size);
++ flags = efi_be_call_pre();
++ status = efi_be_call(le64_to_cpu(runtime->get_next_variable),
++ virt_to_phys(name_size), virt_to_phys(name),
++ virt_to_phys(vendor));
++ efi_be_call_post(flags);
++ *name_size = le64_to_cpu(*name_size);
++ return status;
++}
++
++static efi_status_t efi_be_set_variable(efi_char16_t *name,
++ efi_guid_t *vendor,
++ u32 attr,
++ unsigned long data_size,
++ void *data)
++{
++ unsigned long flags;
++ efi_status_t status;
++
++ flags = efi_be_call_pre();
++ status = efi_be_call(le64_to_cpu(runtime->set_variable),
++ virt_to_phys(name), virt_to_phys(vendor),
++ cpu_to_le32(attr), cpu_to_le64(data_size),
++ virt_to_phys(data));
++ efi_be_call_post(flags);
++ return status;
++}
++
++void efi_be_runtime_setup(void)
++{
++ extern u8 efi_be_phys_call[];
++
++ runtime = ioremap_cache(le64_to_cpu(efi.systab->runtime),
++ sizeof(efi_runtime_services_t));
++ if (!runtime) {
++ pr_err("Failed to set up BE wrappers for UEFI Runtime Services!\n");
++ return;
++ }
++
++ efi_be_call = (void *)virt_to_phys(efi_be_phys_call);
++
++ efi.get_variable = efi_be_get_variable;
++ efi.get_next_variable = efi_be_get_next_variable;
++ efi.set_variable = efi_be_set_variable;
++}
+diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
+index 8ce9b05..760fbb5 100644
+--- a/arch/arm64/kernel/efi-entry.S
++++ b/arch/arm64/kernel/efi-entry.S
+@@ -34,7 +34,34 @@ ENTRY(efi_stub_entry)
+ * Create a stack frame to save FP/LR with extra space
+ * for image_addr variable passed to efi_entry().
+ */
+- stp x29, x30, [sp, #-32]!
++ stp x29, x30, [sp, #-48]!
++ stp x22, x23, [sp, #32]
++
++#ifdef CONFIG_EFI_LE_STUB
++ adr x4, efi_stub_entry
++ ldp w8, w9, [x4, #-32]
++STUB_BE(rev w8, w8 )
++STUB_BE(rev w9, w9 )
++ add x8, x4, w8, sxtw // x8: base of Image
++ add x9, x4, w9, sxtw // x9: offset of linux_banner
++
++ ldp x22, x23, [x4, #-24] // x22: size of Image
++STUB_BE(rev x23, x23 ) // x23: stext offset
++
++ /*
++ * Get a pointer to linux_banner in the outer image and store it
++ * in this image.
++ */
++ adrp x4, le_linux_banner
++ str x9, [x4, #:lo12:le_linux_banner]
++#else
++ adrp x8, _text
++ add x8, x8, #:lo12:_text // x8: base of Image
++ adrp x9, _edata
++ add x9, x9, #:lo12:_edata
++ sub x22, x9, x8 // x22: size of Image
++ ldr x23, =stext_offset // x23: stext offset
++#endif
+
+ /*
+ * Call efi_entry to do the real work.
+@@ -45,8 +72,6 @@ ENTRY(efi_stub_entry)
+ * efi_system_table_t *sys_table,
+ * unsigned long *image_addr) ;
+ */
+- adrp x8, _text
+- add x8, x8, #:lo12:_text
+ add x2, sp, 16
+ str x8, [x2]
+ bl efi_entry
+@@ -61,17 +86,12 @@ ENTRY(efi_stub_entry)
+ */
+ mov x20, x0 // DTB address
+ ldr x0, [sp, #16] // relocated _text address
+- ldr x21, =stext_offset
+- add x21, x0, x21
++ add x21, x0, x23
+
+ /*
+ * Calculate size of the kernel Image (same for original and copy).
+ */
+- adrp x1, _text
+- add x1, x1, #:lo12:_text
+- adrp x2, _edata
+- add x2, x2, #:lo12:_edata
+- sub x1, x2, x1
++ mov x1, x22
+
+ /*
+ * Flush the copied Image to the PoC, and ensure it is not shadowed by
+@@ -117,7 +137,8 @@ ENTRY(efi_stub_entry)
+
+ efi_load_fail:
+ mov x0, #EFI_LOAD_ERROR
+- ldp x29, x30, [sp], #32
++ ldp x22, x23, [sp, #32]
++ ldp x29, x30, [sp], #48
+ ret
+
+ efi_stub_entry_end:
+diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
+index d27dd98..dd6d6bc 100644
+--- a/arch/arm64/kernel/efi-stub.c
++++ b/arch/arm64/kernel/efi-stub.c
+@@ -11,7 +11,6 @@
+ */
+ #include <linux/efi.h>
+ #include <asm/efi.h>
+-#include <asm/sections.h>
+
+ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
+ unsigned long *image_addr,
+@@ -22,22 +21,19 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
+ efi_loaded_image_t *image)
+ {
+ efi_status_t status;
+- unsigned long kernel_size, kernel_memsize = 0;
+
+ /* Relocate the image, if required. */
+- kernel_size = _edata - _text;
+ if (*image_addr != (dram_base + TEXT_OFFSET)) {
+- kernel_memsize = kernel_size + (_end - _edata);
+- status = efi_low_alloc(sys_table, kernel_memsize + TEXT_OFFSET,
++ status = efi_low_alloc(sys_table, image->image_size + TEXT_OFFSET,
+ SZ_2M, reserve_addr);
+ if (status != EFI_SUCCESS) {
+ pr_efi_err(sys_table, "Failed to relocate kernel\n");
+ return status;
+ }
+ memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr,
+- kernel_size);
++ image->image_size);
+ *image_addr = *reserve_addr + TEXT_OFFSET;
+- *reserve_size = kernel_memsize + TEXT_OFFSET;
++ *reserve_size = image->image_size + TEXT_OFFSET;
+ }
+
+
+diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
+index 4178e9e..133c599 100644
+--- a/arch/arm64/kernel/efi.c
++++ b/arch/arm64/kernel/efi.c
+@@ -43,7 +43,7 @@ early_param("uefi_debug", uefi_debug_setup);
+
+ static int __init is_normal_ram(efi_memory_desc_t *md)
+ {
+- if (md->attribute & EFI_MEMORY_WB)
++ if (le64_to_cpu(md->attribute) & EFI_MEMORY_WB)
+ return 1;
+ return 0;
+ }
+@@ -59,10 +59,10 @@ static void __init efi_setup_idmap(void)
+
+ /* map runtime io spaces */
+ for_each_efi_memory_desc(&memmap, md) {
+- if (!(md->attribute & EFI_MEMORY_RUNTIME) || is_normal_ram(md))
++ if (!(le64_to_cpu(md->attribute) & EFI_MEMORY_RUNTIME) || is_normal_ram(md))
+ continue;
+- paddr = md->phys_addr;
+- npages = md->num_pages;
++ paddr = le64_to_cpu(md->phys_addr);
++ npages = le64_to_cpu(md->num_pages);
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+ create_id_mapping(paddr, size, 1);
+@@ -88,29 +88,29 @@ static int __init uefi_init(void)
+ /*
+ * Verify the EFI Table
+ */
+- if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
++ if (le64_to_cpu(efi.systab->hdr.signature) != EFI_SYSTEM_TABLE_SIGNATURE) {
+ pr_err("System table signature incorrect\n");
+ retval = -EINVAL;
+ goto out;
+ }
+- if ((efi.systab->hdr.revision >> 16) < 2)
++ if ((le32_to_cpu(efi.systab->hdr.revision) >> 16) < 2)
+ pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff);
+
+ /* Show what we know for posterity */
+- c16 = early_memremap(efi.systab->fw_vendor,
++ c16 = early_memremap(le64_to_cpu(efi.systab->fw_vendor),
+ sizeof(vendor));
+ if (c16) {
+ for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
+- vendor[i] = c16[i];
++ vendor[i] = le16_to_cpu(c16[i]);
+ vendor[i] = '\0';
+ early_memunmap(c16, sizeof(vendor));
+ }
+
+ pr_info("EFI v%u.%.02u by %s\n",
+- efi.systab->hdr.revision >> 16,
+- efi.systab->hdr.revision & 0xffff, vendor);
++ le32_to_cpu(efi.systab->hdr.revision) >> 16,
++ le32_to_cpu(efi.systab->hdr.revision) & 0xffff, vendor);
+
+ retval = efi_config_init(NULL);
+
+@@ -124,7 +124,7 @@ out:
+ */
+ static __init int is_reserve_region(efi_memory_desc_t *md)
+ {
+- switch (md->type) {
++ switch (le32_to_cpu(md->type)) {
+ case EFI_LOADER_CODE:
+ case EFI_LOADER_DATA:
+ case EFI_BOOT_SERVICES_CODE:
+@@ -146,8 +146,9 @@ static __init void reserve_regions(void)
+ pr_info("Processing EFI memory map:\n");
+
+ for_each_efi_memory_desc(&memmap, md) {
+- paddr = md->phys_addr;
+- npages = md->num_pages;
++ u32 md_type = le32_to_cpu(md->type);
++ paddr = le64_to_cpu(md->phys_addr);
++ npages = le64_to_cpu(md->num_pages);
+
+ if (uefi_debug) {
+ char buf[64];
+@@ -164,8 +165,8 @@ static __init void reserve_regions(void)
+ early_init_dt_add_memory_arch(paddr, size);
+
+ if (is_reserve_region(md) ||
+- md->type == EFI_BOOT_SERVICES_CODE ||
+- md->type == EFI_BOOT_SERVICES_DATA) {
++ md_type == EFI_BOOT_SERVICES_CODE ||
++ md_type == EFI_BOOT_SERVICES_DATA) {
+ memblock_reserve(paddr, size);
+ if (uefi_debug)
+ pr_cont("*");
+@@ -246,17 +247,17 @@ static void __init free_boot_services(void)
+ */
+ if (free_start) {
+ /* adjust free_end then free region */
+- if (free_end > md->phys_addr)
++ if (free_end > le64_to_cpu(md->phys_addr))
+ free_end -= PAGE_SIZE;
+ total_freed += free_region(free_start, free_end);
+ free_start = 0;
+ }
+- keep_end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
++ keep_end = le64_to_cpu(md->phys_addr) + (le64_to_cpu(md->num_pages) << EFI_PAGE_SHIFT);
+ continue;
+ }
+
+- if (md->type != EFI_BOOT_SERVICES_CODE &&
+- md->type != EFI_BOOT_SERVICES_DATA) {
++ if (le32_to_cpu(md->type) != EFI_BOOT_SERVICES_CODE &&
++ le32_to_cpu(md->type) != EFI_BOOT_SERVICES_DATA) {
+ /* no need to free this region */
+ continue;
+ }
+@@ -264,8 +265,8 @@ static void __init free_boot_services(void)
+ /*
+ * We want to free memory from this region.
+ */
+- paddr = md->phys_addr;
+- npages = md->num_pages;
++ paddr = le64_to_cpu(md->phys_addr);
++ npages = le64_to_cpu(md->num_pages);
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+
+@@ -333,8 +334,8 @@ static int __init remap_region(efi_memory_desc_t *md, void **new)
+ {
+ u64 paddr, vaddr, npages, size;
+
+- paddr = md->phys_addr;
+- npages = md->num_pages;
++ paddr = le64_to_cpu(md->phys_addr);
++ npages = le64_to_cpu(md->num_pages);
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+
+@@ -350,7 +351,7 @@ static int __init remap_region(efi_memory_desc_t *md, void **new)
+ }
+
+ /* adjust for any rounding when EFI and system pagesize differs */
+- md->virt_addr = vaddr + (md->phys_addr - paddr);
++ md->virt_addr = vaddr + (le64_to_cpu(md->phys_addr) - paddr);
+
+ if (uefi_debug)
+ pr_info(" EFI remap 0x%012llx => %p\n",
+@@ -395,6 +396,21 @@ static int __init arm64_enter_virtual_mode(void)
+
+ efi.memmap = &memmap;
+
++ if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
++ efi.systab = ioremap_cache(efi_system_table,
++ sizeof(efi_system_table_t));
++ if (!efi.systab) {
++ pr_err("Failed to remap EFI system table!\n");
++ return -1;
++ }
++ free_boot_services();
++ efi_be_runtime_setup();
++
++ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
++ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
++ return 0;
++ }
++
+ /* Map the runtime regions */
+ virtmap = kmalloc(mapsize, GFP_KERNEL);
+ if (!virtmap) {
+diff --git a/arch/arm64/kernel/efistub-le/Makefile b/arch/arm64/kernel/efistub-le/Makefile
+new file mode 100644
+index 0000000..8a1c2a8
+--- /dev/null
++++ b/arch/arm64/kernel/efistub-le/Makefile
+@@ -0,0 +1,52 @@
++
++#
++# Build a little endian EFI stub and wrap it into a single .o
++#
++
++# the LE objects making up the LE efi stub
++le-objs := efi-entry.o efi-stub.o strstr.o cache.o \
++ lib-memchr.o lib-memcmp.o lib-memcpy.o lib-memmove.o \
++ lib-memset.o lib-strchr.o lib-strlen.o lib-strncmp.o \
++ fdt-fdt.o fdt-fdt_ro.o fdt-fdt_rw.o fdt-fdt_sw.o \
++ fdt-fdt_wip.o fdt-fdt_empty_tree.o \
++ libstub-fdt.o libstub-arm-stub.o libstub-efi-stub-helper.o
++
++extra-y := efi-le-stub.bin efi-le-stub.elf $(le-objs)
++
++KBUILD_CFLAGS := $(subst -pg,,$(KBUILD_CFLAGS)) -fno-stack-protector \
++ -mlittle-endian -I$(srctree)/scripts/dtc/libfdt
++
++le-targets := $(addprefix $(obj)/, $(le-objs))
++$(le-targets): KBUILD_AFLAGS += -mlittle-endian -include $(srctree)/$(src)/le.h
++
++$(obj)/efi-entry.o: $(obj)/../efi-entry.S FORCE
++ $(call if_changed_dep,as_o_S)
++
++CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
++$(obj)/efi-stub.o: $(obj)/../efi-stub.c FORCE
++ $(call if_changed_dep,cc_o_c)
++
++$(obj)/cache.o: $(src)/../../mm/cache.S FORCE
++ $(call if_changed_dep,as_o_S)
++
++$(obj)/lib-%.o: $(src)/../../lib/%.S FORCE
++ $(call if_changed_dep,as_o_S)
++
++$(obj)/fdt-%.o: $(srctree)/lib/%.c FORCE
++ $(call if_changed_dep,cc_o_c)
++
++$(obj)/libstub-%.o: $(srctree)/drivers/firmware/efi/libstub/%.c FORCE
++ $(call if_changed_dep,cc_o_c)
++
++$(obj)/efi-le-stub.elf: LDFLAGS=-EL -Map $@.map -T
++$(obj)/efi-le-stub.elf: $(src)/efistub-le.lds $(le-targets) FORCE
++ $(call if_changed,ld)
++
++$(obj)/efi-le-stub.bin: OBJCOPYFLAGS=-O binary
++$(obj)/efi-le-stub.bin: $(obj)/efi-le-stub.elf FORCE
++ $(call if_changed,objcopy)
++
++# the BE object containing the entire LE stub
++obj-y := efi-le-entry.o
++
++$(obj)/efi-le-entry.o: $(obj)/efi-le-stub.bin
+diff --git a/arch/arm64/kernel/efistub-le/efi-le-entry.S b/arch/arm64/kernel/efistub-le/efi-le-entry.S
+new file mode 100644
+index 0000000..755364c
+--- /dev/null
++++ b/arch/arm64/kernel/efistub-le/efi-le-entry.S
+@@ -0,0 +1,12 @@
++#include <linux/linkage.h>
++
++ .text
++ .align 12
++ .long _text - efi_stub_entry
++ .long linux_banner - efi_stub_entry
++ .quad _kernel_size_le
++ .quad stext_offset
++ .quad 0
++ENTRY(efi_stub_entry)
++ .incbin "arch/arm64/kernel/efistub-le/efi-le-stub.bin"
++ENDPROC(efi_stub_entry)
+diff --git a/arch/arm64/kernel/efistub-le/efistub-le.lds b/arch/arm64/kernel/efistub-le/efistub-le.lds
+new file mode 100644
+index 0000000..f64d542
+--- /dev/null
++++ b/arch/arm64/kernel/efistub-le/efistub-le.lds
+@@ -0,0 +1,35 @@
++
++ENTRY(efi_stub_entry)
++
++SECTIONS {
++ /*
++ * The inner and outer alignment of this chunk of code need to be the
++ * same so that PC relative references using adrp/add or adrp/ldr pairs
++ * will work correctly.
++ * Skip 32 bytes here, so we can put the binary blob at an offset of
++ * 4k + 0x20 in the outer image, and use the gap to share constants
++ * emitted by the outer linker but required in the stub.
++ */
++ .text 0x20 : {
++ arch/arm64/kernel/efistub-le/efi-entry.o(.init.text)
++ *(.init.text)
++ *(.text)
++ *(.text*)
++ }
++ .rodata : {
++ . = ALIGN(16);
++ *(.rodata)
++ *(.rodata*)
++ *(.init.rodata)
++ }
++ .data : {
++ . = ALIGN(16);
++ *(.data)
++ *(.data*)
++ le_linux_banner = .;
++ . += 8;
++ }
++ /DISCARD/ : {
++ *(__ex_table)
++ }
++}
+diff --git a/arch/arm64/kernel/efistub-le/le.h b/arch/arm64/kernel/efistub-le/le.h
+new file mode 100644
+index 0000000..a9f6dfc
+--- /dev/null
++++ b/arch/arm64/kernel/efistub-le/le.h
+@@ -0,0 +1,12 @@
++
++/*
++ * This is a bit of a hack, but it is necessary to correctly compile .S files
++ * that contain CPU_LE()/CPU_BE() statements, as these are defined to depend on
++ * CONFIG_ symbols and not on the endianness of the compiler.
++ */
++#ifdef CONFIG_CPU_BIG_ENDIAN
++#define STUB_BE(code...) code
++#else
++#define STUB_BE(code...)
++#endif
++#undef CONFIG_CPU_BIG_ENDIAN
+diff --git a/arch/arm64/kernel/efistub-le/strstr.c b/arch/arm64/kernel/efistub-le/strstr.c
+new file mode 100644
+index 0000000..bd16094
+--- /dev/null
++++ b/arch/arm64/kernel/efistub-le/strstr.c
+@@ -0,0 +1,20 @@
++
++#include <linux/types.h>
++#include <linux/string.h>
++
++char *strstr(const char *s1, const char *s2)
++{
++ size_t l1, l2;
++
++ l2 = strlen(s2);
++ if (!l2)
++ return (char *)s1;
++ l1 = strlen(s1);
++ while (l1 >= l2) {
++ l1--;
++ if (!memcmp(s1, s2, l2))
++ return (char *)s1;
++ s1++;
++ }
++ return NULL;
++}
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index 8ce88e0..8b1eba5 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -126,7 +126,10 @@ efi_head:
+ .byte 0x4d
+ .byte 0x64
+ #ifdef CONFIG_EFI
+- .long pe_header - efi_head // Offset to the PE header.
++ .byte pe_header - efi_head // Offset to the PE header.
++ .byte 0
++ .byte 0
++ .byte 0
+ #else
+ .word 0 // reserved
+ #endif
+@@ -139,30 +142,31 @@ pe_header:
+ .ascii "PE"
+ .short 0
+ coff_header:
+- .short 0xaa64 // AArch64
+- .short 2 // nr_sections
++ le16 0xaa64 // AArch64
++ le16 2 // nr_sections
+ .long 0 // TimeDateStamp
+ .long 0 // PointerToSymbolTable
+- .long 1 // NumberOfSymbols
+- .short section_table - optional_header // SizeOfOptionalHeader
+- .short 0x206 // Characteristics.
++ le32 1 // NumberOfSymbols
++ .byte section_table - optional_header // SizeOfOptionalHeader
++ .byte 0
++ le16 0x206 // Characteristics.
+ // IMAGE_FILE_DEBUG_STRIPPED |
+ // IMAGE_FILE_EXECUTABLE_IMAGE |
+ // IMAGE_FILE_LINE_NUMS_STRIPPED
+ optional_header:
+- .short 0x20b // PE32+ format
++ le16 0x20b // PE32+ format
+ .byte 0x02 // MajorLinkerVersion
+ .byte 0x14 // MinorLinkerVersion
+- .long _end - stext // SizeOfCode
++ .long _efi_code_virtsize_le // SizeOfCode
+ .long 0 // SizeOfInitializedData
+ .long 0 // SizeOfUninitializedData
+- .long efi_stub_entry - efi_head // AddressOfEntryPoint
+- .long stext_offset // BaseOfCode
++ .long _efi_entry_point_le // AddressOfEntryPoint
++ .long _efi_stext_offset_le // BaseOfCode
+
+ extra_header_fields:
+ .quad 0 // ImageBase
+- .long 0x1000 // SectionAlignment
+- .long PECOFF_FILE_ALIGNMENT // FileAlignment
++ le32 0x1000 // SectionAlignment
++ le32 0x200 // FileAlignment
+ .short 0 // MajorOperatingSystemVersion
+ .short 0 // MinorOperatingSystemVersion
+ .short 0 // MajorImageVersion
+@@ -171,19 +175,19 @@ extra_header_fields:
+ .short 0 // MinorSubsystemVersion
+ .long 0 // Win32VersionValue
+
+- .long _end - efi_head // SizeOfImage
++ .long _efi_image_size_le // SizeOfImage
+
+ // Everything before the kernel image is considered part of the header
+- .long stext_offset // SizeOfHeaders
++ .long _efi_stext_offset_le // SizeOfHeaders
+ .long 0 // CheckSum
+- .short 0xa // Subsystem (EFI application)
++ le16 0xa // Subsystem (EFI application)
+ .short 0 // DllCharacteristics
+ .quad 0 // SizeOfStackReserve
+ .quad 0 // SizeOfStackCommit
+ .quad 0 // SizeOfHeapReserve
+ .quad 0 // SizeOfHeapCommit
+ .long 0 // LoaderFlags
+- .long 0x6 // NumberOfRvaAndSizes
++ le32 0x6 // NumberOfRvaAndSizes
+
+ .quad 0 // ExportTable
+ .quad 0 // ImportTable
+@@ -211,23 +215,23 @@ section_table:
+ .long 0 // PointerToLineNumbers
+ .short 0 // NumberOfRelocations
+ .short 0 // NumberOfLineNumbers
+- .long 0x42100040 // Characteristics (section flags)
++ le32 0x42100040 // Characteristics (section flags)
+
+
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 // end of 0 padding of section name
+- .long _end - stext // VirtualSize
+- .long stext_offset // VirtualAddress
+- .long _edata - stext // SizeOfRawData
+- .long stext_offset // PointerToRawData
++ .long _efi_code_virtsize_le // VirtualSize
++ .long _efi_stext_offset_le // VirtualAddress
++ .long _efi_code_rawsize_le // SizeOfRawData
++ .long _efi_stext_offset_le // PointerToRawData
+
+ .long 0 // PointerToRelocations (0 for executables)
+ .long 0 // PointerToLineNumbers (0 for executables)
+ .short 0 // NumberOfRelocations (0 for executables)
+ .short 0 // NumberOfLineNumbers (0 for executables)
+- .long 0xe0500020 // Characteristics (section flags)
++ le32 0xe0500020 // Characteristics (section flags)
+
+ /*
+ * EFI will load stext onwards at the 4k section alignment
+diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
+index 8fae075..d08ce56 100644
+--- a/arch/arm64/kernel/image.h
++++ b/arch/arm64/kernel/image.h
+@@ -37,8 +37,10 @@
+ (((data) & 0x0000ff0000000000) >> 24) | \
+ (((data) & 0x00ff000000000000) >> 40) | \
+ (((data) & 0xff00000000000000) >> 56))
++#define DATA_LE32(data) (DATA_LE64(data) >> 32)
+ #else
+ #define DATA_LE64(data) ((data) & 0xffffffffffffffff)
++#define DATA_LE32(data) ((data) & 0xffffffff)
+ #endif
+
+ #ifdef CONFIG_CPU_BIG_ENDIAN
+@@ -57,6 +59,18 @@
+ #define HEAD_SYMBOLS \
+ _kernel_size_le = DATA_LE64(_end - _text); \
+ _kernel_offset_le = DATA_LE64(TEXT_OFFSET); \
+- _kernel_flags_le = DATA_LE64(__HEAD_FLAGS);
++ _kernel_flags_le = DATA_LE64(__HEAD_FLAGS); \
++ EFI_HEAD_SYMBOLS
++
++#ifdef CONFIG_EFI
++#define EFI_HEAD_SYMBOLS \
++ _efi_stext_offset_le = DATA_LE32(stext_offset); \
++ _efi_code_virtsize_le = DATA_LE32(_end - _text - stext_offset); \
++ _efi_code_rawsize_le = DATA_LE32(_edata - _text - stext_offset); \
++ _efi_image_size_le = DATA_LE32(_end - _text); \
++ _efi_entry_point_le = DATA_LE32(efi_stub_entry - _text);
++#else
++#define EFI_HEAD_SYMBOLS
++#endif
+
+ #endif /* __ASM_IMAGE_H */
+diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
+index 9035c1b..4e98daa 100644
+--- a/drivers/firmware/efi/efi.c
++++ b/drivers/firmware/efi/efi.c
+@@ -296,18 +296,23 @@ static __init int match_config_table(efi_guid_t *guid,
+ int __init efi_config_init(efi_config_table_type_t *arch_tables)
+ {
+ void *config_tables, *tablep;
+- int i, sz;
++ unsigned long __tables;
++ int i, sz, nr_tables;
+
+- if (efi_enabled(EFI_64BIT))
++ if (efi_enabled(EFI_64BIT)) {
+ sz = sizeof(efi_config_table_64_t);
+- else
++ nr_tables = le64_to_cpu((__force __le64)efi.systab->nr_tables);
++ __tables = le64_to_cpu((__force __le64)efi.systab->tables);
++ } else {
+ sz = sizeof(efi_config_table_32_t);
++ nr_tables = le32_to_cpu((__force __le32)efi.systab->nr_tables);
++ __tables = le32_to_cpu((__force __le32)efi.systab->tables);
++ }
+
+ /*
+ * Let's see what config tables the firmware passed to us.
+ */
+- config_tables = early_memremap(efi.systab->tables,
+- efi.systab->nr_tables * sz);
++ config_tables = early_memremap(__tables, nr_tables * sz);
+ if (config_tables == NULL) {
+ pr_err("Could not map Configuration table!\n");
+ return -ENOMEM;
+@@ -315,21 +320,20 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
+
+ tablep = config_tables;
+ pr_info("");
+- for (i = 0; i < efi.systab->nr_tables; i++) {
++ for (i = 0; i < nr_tables; i++) {
+ efi_guid_t guid;
+ unsigned long table;
+
+ if (efi_enabled(EFI_64BIT)) {
+ u64 table64;
+ guid = ((efi_config_table_64_t *)tablep)->guid;
+- table64 = ((efi_config_table_64_t *)tablep)->table;
+- table = table64;
++ table = table64 = le64_to_cpu((__force __le64)
++ ((efi_config_table_64_t *)tablep)->table);
+ #ifndef CONFIG_64BIT
+ if (table64 >> 32) {
+ pr_cont("\n");
+ pr_err("Table located above 4GB, disabling EFI.\n");
+- early_memunmap(config_tables,
+- efi.systab->nr_tables * sz);
++ early_memunmap(config_tables, nr_tables * sz);
+ return -EINVAL;
+ }
+ #endif
+@@ -344,7 +348,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
+ tablep += sz;
+ }
+ pr_cont("\n");
+- early_memunmap(config_tables, efi.systab->nr_tables * sz);
++ early_memunmap(config_tables, nr_tables * sz);
+
+ set_bit(EFI_CONFIG_TABLES, &efi.flags);
+
+diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
+index f256ecd..2b1c8be 100644
+--- a/drivers/firmware/efi/efivars.c
++++ b/drivers/firmware/efi/efivars.c
+@@ -563,7 +563,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
+ /* Convert Unicode to normal chars (assume top bits are 0),
+ ala UTF-8 */
+ for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
+- short_name[i] = variable_name[i] & 0xFF;
++ short_name[i] = le16_to_cpu((__force __le16)variable_name[i]);
+ }
+ /* This is ugly, but necessary to separate one vendor's
+ private variables from another's. */
+diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
+index c846a96..f0f9d54 100644
+--- a/drivers/firmware/efi/libstub/fdt.c
++++ b/drivers/firmware/efi/libstub/fdt.c
+@@ -22,6 +22,10 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
+ unsigned long map_size, unsigned long desc_size,
+ u32 desc_ver)
+ {
++#ifdef CONFIG_EFI_LE_STUB
++ extern char const *le_linux_banner;
++ char const *linux_banner = le_linux_banner;
++#endif
+ int node, prev, num_rsv;
+ int status;
+ u32 fdt_val32;
+--
+1.9.1
+