Merge branch 'efi/urgent' into efi/core, to pick up fixes
authorIngo Molnar <mingo@kernel.org>
Sun, 8 Mar 2020 08:57:58 +0000 (09:57 +0100)
committerIngo Molnar <mingo@kernel.org>
Sun, 8 Mar 2020 08:57:58 +0000 (09:57 +0100)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
70 files changed:
Documentation/x86/boot.rst
arch/arm/boot/compressed/efi-header.S
arch/arm/boot/compressed/head.S
arch/arm64/include/asm/efi.h
arch/arm64/kernel/efi-entry.S
arch/arm64/kernel/efi-header.S
arch/arm64/kernel/image-vars.h
arch/ia64/kernel/efi.c
arch/ia64/kernel/esi.c
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/eboot.c [deleted file]
arch/x86/boot/compressed/eboot.h [deleted file]
arch/x86/boot/compressed/efi_thunk_64.S
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/header.S
arch/x86/boot/tools/build.c
arch/x86/include/asm/efi.h
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/head_32.S
arch/x86/kernel/ima_arch.c
arch/x86/kernel/kexec-bzimage64.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_32.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/efi/efi_stub_32.S
arch/x86/platform/efi/quirks.c
drivers/firmware/efi/Kconfig
drivers/firmware/efi/Makefile
drivers/firmware/efi/apple-properties.c
drivers/firmware/efi/arm-init.c
drivers/firmware/efi/arm-runtime.c
drivers/firmware/efi/capsule-loader.c
drivers/firmware/efi/dev-path-parser.c
drivers/firmware/efi/efi-bgrt.c
drivers/firmware/efi/efi-pstore.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/efivars.c
drivers/firmware/efi/embedded-firmware.c [new file with mode: 0644]
drivers/firmware/efi/esrt.c
drivers/firmware/efi/fdtparams.c [new file with mode: 0644]
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/arm-stub.c
drivers/firmware/efi/libstub/arm32-stub.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/fdt.c
drivers/firmware/efi/libstub/file.c [new file with mode: 0644]
drivers/firmware/efi/libstub/hidden.h [new file with mode: 0644]
drivers/firmware/efi/libstub/mem.c [new file with mode: 0644]
drivers/firmware/efi/libstub/random.c
drivers/firmware/efi/libstub/randomalloc.c [new file with mode: 0644]
drivers/firmware/efi/libstub/skip_spaces.c [new file with mode: 0644]
drivers/firmware/efi/libstub/string.c
drivers/firmware/efi/libstub/x86-stub.c [new file with mode: 0644]
drivers/firmware/efi/memattr.c
drivers/firmware/efi/reboot.c
drivers/firmware/efi/runtime-wrappers.c
drivers/firmware/pcdp.c
drivers/infiniband/hw/hfi1/efivar.c
drivers/rtc/Makefile
drivers/rtc/rtc-efi-platform.c [deleted file]
drivers/scsi/isci/init.c
fs/efivarfs/super.c
include/linux/efi.h
include/linux/efi_embedded_fw.h [new file with mode: 0644]
include/linux/pe.h
security/integrity/platform_certs/load_uefi.c

index c9c2015..fa7ddc0 100644 (file)
@@ -490,15 +490,11 @@ Protocol: 2.00+
                kernel) to not write early messages that require
                accessing the display hardware directly.
 
-  Bit 6 (write): KEEP_SEGMENTS
+  Bit 6 (obsolete): KEEP_SEGMENTS
 
        Protocol: 2.07+
 
-       - If 0, reload the segment registers in the 32bit entry point.
-       - If 1, do not reload the segment registers in the 32bit entry point.
-
-               Assume that %cs %ds %ss %es are all set to flat segments with
-               a base of 0 (or the equivalent for their environment).
+        - This flag is obsolete.
 
   Bit 7 (write): CAN_USE_HEAP
 
index a598358..62286da 100644 (file)
@@ -60,7 +60,7 @@ optional_header:
                .long   __pecoff_code_size              @ SizeOfCode
                .long   __pecoff_data_size              @ SizeOfInitializedData
                .long   0                               @ SizeOfUninitializedData
-               .long   efi_stub_entry - start          @ AddressOfEntryPoint
+               .long   efi_entry - start               @ AddressOfEntryPoint
                .long   start_offset                    @ BaseOfCode
                .long   __pecoff_data_start - start     @ BaseOfData
 
@@ -70,8 +70,8 @@ extra_header_fields:
                .long   SZ_512                          @ FileAlignment
                .short  0                               @ MajorOsVersion
                .short  0                               @ MinorOsVersion
-               .short  0                               @ MajorImageVersion
-               .short  0                               @ MinorImageVersion
+               .short  LINUX_EFISTUB_MAJOR_VERSION     @ MajorImageVersion
+               .short  LINUX_EFISTUB_MINOR_VERSION     @ MinorImageVersion
                .short  0                               @ MajorSubsystemVersion
                .short  0                               @ MinorSubsystemVersion
                .long   0                               @ Win32VersionValue
index 088b0a0..04f7721 100644 (file)
@@ -1437,29 +1437,25 @@ __enter_kernel:
 reloc_code_end:
 
 #ifdef CONFIG_EFI_STUB
-               .align  2
-_start:                .long   start - .
-
-ENTRY(efi_stub_entry)
-               @ allocate space on stack for passing current zImage address
-               @ and for the EFI stub to return of new entry point of
-               @ zImage, as EFI stub may copy the kernel. Pointer address
-               @ is passed in r2. r0 and r1 are passed through from the
-               @ EFI firmware to efi_entry
-               adr     ip, _start
-               ldr     r3, [ip]
-               add     r3, r3, ip
-               stmfd   sp!, {r3, lr}
-               mov     r2, sp                  @ pass zImage address in r2
-               bl      efi_entry
-
-               @ Check for error return from EFI stub. r0 has FDT address
-               @ or error code.
-               cmn     r0, #1
-               beq     efi_load_fail
-
-               @ Preserve return value of efi_entry() in r4
-               mov     r4, r0
+ENTRY(efi_enter_kernel)
+               mov     r7, r0                          @ preserve image base
+               mov     r4, r1                          @ preserve DT pointer
+
+               mov     r0, r4                          @ DT start
+               add     r1, r4, r2                      @ DT end
+               bl      cache_clean_flush
+
+               mov     r0, r7                          @ relocated zImage
+               ldr     r1, =_edata                     @ size of zImage
+               add     r1, r1, r0                      @ end of zImage
+               bl      cache_clean_flush
+
+               @ The PE/COFF loader might not have cleaned the code we are
+               @ running beyond the PoU, and so calling cache_off below from
+               @ inside the PE/COFF loader allocated region is unsafe unless
+               @ we explicitly clean it to the PoC.
+               adr     r0, call_cache_fn               @ region of code we will
+               adr     r1, 0f                          @ run with MMU off
                bl      cache_clean_flush
                bl      cache_off
 
@@ -1469,18 +1465,10 @@ ENTRY(efi_stub_entry)
                mov     r0, #0
                mov     r1, #0xFFFFFFFF
                mov     r2, r4
-
-               @ Branch to (possibly) relocated zImage that is in [sp]
-               ldr     lr, [sp]
-               ldr     ip, =start_offset
-               add     lr, lr, ip
-               mov     pc, lr                          @ no mode switch
-
-efi_load_fail:
-               @ Return EFI_LOAD_ERROR to EFI firmware on error.
-               ldr     r0, =0x80000001
-               ldmfd   sp!, {ip, pc}
-ENDPROC(efi_stub_entry)
+               add     r7, r7, #(__efi_start - start)
+               mov     pc, r7                          @ no mode switch
+ENDPROC(efi_enter_kernel)
+0:
 #endif
 
                .align
index 44531a6..45e8212 100644 (file)
@@ -57,13 +57,6 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
 
 /* arch specific definitions used by the stub code */
 
-/*
- * AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
- * start of kernel and may not cross a 2MiB boundary. We set alignment to
- * 2MiB so we know it won't cross a 2MiB boundary.
- */
-#define EFI_FDT_ALIGN  SZ_2M   /* used by allocate_new_fdt_and_exit_boot() */
-
 /*
  * In some configurations (e.g. VMAP_STACK && 64K pages), stacks built into the
  * kernel need greater alignment than we require the segments to be padded to.
@@ -107,9 +100,6 @@ static inline void free_screen_info(struct screen_info *si)
 {
 }
 
-/* redeclare as 'hidden' so the compiler will generate relative references */
-extern struct screen_info screen_info __attribute__((__visibility__("hidden")));
-
 static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
 {
 }
index 304d5b0..1a03618 100644 (file)
 
 #include <asm/assembler.h>
 
-#define EFI_LOAD_ERROR 0x8000000000000001
-
        __INIT
 
-       /*
-        * We arrive here from the EFI boot manager with:
-        *
-        *    * CPU in little-endian mode
-        *    * MMU on with identity-mapped RAM
-        *    * Icache and Dcache on
-        *
-        * We will most likely be running from some place other than where
-        * we want to be. The kernel image wants to be placed at TEXT_OFFSET
-        * from start of RAM.
-        */
-ENTRY(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]!
-       mov     x29, sp
-
-       /*
-        * Call efi_entry to do the real work.
-        * x0 and x1 are already set up by firmware. Current runtime
-        * address of image is calculated and passed via *image_addr.
-        *
-        * unsigned long efi_entry(void *handle,
-        *                         efi_system_table_t *sys_table,
-        *                         unsigned long *image_addr) ;
-        */
-       adr_l   x8, _text
-       add     x2, sp, 16
-       str     x8, [x2]
-       bl      efi_entry
-       cmn     x0, #1
-       b.eq    efi_load_fail
-
+SYM_CODE_START(efi_enter_kernel)
        /*
         * efi_entry() will have copied the kernel image if necessary and we
-        * return here with device tree address in x0 and the kernel entry
-        * point stored at *image_addr. Save those values in registers which
-        * are callee preserved.
-        */
-       mov     x20, x0         // DTB address
-       ldr     x0, [sp, #16]   // relocated _text address
-       ldr     w21, =stext_offset
-       add     x21, x0, x21
-
-       /*
-        * Calculate size of the kernel Image (same for original and copy).
+        * end up here with device tree address in x1 and the kernel entry
+        * point stored in x0. Save those values in registers which are
+        * callee preserved.
         */
-       adr_l   x1, _text
-       adr_l   x2, _edata
-       sub     x1, x2, x1
+       ldr     w2, =stext_offset
+       add     x19, x0, x2             // relocated Image entrypoint
+       mov     x20, x1                 // DTB address
 
        /*
-        * Flush the copied Image to the PoC, and ensure it is not shadowed by
+        * Clean the copied Image to the PoC, and ensure it is not shadowed by
         * stale icache entries from before relocation.
         */
-       bl      __flush_dcache_area
+       ldr     w1, =kernel_size
+       bl      __clean_dcache_area_poc
        ic      ialluis
 
        /*
-        * Ensure that the rest of this function (in the original Image) is
-        * visible when the caches are disabled. The I-cache can't have stale
-        * entries for the VA range of the current image, so no maintenance is
-        * necessary.
+        * Clean the remainder of this routine to the PoC
+        * so that we can safely disable the MMU and caches.
         */
-       adr     x0, entry
-       adr     x1, entry_end
-       sub     x1, x1, x0
-       bl      __flush_dcache_area
-
+       adr     x0, 0f
+       ldr     w1, 3f
+       bl      __clean_dcache_area_poc
+0:
        /* Turn off Dcache and MMU */
        mrs     x0, CurrentEL
        cmp     x0, #CurrentEL_EL2
@@ -109,12 +63,6 @@ ENTRY(entry)
        mov     x1, xzr
        mov     x2, xzr
        mov     x3, xzr
-       br      x21
-
-efi_load_fail:
-       mov     x0, #EFI_LOAD_ERROR
-       ldp     x29, x30, [sp], #32
-       ret
-
-entry_end:
-ENDPROC(entry)
+       br      x19
+SYM_CODE_END(efi_enter_kernel)
+3:     .long   . - 0b
index a7cfacc..914999c 100644 (file)
@@ -27,7 +27,7 @@ optional_header:
        .long   __initdata_begin - efi_header_end       // SizeOfCode
        .long   __pecoff_data_size                      // SizeOfInitializedData
        .long   0                                       // SizeOfUninitializedData
-       .long   __efistub_entry - _head                 // AddressOfEntryPoint
+       .long   __efistub_efi_entry - _head             // AddressOfEntryPoint
        .long   efi_header_end - _head                  // BaseOfCode
 
 extra_header_fields:
@@ -36,8 +36,8 @@ extra_header_fields:
        .long   PECOFF_FILE_ALIGNMENT                   // FileAlignment
        .short  0                                       // MajorOperatingSystemVersion
        .short  0                                       // MinorOperatingSystemVersion
-       .short  0                                       // MajorImageVersion
-       .short  0                                       // MinorImageVersion
+       .short  LINUX_EFISTUB_MAJOR_VERSION             // MajorImageVersion
+       .short  LINUX_EFISTUB_MINOR_VERSION             // MinorImageVersion
        .short  0                                       // MajorSubsystemVersion
        .short  0                                       // MinorSubsystemVersion
        .long   0                                       // Win32VersionValue
index 25a2a9b..7f06ad9 100644 (file)
@@ -12,7 +12,9 @@
 
 #ifdef CONFIG_EFI
 
-__efistub_stext_offset = stext - _text;
+__efistub_kernel_size          = _edata - _text;
+__efistub_stext_offset         = stext - _text;
+
 
 /*
  * The EFI stub has its own symbol namespace prefixed by __efistub_, to
@@ -33,7 +35,7 @@ __efistub_strnlen             = __pi_strnlen;
 __efistub_strcmp               = __pi_strcmp;
 __efistub_strncmp              = __pi_strncmp;
 __efistub_strrchr              = __pi_strrchr;
-__efistub___flush_dcache_area  = __pi___flush_dcache_area;
+__efistub___clean_dcache_area_poc = __pi___clean_dcache_area_poc;
 
 #ifdef CONFIG_KASAN
 __efistub___memcpy             = __pi_memcpy;
@@ -45,6 +47,7 @@ __efistub__text                       = _text;
 __efistub__end                 = _end;
 __efistub__edata               = _edata;
 __efistub_screen_info          = screen_info;
+__efistub__ctype               = _ctype;
 
 #endif
 
index 0a34dcc..f69f3fe 100644 (file)
 
 #define EFI_DEBUG      0
 
+#define ESI_TABLE_GUID                                 \
+    EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3,         \
+            0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
+
+static unsigned long mps_phys = EFI_INVALID_TABLE_ADDR;
 static __initdata unsigned long palo_phys;
 
+unsigned long __initdata esi_phys = EFI_INVALID_TABLE_ADDR;
+unsigned long hcdp_phys = EFI_INVALID_TABLE_ADDR;
 unsigned long sal_systab_phys = EFI_INVALID_TABLE_ADDR;
 
-static __initdata efi_config_table_type_t arch_tables[] = {
+static const efi_config_table_type_t arch_tables[] __initconst = {
+       {ESI_TABLE_GUID, "ESI", &esi_phys},
+       {HCDP_TABLE_GUID, "HCDP", &hcdp_phys},
+       {MPS_TABLE_GUID, "MPS", &mps_phys},
        {PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys},
        {SAL_SYSTEM_TABLE_GUID, "SALsystab", &sal_systab_phys},
        {NULL_GUID, NULL, 0},
@@ -474,11 +484,10 @@ efi_map_pal_code (void)
 void __init
 efi_init (void)
 {
+       const efi_system_table_t *efi_systab;
        void *efi_map_start, *efi_map_end;
-       efi_char16_t *c16;
        u64 efi_desc_size;
-       char *cp, vendor[100] = "unknown";
-       int i;
+       char *cp;
 
        set_bit(EFI_BOOT, &efi.flags);
        set_bit(EFI_64BIT, &efi.flags);
@@ -508,42 +517,29 @@ efi_init (void)
                printk(KERN_INFO "Ignoring memory above %lluMB\n",
                       max_addr >> 20);
 
-       efi.systab = __va(ia64_boot_param->efi_systab);
+       efi_systab = __va(ia64_boot_param->efi_systab);
 
        /*
         * Verify the EFI Table
         */
-       if (efi.systab == NULL)
+       if (efi_systab == NULL)
                panic("Whoa! Can't find EFI system table.\n");
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+       if (efi_systab_check_header(&efi_systab->hdr, 1))
                panic("Whoa! EFI system table signature incorrect\n");
-       if ((efi.systab->hdr.revision >> 16) == 0)
-               printk(KERN_WARNING "Warning: EFI system table version "
-                      "%d.%02d, expected 1.00 or greater\n",
-                      efi.systab->hdr.revision >> 16,
-                      efi.systab->hdr.revision & 0xffff);
-
-       /* Show what we know for posterity */
-       c16 = __va(efi.systab->fw_vendor);
-       if (c16) {
-               for (i = 0;i < (int) sizeof(vendor) - 1 && *c16; ++i)
-                       vendor[i] = *c16++;
-               vendor[i] = '\0';
-       }
 
-       printk(KERN_INFO "EFI v%u.%.02u by %s:",
-              efi.systab->hdr.revision >> 16,
-              efi.systab->hdr.revision & 0xffff, vendor);
+       efi_systab_report_header(&efi_systab->hdr, efi_systab->fw_vendor);
 
        palo_phys      = EFI_INVALID_TABLE_ADDR;
 
-       if (efi_config_init(arch_tables) != 0)
+       if (efi_config_parse_tables(__va(efi_systab->tables),
+                                   efi_systab->nr_tables,
+                                   arch_tables) != 0)
                return;
 
        if (palo_phys != EFI_INVALID_TABLE_ADDR)
                handle_palo(palo_phys);
 
-       runtime = __va(efi.systab->runtime);
+       runtime = __va(efi_systab->runtime);
        efi.get_time = phys_get_time;
        efi.set_time = phys_set_time;
        efi.get_wakeup_time = phys_get_wakeup_time;
@@ -1351,3 +1347,12 @@ vmcore_find_descriptor_size (unsigned long address)
        return ret;
 }
 #endif
+
+char *efi_systab_show_arch(char *str)
+{
+       if (mps_phys != EFI_INVALID_TABLE_ADDR)
+               str += sprintf(str, "MPS=0x%lx\n", mps_phys);
+       if (hcdp_phys != EFI_INVALID_TABLE_ADDR)
+               str += sprintf(str, "HCDP=0x%lx\n", hcdp_phys);
+       return str;
+}
index cb51412..4df57c9 100644 (file)
@@ -19,10 +19,6 @@ MODULE_LICENSE("GPL");
 
 #define MODULE_NAME    "esi"
 
-#define ESI_TABLE_GUID                                 \
-    EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3,         \
-            0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
-
 enum esi_systab_entry_type {
        ESI_DESC_ENTRY_POINT = 0
 };
@@ -48,27 +44,18 @@ struct pdesc {
 
 static struct ia64_sal_systab *esi_systab;
 
+extern unsigned long esi_phys;
+
 static int __init esi_init (void)
 {
-       efi_config_table_t *config_tables;
        struct ia64_sal_systab *systab;
-       unsigned long esi = 0;
        char *p;
        int i;
 
-       config_tables = __va(efi.systab->tables);
-
-       for (i = 0; i < (int) efi.systab->nr_tables; ++i) {
-               if (efi_guidcmp(config_tables[i].guid, ESI_TABLE_GUID) == 0) {
-                       esi = config_tables[i].table;
-                       break;
-               }
-       }
-
-       if (!esi)
+       if (esi_phys == EFI_INVALID_TABLE_ADDR)
                return -ENODEV;
 
-       systab = __va(esi);
+       systab = __va(esi_phys);
 
        if (strncmp(systab->signature, "ESIT", 4) != 0) {
                printk(KERN_ERR "bad signature in ESI system table!");
index 012b82f..ef9e1f2 100644 (file)
@@ -88,7 +88,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
 
 SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
 
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
 
 quiet_cmd_zoffset = ZOFFSET $@
       cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
index 26050ae..e51879b 100644 (file)
@@ -87,10 +87,7 @@ endif
 
 vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
 
-$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
-
-vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o \
-       $(objtree)/drivers/firmware/efi/libstub/lib.a
+vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
 vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
 
 # The compressed kernel is built with -fPIC/-fPIE so that a boot loader
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
deleted file mode 100644 (file)
index 287393d..0000000
+++ /dev/null
@@ -1,889 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-/* -----------------------------------------------------------------------
- *
- *   Copyright 2011 Intel Corporation; author Matt Fleming
- *
- * ----------------------------------------------------------------------- */
-
-#pragma GCC visibility push(hidden)
-
-#include <linux/efi.h>
-#include <linux/pci.h>
-
-#include <asm/efi.h>
-#include <asm/e820/types.h>
-#include <asm/setup.h>
-#include <asm/desc.h>
-#include <asm/boot.h>
-
-#include "../string.h"
-#include "eboot.h"
-
-static efi_system_table_t *sys_table;
-extern const bool efi_is64;
-
-__pure efi_system_table_t *efi_system_table(void)
-{
-       return sys_table;
-}
-
-__attribute_const__ bool efi_is_64bit(void)
-{
-       if (IS_ENABLED(CONFIG_EFI_MIXED))
-               return efi_is64;
-       return IS_ENABLED(CONFIG_X86_64);
-}
-
-static efi_status_t
-preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
-{
-       struct pci_setup_rom *rom = NULL;
-       efi_status_t status;
-       unsigned long size;
-       uint64_t romsize;
-       void *romimage;
-
-       /*
-        * Some firmware images contain EFI function pointers at the place where
-        * the romimage and romsize fields are supposed to be. Typically the EFI
-        * code is mapped at high addresses, translating to an unrealistically
-        * large romsize. The UEFI spec limits the size of option ROMs to 16
-        * MiB so we reject any ROMs over 16 MiB in size to catch this.
-        */
-       romimage = efi_table_attr(pci, romimage);
-       romsize = efi_table_attr(pci, romsize);
-       if (!romimage || !romsize || romsize > SZ_16M)
-               return EFI_INVALID_PARAMETER;
-
-       size = romsize + sizeof(*rom);
-
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
-                            (void **)&rom);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate memory for 'rom'\n");
-               return status;
-       }
-
-       memset(rom, 0, sizeof(*rom));
-
-       rom->data.type  = SETUP_PCI;
-       rom->data.len   = size - sizeof(struct setup_data);
-       rom->data.next  = 0;
-       rom->pcilen     = pci->romsize;
-       *__rom = rom;
-
-       status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
-                               PCI_VENDOR_ID, 1, &rom->vendor);
-
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to read rom->vendor\n");
-               goto free_struct;
-       }
-
-       status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
-                               PCI_DEVICE_ID, 1, &rom->devid);
-
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to read rom->devid\n");
-               goto free_struct;
-       }
-
-       status = efi_call_proto(pci, get_location, &rom->segment, &rom->bus,
-                               &rom->device, &rom->function);
-
-       if (status != EFI_SUCCESS)
-               goto free_struct;
-
-       memcpy(rom->romdata, romimage, romsize);
-       return status;
-
-free_struct:
-       efi_bs_call(free_pool, rom);
-       return status;
-}
-
-/*
- * There's no way to return an informative status from this function,
- * because any analysis (and printing of error messages) needs to be
- * done directly at the EFI function call-site.
- *
- * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we
- * just didn't find any PCI devices, but there's no way to tell outside
- * the context of the call.
- */
-static void setup_efi_pci(struct boot_params *params)
-{
-       efi_status_t status;
-       void **pci_handle = NULL;
-       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
-       unsigned long size = 0;
-       struct setup_data *data;
-       efi_handle_t h;
-       int i;
-
-       status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
-                            &pci_proto, NULL, &size, pci_handle);
-
-       if (status == EFI_BUFFER_TOO_SMALL) {
-               status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
-                                    (void **)&pci_handle);
-
-               if (status != EFI_SUCCESS) {
-                       efi_printk("Failed to allocate memory for 'pci_handle'\n");
-                       return;
-               }
-
-               status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
-                                    &pci_proto, NULL, &size, pci_handle);
-       }
-
-       if (status != EFI_SUCCESS)
-               goto free_handle;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       for_each_efi_handle(h, pci_handle, size, i) {
-               efi_pci_io_protocol_t *pci = NULL;
-               struct pci_setup_rom *rom;
-
-               status = efi_bs_call(handle_protocol, h, &pci_proto,
-                                    (void **)&pci);
-               if (status != EFI_SUCCESS || !pci)
-                       continue;
-
-               status = preserve_pci_rom_image(pci, &rom);
-               if (status != EFI_SUCCESS)
-                       continue;
-
-               if (data)
-                       data->next = (unsigned long)rom;
-               else
-                       params->hdr.setup_data = (unsigned long)rom;
-
-               data = (struct setup_data *)rom;
-       }
-
-free_handle:
-       efi_bs_call(free_pool, pci_handle);
-}
-
-static void retrieve_apple_device_properties(struct boot_params *boot_params)
-{
-       efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
-       struct setup_data *data, *new;
-       efi_status_t status;
-       u32 size = 0;
-       apple_properties_protocol_t *p;
-
-       status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&p);
-       if (status != EFI_SUCCESS)
-               return;
-
-       if (efi_table_attr(p, version) != 0x10000) {
-               efi_printk("Unsupported properties proto version\n");
-               return;
-       }
-
-       efi_call_proto(p, get_all, NULL, &size);
-       if (!size)
-               return;
-
-       do {
-               status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
-                                    size + sizeof(struct setup_data),
-                                    (void **)&new);
-               if (status != EFI_SUCCESS) {
-                       efi_printk("Failed to allocate memory for 'properties'\n");
-                       return;
-               }
-
-               status = efi_call_proto(p, get_all, new->data, &size);
-
-               if (status == EFI_BUFFER_TOO_SMALL)
-                       efi_bs_call(free_pool, new);
-       } while (status == EFI_BUFFER_TOO_SMALL);
-
-       new->type = SETUP_APPLE_PROPERTIES;
-       new->len  = size;
-       new->next = 0;
-
-       data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
-       if (!data) {
-               boot_params->hdr.setup_data = (unsigned long)new;
-       } else {
-               while (data->next)
-                       data = (struct setup_data *)(unsigned long)data->next;
-               data->next = (unsigned long)new;
-       }
-}
-
-static const efi_char16_t apple[] = L"Apple";
-
-static void setup_quirks(struct boot_params *boot_params)
-{
-       efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
-               efi_table_attr(efi_system_table(), fw_vendor);
-
-       if (!memcmp(fw_vendor, apple, sizeof(apple))) {
-               if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
-                       retrieve_apple_device_properties(boot_params);
-       }
-}
-
-/*
- * See if we have Universal Graphics Adapter (UGA) protocol
- */
-static efi_status_t
-setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size)
-{
-       efi_status_t status;
-       u32 width, height;
-       void **uga_handle = NULL;
-       efi_uga_draw_protocol_t *uga = NULL, *first_uga;
-       efi_handle_t handle;
-       int i;
-
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
-                            (void **)&uga_handle);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
-                            uga_proto, NULL, &size, uga_handle);
-       if (status != EFI_SUCCESS)
-               goto free_handle;
-
-       height = 0;
-       width = 0;
-
-       first_uga = NULL;
-       for_each_efi_handle(handle, uga_handle, size, i) {
-               efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
-               u32 w, h, depth, refresh;
-               void *pciio;
-
-               status = efi_bs_call(handle_protocol, handle, uga_proto,
-                                    (void **)&uga);
-               if (status != EFI_SUCCESS)
-                       continue;
-
-               pciio = NULL;
-               efi_bs_call(handle_protocol, handle, &pciio_proto, &pciio);
-
-               status = efi_call_proto(uga, get_mode, &w, &h, &depth, &refresh);
-               if (status == EFI_SUCCESS && (!first_uga || pciio)) {
-                       width = w;
-                       height = h;
-
-                       /*
-                        * Once we've found a UGA supporting PCIIO,
-                        * don't bother looking any further.
-                        */
-                       if (pciio)
-                               break;
-
-                       first_uga = uga;
-               }
-       }
-
-       if (!width && !height)
-               goto free_handle;
-
-       /* EFI framebuffer */
-       si->orig_video_isVGA    = VIDEO_TYPE_EFI;
-
-       si->lfb_depth           = 32;
-       si->lfb_width           = width;
-       si->lfb_height          = height;
-
-       si->red_size            = 8;
-       si->red_pos             = 16;
-       si->green_size          = 8;
-       si->green_pos           = 8;
-       si->blue_size           = 8;
-       si->blue_pos            = 0;
-       si->rsvd_size           = 8;
-       si->rsvd_pos            = 24;
-
-free_handle:
-       efi_bs_call(free_pool, uga_handle);
-
-       return status;
-}
-
-void setup_graphics(struct boot_params *boot_params)
-{
-       efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
-       struct screen_info *si;
-       efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
-       efi_status_t status;
-       unsigned long size;
-       void **gop_handle = NULL;
-       void **uga_handle = NULL;
-
-       si = &boot_params->screen_info;
-       memset(si, 0, sizeof(*si));
-
-       size = 0;
-       status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
-                            &graphics_proto, NULL, &size, gop_handle);
-       if (status == EFI_BUFFER_TOO_SMALL)
-               status = efi_setup_gop(si, &graphics_proto, size);
-
-       if (status != EFI_SUCCESS) {
-               size = 0;
-               status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
-                                    &uga_proto, NULL, &size, uga_handle);
-               if (status == EFI_BUFFER_TOO_SMALL)
-                       setup_uga(si, &uga_proto, size);
-       }
-}
-
-void startup_32(struct boot_params *boot_params);
-
-void __noreturn efi_stub_entry(efi_handle_t handle,
-                              efi_system_table_t *sys_table_arg,
-                              struct boot_params *boot_params);
-
-/*
- * Because the x86 boot code expects to be passed a boot_params we
- * need to create one ourselves (usually the bootloader would create
- * one for us).
- */
-efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
-                                  efi_system_table_t *sys_table_arg)
-{
-       struct boot_params *boot_params;
-       struct apm_bios_info *bi;
-       struct setup_header *hdr;
-       efi_loaded_image_t *image;
-       efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
-       int options_size = 0;
-       efi_status_t status;
-       char *cmdline_ptr;
-       unsigned long ramdisk_addr;
-       unsigned long ramdisk_size;
-
-       sys_table = sys_table_arg;
-
-       /* Check if we were booted by the EFI firmware */
-       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-               return EFI_INVALID_PARAMETER;
-
-       status = efi_bs_call(handle_protocol, handle, &proto, (void *)&image);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
-               return status;
-       }
-
-       status = efi_low_alloc(0x4000, 1, (unsigned long *)&boot_params);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate lowmem for boot params\n");
-               return status;
-       }
-
-       memset(boot_params, 0x0, 0x4000);
-
-       hdr = &boot_params->hdr;
-       bi = &boot_params->apm_bios_info;
-
-       /* Copy the second sector to boot_params */
-       memcpy(&hdr->jump, image->image_base + 512, 512);
-
-       /*
-        * Fill out some of the header fields ourselves because the
-        * EFI firmware loader doesn't load the first sector.
-        */
-       hdr->root_flags = 1;
-       hdr->vid_mode   = 0xffff;
-       hdr->boot_flag  = 0xAA55;
-
-       hdr->type_of_loader = 0x21;
-
-       /* Convert unicode cmdline to ascii */
-       cmdline_ptr = efi_convert_cmdline(image, &options_size);
-       if (!cmdline_ptr)
-               goto fail;
-
-       hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
-       /* Fill in upper bits of command line address, NOP on 32 bit  */
-       boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
-
-       hdr->ramdisk_image = 0;
-       hdr->ramdisk_size = 0;
-
-       /* Clear APM BIOS info */
-       memset(bi, 0, sizeof(*bi));
-
-       status = efi_parse_options(cmdline_ptr);
-       if (status != EFI_SUCCESS)
-               goto fail2;
-
-       status = handle_cmdline_files(image,
-                                     (char *)(unsigned long)hdr->cmd_line_ptr,
-                                     "initrd=", hdr->initrd_addr_max,
-                                     &ramdisk_addr, &ramdisk_size);
-
-       if (status != EFI_SUCCESS &&
-           hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
-               efi_printk("Trying to load files to higher address\n");
-               status = handle_cmdline_files(image,
-                                     (char *)(unsigned long)hdr->cmd_line_ptr,
-                                     "initrd=", -1UL,
-                                     &ramdisk_addr, &ramdisk_size);
-       }
-
-       if (status != EFI_SUCCESS)
-               goto fail2;
-       hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
-       hdr->ramdisk_size  = ramdisk_size & 0xffffffff;
-       boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
-       boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
-
-       hdr->code32_start = (u32)(unsigned long)startup_32;
-
-       efi_stub_entry(handle, sys_table, boot_params);
-       /* not reached */
-
-fail2:
-       efi_free(options_size, hdr->cmd_line_ptr);
-fail:
-       efi_free(0x4000, (unsigned long)boot_params);
-
-       return status;
-}
-
-static void add_e820ext(struct boot_params *params,
-                       struct setup_data *e820ext, u32 nr_entries)
-{
-       struct setup_data *data;
-
-       e820ext->type = SETUP_E820_EXT;
-       e820ext->len  = nr_entries * sizeof(struct boot_e820_entry);
-       e820ext->next = 0;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       if (data)
-               data->next = (unsigned long)e820ext;
-       else
-               params->hdr.setup_data = (unsigned long)e820ext;
-}
-
-static efi_status_t
-setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_size)
-{
-       struct boot_e820_entry *entry = params->e820_table;
-       struct efi_info *efi = &params->efi_info;
-       struct boot_e820_entry *prev = NULL;
-       u32 nr_entries;
-       u32 nr_desc;
-       int i;
-
-       nr_entries = 0;
-       nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
-
-       for (i = 0; i < nr_desc; i++) {
-               efi_memory_desc_t *d;
-               unsigned int e820_type = 0;
-               unsigned long m = efi->efi_memmap;
-
-#ifdef CONFIG_X86_64
-               m |= (u64)efi->efi_memmap_hi << 32;
-#endif
-
-               d = efi_early_memdesc_ptr(m, efi->efi_memdesc_size, i);
-               switch (d->type) {
-               case EFI_RESERVED_TYPE:
-               case EFI_RUNTIME_SERVICES_CODE:
-               case EFI_RUNTIME_SERVICES_DATA:
-               case EFI_MEMORY_MAPPED_IO:
-               case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
-               case EFI_PAL_CODE:
-                       e820_type = E820_TYPE_RESERVED;
-                       break;
-
-               case EFI_UNUSABLE_MEMORY:
-                       e820_type = E820_TYPE_UNUSABLE;
-                       break;
-
-               case EFI_ACPI_RECLAIM_MEMORY:
-                       e820_type = E820_TYPE_ACPI;
-                       break;
-
-               case EFI_LOADER_CODE:
-               case EFI_LOADER_DATA:
-               case EFI_BOOT_SERVICES_CODE:
-               case EFI_BOOT_SERVICES_DATA:
-               case EFI_CONVENTIONAL_MEMORY:
-                       if (efi_soft_reserve_enabled() &&
-                           (d->attribute & EFI_MEMORY_SP))
-                               e820_type = E820_TYPE_SOFT_RESERVED;
-                       else
-                               e820_type = E820_TYPE_RAM;
-                       break;
-
-               case EFI_ACPI_MEMORY_NVS:
-                       e820_type = E820_TYPE_NVS;
-                       break;
-
-               case EFI_PERSISTENT_MEMORY:
-                       e820_type = E820_TYPE_PMEM;
-                       break;
-
-               default:
-                       continue;
-               }
-
-               /* Merge adjacent mappings */
-               if (prev && prev->type == e820_type &&
-                   (prev->addr + prev->size) == d->phys_addr) {
-                       prev->size += d->num_pages << 12;
-                       continue;
-               }
-
-               if (nr_entries == ARRAY_SIZE(params->e820_table)) {
-                       u32 need = (nr_desc - i) * sizeof(struct e820_entry) +
-                                  sizeof(struct setup_data);
-
-                       if (!e820ext || e820ext_size < need)
-                               return EFI_BUFFER_TOO_SMALL;
-
-                       /* boot_params map full, switch to e820 extended */
-                       entry = (struct boot_e820_entry *)e820ext->data;
-               }
-
-               entry->addr = d->phys_addr;
-               entry->size = d->num_pages << PAGE_SHIFT;
-               entry->type = e820_type;
-               prev = entry++;
-               nr_entries++;
-       }
-
-       if (nr_entries > ARRAY_SIZE(params->e820_table)) {
-               u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_table);
-
-               add_e820ext(params, e820ext, nr_e820ext);
-               nr_entries -= nr_e820ext;
-       }
-
-       params->e820_entries = (u8)nr_entries;
-
-       return EFI_SUCCESS;
-}
-
-static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
-                                 u32 *e820ext_size)
-{
-       efi_status_t status;
-       unsigned long size;
-
-       size = sizeof(struct setup_data) +
-               sizeof(struct e820_entry) * nr_desc;
-
-       if (*e820ext) {
-               efi_bs_call(free_pool, *e820ext);
-               *e820ext = NULL;
-               *e820ext_size = 0;
-       }
-
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
-                            (void **)e820ext);
-       if (status == EFI_SUCCESS)
-               *e820ext_size = size;
-
-       return status;
-}
-
-static efi_status_t allocate_e820(struct boot_params *params,
-                                 struct setup_data **e820ext,
-                                 u32 *e820ext_size)
-{
-       unsigned long map_size, desc_size, buff_size;
-       struct efi_boot_memmap boot_map;
-       efi_memory_desc_t *map;
-       efi_status_t status;
-       __u32 nr_desc;
-
-       boot_map.map            = &map;
-       boot_map.map_size       = &map_size;
-       boot_map.desc_size      = &desc_size;
-       boot_map.desc_ver       = NULL;
-       boot_map.key_ptr        = NULL;
-       boot_map.buff_size      = &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       nr_desc = buff_size / desc_size;
-
-       if (nr_desc > ARRAY_SIZE(params->e820_table)) {
-               u32 nr_e820ext = nr_desc - ARRAY_SIZE(params->e820_table);
-
-               status = alloc_e820ext(nr_e820ext, e820ext, e820ext_size);
-               if (status != EFI_SUCCESS)
-                       return status;
-       }
-
-       return EFI_SUCCESS;
-}
-
-struct exit_boot_struct {
-       struct boot_params      *boot_params;
-       struct efi_info         *efi;
-};
-
-static efi_status_t exit_boot_func(struct efi_boot_memmap *map,
-                                  void *priv)
-{
-       const char *signature;
-       struct exit_boot_struct *p = priv;
-
-       signature = efi_is_64bit() ? EFI64_LOADER_SIGNATURE
-                                  : EFI32_LOADER_SIGNATURE;
-       memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
-
-       p->efi->efi_systab              = (unsigned long)efi_system_table();
-       p->efi->efi_memdesc_size        = *map->desc_size;
-       p->efi->efi_memdesc_version     = *map->desc_ver;
-       p->efi->efi_memmap              = (unsigned long)*map->map;
-       p->efi->efi_memmap_size         = *map->map_size;
-
-#ifdef CONFIG_X86_64
-       p->efi->efi_systab_hi           = (unsigned long)efi_system_table() >> 32;
-       p->efi->efi_memmap_hi           = (unsigned long)*map->map >> 32;
-#endif
-
-       return EFI_SUCCESS;
-}
-
-static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
-{
-       unsigned long map_sz, key, desc_size, buff_size;
-       efi_memory_desc_t *mem_map;
-       struct setup_data *e820ext = NULL;
-       __u32 e820ext_size = 0;
-       efi_status_t status;
-       __u32 desc_version;
-       struct efi_boot_memmap map;
-       struct exit_boot_struct priv;
-
-       map.map                 = &mem_map;
-       map.map_size            = &map_sz;
-       map.desc_size           = &desc_size;
-       map.desc_ver            = &desc_version;
-       map.key_ptr             = &key;
-       map.buff_size           = &buff_size;
-       priv.boot_params        = boot_params;
-       priv.efi                = &boot_params->efi_info;
-
-       status = allocate_e820(boot_params, &e820ext, &e820ext_size);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       /* Might as well exit boot services now */
-       status = efi_exit_boot_services(handle, &map, &priv, exit_boot_func);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       /* Historic? */
-       boot_params->alt_mem_k  = 32 * 1024;
-
-       status = setup_e820(boot_params, e820ext, e820ext_size);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       return EFI_SUCCESS;
-}
-
-/*
- * On success we return a pointer to a boot_params structure, and NULL
- * on failure.
- */
-struct boot_params *efi_main(efi_handle_t handle,
-                            efi_system_table_t *sys_table_arg,
-                            struct boot_params *boot_params)
-{
-       struct desc_ptr *gdt = NULL;
-       struct setup_header *hdr = &boot_params->hdr;
-       efi_status_t status;
-       struct desc_struct *desc;
-       unsigned long cmdline_paddr;
-
-       sys_table = sys_table_arg;
-
-       /* Check if we were booted by the EFI firmware */
-       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-               goto fail;
-
-       /*
-        * make_boot_params() may have been called before efi_main(), in which
-        * case this is the second time we parse the cmdline. This is ok,
-        * parsing the cmdline multiple times does not have side-effects.
-        */
-       cmdline_paddr = ((u64)hdr->cmd_line_ptr |
-                        ((u64)boot_params->ext_cmd_line_ptr << 32));
-       efi_parse_options((char *)cmdline_paddr);
-
-       /*
-        * If the boot loader gave us a value for secure_boot then we use that,
-        * otherwise we ask the BIOS.
-        */
-       if (boot_params->secure_boot == efi_secureboot_mode_unset)
-               boot_params->secure_boot = efi_get_secureboot();
-
-       /* Ask the firmware to clear memory on unclean shutdown */
-       efi_enable_reset_attack_mitigation();
-
-       efi_random_get_seed();
-
-       efi_retrieve_tpm2_eventlog();
-
-       setup_graphics(boot_params);
-
-       setup_efi_pci(boot_params);
-
-       setup_quirks(boot_params);
-
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*gdt),
-                            (void **)&gdt);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate memory for 'gdt' structure\n");
-               goto fail;
-       }
-
-       gdt->size = 0x800;
-       status = efi_low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate memory for 'gdt'\n");
-               goto fail;
-       }
-
-       /*
-        * If the kernel isn't already loaded at the preferred load
-        * address, relocate it.
-        */
-       if (hdr->pref_address != hdr->code32_start) {
-               unsigned long bzimage_addr = hdr->code32_start;
-               status = efi_relocate_kernel(&bzimage_addr,
-                                            hdr->init_size, hdr->init_size,
-                                            hdr->pref_address,
-                                            hdr->kernel_alignment,
-                                            LOAD_PHYSICAL_ADDR);
-               if (status != EFI_SUCCESS) {
-                       efi_printk("efi_relocate_kernel() failed!\n");
-                       goto fail;
-               }
-
-               hdr->pref_address = hdr->code32_start;
-               hdr->code32_start = bzimage_addr;
-       }
-
-       status = exit_boot(boot_params, handle);
-       if (status != EFI_SUCCESS) {
-               efi_printk("exit_boot() failed!\n");
-               goto fail;
-       }
-
-       memset((char *)gdt->address, 0x0, gdt->size);
-       desc = (struct desc_struct *)gdt->address;
-
-       /* The first GDT is a dummy. */
-       desc++;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               /* __KERNEL32_CS */
-               desc->limit0    = 0xffff;
-               desc->base0     = 0x0000;
-               desc->base1     = 0x0000;
-               desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-               desc->s         = DESC_TYPE_CODE_DATA;
-               desc->dpl       = 0;
-               desc->p         = 1;
-               desc->limit1    = 0xf;
-               desc->avl       = 0;
-               desc->l         = 0;
-               desc->d         = SEG_OP_SIZE_32BIT;
-               desc->g         = SEG_GRANULARITY_4KB;
-               desc->base2     = 0x00;
-
-               desc++;
-       } else {
-               /* Second entry is unused on 32-bit */
-               desc++;
-       }
-
-       /* __KERNEL_CS */
-       desc->limit0    = 0xffff;
-       desc->base0     = 0x0000;
-       desc->base1     = 0x0000;
-       desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-       desc->s         = DESC_TYPE_CODE_DATA;
-       desc->dpl       = 0;
-       desc->p         = 1;
-       desc->limit1    = 0xf;
-       desc->avl       = 0;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               desc->l = 1;
-               desc->d = 0;
-       } else {
-               desc->l = 0;
-               desc->d = SEG_OP_SIZE_32BIT;
-       }
-       desc->g         = SEG_GRANULARITY_4KB;
-       desc->base2     = 0x00;
-       desc++;
-
-       /* __KERNEL_DS */
-       desc->limit0    = 0xffff;
-       desc->base0     = 0x0000;
-       desc->base1     = 0x0000;
-       desc->type      = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
-       desc->s         = DESC_TYPE_CODE_DATA;
-       desc->dpl       = 0;
-       desc->p         = 1;
-       desc->limit1    = 0xf;
-       desc->avl       = 0;
-       desc->l         = 0;
-       desc->d         = SEG_OP_SIZE_32BIT;
-       desc->g         = SEG_GRANULARITY_4KB;
-       desc->base2     = 0x00;
-       desc++;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               /* Task segment value */
-               desc->limit0    = 0x0000;
-               desc->base0     = 0x0000;
-               desc->base1     = 0x0000;
-               desc->type      = SEG_TYPE_TSS;
-               desc->s         = 0;
-               desc->dpl       = 0;
-               desc->p         = 1;
-               desc->limit1    = 0x0;
-               desc->avl       = 0;
-               desc->l         = 0;
-               desc->d         = 0;
-               desc->g         = SEG_GRANULARITY_4KB;
-               desc->base2     = 0x00;
-               desc++;
-       }
-
-       asm volatile("cli");
-       asm volatile ("lgdt %0" : : "m" (*gdt));
-
-       return boot_params;
-fail:
-       efi_printk("efi_main() failed!\n");
-
-       for (;;)
-               asm("hlt");
-}
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
deleted file mode 100644 (file)
index 99f3534..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef BOOT_COMPRESSED_EBOOT_H
-#define BOOT_COMPRESSED_EBOOT_H
-
-#define SEG_TYPE_DATA          (0 << 3)
-#define SEG_TYPE_READ_WRITE    (1 << 1)
-#define SEG_TYPE_CODE          (1 << 3)
-#define SEG_TYPE_EXEC_READ     (1 << 1)
-#define SEG_TYPE_TSS           ((1 << 3) | (1 << 0))
-#define SEG_OP_SIZE_32BIT      (1 << 0)
-#define SEG_GRANULARITY_4KB    (1 << 0)
-
-#define DESC_TYPE_CODE_DATA    (1 << 0)
-
-typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t;
-
-union efi_uga_draw_protocol {
-       struct {
-               efi_status_t (__efiapi *get_mode)(efi_uga_draw_protocol_t *,
-                                                 u32*, u32*, u32*, u32*);
-               void *set_mode;
-               void *blt;
-       };
-       struct {
-               u32 get_mode;
-               u32 set_mode;
-               u32 blt;
-       } mixed_mode;
-};
-
-#endif /* BOOT_COMPRESSED_EBOOT_H */
index 8fb7f67..2b20492 100644 (file)
@@ -54,11 +54,16 @@ SYM_FUNC_START(__efi64_thunk)
         * Switch to gdt with 32-bit segments. This is the firmware GDT
         * that was installed when the kernel started executing. This
         * pointer was saved at the EFI stub entry point in head_64.S.
+        *
+        * Pass the saved DS selector to the 32-bit code, and use far return to
+        * restore the saved CS selector.
         */
        leaq    efi32_boot_gdt(%rip), %rax
        lgdt    (%rax)
 
-       pushq   $__KERNEL_CS
+       movzwl  efi32_boot_ds(%rip), %edx
+       movzwq  efi32_boot_cs(%rip), %rax
+       pushq   %rax
        leaq    efi_enter32(%rip), %rax
        pushq   %rax
        lretq
@@ -73,6 +78,10 @@ SYM_FUNC_START(__efi64_thunk)
        movl    %ebx, %es
        pop     %rbx
        movl    %ebx, %ds
+       /* Clear out 32-bit selector from FS and GS */
+       xorl    %ebx, %ebx
+       movl    %ebx, %fs
+       movl    %ebx, %gs
 
        /*
         * Convert 32-bit status code into 64-bit.
@@ -92,10 +101,12 @@ SYM_FUNC_END(__efi64_thunk)
  * The stack should represent the 32-bit calling convention.
  */
 SYM_FUNC_START_LOCAL(efi_enter32)
-       movl    $__KERNEL_DS, %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    %eax, %ss
+       /* Load firmware selector into data and stack segment registers */
+       movl    %edx, %ds
+       movl    %edx, %es
+       movl    %edx, %fs
+       movl    %edx, %gs
+       movl    %edx, %ss
 
        /* Reload pgtables */
        movl    %cr3, %eax
@@ -157,6 +168,14 @@ SYM_DATA_START(efi32_boot_gdt)
        .quad   0
 SYM_DATA_END(efi32_boot_gdt)
 
+SYM_DATA_START(efi32_boot_cs)
+       .word   0
+SYM_DATA_END(efi32_boot_cs)
+
+SYM_DATA_START(efi32_boot_ds)
+       .word   0
+SYM_DATA_END(efi32_boot_ds)
+
 SYM_DATA_START(efi_gdt64)
        .word   efi_gdt64_end - efi_gdt64
        .long   0                       /* Filled out by user */
index 73f17d0..2f8138b 100644 (file)
        __HEAD
 SYM_FUNC_START(startup_32)
        cld
-       /*
-        * Test KEEP_SEGMENTS flag to see if the bootloader is asking
-        * us to not reload segments
-        */
-       testb   $KEEP_SEGMENTS, BP_loadflags(%esi)
-       jnz     1f
-
        cli
-       movl    $__BOOT_DS, %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    %eax, %fs
-       movl    %eax, %gs
-       movl    %eax, %ss
-1:
 
 /*
  * Calculate the delta between where we were compiled to run
@@ -92,6 +78,19 @@ SYM_FUNC_START(startup_32)
 1:     popl    %ebp
        subl    $1b, %ebp
 
+       /* Load new GDT */
+       leal    gdt(%ebp), %eax
+       movl    %eax, 2(%eax)
+       lgdt    (%eax)
+
+       /* Load segment registers with our descriptors */
+       movl    $__BOOT_DS, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %fs
+       movl    %eax, %gs
+       movl    %eax, %ss
+
 /*
  * %ebp contains the address we are loaded at by the boot loader and %ebx
  * contains the address where we should move the kernel image temporarily
@@ -137,6 +136,15 @@ SYM_FUNC_START(startup_32)
        cld
        popl    %esi
 
+       /*
+        * The GDT may get overwritten either during the copy we just did or
+        * during extract_kernel below. To avoid any issues, repoint the GDTR
+        * to the new copy of the GDT.
+        */
+       leal    gdt(%ebx), %eax
+       movl    %eax, 2(%eax)
+       lgdt    (%eax)
+
 /*
  * Jump to the relocated address.
  */
@@ -209,6 +217,17 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
        jmp     *%eax
 SYM_FUNC_END(.Lrelocated)
 
+       .data
+       .balign 8
+SYM_DATA_START_LOCAL(gdt)
+       .word   gdt_end - gdt - 1
+       .long   0
+       .word   0
+       .quad   0x0000000000000000      /* Reserved */
+       .quad   0x00cf9a000000ffff      /* __KERNEL_CS */
+       .quad   0x00cf92000000ffff      /* __KERNEL_DS */
+SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
+
 /*
  * Stack and heap for uncompression
  */
index 1f1f6c8..fcf8fea 100644 (file)
@@ -53,19 +53,7 @@ SYM_FUNC_START(startup_32)
         * all need to be under the 4G limit.
         */
        cld
-       /*
-        * Test KEEP_SEGMENTS flag to see if the bootloader is asking
-        * us to not reload segments
-        */
-       testb $KEEP_SEGMENTS, BP_loadflags(%esi)
-       jnz 1f
-
        cli
-       movl    $(__BOOT_DS), %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    %eax, %ss
-1:
 
 /*
  * Calculate the delta between where we were compiled to run
@@ -80,10 +68,21 @@ SYM_FUNC_START(startup_32)
 1:     popl    %ebp
        subl    $1b, %ebp
 
+       /* Load new GDT with the 64bit segments using 32bit descriptor */
+       leal    gdt(%ebp), %eax
+       movl    %eax, 2(%eax)
+       lgdt    (%eax)
+
+       /* Load segment registers with our descriptors */
+       movl    $__BOOT_DS, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %fs
+       movl    %eax, %gs
+       movl    %eax, %ss
+
 /* setup a stack and make sure cpu supports long mode. */
-       movl    $boot_stack_end, %eax
-       addl    %ebp, %eax
-       movl    %eax, %esp
+       leal    boot_stack_end(%ebp), %esp
 
        call    verify_cpu
        testl   %eax, %eax
@@ -120,10 +119,6 @@ SYM_FUNC_START(startup_32)
  * Prepare for entering 64 bit mode
  */
 
-       /* Load new GDT with the 64bit segments using 32bit descriptor */
-       addl    %ebp, gdt+2(%ebp)
-       lgdt    gdt(%ebp)
-
        /* Enable PAE mode */
        movl    %cr4, %eax
        orl     $X86_CR4_PAE, %eax
@@ -212,8 +207,13 @@ SYM_FUNC_START(startup_32)
        cmp     $0, %edi
        jz      1f
        leal    efi64_stub_entry(%ebp), %eax
-       movl    %esi, %edx
        movl    efi32_boot_args+4(%ebp), %esi
+       movl    efi32_boot_args+8(%ebp), %edx   // saved bootparams pointer
+       cmpl    $0, %edx
+       jnz     1f
+       leal    efi_pe_entry(%ebp), %eax
+       movl    %edi, %ecx                      // MS calling convention
+       movl    %esi, %edx
 1:
 #endif
        pushl   %eax
@@ -238,11 +238,17 @@ SYM_FUNC_START(efi32_stub_entry)
 1:     pop     %ebp
        subl    $1b, %ebp
 
+       movl    %esi, efi32_boot_args+8(%ebp)
+SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
        movl    %ecx, efi32_boot_args(%ebp)
        movl    %edx, efi32_boot_args+4(%ebp)
-       sgdtl   efi32_boot_gdt(%ebp)
        movb    $0, efi_is64(%ebp)
 
+       /* Save firmware GDTR and code/data selectors */
+       sgdtl   efi32_boot_gdt(%ebp)
+       movw    %cs, efi32_boot_cs(%ebp)
+       movw    %ds, efi32_boot_ds(%ebp)
+
        /* Disable paging */
        movl    %cr0, %eax
        btrl    $X86_CR0_PG_BIT, %eax
@@ -266,6 +272,9 @@ SYM_CODE_START(startup_64)
         * and command line.
         */
 
+       cld
+       cli
+
        /* Setup data segments. */
        xorl    %eax, %eax
        movl    %eax, %ds
@@ -354,9 +363,9 @@ SYM_CODE_START(startup_64)
         */
 
        /* Make sure we have GDT with 32-bit code segment */
-       leaq    gdt(%rip), %rax
-       movq    %rax, gdt64+2(%rip)
-       lgdt    gdt64(%rip)
+       leaq    gdt64(%rip), %rax
+       addq    %rax, 2(%rax)
+       lgdt    (%rax)
 
        /*
         * paging_prepare() sets up the trampoline and checks if we need to
@@ -441,6 +450,16 @@ trampoline_return:
        cld
        popq    %rsi
 
+       /*
+        * The GDT may get overwritten either during the copy we just did or
+        * during extract_kernel below. To avoid any issues, repoint the GDTR
+        * to the new copy of the GDT.
+        */
+       leaq    gdt64(%rbx), %rax
+       leaq    gdt(%rbx), %rdx
+       movq    %rdx, 2(%rax)
+       lgdt    (%rax)
+
 /*
  * Jump to the relocated address.
  */
@@ -613,13 +632,13 @@ SYM_FUNC_END(.Lno_longmode)
 
        .data
 SYM_DATA_START_LOCAL(gdt64)
-       .word   gdt_end - gdt
-       .quad   0
+       .word   gdt_end - gdt - 1
+       .quad   gdt - gdt64
 SYM_DATA_END(gdt64)
        .balign 8
 SYM_DATA_START_LOCAL(gdt)
-       .word   gdt_end - gdt
-       .long   gdt
+       .word   gdt_end - gdt - 1
+       .long   0
        .word   0
        .quad   0x00cf9a000000ffff      /* __KERNEL32_CS */
        .quad   0x00af9a000000ffff      /* __KERNEL_CS */
@@ -629,8 +648,56 @@ SYM_DATA_START_LOCAL(gdt)
 SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
 
 #ifdef CONFIG_EFI_MIXED
-SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0)
+SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
 SYM_DATA(efi_is64, .byte 1)
+
+#define ST32_boottime          60 // offsetof(efi_system_table_32_t, boottime)
+#define BS32_handle_protocol   88 // offsetof(efi_boot_services_32_t, handle_protocol)
+#define LI32_image_base                32 // offsetof(efi_loaded_image_32_t, image_base)
+
+       .text
+       .code32
+SYM_FUNC_START(efi32_pe_entry)
+       pushl   %ebp
+
+       call    verify_cpu                      // check for long mode support
+       testl   %eax, %eax
+       movl    $0x80000003, %eax               // EFI_UNSUPPORTED
+       jnz     3f
+
+       call    1f
+1:     pop     %ebp
+       subl    $1b, %ebp
+
+       /* Get the loaded image protocol pointer from the image handle */
+       subl    $12, %esp                       // space for the loaded image pointer
+       pushl   %esp                            // pass its address
+       leal    4f(%ebp), %eax
+       pushl   %eax                            // pass the GUID address
+       pushl   28(%esp)                        // pass the image handle
+
+       movl    36(%esp), %eax                  // sys_table
+       movl    ST32_boottime(%eax), %eax       // sys_table->boottime
+       call    *BS32_handle_protocol(%eax)     // sys_table->boottime->handle_protocol
+       cmp     $0, %eax
+       jnz     2f
+
+       movl    32(%esp), %ecx                  // image_handle
+       movl    36(%esp), %edx                  // sys_table
+       movl    12(%esp), %esi                  // loaded_image
+       movl    LI32_image_base(%esi), %esi     // loaded_image->image_base
+       jmp     efi32_pe_stub_entry
+
+2:     addl    $24, %esp
+3:     popl    %ebp
+       ret
+SYM_FUNC_END(efi32_pe_entry)
+
+       .section ".rodata"
+       /* EFI loaded image protocol GUID */
+4:     .long   0x5B1B31A1
+       .word   0x9562, 0x11d2
+       .byte   0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B
 #endif
 
 /*
index 97d9b6d..4ee25e2 100644 (file)
@@ -15,7 +15,7 @@
  * hex while segment addresses are written as segment:offset.
  *
  */
-
+#include <linux/pe.h>
 #include <asm/segment.h>
 #include <asm/boot.h>
 #include <asm/page_types.h>
@@ -43,8 +43,7 @@ SYSSEG                = 0x1000                /* historical load address >> 4 */
 bootsect_start:
 #ifdef CONFIG_EFI_STUB
        # "MZ", MS-DOS header
-       .byte 0x4d
-       .byte 0x5a
+       .word   MZ_MAGIC
 #endif
 
        # Normalize the start address
@@ -97,39 +96,30 @@ bugger_off_msg:
 
 #ifdef CONFIG_EFI_STUB
 pe_header:
-       .ascii  "PE"
-       .word   0
+       .long   PE_MAGIC
 
 coff_header:
 #ifdef CONFIG_X86_32
-       .word   0x14c                           # i386
+       .set    image_file_add_flags, IMAGE_FILE_32BIT_MACHINE
+       .set    pe_opt_magic, PE_OPT_MAGIC_PE32
+       .word   IMAGE_FILE_MACHINE_I386
 #else
-       .word   0x8664                          # x86-64
+       .set    image_file_add_flags, 0
+       .set    pe_opt_magic, PE_OPT_MAGIC_PE32PLUS
+       .word   IMAGE_FILE_MACHINE_AMD64
 #endif
-       .word   4                               # nr_sections
+       .word   section_count                   # nr_sections
        .long   0                               # TimeDateStamp
        .long   0                               # PointerToSymbolTable
        .long   1                               # NumberOfSymbols
        .word   section_table - optional_header # SizeOfOptionalHeader
-#ifdef CONFIG_X86_32
-       .word   0x306                           # Characteristics.
-                                               # IMAGE_FILE_32BIT_MACHINE |
-                                               # IMAGE_FILE_DEBUG_STRIPPED |
-                                               # IMAGE_FILE_EXECUTABLE_IMAGE |
-                                               # IMAGE_FILE_LINE_NUMS_STRIPPED
-#else
-       .word   0x206                           # Characteristics
-                                               # IMAGE_FILE_DEBUG_STRIPPED |
-                                               # IMAGE_FILE_EXECUTABLE_IMAGE |
-                                               # IMAGE_FILE_LINE_NUMS_STRIPPED
-#endif
+       .word   IMAGE_FILE_EXECUTABLE_IMAGE     | \
+               image_file_add_flags            | \
+               IMAGE_FILE_DEBUG_STRIPPED       | \
+               IMAGE_FILE_LINE_NUMS_STRIPPED   # Characteristics
 
 optional_header:
-#ifdef CONFIG_X86_32
-       .word   0x10b                           # PE32 format
-#else
-       .word   0x20b                           # PE32+ format
-#endif
+       .word   pe_opt_magic
        .byte   0x02                            # MajorLinkerVersion
        .byte   0x14                            # MinorLinkerVersion
 
@@ -157,8 +147,8 @@ extra_header_fields:
        .long   0x20                            # FileAlignment
        .word   0                               # MajorOperatingSystemVersion
        .word   0                               # MinorOperatingSystemVersion
-       .word   0                               # MajorImageVersion
-       .word   0                               # MinorImageVersion
+       .word   LINUX_EFISTUB_MAJOR_VERSION     # MajorImageVersion
+       .word   LINUX_EFISTUB_MINOR_VERSION     # MinorImageVersion
        .word   0                               # MajorSubsystemVersion
        .word   0                               # MinorSubsystemVersion
        .long   0                               # Win32VersionValue
@@ -170,7 +160,7 @@ extra_header_fields:
 
        .long   0x200                           # SizeOfHeaders
        .long   0                               # CheckSum
-       .word   0xa                             # Subsystem (EFI application)
+       .word   IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
        .word   0                               # DllCharacteristics
 #ifdef CONFIG_X86_32
        .long   0                               # SizeOfStackReserve
@@ -184,7 +174,7 @@ extra_header_fields:
        .quad   0                               # SizeOfHeapCommit
 #endif
        .long   0                               # LoaderFlags
-       .long   0x6                             # NumberOfRvaAndSizes
+       .long   (section_table - .) / 8         # NumberOfRvaAndSizes
 
        .quad   0                               # ExportTable
        .quad   0                               # ImportTable
@@ -210,7 +200,10 @@ section_table:
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0x60500020                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_CODE              | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_EXECUTE           | \
+               IMAGE_SCN_ALIGN_16BYTES         # Characteristics
 
        #
        # The EFI application loader requires a relocation section
@@ -228,45 +221,53 @@ section_table:
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0x42100040                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_INITIALIZED_DATA  | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_DISCARDABLE       | \
+               IMAGE_SCN_ALIGN_1BYTES          # Characteristics
 
+#ifdef CONFIG_EFI_MIXED
        #
        # The offset & size fields are filled in by build.c.
        #
-       .ascii  ".text"
-       .byte   0
-       .byte   0
-       .byte   0
+       .asciz  ".compat"
        .long   0
-       .long   0x0                             # startup_{32,64}
+       .long   0x0
        .long   0                               # Size of initialized data
                                                # on disk
-       .long   0x0                             # startup_{32,64}
+       .long   0x0
        .long   0                               # PointerToRelocations
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0x60500020                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_INITIALIZED_DATA  | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_DISCARDABLE       | \
+               IMAGE_SCN_ALIGN_1BYTES          # Characteristics
+#endif
 
        #
        # The offset & size fields are filled in by build.c.
        #
-       .ascii  ".bss"
-       .byte   0
+       .ascii  ".text"
        .byte   0
        .byte   0
        .byte   0
        .long   0
-       .long   0x0
+       .long   0x0                             # startup_{32,64}
        .long   0                               # Size of initialized data
                                                # on disk
-       .long   0x0
+       .long   0x0                             # startup_{32,64}
        .long   0                               # PointerToRelocations
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0xc8000080                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_CODE              | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_EXECUTE           | \
+               IMAGE_SCN_ALIGN_16BYTES         # Characteristics
 
+       .set    section_count, (. - section_table) / 40
 #endif /* CONFIG_EFI_STUB */
 
        # Kernel attributes; used by setup.  This is part 1 of the
index 55e669d..90d403d 100644 (file)
@@ -53,9 +53,16 @@ u8 buf[SETUP_SECT_MAX*512];
 
 #define PECOFF_RELOC_RESERVE 0x20
 
+#ifdef CONFIG_EFI_MIXED
+#define PECOFF_COMPAT_RESERVE 0x20
+#else
+#define PECOFF_COMPAT_RESERVE 0x0
+#endif
+
 unsigned long efi32_stub_entry;
 unsigned long efi64_stub_entry;
 unsigned long efi_pe_entry;
+unsigned long efi32_pe_entry;
 unsigned long kernel_info;
 unsigned long startup_64;
 
@@ -189,7 +196,10 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz
 static void update_pecoff_setup_and_reloc(unsigned int size)
 {
        u32 setup_offset = 0x200;
-       u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
+       u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
+#ifdef CONFIG_EFI_MIXED
+       u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
+#endif
        u32 setup_size = reloc_offset - setup_offset;
 
        update_pecoff_section_header(".setup", setup_offset, setup_size);
@@ -201,43 +211,63 @@ static void update_pecoff_setup_and_reloc(unsigned int size)
         */
        put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
        put_unaligned_le32(10, &buf[reloc_offset + 4]);
+
+#ifdef CONFIG_EFI_MIXED
+       update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
+
+       /*
+        * Put the IA-32 machine type (0x14c) and the associated entry point
+        * address in the .compat section, so loaders can figure out which other
+        * execution modes this image supports.
+        */
+       buf[compat_offset] = 0x1;
+       buf[compat_offset + 1] = 0x8;
+       put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
+       put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
+#endif
 }
 
-static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
+static void update_pecoff_text(unsigned int text_start, unsigned int file_sz,
+                              unsigned int init_sz)
 {
        unsigned int pe_header;
        unsigned int text_sz = file_sz - text_start;
+       unsigned int bss_sz = init_sz + text_start - file_sz;
 
        pe_header = get_unaligned_le32(&buf[0x3c]);
 
+#ifdef CONFIG_EFI_MIXED
+       /*
+        * In mixed mode, we will execute startup_32() at whichever offset in
+        * memory it happened to land when the PE/COFF loader loaded the image,
+        * which may be misaligned with respect to the kernel_alignment field
+        * in the setup header.
+        *
+        * In order for startup_32 to safely execute in place at this offset,
+        * we need to ensure that the CONFIG_PHYSICAL_ALIGN aligned allocation
+        * it creates for the page tables does not extend beyond the declared
+        * size of the image in the PE/COFF header. So add the required slack.
+        */
+       bss_sz  += CONFIG_PHYSICAL_ALIGN;
+       init_sz += CONFIG_PHYSICAL_ALIGN;
+#endif
+
        /*
         * Size of code: Subtract the size of the first sector (512 bytes)
         * which includes the header.
         */
-       put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
+       put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]);
+
+       /* Size of image */
+       put_unaligned_le32(init_sz + text_start, &buf[pe_header + 0x50]);
 
        /*
         * Address of entry point for PE/COFF executable
         */
        put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
 
-       update_pecoff_section_header(".text", text_start, text_sz);
-}
-
-static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz)
-{
-       unsigned int pe_header;
-       unsigned int bss_sz = init_sz - file_sz;
-
-       pe_header = get_unaligned_le32(&buf[0x3c]);
-
-       /* Size of uninitialized data */
-       put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]);
-
-       /* Size of image */
-       put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
-
-       update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0);
+       update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
+                                           text_sz, text_start);
 }
 
 static int reserve_pecoff_reloc_section(int c)
@@ -278,9 +308,8 @@ static void efi_stub_entry_update(void)
 
 static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
 static inline void update_pecoff_text(unsigned int text_start,
-                                     unsigned int file_sz) {}
-static inline void update_pecoff_bss(unsigned int file_sz,
-                                    unsigned int init_sz) {}
+                                     unsigned int file_sz,
+                                     unsigned int init_sz) {}
 static inline void efi_stub_defaults(void) {}
 static inline void efi_stub_entry_update(void) {}
 
@@ -290,6 +319,12 @@ static inline int reserve_pecoff_reloc_section(int c)
 }
 #endif /* CONFIG_EFI_STUB */
 
+static int reserve_pecoff_compat_section(int c)
+{
+       /* Reserve 0x20 bytes for .compat section */
+       memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
+       return PECOFF_COMPAT_RESERVE;
+}
 
 /*
  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
@@ -322,6 +357,7 @@ static void parse_zoffset(char *fname)
                PARSE_ZOFS(p, efi32_stub_entry);
                PARSE_ZOFS(p, efi64_stub_entry);
                PARSE_ZOFS(p, efi_pe_entry);
+               PARSE_ZOFS(p, efi32_pe_entry);
                PARSE_ZOFS(p, kernel_info);
                PARSE_ZOFS(p, startup_64);
 
@@ -365,6 +401,7 @@ int main(int argc, char ** argv)
                die("Boot block hasn't got boot flag (0xAA55)");
        fclose(file);
 
+       c += reserve_pecoff_compat_section(c);
        c += reserve_pecoff_reloc_section(c);
 
        /* Pad unused space with zeros */
@@ -406,9 +443,8 @@ int main(int argc, char ** argv)
        buf[0x1f1] = setup_sectors-1;
        put_unaligned_le32(sys_size, &buf[0x1f4]);
 
-       update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
        init_sz = get_unaligned_le32(&buf[0x260]);
-       update_pecoff_bss(i + (sys_size * 16), init_sz);
+       update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz);
 
        efi_stub_entry_update();
 
index 86169a2..cdcf48d 100644 (file)
@@ -10,6 +10,8 @@
 #include <asm/mmu_context.h>
 #include <linux/build_bug.h>
 
+extern unsigned long efi_fw_vendor, efi_config_table;
+
 /*
  * We map the EFI regions needed for runtime services non-contiguously,
  * with preserved alignment on virtual addresses starting from -4G down
@@ -34,8 +36,6 @@ static inline bool efi_have_uv1_memmap(void)
 #define EFI32_LOADER_SIGNATURE "EL32"
 #define EFI64_LOADER_SIGNATURE "EL64"
 
-#define MAX_CMDLINE_ADDRESS    UINT_MAX
-
 #define ARCH_EFI_IRQ_FLAGS_MASK        X86_EFLAGS_IF
 
 /*
@@ -180,7 +180,6 @@ extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
 
 struct efi_setup_data {
        u64 fw_vendor;
-       u64 runtime;
        u64 tables;
        u64 smbios;
        u64 reserved[8];
@@ -219,7 +218,8 @@ extern void efi_thunk_runtime_setup(void);
 efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
                                         unsigned long descriptor_size,
                                         u32 descriptor_version,
-                                        efi_memory_desc_t *virtual_map);
+                                        efi_memory_desc_t *virtual_map,
+                                        unsigned long systab_phys);
 
 /* arch specific definitions used by the stub code */
 
@@ -270,6 +270,11 @@ static inline void *efi64_zero_upper(void *p)
        return p;
 }
 
+static inline u32 efi64_convert_status(efi_status_t status)
+{
+       return (u32)(status | (u64)status >> 32);
+}
+
 #define __efi64_argmap_free_pages(addr, size)                          \
        ((addr), 0, (size))
 
@@ -285,11 +290,21 @@ static inline void *efi64_zero_upper(void *p)
 #define __efi64_argmap_locate_protocol(protocol, reg, interface)       \
        ((protocol), (reg), efi64_zero_upper(interface))
 
+#define __efi64_argmap_locate_device_path(protocol, path, handle)      \
+       ((protocol), (path), efi64_zero_upper(handle))
+
+#define __efi64_argmap_exit(handle, status, size, data)                        \
+       ((handle), efi64_convert_status(status), (size), (data))
+
 /* PCI I/O */
 #define __efi64_argmap_get_location(protocol, seg, bus, dev, func)     \
        ((protocol), efi64_zero_upper(seg), efi64_zero_upper(bus),      \
         efi64_zero_upper(dev), efi64_zero_upper(func))
 
+/* LoadFile */
+#define __efi64_argmap_load_file(protocol, path, policy, bufsize, buf) \
+       ((protocol), (path), (policy), efi64_zero_upper(bufsize), (buf))
+
 /*
  * The macros below handle the plumbing for the argument mapping. To add a
  * mapping for a specific EFI method, simply define a macro
index 82826f2..2b4256e 100644 (file)
@@ -3,6 +3,8 @@
 # error "Please do not build this file directly, build asm-offsets.c instead"
 #endif
 
+#include <linux/efi.h>
+
 #include <asm/ucontext.h>
 
 #define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
@@ -64,4 +66,7 @@ void foo(void)
        BLANK();
        DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
        DEFINE(NR_syscalls, sizeof(syscalls));
+
+       BLANK();
+       DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
 }
index 3923ab4..f66a6b9 100644 (file)
@@ -67,11 +67,6 @@ __HEAD
 SYM_CODE_START(startup_32)
        movl pa(initial_stack),%ecx
        
-       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
-               us to not reload segments */
-       testb $KEEP_SEGMENTS, BP_loadflags(%esi)
-       jnz 2f
-
 /*
  * Set segments to known values.
  */
@@ -82,7 +77,6 @@ SYM_CODE_START(startup_32)
        movl %eax,%fs
        movl %eax,%gs
        movl %eax,%ss
-2:
        leal -__PAGE_OFFSET(%ecx),%esp
 
 /*
index 2305490..7dfb1e8 100644 (file)
@@ -17,7 +17,7 @@ static enum efi_secureboot_mode get_sb_mode(void)
 
        size = sizeof(secboot);
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
                pr_info("ima: secureboot mode unknown, no efi\n");
                return efi_secureboot_mode_unknown;
        }
index f293d87..db6578d 100644 (file)
@@ -141,9 +141,8 @@ prepare_add_efi_setup_data(struct boot_params *params,
        struct setup_data *sd = (void *)params + efi_setup_data_offset;
        struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data);
 
-       esd->fw_vendor = efi.fw_vendor;
-       esd->runtime = efi.runtime;
-       esd->tables = efi.config_table;
+       esd->fw_vendor = efi_fw_vendor;
+       esd->tables = efi_config_table;
        esd->smbios = efi.smbios;
 
        sd->type = SETUP_EFI;
index ae923ee..1aae530 100644 (file)
 #include <asm/x86_init.h>
 #include <asm/uv/uv.h>
 
-static efi_system_table_t efi_systab __initdata;
-static u64 efi_systab_phys __initdata;
+static unsigned long efi_systab_phys __initdata;
+static unsigned long prop_phys = EFI_INVALID_TABLE_ADDR;
+static unsigned long uga_phys = EFI_INVALID_TABLE_ADDR;
+static unsigned long efi_runtime, efi_nr_tables;
 
-static efi_config_table_type_t arch_tables[] __initdata = {
+unsigned long efi_fw_vendor, efi_config_table;
+
+static const efi_config_table_type_t arch_tables[] __initconst = {
+       {EFI_PROPERTIES_TABLE_GUID, "PROP", &prop_phys},
+       {UGA_IO_PROTOCOL_GUID, "UGA", &uga_phys},
 #ifdef CONFIG_X86_UV
        {UV_SYSTEM_TABLE_GUID, "UVsystab", &uv_systab_phys},
 #endif
@@ -65,26 +71,26 @@ static efi_config_table_type_t arch_tables[] __initdata = {
 };
 
 static const unsigned long * const efi_tables[] = {
-       &efi.mps,
        &efi.acpi,
        &efi.acpi20,
        &efi.smbios,
        &efi.smbios3,
-       &efi.boot_info,
-       &efi.hcdp,
-       &efi.uga,
+       &uga_phys,
 #ifdef CONFIG_X86_UV
        &uv_systab_phys,
 #endif
-       &efi.fw_vendor,
-       &efi.runtime,
-       &efi.config_table,
+       &efi_fw_vendor,
+       &efi_runtime,
+       &efi_config_table,
        &efi.esrt,
-       &efi.properties_table,
-       &efi.mem_attr_table,
+       &prop_phys,
+       &efi_mem_attr_table,
 #ifdef CONFIG_EFI_RCI2_TABLE
        &rci2_table_phys,
 #endif
+       &efi.tpm_log,
+       &efi.tpm_final_log,
+       &efi_rng_seed,
 };
 
 u64 efi_setup;         /* efi setup_data physical address */
@@ -214,16 +220,13 @@ int __init efi_memblock_x86_reserve_range(void)
        if (efi_enabled(EFI_PARAVIRT))
                return 0;
 
-#ifdef CONFIG_X86_32
-       /* Can't handle data above 4GB at this time */
-       if (e->efi_memmap_hi) {
+       /* Can't handle firmware tables above 4GB on i386 */
+       if (IS_ENABLED(CONFIG_X86_32) && e->efi_memmap_hi > 0) {
                pr_err("Memory map is above 4GB, disabling EFI.\n");
                return -EINVAL;
        }
-       pmap =  e->efi_memmap;
-#else
-       pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32));
-#endif
+       pmap = (phys_addr_t)(e->efi_memmap | ((u64)e->efi_memmap_hi << 32));
+
        data.phys_map           = pmap;
        data.size               = e->efi_memmap_size;
        data.desc_size          = e->efi_memdesc_size;
@@ -243,6 +246,7 @@ int __init efi_memblock_x86_reserve_range(void)
             efi.memmap.desc_version);
 
        memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size);
+       set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags);
 
        return 0;
 }
@@ -305,11 +309,11 @@ static void __init efi_clean_memmap(void)
 
        if (n_removal > 0) {
                struct efi_memory_map_data data = {
-                       .phys_map = efi.memmap.phys_map,
-                       .desc_version = efi.memmap.desc_version,
-                       .desc_size = efi.memmap.desc_size,
-                       .size = efi.memmap.desc_size * (efi.memmap.nr_map - n_removal),
-                       .flags = 0,
+                       .phys_map       = efi.memmap.phys_map,
+                       .desc_version   = efi.memmap.desc_version,
+                       .desc_size      = efi.memmap.desc_size,
+                       .size           = efi.memmap.desc_size * (efi.memmap.nr_map - n_removal),
+                       .flags          = 0,
                };
 
                pr_warn("Removing %d invalid memory map entries.\n", n_removal);
@@ -333,43 +337,32 @@ void __init efi_print_memmap(void)
        }
 }
 
-static int __init efi_systab_init(u64 phys)
+static int __init efi_systab_init(unsigned long phys)
 {
        int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
                                          : sizeof(efi_system_table_32_t);
+       const efi_table_hdr_t *hdr;
        bool over4g = false;
        void *p;
+       int ret;
 
-       p = early_memremap_ro(phys, size);
+       hdr = p = early_memremap_ro(phys, size);
        if (p == NULL) {
                pr_err("Couldn't map the system table!\n");
                return -ENOMEM;
        }
 
+       ret = efi_systab_check_header(hdr, 1);
+       if (ret) {
+               early_memunmap(p, size);
+               return ret;
+       }
+
        if (efi_enabled(EFI_64BIT)) {
                const efi_system_table_64_t *systab64 = p;
 
-               efi_systab.hdr                  = systab64->hdr;
-               efi_systab.fw_vendor            = systab64->fw_vendor;
-               efi_systab.fw_revision          = systab64->fw_revision;
-               efi_systab.con_in_handle        = systab64->con_in_handle;
-               efi_systab.con_in               = systab64->con_in;
-               efi_systab.con_out_handle       = systab64->con_out_handle;
-               efi_systab.con_out              = (void *)(unsigned long)systab64->con_out;
-               efi_systab.stderr_handle        = systab64->stderr_handle;
-               efi_systab.stderr               = systab64->stderr;
-               efi_systab.runtime              = (void *)(unsigned long)systab64->runtime;
-               efi_systab.boottime             = (void *)(unsigned long)systab64->boottime;
-               efi_systab.nr_tables            = systab64->nr_tables;
-               efi_systab.tables               = systab64->tables;
-
-               over4g = systab64->con_in_handle        > U32_MAX ||
-                        systab64->con_in               > U32_MAX ||
-                        systab64->con_out_handle       > U32_MAX ||
-                        systab64->con_out              > U32_MAX ||
-                        systab64->stderr_handle        > U32_MAX ||
-                        systab64->stderr               > U32_MAX ||
-                        systab64->boottime             > U32_MAX;
+               efi_runtime     = systab64->runtime;
+               over4g          = systab64->runtime > U32_MAX;
 
                if (efi_setup) {
                        struct efi_setup_data *data;
@@ -380,38 +373,33 @@ static int __init efi_systab_init(u64 phys)
                                return -ENOMEM;
                        }
 
-                       efi_systab.fw_vendor    = (unsigned long)data->fw_vendor;
-                       efi_systab.runtime      = (void *)(unsigned long)data->runtime;
-                       efi_systab.tables       = (unsigned long)data->tables;
+                       efi_fw_vendor           = (unsigned long)data->fw_vendor;
+                       efi_config_table        = (unsigned long)data->tables;
 
                        over4g |= data->fw_vendor       > U32_MAX ||
-                                 data->runtime         > U32_MAX ||
                                  data->tables          > U32_MAX;
 
                        early_memunmap(data, sizeof(*data));
                } else {
+                       efi_fw_vendor           = systab64->fw_vendor;
+                       efi_config_table        = systab64->tables;
+
                        over4g |= systab64->fw_vendor   > U32_MAX ||
-                                 systab64->runtime     > U32_MAX ||
                                  systab64->tables      > U32_MAX;
                }
+               efi_nr_tables = systab64->nr_tables;
        } else {
                const efi_system_table_32_t *systab32 = p;
 
-               efi_systab.hdr                  = systab32->hdr;
-               efi_systab.fw_vendor            = systab32->fw_vendor;
-               efi_systab.fw_revision          = systab32->fw_revision;
-               efi_systab.con_in_handle        = systab32->con_in_handle;
-               efi_systab.con_in               = systab32->con_in;
-               efi_systab.con_out_handle       = systab32->con_out_handle;
-               efi_systab.con_out              = (void *)(unsigned long)systab32->con_out;
-               efi_systab.stderr_handle        = systab32->stderr_handle;
-               efi_systab.stderr               = systab32->stderr;
-               efi_systab.runtime              = (void *)(unsigned long)systab32->runtime;
-               efi_systab.boottime             = (void *)(unsigned long)systab32->boottime;
-               efi_systab.nr_tables            = systab32->nr_tables;
-               efi_systab.tables               = systab32->tables;
+               efi_fw_vendor           = systab32->fw_vendor;
+               efi_runtime             = systab32->runtime;
+               efi_config_table        = systab32->tables;
+               efi_nr_tables           = systab32->nr_tables;
        }
 
+       efi.runtime_version = hdr->revision;
+
+       efi_systab_report_header(hdr, efi_fw_vendor);
        early_memunmap(p, size);
 
        if (IS_ENABLED(CONFIG_X86_32) && over4g) {
@@ -419,29 +407,40 @@ static int __init efi_systab_init(u64 phys)
                return -EINVAL;
        }
 
-       efi.systab = &efi_systab;
+       return 0;
+}
+
+static int __init efi_config_init(const efi_config_table_type_t *arch_tables)
+{
+       void *config_tables;
+       int sz, ret;
+
+       if (efi_nr_tables == 0)
+               return 0;
+
+       if (efi_enabled(EFI_64BIT))
+               sz = sizeof(efi_config_table_64_t);
+       else
+               sz = sizeof(efi_config_table_32_t);
 
        /*
-        * Verify the EFI Table
+        * Let's see what config tables the firmware passed to us.
         */
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
-               pr_err("System table signature incorrect!\n");
-               return -EINVAL;
+       config_tables = early_memremap(efi_config_table, efi_nr_tables * sz);
+       if (config_tables == NULL) {
+               pr_err("Could not map Configuration table!\n");
+               return -ENOMEM;
        }
-       if ((efi.systab->hdr.revision >> 16) == 0)
-               pr_err("Warning: System table version %d.%02d, expected 1.00 or greater!\n",
-                      efi.systab->hdr.revision >> 16,
-                      efi.systab->hdr.revision & 0xffff);
 
-       return 0;
+       ret = efi_config_parse_tables(config_tables, efi_nr_tables,
+                                     arch_tables);
+
+       early_memunmap(config_tables, efi_nr_tables * sz);
+       return ret;
 }
 
 void __init efi_init(void)
 {
-       efi_char16_t *c16;
-       char vendor[100] = "unknown";
-       int i = 0;
-
        if (IS_ENABLED(CONFIG_X86_32) &&
            (boot_params.efi_info.efi_systab_hi ||
             boot_params.efi_info.efi_memmap_hi)) {
@@ -455,29 +454,7 @@ void __init efi_init(void)
        if (efi_systab_init(efi_systab_phys))
                return;
 
-       efi.config_table = (unsigned long)efi.systab->tables;
-       efi.fw_vendor    = (unsigned long)efi.systab->fw_vendor;
-       efi.runtime      = (unsigned long)efi.systab->runtime;
-
-       /*
-        * Show what we know for posterity
-        */
-       c16 = early_memremap_ro(efi.systab->fw_vendor,
-                               sizeof(vendor) * sizeof(efi_char16_t));
-       if (c16) {
-               for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
-                       vendor[i] = c16[i];
-               vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
-       } else {
-               pr_err("Could not map the firmware vendor!\n");
-       }
-
-       pr_info("EFI v%u.%.02u by %s\n",
-               efi.systab->hdr.revision >> 16,
-               efi.systab->hdr.revision & 0xffff, vendor);
-
-       if (efi_reuse_config(efi.systab->tables, efi.systab->nr_tables))
+       if (efi_reuse_config(efi_config_table, efi_nr_tables))
                return;
 
        if (efi_config_init(arch_tables))
@@ -496,6 +473,22 @@ void __init efi_init(void)
                return;
        }
 
+       /* Parse the EFI Properties table if it exists */
+       if (prop_phys != EFI_INVALID_TABLE_ADDR) {
+               efi_properties_table_t *tbl;
+
+               tbl = early_memremap_ro(prop_phys, sizeof(*tbl));
+               if (tbl == NULL) {
+                       pr_err("Could not map Properties table!\n");
+               } else {
+                       if (tbl->memory_protection_attribute &
+                           EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
+                               set_bit(EFI_NX_PE_DATA, &efi.flags);
+
+                       early_memunmap(tbl, sizeof(*tbl));
+               }
+       }
+
        set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
        efi_clean_memmap();
 
@@ -602,20 +595,6 @@ static void __init efi_merge_regions(void)
        }
 }
 
-static void __init get_systab_virt_addr(efi_memory_desc_t *md)
-{
-       unsigned long size;
-       u64 end, systab;
-
-       size = md->num_pages << EFI_PAGE_SHIFT;
-       end = md->phys_addr + size;
-       systab = efi_systab_phys;
-       if (md->phys_addr <= systab && systab < end) {
-               systab += md->virt_addr - md->phys_addr;
-               efi.systab = (efi_system_table_t *)(unsigned long)systab;
-       }
-}
-
 static void *realloc_pages(void *old_memmap, int old_shift)
 {
        void *ret;
@@ -771,7 +750,6 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
                        continue;
 
                efi_map_region(md);
-               get_systab_virt_addr(md);
 
                if (left < desc_size) {
                        new_memmap = realloc_pages(new_memmap, *pg_shift);
@@ -797,8 +775,6 @@ static void __init kexec_enter_virtual_mode(void)
        efi_memory_desc_t *md;
        unsigned int num_pages;
 
-       efi.systab = NULL;
-
        /*
         * We don't do virtual mode, since we don't do runtime services, on
         * non-native EFI. With the UV1 memmap, we don't do runtime services in
@@ -821,10 +797,8 @@ static void __init kexec_enter_virtual_mode(void)
        * Map efi regions which were passed via setup_data. The virt_addr is a
        * fixed addr which was used in first kernel of a kexec boot.
        */
-       for_each_efi_memory_desc(md) {
+       for_each_efi_memory_desc(md)
                efi_map_region_fixed(md); /* FIXME: add error handling */
-               get_systab_virt_addr(md);
-       }
 
        /*
         * Unregister the early EFI memmap from efi_init() and install
@@ -839,8 +813,6 @@ static void __init kexec_enter_virtual_mode(void)
                return;
        }
 
-       BUG_ON(!efi.systab);
-
        num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE);
        num_pages >>= PAGE_SHIFT;
 
@@ -850,15 +822,6 @@ static void __init kexec_enter_virtual_mode(void)
        }
 
        efi_sync_low_kernel_mappings();
-
-       /*
-        * Now that EFI is in virtual mode, update the function
-        * pointers in the runtime service table to the new virtual addresses.
-        *
-        * Call EFI services through wrapper functions.
-        */
-       efi.runtime_version = efi_systab.hdr.revision;
-
        efi_native_runtime_setup();
 #endif
 }
@@ -892,8 +855,6 @@ static void __init __efi_enter_virtual_mode(void)
        efi_status_t status;
        unsigned long pa;
 
-       efi.systab = NULL;
-
        if (efi_alloc_page_tables()) {
                pr_err("Failed to allocate EFI page tables\n");
                goto err;
@@ -925,9 +886,6 @@ static void __init __efi_enter_virtual_mode(void)
                efi_print_memmap();
        }
 
-       if (WARN_ON(!efi.systab))
-               goto err;
-
        if (efi_setup_page_tables(pa, 1 << pg_shift))
                goto err;
 
@@ -936,23 +894,17 @@ static void __init __efi_enter_virtual_mode(void)
        status = efi_set_virtual_address_map(efi.memmap.desc_size * count,
                                             efi.memmap.desc_size,
                                             efi.memmap.desc_version,
-                                            (efi_memory_desc_t *)pa);
+                                            (efi_memory_desc_t *)pa,
+                                            efi_systab_phys);
        if (status != EFI_SUCCESS) {
                pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",
                       status);
                goto err;
        }
 
+       efi_check_for_embedded_firmwares();
        efi_free_boot_services();
 
-       /*
-        * Now that EFI is in virtual mode, update the function
-        * pointers in the runtime service table to the new virtual addresses.
-        *
-        * Call EFI services through wrapper functions.
-        */
-       efi.runtime_version = efi_systab.hdr.revision;
-
        if (!efi_is_mixed())
                efi_native_runtime_setup();
        else
@@ -978,6 +930,8 @@ void __init efi_enter_virtual_mode(void)
        if (efi_enabled(EFI_PARAVIRT))
                return;
 
+       efi.runtime = (efi_runtime_services_t *)efi_runtime;
+
        if (efi_setup)
                kexec_enter_virtual_mode();
        else
@@ -999,3 +953,43 @@ bool efi_is_table_address(unsigned long phys_addr)
 
        return false;
 }
+
+char *efi_systab_show_arch(char *str)
+{
+       if (uga_phys != EFI_INVALID_TABLE_ADDR)
+               str += sprintf(str, "UGA=0x%lx\n", uga_phys);
+       return str;
+}
+
+#define EFI_FIELD(var) efi_ ## var
+
+#define EFI_ATTR_SHOW(name) \
+static ssize_t name##_show(struct kobject *kobj, \
+                               struct kobj_attribute *attr, char *buf) \
+{ \
+       return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
+}
+
+EFI_ATTR_SHOW(fw_vendor);
+EFI_ATTR_SHOW(runtime);
+EFI_ATTR_SHOW(config_table);
+
+struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
+struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
+struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
+
+umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+       if (attr == &efi_attr_fw_vendor.attr) {
+               if (efi_enabled(EFI_PARAVIRT) ||
+                               efi_fw_vendor == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       } else if (attr == &efi_attr_runtime.attr) {
+               if (efi_runtime == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       } else if (attr == &efi_attr_config_table.attr) {
+               if (efi_config_table == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       }
+       return attr->mode;
+}
index 081d466..c049c43 100644 (file)
@@ -66,14 +66,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
 void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
 void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
 
-efi_status_t efi_call_svam(efi_set_virtual_address_map_t *__efiapi *,
-                          u32, u32, u32, void *);
+efi_status_t efi_call_svam(efi_runtime_services_t * const *,
+                          u32, u32, u32, void *, u32);
 
 efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
                                                unsigned long descriptor_size,
                                                u32 descriptor_version,
-                                               efi_memory_desc_t *virtual_map)
+                                               efi_memory_desc_t *virtual_map,
+                                               unsigned long systab_phys)
 {
+       const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
        struct desc_ptr gdt_descr;
        efi_status_t status;
        unsigned long flags;
@@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
 
        /* Disable interrupts around EFI calls: */
        local_irq_save(flags);
-       status = efi_call_svam(&efi.systab->runtime->set_virtual_address_map,
+       status = efi_call_svam(&systab->runtime,
                               memory_map_size, descriptor_size,
-                              descriptor_version, virtual_map);
+                              descriptor_version, virtual_map,
+                              __pa(&efi.runtime));
        local_irq_restore(flags);
 
        load_fixmap_gdt(0);
index d19a2ed..211bb93 100644 (file)
@@ -497,12 +497,9 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
  */
 #define __efi_thunk(func, ...)                                         \
 ({                                                                     \
-       efi_runtime_services_32_t *__rt;                                \
        unsigned short __ds, __es;                                      \
        efi_status_t ____s;                                             \
                                                                        \
-       __rt = (void *)(unsigned long)efi.systab->mixed_mode.runtime;   \
-                                                                       \
        savesegment(ds, __ds);                                          \
        savesegment(es, __es);                                          \
                                                                        \
@@ -510,7 +507,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
        loadsegment(ds, __KERNEL_DS);                                   \
        loadsegment(es, __KERNEL_DS);                                   \
                                                                        \
-       ____s = efi64_thunk(__rt->func, __VA_ARGS__);                   \
+       ____s = efi64_thunk(efi.runtime->mixed_mode.func, __VA_ARGS__); \
                                                                        \
        loadsegment(ds, __ds);                                          \
        loadsegment(es, __es);                                          \
@@ -839,8 +836,10 @@ efi_status_t __init __no_sanitize_address
 efi_set_virtual_address_map(unsigned long memory_map_size,
                            unsigned long descriptor_size,
                            u32 descriptor_version,
-                           efi_memory_desc_t *virtual_map)
+                           efi_memory_desc_t *virtual_map,
+                           unsigned long systab_phys)
 {
+       const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
        efi_status_t status;
        unsigned long flags;
        pgd_t *save_pgd = NULL;
@@ -863,13 +862,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size,
 
        /* Disable interrupts around EFI calls: */
        local_irq_save(flags);
-       status = efi_call(efi.systab->runtime->set_virtual_address_map,
+       status = efi_call(efi.runtime->set_virtual_address_map,
                          memory_map_size, descriptor_size,
                          descriptor_version, virtual_map);
        local_irq_restore(flags);
 
        kernel_fpu_end();
 
+       /* grab the virtually remapped EFI runtime services table pointer */
+       efi.runtime = READ_ONCE(systab->runtime);
+
        if (save_pgd)
                efi_uv1_memmap_phys_epilog(save_pgd);
        else
index 75c46e7..0923723 100644 (file)
@@ -8,14 +8,20 @@
 
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <asm/asm-offsets.h>
 #include <asm/page_types.h>
 
        __INIT
 SYM_FUNC_START(efi_call_svam)
-       push    8(%esp)
-       push    8(%esp)
+       push    %ebp
+       movl    %esp, %ebp
+       push    %ebx
+
+       push    16(%esp)
+       push    16(%esp)
        push    %ecx
        push    %edx
+       movl    %eax, %ebx              // &systab_phys->runtime
 
        /*
         * Switch to the flat mapped alias of this routine, by jumping to the
@@ -35,15 +41,20 @@ SYM_FUNC_START(efi_call_svam)
        subl    $__PAGE_OFFSET, %esp
 
        /* call the EFI routine */
-       call    *(%eax)
+       movl    (%eax), %eax
+       call    *EFI_svam(%eax)
 
-       /* convert ESP back to a kernel VA, and pop the outgoing args */
-       addl    $__PAGE_OFFSET + 16, %esp
+       /* grab the virtually remapped EFI runtime services table pointer */
+       movl    (%ebx), %ecx
+       movl    36(%esp), %edx          // &efi.runtime
+       movl    %ecx, (%edx)
 
        /* re-enable paging */
        movl    %cr0, %edx
        orl     $0x80000000, %edx
        movl    %edx, %cr0
 
+       pop     %ebx
+       leave
        ret
 SYM_FUNC_END(efi_call_svam)
index 88d32c0..ce82f49 100644 (file)
@@ -410,6 +410,10 @@ void __init efi_free_boot_services(void)
        int num_entries = 0;
        void *new, *new_md;
 
+       /* Keep all regions for /sys/kernel/debug/efi */
+       if (efi_enabled(EFI_DBG))
+               return;
+
        for_each_efi_memory_desc(md) {
                unsigned long long start = md->phys_addr;
                unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -537,7 +541,7 @@ int __init efi_reuse_config(u64 tables, int nr_tables)
                goto out_memremap;
        }
 
-       for (i = 0; i < efi.systab->nr_tables; i++) {
+       for (i = 0; i < nr_tables; i++) {
                efi_guid_t guid;
 
                guid = ((efi_config_table_64_t *)p)->guid;
index ecc83e2..613828d 100644 (file)
@@ -239,6 +239,11 @@ config EFI_DISABLE_PCI_DMA
 
 endmenu
 
+config EFI_EMBEDDED_FIRMWARE
+       bool
+       depends on EFI
+       select CRYPTO_LIB_SHA256
+
 config UEFI_CPER
        bool
 
index 554d795..317a05c 100644 (file)
@@ -13,6 +13,7 @@ KASAN_SANITIZE_runtime-wrappers.o     := n
 obj-$(CONFIG_ACPI_BGRT)                += efi-bgrt.o
 obj-$(CONFIG_EFI)                      += efi.o vars.o reboot.o memattr.o tpm.o
 obj-$(CONFIG_EFI)                      += capsule.o memmap.o
+obj-$(CONFIG_EFI_PARAMS_FROM_FDT)      += fdtparams.o
 obj-$(CONFIG_EFI_VARS)                 += efivars.o
 obj-$(CONFIG_EFI_ESRT)                 += esrt.o
 obj-$(CONFIG_EFI_VARS_PSTORE)          += efi-pstore.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_EFI_TEST)                        += test/
 obj-$(CONFIG_EFI_DEV_PATH_PARSER)      += dev-path-parser.o
 obj-$(CONFIG_APPLE_PROPERTIES)         += apple-properties.o
 obj-$(CONFIG_EFI_RCI2_TABLE)           += rci2-table.o
+obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE)    += embedded-firmware.o
 
 fake_map-y                             += fake_mem.o
 fake_map-$(CONFIG_X86)                 += x86_fake_mem.o
index 5ccf399..34f53d8 100644 (file)
@@ -31,7 +31,7 @@ __setup("dump_apple_properties", dump_properties_enable);
 struct dev_header {
        u32 len;
        u32 prop_count;
-       struct efi_dev_path path[0];
+       struct efi_dev_path path[];
        /*
         * followed by key/value pairs, each key and value preceded by u32 len,
         * len includes itself, value may be empty (in which case its len is 4)
@@ -42,11 +42,11 @@ struct properties_header {
        u32 len;
        u32 version;
        u32 dev_count;
-       struct dev_header dev_header[0];
+       struct dev_header dev_header[];
 };
 
 static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
-                                            struct device *dev, void *ptr,
+                                            struct device *dev, const void *ptr,
                                             struct property_entry entry[])
 {
        int i;
@@ -117,10 +117,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
        while (offset + sizeof(struct dev_header) < properties->len) {
                struct dev_header *dev_header = (void *)properties + offset;
                struct property_entry *entry = NULL;
+               const struct efi_dev_path *ptr;
                struct device *dev;
                size_t len;
                int ret, i;
-               void *ptr;
 
                if (offset + dev_header->len > properties->len ||
                    dev_header->len <= sizeof(*dev_header)) {
@@ -131,10 +131,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
                ptr = dev_header->path;
                len = dev_header->len - sizeof(*dev_header);
 
-               dev = efi_get_device_by_path((struct efi_dev_path **)&ptr, &len);
+               dev = efi_get_device_by_path(&ptr, &len);
                if (IS_ERR(dev)) {
                        pr_err("device path parse error %ld at %#zx:\n",
-                              PTR_ERR(dev), ptr - (void *)dev_header);
+                              PTR_ERR(dev), (void *)ptr - (void *)dev_header);
                        print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
                               16, 1, dev_header, dev_header->len, true);
                        dev = NULL;
index d99f5b0..2791a80 100644 (file)
@@ -22,8 +22,6 @@
 
 #include <asm/efi.h>
 
-u64 efi_system_table;
-
 static int __init is_memory(efi_memory_desc_t *md)
 {
        if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC))
@@ -36,7 +34,7 @@ static int __init is_memory(efi_memory_desc_t *md)
  * as some data members of the EFI system table are virtually remapped after
  * SetVirtualAddressMap() has been called.
  */
-static phys_addr_t efi_to_phys(unsigned long addr)
+static phys_addr_t __init efi_to_phys(unsigned long addr)
 {
        efi_memory_desc_t *md;
 
@@ -55,7 +53,7 @@ static phys_addr_t efi_to_phys(unsigned long addr)
 
 static __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR;
 
-static __initdata efi_config_table_type_t arch_tables[] = {
+static const efi_config_table_type_t arch_tables[] __initconst = {
        {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, NULL, &screen_info_table},
        {NULL_GUID, NULL, NULL}
 };
@@ -83,17 +81,15 @@ static void __init init_screen_info(void)
                memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size);
 }
 
-static int __init uefi_init(void)
+static int __init uefi_init(u64 efi_system_table)
 {
-       efi_char16_t *c16;
-       void *config_tables;
+       efi_config_table_t *config_tables;
+       efi_system_table_t *systab;
        size_t table_size;
-       char vendor[100] = "unknown";
-       int i, retval;
+       int retval;
 
-       efi.systab = early_memremap_ro(efi_system_table,
-                                      sizeof(efi_system_table_t));
-       if (efi.systab == NULL) {
+       systab = early_memremap_ro(efi_system_table, sizeof(efi_system_table_t));
+       if (systab == NULL) {
                pr_warn("Unable to map EFI system table.\n");
                return -ENOMEM;
        }
@@ -102,53 +98,29 @@ static int __init uefi_init(void)
        if (IS_ENABLED(CONFIG_64BIT))
                set_bit(EFI_64BIT, &efi.flags);
 
-       /*
-        * Verify the EFI Table
-        */
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
-               pr_err("System table signature incorrect\n");
-               retval = -EINVAL;
+       retval = efi_systab_check_header(&systab->hdr, 2);
+       if (retval)
                goto out;
-       }
-       if ((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);
-
-       efi.runtime_version = efi.systab->hdr.revision;
-
-       /* Show what we know for posterity */
-       c16 = early_memremap_ro(efi_to_phys(efi.systab->fw_vendor),
-                               sizeof(vendor) * sizeof(efi_char16_t));
-       if (c16) {
-               for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
-                       vendor[i] = c16[i];
-               vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
-       }
 
-       pr_info("EFI v%u.%.02u by %s\n",
-               efi.systab->hdr.revision >> 16,
-               efi.systab->hdr.revision & 0xffff, vendor);
+       efi.runtime = systab->runtime;
+       efi.runtime_version = systab->hdr.revision;
 
-       table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
-       config_tables = early_memremap_ro(efi_to_phys(efi.systab->tables),
+       efi_systab_report_header(&systab->hdr, efi_to_phys(systab->fw_vendor));
+
+       table_size = sizeof(efi_config_table_t) * systab->nr_tables;
+       config_tables = early_memremap_ro(efi_to_phys(systab->tables),
                                          table_size);
        if (config_tables == NULL) {
                pr_warn("Unable to map EFI config table array.\n");
                retval = -ENOMEM;
                goto out;
        }
-       retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
-                                        sizeof(efi_config_table_t),
+       retval = efi_config_parse_tables(config_tables, systab->nr_tables,
                                         arch_tables);
 
-       if (!retval)
-               efi.config_table = (unsigned long)efi.systab->tables;
-
        early_memunmap(config_tables, table_size);
 out:
-       early_memunmap(efi.systab,  sizeof(efi_system_table_t));
+       early_memunmap(systab, sizeof(efi_system_table_t));
        return retval;
 }
 
@@ -233,19 +205,13 @@ static __init void reserve_regions(void)
 void __init efi_init(void)
 {
        struct efi_memory_map_data data;
-       struct efi_fdt_params params;
+       u64 efi_system_table;
 
        /* Grab UEFI information placed in FDT by stub */
-       if (!efi_get_fdt_params(&params))
+       efi_system_table = efi_get_fdt_params(&data);
+       if (!efi_system_table)
                return;
 
-       efi_system_table = params.system_table;
-
-       data.desc_version = params.desc_ver;
-       data.desc_size = params.desc_size;
-       data.size = params.mmap_size;
-       data.phys_map = params.mmap;
-
        if (efi_memmap_init_early(&data) < 0) {
                /*
                * If we are booting via UEFI, the UEFI memory map is the only
@@ -259,7 +225,7 @@ void __init efi_init(void)
             "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
              efi.memmap.desc_version);
 
-       if (uefi_init() < 0) {
+       if (uefi_init(efi_system_table) < 0) {
                efi_memmap_unmap();
                return;
        }
@@ -267,9 +233,8 @@ void __init efi_init(void)
        reserve_regions();
        efi_esrt_init();
 
-       memblock_reserve(params.mmap & PAGE_MASK,
-                        PAGE_ALIGN(params.mmap_size +
-                                   (params.mmap & ~PAGE_MASK)));
+       memblock_reserve(data.phys_map & PAGE_MASK,
+                        PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
 
        init_screen_info();
 
index 9dda260..b876373 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 
-extern u64 efi_system_table;
-
 #if defined(CONFIG_PTDUMP_DEBUGFS) && defined(CONFIG_ARM64)
 #include <asm/ptdump.h>
 
@@ -54,13 +52,11 @@ device_initcall(ptdump_init);
 static bool __init efi_virtmap_init(void)
 {
        efi_memory_desc_t *md;
-       bool systab_found;
 
        efi_mm.pgd = pgd_alloc(&efi_mm);
        mm_init_cpumask(&efi_mm);
        init_new_context(NULL, &efi_mm);
 
-       systab_found = false;
        for_each_efi_memory_desc(md) {
                phys_addr_t phys = md->phys_addr;
                int ret;
@@ -76,20 +72,6 @@ static bool __init efi_virtmap_init(void)
                                &phys, ret);
                        return false;
                }
-               /*
-                * If this entry covers the address of the UEFI system table,
-                * calculate and record its virtual address.
-                */
-               if (efi_system_table >= phys &&
-                   efi_system_table < phys + (md->num_pages * EFI_PAGE_SIZE)) {
-                       efi.systab = (void *)(unsigned long)(efi_system_table -
-                                                            phys + md->virt_addr);
-                       systab_found = true;
-               }
-       }
-       if (!systab_found) {
-               pr_err("No virtual mapping found for the UEFI System Table\n");
-               return false;
        }
 
        if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
index d3067cb..4dde8ed 100644 (file)
@@ -168,7 +168,7 @@ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info)
 static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
                                 size_t count, loff_t *offp)
 {
-       int ret = 0;
+       int ret;
        struct capsule_info *cap_info = file->private_data;
        struct page *page;
        void *kbuff = NULL;
index 2012338..5c9625e 100644 (file)
@@ -31,13 +31,13 @@ static int __init match_acpi_dev(struct device *dev, const void *data)
                return !strcmp("0", hid_uid.uid);
 }
 
-static long __init parse_acpi_path(struct efi_dev_path *node,
+static long __init parse_acpi_path(const struct efi_dev_path *node,
                                   struct device *parent, struct device **child)
 {
        struct acpi_hid_uid hid_uid = {};
        struct device *phys_dev;
 
-       if (node->length != 12)
+       if (node->header.length != 12)
                return -EINVAL;
 
        sprintf(hid_uid.hid[0].id, "%c%c%c%04X",
@@ -69,12 +69,12 @@ static int __init match_pci_dev(struct device *dev, void *data)
        return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn;
 }
 
-static long __init parse_pci_path(struct efi_dev_path *node,
+static long __init parse_pci_path(const struct efi_dev_path *node,
                                  struct device *parent, struct device **child)
 {
        unsigned int devfn;
 
-       if (node->length != 6)
+       if (node->header.length != 6)
                return -EINVAL;
        if (!parent)
                return -EINVAL;
@@ -105,19 +105,19 @@ static long __init parse_pci_path(struct efi_dev_path *node,
  * search for a device.
  */
 
-static long __init parse_end_path(struct efi_dev_path *node,
+static long __init parse_end_path(const struct efi_dev_path *node,
                                  struct device *parent, struct device **child)
 {
-       if (node->length != 4)
+       if (node->header.length != 4)
                return -EINVAL;
-       if (node->sub_type != EFI_DEV_END_INSTANCE &&
-           node->sub_type != EFI_DEV_END_ENTIRE)
+       if (node->header.sub_type != EFI_DEV_END_INSTANCE &&
+           node->header.sub_type != EFI_DEV_END_ENTIRE)
                return -EINVAL;
        if (!parent)
                return -ENODEV;
 
        *child = get_device(parent);
-       return node->sub_type;
+       return node->header.sub_type;
 }
 
 /**
@@ -156,7 +156,7 @@ static long __init parse_end_path(struct efi_dev_path *node,
  *     %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len,
  *     %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented.
  */
-struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
+struct device * __init efi_get_device_by_path(const struct efi_dev_path **node,
                                              size_t *len)
 {
        struct device *parent = NULL, *child;
@@ -166,16 +166,16 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
                return NULL;
 
        while (!ret) {
-               if (*len < 4 || *len < (*node)->length)
+               if (*len < 4 || *len < (*node)->header.length)
                        ret = -EINVAL;
-               else if ((*node)->type     == EFI_DEV_ACPI &&
-                        (*node)->sub_type == EFI_DEV_BASIC_ACPI)
+               else if ((*node)->header.type           == EFI_DEV_ACPI &&
+                        (*node)->header.sub_type       == EFI_DEV_BASIC_ACPI)
                        ret = parse_acpi_path(*node, parent, &child);
-               else if ((*node)->type     == EFI_DEV_HW &&
-                        (*node)->sub_type == EFI_DEV_PCI)
+               else if ((*node)->header.type           == EFI_DEV_HW &&
+                        (*node)->header.sub_type       == EFI_DEV_PCI)
                        ret = parse_pci_path(*node, parent, &child);
-               else if (((*node)->type    == EFI_DEV_END_PATH ||
-                         (*node)->type    == EFI_DEV_END_PATH2))
+               else if (((*node)->header.type          == EFI_DEV_END_PATH ||
+                         (*node)->header.type          == EFI_DEV_END_PATH2))
                        ret = parse_end_path(*node, parent, &child);
                else
                        ret = -ENOTSUPP;
@@ -185,8 +185,8 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
                        return ERR_PTR(ret);
 
                parent = child;
-               *node  = (void *)*node + (*node)->length;
-               *len  -= (*node)->length;
+               *node  = (void *)*node + (*node)->header.length;
+               *len  -= (*node)->header.length;
        }
 
        if (ret == EFI_DEV_END_ENTIRE)
index b07c176..6aafdb6 100644 (file)
@@ -42,7 +42,12 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
                return;
        }
        *bgrt = *(struct acpi_table_bgrt *)table;
-       if (bgrt->version != 1) {
+       /*
+        * Only version 1 is defined but some older laptops (seen on Lenovo
+        * Ivy Bridge models) have a correct version 1 BGRT table with the
+        * version set to 0, so we accept version 0 and 1.
+        */
+       if (bgrt->version > 1) {
                pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n",
                       bgrt->version);
                goto out;
index 9ea13e8..d2f6855 100644 (file)
@@ -356,7 +356,7 @@ static struct pstore_info efi_pstore_info = {
 
 static __init int efivars_pstore_init(void)
 {
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
                return 0;
 
        if (!efivars_kobject())
index 21ea99f..3f41947 100644 (file)
 #include <linux/kobject.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/efi.h>
 #include <linux/of.h>
-#include <linux/of_fdt.h>
 #include <linux/io.h>
 #include <linux/kexec.h>
 #include <linux/platform_device.h>
 #include <asm/early_ioremap.h>
 
 struct efi __read_mostly efi = {
-       .mps                    = EFI_INVALID_TABLE_ADDR,
+       .runtime_supported_mask = EFI_RT_SUPPORTED_ALL,
        .acpi                   = EFI_INVALID_TABLE_ADDR,
        .acpi20                 = EFI_INVALID_TABLE_ADDR,
        .smbios                 = EFI_INVALID_TABLE_ADDR,
        .smbios3                = EFI_INVALID_TABLE_ADDR,
-       .boot_info              = EFI_INVALID_TABLE_ADDR,
-       .hcdp                   = EFI_INVALID_TABLE_ADDR,
-       .uga                    = EFI_INVALID_TABLE_ADDR,
-       .fw_vendor              = EFI_INVALID_TABLE_ADDR,
-       .runtime                = EFI_INVALID_TABLE_ADDR,
-       .config_table           = EFI_INVALID_TABLE_ADDR,
        .esrt                   = EFI_INVALID_TABLE_ADDR,
-       .properties_table       = EFI_INVALID_TABLE_ADDR,
-       .mem_attr_table         = EFI_INVALID_TABLE_ADDR,
-       .rng_seed               = EFI_INVALID_TABLE_ADDR,
        .tpm_log                = EFI_INVALID_TABLE_ADDR,
        .tpm_final_log          = EFI_INVALID_TABLE_ADDR,
-       .mem_reserve            = EFI_INVALID_TABLE_ADDR,
 };
 EXPORT_SYMBOL(efi);
 
+unsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR;
+static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
+static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
+
 struct mm_struct efi_mm = {
        .mm_rb                  = RB_ROOT,
        .mm_users               = ATOMIC_INIT(2),
@@ -122,8 +116,6 @@ static ssize_t systab_show(struct kobject *kobj,
        if (!kobj || !buf)
                return -EINVAL;
 
-       if (efi.mps != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "MPS=0x%lx\n", efi.mps);
        if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
                str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
        if (efi.acpi != EFI_INVALID_TABLE_ADDR)
@@ -137,30 +129,17 @@ static ssize_t systab_show(struct kobject *kobj,
                str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
        if (efi.smbios != EFI_INVALID_TABLE_ADDR)
                str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
-       if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
-       if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
-       if (efi.uga != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "UGA=0x%lx\n", efi.uga);
-
-       return str - buf;
-}
 
-static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
+       if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86)) {
+               extern char *efi_systab_show_arch(char *str);
 
-#define EFI_FIELD(var) efi.var
+               str = efi_systab_show_arch(str);
+       }
 
-#define EFI_ATTR_SHOW(name) \
-static ssize_t name##_show(struct kobject *kobj, \
-                               struct kobj_attribute *attr, char *buf) \
-{ \
-       return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
+       return str - buf;
 }
 
-EFI_ATTR_SHOW(fw_vendor);
-EFI_ATTR_SHOW(runtime);
-EFI_ATTR_SHOW(config_table);
+static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
 
 static ssize_t fw_platform_size_show(struct kobject *kobj,
                                     struct kobj_attribute *attr, char *buf)
@@ -168,36 +147,24 @@ static ssize_t fw_platform_size_show(struct kobject *kobj,
        return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
 }
 
-static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
-static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
-static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
+extern __weak struct kobj_attribute efi_attr_fw_vendor;
+extern __weak struct kobj_attribute efi_attr_runtime;
+extern __weak struct kobj_attribute efi_attr_config_table;
 static struct kobj_attribute efi_attr_fw_platform_size =
        __ATTR_RO(fw_platform_size);
 
 static struct attribute *efi_subsys_attrs[] = {
        &efi_attr_systab.attr,
+       &efi_attr_fw_platform_size.attr,
        &efi_attr_fw_vendor.attr,
        &efi_attr_runtime.attr,
        &efi_attr_config_table.attr,
-       &efi_attr_fw_platform_size.attr,
        NULL,
 };
 
-static umode_t efi_attr_is_visible(struct kobject *kobj,
-                                  struct attribute *attr, int n)
+umode_t __weak efi_attr_is_visible(struct kobject *kobj, struct attribute *attr,
+                                  int n)
 {
-       if (attr == &efi_attr_fw_vendor.attr) {
-               if (efi_enabled(EFI_PARAVIRT) ||
-                               efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
-                       return 0;
-       } else if (attr == &efi_attr_runtime.attr) {
-               if (efi.runtime == EFI_INVALID_TABLE_ADDR)
-                       return 0;
-       } else if (attr == &efi_attr_config_table.attr) {
-               if (efi.config_table == EFI_INVALID_TABLE_ADDR)
-                       return 0;
-       }
-
        return attr->mode;
 }
 
@@ -325,6 +292,59 @@ free_entry:
 static inline int efivar_ssdt_load(void) { return 0; }
 #endif
 
+#ifdef CONFIG_DEBUG_FS
+
+#define EFI_DEBUGFS_MAX_BLOBS 32
+
+static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS];
+
+static void __init efi_debugfs_init(void)
+{
+       struct dentry *efi_debugfs;
+       efi_memory_desc_t *md;
+       char name[32];
+       int type_count[EFI_BOOT_SERVICES_DATA + 1] = {};
+       int i = 0;
+
+       efi_debugfs = debugfs_create_dir("efi", NULL);
+       if (IS_ERR_OR_NULL(efi_debugfs))
+               return;
+
+       for_each_efi_memory_desc(md) {
+               switch (md->type) {
+               case EFI_BOOT_SERVICES_CODE:
+                       snprintf(name, sizeof(name), "boot_services_code%d",
+                                type_count[md->type]++);
+                       break;
+               case EFI_BOOT_SERVICES_DATA:
+                       snprintf(name, sizeof(name), "boot_services_data%d",
+                                type_count[md->type]++);
+                       break;
+               default:
+                       continue;
+               }
+
+               if (i >= EFI_DEBUGFS_MAX_BLOBS) {
+                       pr_warn("More then %d EFI boot service segments, only showing first %d in debugfs\n",
+                               EFI_DEBUGFS_MAX_BLOBS, EFI_DEBUGFS_MAX_BLOBS);
+                       break;
+               }
+
+               debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT;
+               debugfs_blob[i].data = memremap(md->phys_addr,
+                                               debugfs_blob[i].size,
+                                               MEMREMAP_WB);
+               if (!debugfs_blob[i].data)
+                       continue;
+
+               debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]);
+               i++;
+       }
+}
+#else
+static inline void efi_debugfs_init(void) {}
+#endif
+
 /*
  * We register the efi subsystem with the firmware subsystem and the
  * efivars subsystem with the efi subsystem, if the system was booted with
@@ -334,21 +354,30 @@ static int __init efisubsys_init(void)
 {
        int error;
 
+       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+               efi.runtime_supported_mask = 0;
+
        if (!efi_enabled(EFI_BOOT))
                return 0;
 
-       /*
-        * Since we process only one efi_runtime_service() at a time, an
-        * ordered workqueue (which creates only one execution context)
-        * should suffice all our needs.
-        */
-       efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
-       if (!efi_rts_wq) {
-               pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
-               clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-               return 0;
+       if (efi.runtime_supported_mask) {
+               /*
+                * Since we process only one efi_runtime_service() at a time, an
+                * ordered workqueue (which creates only one execution context)
+                * should suffice for all our needs.
+                */
+               efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
+               if (!efi_rts_wq) {
+                       pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
+                       clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+                       efi.runtime_supported_mask = 0;
+                       return 0;
+               }
        }
 
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_TIME_SERVICES))
+               platform_device_register_simple("rtc-efi", 0, NULL, 0);
+
        /* We register the efi directory at /sys/firmware/efi */
        efi_kobj = kobject_create_and_add("efi", firmware_kobj);
        if (!efi_kobj) {
@@ -356,12 +385,13 @@ static int __init efisubsys_init(void)
                return -ENOMEM;
        }
 
-       error = generic_ops_register();
-       if (error)
-               goto err_put;
-
-       if (efi_enabled(EFI_RUNTIME_SERVICES))
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES)) {
                efivar_ssdt_load();
+               error = generic_ops_register();
+               if (error)
+                       goto err_put;
+               platform_device_register_simple("efivars", 0, NULL, 0);
+       }
 
        error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
        if (error) {
@@ -381,12 +411,16 @@ static int __init efisubsys_init(void)
                goto err_remove_group;
        }
 
+       if (efi_enabled(EFI_DBG) && efi_enabled(EFI_PRESERVE_BS_REGIONS))
+               efi_debugfs_init();
+
        return 0;
 
 err_remove_group:
        sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
 err_unregister:
-       generic_ops_unregister();
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
+               generic_ops_unregister();
 err_put:
        kobject_put(efi_kobj);
        return error;
@@ -467,30 +501,27 @@ void __init efi_mem_reserve(phys_addr_t addr, u64 size)
        efi_arch_mem_reserve(addr, size);
 }
 
-static __initdata efi_config_table_type_t common_tables[] = {
+static const efi_config_table_type_t common_tables[] __initconst = {
        {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
        {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
-       {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
-       {MPS_TABLE_GUID, "MPS", &efi.mps},
        {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
        {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
-       {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
        {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
-       {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
-       {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
-       {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
+       {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi_mem_attr_table},
+       {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi_rng_seed},
        {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
        {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
-       {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
+       {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &mem_reserve},
+       {EFI_RT_PROPERTIES_TABLE_GUID, "RTPROP", &rt_prop},
 #ifdef CONFIG_EFI_RCI2_TABLE
        {DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys},
 #endif
        {NULL_GUID, NULL, NULL},
 };
 
-static __init int match_config_table(efi_guid_t *guid,
+static __init int match_config_table(const efi_guid_t *guid,
                                     unsigned long table,
-                                    efi_config_table_type_t *table_types)
+                                    const efi_config_table_type_t *table_types)
 {
        int i;
 
@@ -509,48 +540,47 @@ static __init int match_config_table(efi_guid_t *guid,
        return 0;
 }
 
-int __init efi_config_parse_tables(void *config_tables, int count, int sz,
-                                  efi_config_table_type_t *arch_tables)
+int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
+                                  int count,
+                                  const efi_config_table_type_t *arch_tables)
 {
-       void *tablep;
+       const efi_config_table_64_t *tbl64 = (void *)config_tables;
+       const efi_config_table_32_t *tbl32 = (void *)config_tables;
+       const efi_guid_t *guid;
+       unsigned long table;
        int i;
 
-       tablep = config_tables;
        pr_info("");
        for (i = 0; i < count; 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;
-#ifndef CONFIG_64BIT
-                       if (table64 >> 32) {
+               if (!IS_ENABLED(CONFIG_X86)) {
+                       guid = &config_tables[i].guid;
+                       table = (unsigned long)config_tables[i].table;
+               } else if (efi_enabled(EFI_64BIT)) {
+                       guid = &tbl64[i].guid;
+                       table = tbl64[i].table;
+
+                       if (IS_ENABLED(CONFIG_X86_32) &&
+                           tbl64[i].table > U32_MAX) {
                                pr_cont("\n");
                                pr_err("Table located above 4GB, disabling EFI.\n");
                                return -EINVAL;
                        }
-#endif
                } else {
-                       guid = ((efi_config_table_32_t *)tablep)->guid;
-                       table = ((efi_config_table_32_t *)tablep)->table;
+                       guid = &tbl32[i].guid;
+                       table = tbl32[i].table;
                }
 
-               if (!match_config_table(&guid, table, common_tables))
-                       match_config_table(&guid, table, arch_tables);
-
-               tablep += sz;
+               if (!match_config_table(guid, table, common_tables))
+                       match_config_table(guid, table, arch_tables);
        }
        pr_cont("\n");
        set_bit(EFI_CONFIG_TABLES, &efi.flags);
 
-       if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
+       if (efi_rng_seed != EFI_INVALID_TABLE_ADDR) {
                struct linux_efi_random_seed *seed;
                u32 size = 0;
 
-               seed = early_memremap(efi.rng_seed, sizeof(*seed));
+               seed = early_memremap(efi_rng_seed, sizeof(*seed));
                if (seed != NULL) {
                        size = READ_ONCE(seed->size);
                        early_memunmap(seed, sizeof(*seed));
@@ -558,7 +588,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
                        pr_err("Could not map UEFI random seed!\n");
                }
                if (size > 0) {
-                       seed = early_memremap(efi.rng_seed,
+                       seed = early_memremap(efi_rng_seed,
                                              sizeof(*seed) + size);
                        if (seed != NULL) {
                                pr_notice("seeding entropy pool\n");
@@ -575,30 +605,12 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
 
        efi_tpm_eventlog_init();
 
-       /* Parse the EFI Properties table if it exists */
-       if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
-               efi_properties_table_t *tbl;
-
-               tbl = early_memremap(efi.properties_table, sizeof(*tbl));
-               if (tbl == NULL) {
-                       pr_err("Could not map Properties table!\n");
-                       return -ENOMEM;
-               }
-
-               if (tbl->memory_protection_attribute &
-                   EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
-                       set_bit(EFI_NX_PE_DATA, &efi.flags);
-
-               early_memunmap(tbl, sizeof(*tbl));
-       }
-
-       if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) {
-               unsigned long prsv = efi.mem_reserve;
+       if (mem_reserve != EFI_INVALID_TABLE_ADDR) {
+               unsigned long prsv = mem_reserve;
 
                while (prsv) {
                        struct linux_efi_memreserve *rsv;
                        u8 *p;
-                       int i;
 
                        /*
                         * Just map a full page: that is what we will get
@@ -627,186 +639,78 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
                }
        }
 
-       return 0;
-}
-
-int __init efi_config_init(efi_config_table_type_t *arch_tables)
-{
-       void *config_tables;
-       int sz, ret;
-
-       if (efi.systab->nr_tables == 0)
-               return 0;
-
-       if (efi_enabled(EFI_64BIT))
-               sz = sizeof(efi_config_table_64_t);
-       else
-               sz = sizeof(efi_config_table_32_t);
+       if (rt_prop != EFI_INVALID_TABLE_ADDR) {
+               efi_rt_properties_table_t *tbl;
 
-       /*
-        * Let's see what config tables the firmware passed to us.
-        */
-       config_tables = early_memremap(efi.systab->tables,
-                                      efi.systab->nr_tables * sz);
-       if (config_tables == NULL) {
-               pr_err("Could not map Configuration table!\n");
-               return -ENOMEM;
+               tbl = early_memremap(rt_prop, sizeof(*tbl));
+               if (tbl) {
+                       efi.runtime_supported_mask &= tbl->runtime_services_supported;
+                       early_memunmap(tbl, sizeof(*tbl));
+               }
        }
 
-       ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
-                                     arch_tables);
-
-       early_memunmap(config_tables, efi.systab->nr_tables * sz);
-       return ret;
+       return 0;
 }
 
-#ifdef CONFIG_EFI_VARS_MODULE
-static int __init efi_load_efivars(void)
+int __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr,
+                                  int min_major_version)
 {
-       struct platform_device *pdev;
-
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
-               return 0;
-
-       pdev = platform_device_register_simple("efivars", 0, NULL, 0);
-       return PTR_ERR_OR_ZERO(pdev);
-}
-device_initcall(efi_load_efivars);
-#endif
-
-#ifdef CONFIG_EFI_PARAMS_FROM_FDT
-
-#define UEFI_PARAM(name, prop, field)                     \
-       {                                                  \
-               { name },                                  \
-               { prop },                                  \
-               offsetof(struct efi_fdt_params, field),    \
-               sizeof_field(struct efi_fdt_params, field) \
+       if (systab_hdr->signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+               pr_err("System table signature incorrect!\n");
+               return -EINVAL;
        }
 
-struct params {
-       const char name[32];
-       const char propname[32];
-       int offset;
-       int size;
-};
-
-static __initdata struct params fdt_params[] = {
-       UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
-       UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
-       UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
-       UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
-       UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
-};
+       if ((systab_hdr->revision >> 16) < min_major_version)
+               pr_err("Warning: System table version %d.%02d, expected %d.00 or greater!\n",
+                      systab_hdr->revision >> 16,
+                      systab_hdr->revision & 0xffff,
+                      min_major_version);
 
-static __initdata struct params xen_fdt_params[] = {
-       UEFI_PARAM("System Table", "xen,uefi-system-table", system_table),
-       UEFI_PARAM("MemMap Address", "xen,uefi-mmap-start", mmap),
-       UEFI_PARAM("MemMap Size", "xen,uefi-mmap-size", mmap_size),
-       UEFI_PARAM("MemMap Desc. Size", "xen,uefi-mmap-desc-size", desc_size),
-       UEFI_PARAM("MemMap Desc. Version", "xen,uefi-mmap-desc-ver", desc_ver)
-};
-
-#define EFI_FDT_PARAMS_SIZE    ARRAY_SIZE(fdt_params)
-
-static __initdata struct {
-       const char *uname;
-       const char *subnode;
-       struct params *params;
-} dt_params[] = {
-       { "hypervisor", "uefi", xen_fdt_params },
-       { "chosen", NULL, fdt_params },
-};
-
-struct param_info {
-       int found;
-       void *params;
-       const char *missing;
-};
+       return 0;
+}
 
-static int __init __find_uefi_params(unsigned long node,
-                                    struct param_info *info,
-                                    struct params *params)
+#ifndef CONFIG_IA64
+static const efi_char16_t *__init map_fw_vendor(unsigned long fw_vendor,
+                                               size_t size)
 {
-       const void *prop;
-       void *dest;
-       u64 val;
-       int i, len;
-
-       for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) {
-               prop = of_get_flat_dt_prop(node, params[i].propname, &len);
-               if (!prop) {
-                       info->missing = params[i].name;
-                       return 0;
-               }
+       const efi_char16_t *ret;
 
-               dest = info->params + params[i].offset;
-               info->found++;
-
-               val = of_read_number(prop, len / sizeof(u32));
-
-               if (params[i].size == sizeof(u32))
-                       *(u32 *)dest = val;
-               else
-                       *(u64 *)dest = val;
-
-               if (efi_enabled(EFI_DBG))
-                       pr_info("  %s: 0x%0*llx\n", params[i].name,
-                               params[i].size * 2, val);
-       }
-
-       return 1;
+       ret = early_memremap_ro(fw_vendor, size);
+       if (!ret)
+               pr_err("Could not map the firmware vendor!\n");
+       return ret;
 }
 
-static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
-                                      int depth, void *data)
+static void __init unmap_fw_vendor(const void *fw_vendor, size_t size)
 {
-       struct param_info *info = data;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
-               const char *subnode = dt_params[i].subnode;
-
-               if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) {
-                       info->missing = dt_params[i].params[0].name;
-                       continue;
-               }
-
-               if (subnode) {
-                       int err = of_get_flat_dt_subnode_by_name(node, subnode);
-
-                       if (err < 0)
-                               return 0;
-
-                       node = err;
-               }
-
-               return __find_uefi_params(node, info, dt_params[i].params);
-       }
-
-       return 0;
+       early_memunmap((void *)fw_vendor, size);
 }
+#else
+#define map_fw_vendor(p, s)    __va(p)
+#define unmap_fw_vendor(v, s)
+#endif
 
-int __init efi_get_fdt_params(struct efi_fdt_params *params)
+void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
+                                    unsigned long fw_vendor)
 {
-       struct param_info info;
-       int ret;
+       char vendor[100] = "unknown";
+       const efi_char16_t *c16;
+       size_t i;
 
-       pr_info("Getting EFI parameters from FDT:\n");
+       c16 = map_fw_vendor(fw_vendor, sizeof(vendor) * sizeof(efi_char16_t));
+       if (c16) {
+               for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
+                       vendor[i] = c16[i];
+               vendor[i] = '\0';
 
-       info.found = 0;
-       info.params = params;
-
-       ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
-       if (!info.found)
-               pr_info("UEFI not found.\n");
-       else if (!ret)
-               pr_err("Can't find '%s' in device tree!\n",
-                      info.missing);
+               unmap_fw_vendor(c16, sizeof(vendor) * sizeof(efi_char16_t));
+       }
 
-       return ret;
+       pr_info("EFI v%u.%.02u by %s\n",
+               systab_hdr->revision >> 16,
+               systab_hdr->revision & 0xffff,
+               vendor);
 }
-#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
 
 static __initdata char memory_type_name[][20] = {
        "Reserved",
@@ -968,10 +872,10 @@ static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
 
 static int __init efi_memreserve_map_root(void)
 {
-       if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR)
+       if (mem_reserve == EFI_INVALID_TABLE_ADDR)
                return -ENODEV;
 
-       efi_memreserve_root = memremap(efi.mem_reserve,
+       efi_memreserve_root = memremap(mem_reserve,
                                       sizeof(*efi_memreserve_root),
                                       MEMREMAP_WB);
        if (WARN_ON_ONCE(!efi_memreserve_root))
@@ -1076,7 +980,7 @@ static int update_efi_random_seed(struct notifier_block *nb,
        if (!kexec_in_progress)
                return NOTIFY_DONE;
 
-       seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB);
+       seed = memremap(efi_rng_seed, sizeof(*seed), MEMREMAP_WB);
        if (seed != NULL) {
                size = min(seed->size, EFI_RANDOM_SEED_SIZE);
                memunmap(seed);
@@ -1084,7 +988,7 @@ static int update_efi_random_seed(struct notifier_block *nb,
                pr_err("Could not map UEFI random seed!\n");
        }
        if (size > 0) {
-               seed = memremap(efi.rng_seed, sizeof(*seed) + size,
+               seed = memremap(efi_rng_seed, sizeof(*seed) + size,
                                MEMREMAP_WB);
                if (seed != NULL) {
                        seed->size = size;
@@ -1101,9 +1005,9 @@ static struct notifier_block efi_random_seed_nb = {
        .notifier_call = update_efi_random_seed,
 };
 
-static int register_update_efi_random_seed(void)
+static int __init register_update_efi_random_seed(void)
 {
-       if (efi.rng_seed == EFI_INVALID_TABLE_ADDR)
+       if (efi_rng_seed == EFI_INVALID_TABLE_ADDR)
                return 0;
        return register_reboot_notifier(&efi_random_seed_nb);
 }
index aff3dfb..78ad1ba 100644 (file)
@@ -678,7 +678,7 @@ int efivars_sysfs_init(void)
        struct kobject *parent_kobj = efivars_kobject();
        int error = 0;
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
                return -ENODEV;
 
        /* No efivars has been registered yet */
diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c
new file mode 100644 (file)
index 0000000..1bc9cda
--- /dev/null
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for extracting embedded firmware for peripherals from EFI code,
+ *
+ * Copyright (c) 2018 Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/dmi.h>
+#include <linux/efi.h>
+#include <linux/efi_embedded_fw.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <crypto/sha.h>
+
+/* Exported for use by lib/test_firmware.c only */
+LIST_HEAD(efi_embedded_fw_list);
+EXPORT_SYMBOL_GPL(efi_embedded_fw_list);
+
+static bool checked_for_fw;
+
+static const struct dmi_system_id * const embedded_fw_table[] = {
+       NULL
+};
+
+/*
+ * Note the efi_check_for_embedded_firmwares() code currently makes the
+ * following 2 assumptions. This may needs to be revisited if embedded firmware
+ * is found where this is not true:
+ * 1) The firmware is only found in EFI_BOOT_SERVICES_CODE memory segments
+ * 2) The firmware always starts at an offset which is a multiple of 8 bytes
+ */
+static int __init efi_check_md_for_embedded_firmware(
+       efi_memory_desc_t *md, const struct efi_embedded_fw_desc *desc)
+{
+       struct sha256_state sctx;
+       struct efi_embedded_fw *fw;
+       u8 sha256[32];
+       u64 i, size;
+       u8 *map;
+
+       size = md->num_pages << EFI_PAGE_SHIFT;
+       map = memremap(md->phys_addr, size, MEMREMAP_WB);
+       if (!map) {
+               pr_err("Error mapping EFI mem at %#llx\n", md->phys_addr);
+               return -ENOMEM;
+       }
+
+       for (i = 0; (i + desc->length) <= size; i += 8) {
+               if (memcmp(map + i, desc->prefix, EFI_EMBEDDED_FW_PREFIX_LEN))
+                       continue;
+
+               sha256_init(&sctx);
+               sha256_update(&sctx, map + i, desc->length);
+               sha256_final(&sctx, sha256);
+               if (memcmp(sha256, desc->sha256, 32) == 0)
+                       break;
+       }
+       if ((i + desc->length) > size) {
+               memunmap(map);
+               return -ENOENT;
+       }
+
+       pr_info("Found EFI embedded fw '%s'\n", desc->name);
+
+       fw = kmalloc(sizeof(*fw), GFP_KERNEL);
+       if (!fw) {
+               memunmap(map);
+               return -ENOMEM;
+       }
+
+       fw->data = kmemdup(map + i, desc->length, GFP_KERNEL);
+       memunmap(map);
+       if (!fw->data) {
+               kfree(fw);
+               return -ENOMEM;
+       }
+
+       fw->name = desc->name;
+       fw->length = desc->length;
+       list_add(&fw->list, &efi_embedded_fw_list);
+
+       return 0;
+}
+
+void __init efi_check_for_embedded_firmwares(void)
+{
+       const struct efi_embedded_fw_desc *fw_desc;
+       const struct dmi_system_id *dmi_id;
+       efi_memory_desc_t *md;
+       int i, r;
+
+       for (i = 0; embedded_fw_table[i]; i++) {
+               dmi_id = dmi_first_match(embedded_fw_table[i]);
+               if (!dmi_id)
+                       continue;
+
+               fw_desc = dmi_id->driver_data;
+
+               /*
+                * In some drivers the struct driver_data contains may contain
+                * other driver specific data after the fw_desc struct; and
+                * the fw_desc struct itself may be empty, skip these.
+                */
+               if (!fw_desc->name)
+                       continue;
+
+               for_each_efi_memory_desc(md) {
+                       if (md->type != EFI_BOOT_SERVICES_CODE)
+                               continue;
+
+                       r = efi_check_md_for_embedded_firmware(md, fw_desc);
+                       if (r == 0)
+                               break;
+               }
+       }
+
+       checked_for_fw = true;
+}
+
+int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size)
+{
+       struct efi_embedded_fw *iter, *fw = NULL;
+
+       if (!checked_for_fw) {
+               pr_warn("Warning %s called while we did not check for embedded fw\n",
+                       __func__);
+               return -ENOENT;
+       }
+
+       list_for_each_entry(iter, &efi_embedded_fw_list, list) {
+               if (strcmp(name, iter->name) == 0) {
+                       fw = iter;
+                       break;
+               }
+       }
+
+       if (!fw)
+               return -ENOENT;
+
+       *data = fw->data;
+       *size = fw->length;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(efi_get_embedded_fw);
index 2762e06..e3d6926 100644 (file)
@@ -240,7 +240,6 @@ void __init efi_esrt_init(void)
 {
        void *va;
        struct efi_system_resource_table tmpesrt;
-       struct efi_system_resource_entry_v1 *v1_entries;
        size_t size, max, entry_size, entries_size;
        efi_memory_desc_t md;
        int rc;
@@ -288,14 +287,13 @@ void __init efi_esrt_init(void)
        memcpy(&tmpesrt, va, sizeof(tmpesrt));
        early_memunmap(va, size);
 
-       if (tmpesrt.fw_resource_version == 1) {
-               entry_size = sizeof (*v1_entries);
-       } else {
+       if (tmpesrt.fw_resource_version != 1) {
                pr_err("Unsupported ESRT version %lld.\n",
                       tmpesrt.fw_resource_version);
                return;
        }
 
+       entry_size = sizeof(struct efi_system_resource_entry_v1);
        if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) {
                pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n",
                       max - size, entry_size);
diff --git a/drivers/firmware/efi/fdtparams.c b/drivers/firmware/efi/fdtparams.c
new file mode 100644 (file)
index 0000000..bb042ab
--- /dev/null
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "efi: " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/efi.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+
+#include <asm/unaligned.h>
+
+enum {
+       SYSTAB,
+       MMBASE,
+       MMSIZE,
+       DCSIZE,
+       DCVERS,
+
+       PARAMCOUNT
+};
+
+static __initconst const char name[][22] = {
+       [SYSTAB] = "System Table         ",
+       [MMBASE] = "MemMap Address       ",
+       [MMSIZE] = "MemMap Size          ",
+       [DCSIZE] = "MemMap Desc. Size    ",
+       [DCVERS] = "MemMap Desc. Version ",
+};
+
+static __initconst const struct {
+       const char      path[17];
+       const char      params[PARAMCOUNT][26];
+} dt_params[] = {
+       {
+#ifdef CONFIG_XEN    //  <-------17------>
+               .path = "/hypervisor/uefi",
+               .params = {
+                       [SYSTAB] = "xen,uefi-system-table",
+                       [MMBASE] = "xen,uefi-mmap-start",
+                       [MMSIZE] = "xen,uefi-mmap-size",
+                       [DCSIZE] = "xen,uefi-mmap-desc-size",
+                       [DCVERS] = "xen,uefi-mmap-desc-ver",
+               }
+       }, {
+#endif
+               .path = "/chosen",
+               .params = {     //  <-----------26----------->
+                       [SYSTAB] = "linux,uefi-system-table",
+                       [MMBASE] = "linux,uefi-mmap-start",
+                       [MMSIZE] = "linux,uefi-mmap-size",
+                       [DCSIZE] = "linux,uefi-mmap-desc-size",
+                       [DCVERS] = "linux,uefi-mmap-desc-ver",
+               }
+       }
+};
+
+static int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
+                                  const char *rname, void *var, int size)
+{
+       const void *prop;
+       int len;
+       u64 val;
+
+       prop = fdt_getprop(fdt, node, pname, &len);
+       if (!prop)
+               return 1;
+
+       val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
+
+       if (size == 8)
+               *(u64 *)var = val;
+       else
+               *(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate
+
+       if (efi_enabled(EFI_DBG))
+               pr_info("  %s: 0x%0*llx\n", rname, size * 2, val);
+
+       return 0;
+}
+
+u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
+{
+       const void *fdt = initial_boot_params;
+       unsigned long systab;
+       int i, j, node;
+       struct {
+               void    *var;
+               int     size;
+       } target[] = {
+               [SYSTAB] = { &systab,           sizeof(systab) },
+               [MMBASE] = { &mm->phys_map,     sizeof(mm->phys_map) },
+               [MMSIZE] = { &mm->size,         sizeof(mm->size) },
+               [DCSIZE] = { &mm->desc_size,    sizeof(mm->desc_size) },
+               [DCVERS] = { &mm->desc_version, sizeof(mm->desc_version) },
+       };
+
+       BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
+       BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
+
+       for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
+               node = fdt_path_offset(fdt, dt_params[i].path);
+               if (node < 0)
+                       continue;
+
+               if (efi_enabled(EFI_DBG))
+                       pr_info("Getting UEFI parameters from %s in DT:\n",
+                               dt_params[i].path);
+
+               for (j = 0; j < ARRAY_SIZE(target); j++) {
+                       const char *pname = dt_params[i].params[j];
+
+                       if (!efi_get_fdt_prop(fdt, node, pname, name[j],
+                                             target[j].var, target[j].size))
+                               continue;
+                       if (!j)
+                               goto notfound;
+                       pr_err("Can't find property '%s' in DT!\n", pname);
+                       return 0;
+               }
+               return systab;
+       }
+notfound:
+       pr_info("UEFI not found.\n");
+       return 0;
+}
index 98a8157..4d6246c 100644 (file)
@@ -25,6 +25,7 @@ cflags-$(CONFIG_ARM)          := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
 cflags-$(CONFIG_EFI_ARMSTUB)   += -I$(srctree)/scripts/dtc/libfdt
 
 KBUILD_CFLAGS                  := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
+                                  -include $(srctree)/drivers/firmware/efi/libstub/hidden.h \
                                   -D__NO_FORTIFY \
                                   $(call cc-option,-ffreestanding) \
                                   $(call cc-option,-fno-stack-protector) \
@@ -39,11 +40,11 @@ OBJECT_FILES_NON_STANDARD   := y
 KCOV_INSTRUMENT                        := n
 
 lib-y                          := efi-stub-helper.o gop.o secureboot.o tpm.o \
-                                  random.o pci.o
+                                  file.o mem.o random.o randomalloc.o pci.o \
+                                  skip_spaces.o lib-cmdline.o lib-ctype.o
 
 # include the stub's generic dependencies from lib/ when building for ARM/arm64
 arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
-arm-deps-$(CONFIG_ARM64) += sort.c
 
 $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
        $(call if_changed_rule,cc_o_c)
@@ -53,6 +54,7 @@ lib-$(CONFIG_EFI_ARMSTUB)     += arm-stub.o fdt.o string.o \
 
 lib-$(CONFIG_ARM)              += arm32-stub.o
 lib-$(CONFIG_ARM64)            += arm64-stub.o
+lib-$(CONFIG_X86)              += x86-stub.o
 CFLAGS_arm32-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
 CFLAGS_arm64-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
index 7bbef4a..13559c7 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/efi.h>
-#include <linux/sort.h>
+#include <linux/libfdt.h>
 #include <asm/efi.h>
 
 #include "efistub.h"
@@ -36,6 +36,7 @@
 #endif
 
 static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
+static bool __efistub_global flat_va_mapping;
 
 static efi_system_table_t *__efistub_global sys_table;
 
@@ -87,6 +88,39 @@ void install_memreserve_table(void)
                pr_efi_err("Failed to install memreserve config table!\n");
 }
 
+static unsigned long get_dram_base(void)
+{
+       efi_status_t status;
+       unsigned long map_size, buff_size;
+       unsigned long membase  = EFI_ERROR;
+       struct efi_memory_map map;
+       efi_memory_desc_t *md;
+       struct efi_boot_memmap boot_map;
+
+       boot_map.map            = (efi_memory_desc_t **)&map.map;
+       boot_map.map_size       = &map_size;
+       boot_map.desc_size      = &map.desc_size;
+       boot_map.desc_ver       = NULL;
+       boot_map.key_ptr        = NULL;
+       boot_map.buff_size      = &buff_size;
+
+       status = efi_get_memory_map(&boot_map);
+       if (status != EFI_SUCCESS)
+               return membase;
+
+       map.map_end = map.map + map_size;
+
+       for_each_efi_memory_desc_in_map(&map, md) {
+               if (md->attribute & EFI_MEMORY_WB) {
+                       if (membase > md->phys_addr)
+                               membase = md->phys_addr;
+               }
+       }
+
+       efi_bs_call(free_pool, map.map);
+
+       return membase;
+}
 
 /*
  * This function handles the architcture specific differences between arm and
@@ -100,38 +134,46 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                                 unsigned long *reserve_size,
                                 unsigned long dram_base,
                                 efi_loaded_image_t *image);
+
+asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
+                                           unsigned long fdt_addr,
+                                           unsigned long fdt_size);
+
 /*
  * EFI entry point for the arm/arm64 EFI stubs.  This is the entrypoint
  * that is described in the PE/COFF header.  Most of the code is the same
  * for both archictectures, with the arch-specific code provided in the
  * handle_kernel_image() function.
  */
-unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
-                              unsigned long *image_addr)
+efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
 {
        efi_loaded_image_t *image;
        efi_status_t status;
+       unsigned long image_addr;
        unsigned long image_size = 0;
        unsigned long dram_base;
        /* addr/point and size pairs for memory management*/
-       unsigned long initrd_addr;
-       u64 initrd_size = 0;
+       unsigned long initrd_addr = 0;
+       unsigned long initrd_size = 0;
        unsigned long fdt_addr = 0;  /* Original DTB */
        unsigned long fdt_size = 0;
        char *cmdline_ptr = NULL;
        int cmdline_size = 0;
-       unsigned long new_fdt_addr;
        efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
        unsigned long reserve_addr = 0;
        unsigned long reserve_size = 0;
        enum efi_secureboot_mode secure_boot;
        struct screen_info *si;
+       efi_properties_table_t *prop_tbl;
+       unsigned long max_addr;
 
        sys_table = sys_table_arg;
 
        /* Check if we were booted by the EFI firmware */
-       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+               status = EFI_INVALID_PARAMETER;
                goto fail;
+       }
 
        status = check_platform_features();
        if (status != EFI_SUCCESS)
@@ -152,6 +194,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
        dram_base = get_dram_base();
        if (dram_base == EFI_ERROR) {
                pr_efi_err("Failed to find DRAM base\n");
+               status = EFI_LOAD_ERROR;
                goto fail;
        }
 
@@ -160,9 +203,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
         * protocol. We are going to copy the command line into the
         * device tree, so this can be allocated anywhere.
         */
-       cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
+       cmdline_ptr = efi_convert_cmdline(image, &cmdline_size, ULONG_MAX);
        if (!cmdline_ptr) {
                pr_efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
+               status = EFI_OUT_OF_RESOURCES;
                goto fail;
        }
 
@@ -178,7 +222,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
 
        si = setup_graphics();
 
-       status = handle_kernel_image(image_addr, &image_size,
+       status = handle_kernel_image(&image_addr, &image_size,
                                     &reserve_addr,
                                     &reserve_size,
                                     dram_base, image);
@@ -204,8 +248,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
                if (strstr(cmdline_ptr, "dtb="))
                        pr_efi("Ignoring DTB from command line.\n");
        } else {
-               status = handle_cmdline_files(image, cmdline_ptr, "dtb=",
-                                             ~0UL, &fdt_addr, &fdt_size);
+               status = efi_load_dtb(image, &fdt_addr, &fdt_size);
 
                if (status != EFI_SUCCESS) {
                        pr_efi_err("Failed to load device tree!\n");
@@ -225,18 +268,38 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
        if (!fdt_addr)
                pr_efi("Generating empty DTB\n");
 
-       status = handle_cmdline_files(image, cmdline_ptr, "initrd=",
-                                     efi_get_max_initrd_addr(dram_base,
-                                                             *image_addr),
-                                     (unsigned long *)&initrd_addr,
-                                     (unsigned long *)&initrd_size);
-       if (status != EFI_SUCCESS)
-               pr_efi_err("Failed initrd from command line!\n");
+       if (!noinitrd()) {
+               max_addr = efi_get_max_initrd_addr(dram_base, image_addr);
+               status = efi_load_initrd_dev_path(&initrd_addr, &initrd_size,
+                                                 max_addr);
+               if (status == EFI_SUCCESS) {
+                       pr_efi("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
+               } else if (status == EFI_NOT_FOUND) {
+                       status = efi_load_initrd(image, &initrd_addr, &initrd_size,
+                                                ULONG_MAX, max_addr);
+                       if (status == EFI_SUCCESS)
+                               pr_efi("Loaded initrd from command line option\n");
+               }
+               if (status != EFI_SUCCESS)
+                       pr_efi_err("Failed to load initrd!\n");
+       }
 
        efi_random_get_seed();
 
+       /*
+        * If the NX PE data feature is enabled in the properties table, we
+        * should take care not to create a virtual mapping that changes the
+        * relative placement of runtime services code and data regions, as
+        * they may belong to the same PE/COFF executable image in memory.
+        * The easiest way to achieve that is to simply use a 1:1 mapping.
+        */
+       prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
+       flat_va_mapping = prop_tbl &&
+                         (prop_tbl->memory_protection_attribute &
+                          EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
+
        /* hibernation expects the runtime regions to stay in the same place */
-       if (!IS_ENABLED(CONFIG_HIBERNATION) && !nokaslr()) {
+       if (!IS_ENABLED(CONFIG_HIBERNATION) && !nokaslr() && !flat_va_mapping) {
                /*
                 * Randomize the base of the UEFI runtime services region.
                 * Preserve the 2 MB alignment of the region by taking a
@@ -257,71 +320,30 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
 
        install_memreserve_table();
 
-       new_fdt_addr = fdt_addr;
-       status = allocate_new_fdt_and_exit_boot(handle,
-                               &new_fdt_addr, efi_get_max_fdt_addr(dram_base),
-                               initrd_addr, initrd_size, cmdline_ptr,
-                               fdt_addr, fdt_size);
+       status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
+                                               efi_get_max_fdt_addr(dram_base),
+                                               initrd_addr, initrd_size,
+                                               cmdline_ptr, fdt_addr, fdt_size);
+       if (status != EFI_SUCCESS)
+               goto fail_free_initrd;
 
-       /*
-        * If all went well, we need to return the FDT address to the
-        * calling function so it can be passed to kernel as part of
-        * the kernel boot protocol.
-        */
-       if (status == EFI_SUCCESS)
-               return new_fdt_addr;
+       efi_enter_kernel(image_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
+       /* not reached */
 
+fail_free_initrd:
        pr_efi_err("Failed to update FDT and exit boot services\n");
 
        efi_free(initrd_size, initrd_addr);
        efi_free(fdt_size, fdt_addr);
 
 fail_free_image:
-       efi_free(image_size, *image_addr);
+       efi_free(image_size, image_addr);
        efi_free(reserve_size, reserve_addr);
 fail_free_cmdline:
        free_screen_info(si);
        efi_free(cmdline_size, (unsigned long)cmdline_ptr);
 fail:
-       return EFI_ERROR;
-}
-
-static int cmp_mem_desc(const void *l, const void *r)
-{
-       const efi_memory_desc_t *left = l, *right = r;
-
-       return (left->phys_addr > right->phys_addr) ? 1 : -1;
-}
-
-/*
- * Returns whether region @left ends exactly where region @right starts,
- * or false if either argument is NULL.
- */
-static bool regions_are_adjacent(efi_memory_desc_t *left,
-                                efi_memory_desc_t *right)
-{
-       u64 left_end;
-
-       if (left == NULL || right == NULL)
-               return false;
-
-       left_end = left->phys_addr + left->num_pages * EFI_PAGE_SIZE;
-
-       return left_end == right->phys_addr;
-}
-
-/*
- * Returns whether region @left and region @right have compatible memory type
- * mapping attributes, and are both EFI_MEMORY_RUNTIME regions.
- */
-static bool regions_have_compatible_memory_type_attrs(efi_memory_desc_t *left,
-                                                     efi_memory_desc_t *right)
-{
-       static const u64 mem_type_mask = EFI_MEMORY_WB | EFI_MEMORY_WT |
-                                        EFI_MEMORY_WC | EFI_MEMORY_UC |
-                                        EFI_MEMORY_RUNTIME;
-
-       return ((left->attribute ^ right->attribute) & mem_type_mask) == 0;
+       return status;
 }
 
 /*
@@ -336,23 +358,10 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                     int *count)
 {
        u64 efi_virt_base = virtmap_base;
-       efi_memory_desc_t *in, *prev = NULL, *out = runtime_map;
+       efi_memory_desc_t *in, *out = runtime_map;
        int l;
 
-       /*
-        * To work around potential issues with the Properties Table feature
-        * introduced in UEFI 2.5, which may split PE/COFF executable images
-        * in memory into several RuntimeServicesCode and RuntimeServicesData
-        * regions, we need to preserve the relative offsets between adjacent
-        * EFI_MEMORY_RUNTIME regions with the same memory type attributes.
-        * The easiest way to find adjacent regions is to sort the memory map
-        * before traversing it.
-        */
-       if (IS_ENABLED(CONFIG_ARM64))
-               sort(memory_map, map_size / desc_size, desc_size, cmp_mem_desc,
-                    NULL);
-
-       for (l = 0; l < map_size; l += desc_size, prev = in) {
+       for (l = 0; l < map_size; l += desc_size) {
                u64 paddr, size;
 
                in = (void *)memory_map + l;
@@ -362,8 +371,8 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                paddr = in->phys_addr;
                size = in->num_pages * EFI_PAGE_SIZE;
 
+               in->virt_addr = in->phys_addr;
                if (novamap()) {
-                       in->virt_addr = in->phys_addr;
                        continue;
                }
 
@@ -372,9 +381,7 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                 * a 4k page size kernel to kexec a 64k page size kernel and
                 * vice versa.
                 */
-               if ((IS_ENABLED(CONFIG_ARM64) &&
-                    !regions_are_adjacent(prev, in)) ||
-                   !regions_have_compatible_memory_type_attrs(prev, in)) {
+               if (!flat_va_mapping) {
 
                        paddr = round_down(in->phys_addr, SZ_64K);
                        size += in->phys_addr - paddr;
@@ -389,10 +396,10 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                                efi_virt_base = round_up(efi_virt_base, SZ_2M);
                        else
                                efi_virt_base = round_up(efi_virt_base, SZ_64K);
-               }
 
-               in->virt_addr = efi_virt_base + in->phys_addr - paddr;
-               efi_virt_base += size;
+                       in->virt_addr += efi_virt_base - paddr;
+                       efi_virt_base += size;
+               }
 
                memcpy(out, in, desc_size);
                out = (void *)out + desc_size;
index 7b2a638..7826553 100644 (file)
@@ -227,6 +227,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
         * Relocate the zImage, so that it appears in the lowest 128 MB
         * memory window.
         */
+       *image_addr = (unsigned long)image->image_base;
        *image_size = image->image_size;
        status = efi_relocate_kernel(image_addr, *image_size, *image_size,
                                     kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
index 2915b44..9254cd8 100644 (file)
@@ -6,17 +6,11 @@
  * Adapted from ARM version by Mark Salter <msalter@redhat.com>
  */
 
-/*
- * To prevent the compiler from emitting GOT-indirected (and thus absolute)
- * references to the section markers, override their visibility as 'hidden'
- */
-#pragma GCC visibility push(hidden)
-#include <asm/sections.h>
-#pragma GCC visibility pop
 
 #include <linux/efi.h>
 #include <asm/efi.h>
 #include <asm/memory.h>
+#include <asm/sections.h>
 #include <asm/sysreg.h>
 
 #include "efistub.h"
@@ -49,7 +43,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 {
        efi_status_t status;
        unsigned long kernel_size, kernel_memsize = 0;
-       void *old_image_addr = (void *)*image_addr;
        unsigned long preferred_offset;
        u64 phys_seed = 0;
 
@@ -147,7 +140,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                }
                *image_addr = *reserve_addr + TEXT_OFFSET;
        }
-       memcpy((void *)*image_addr, old_image_addr, kernel_size);
+       memcpy((void *)*image_addr, image->image_base, kernel_size);
 
        return EFI_SUCCESS;
 }
index 74ddfb4..9f34c72 100644 (file)
 
 #include "efistub.h"
 
-/*
- * Some firmware implementations have problems reading files in one go.
- * A read chunk size of 1MB seems to work for most platforms.
- *
- * Unfortunately, reading files in chunks triggers *other* bugs on some
- * platforms, so we provide a way to disable this workaround, which can
- * be done by passing "efi=nochunk" on the EFI boot stub command line.
- *
- * If you experience issues with initrd images being corrupt it's worth
- * trying efi=nochunk, but chunking is enabled by default because there
- * are far more machines that require the workaround than those that
- * break with it enabled.
- */
-#define EFI_READ_CHUNK_SIZE    (1024 * 1024)
-
-static unsigned long efi_chunk_size = EFI_READ_CHUNK_SIZE;
-
+static bool __efistub_global efi_nochunk;
 static bool __efistub_global efi_nokaslr;
+static bool __efistub_global efi_noinitrd;
 static bool __efistub_global efi_quiet;
 static bool __efistub_global efi_novamap;
 static bool __efistub_global efi_nosoftreserve;
 static bool __efistub_global efi_disable_pci_dma =
                                        IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
 
+bool __pure nochunk(void)
+{
+       return efi_nochunk;
+}
 bool __pure nokaslr(void)
 {
        return efi_nokaslr;
 }
+bool __pure noinitrd(void)
+{
+       return efi_noinitrd;
+}
 bool __pure is_quiet(void)
 {
        return efi_quiet;
@@ -53,13 +46,6 @@ bool __pure __efi_soft_reserve_enabled(void)
        return !efi_nosoftreserve;
 }
 
-#define EFI_MMAP_NR_SLACK_SLOTS        8
-
-struct file_info {
-       efi_file_handle_t *handle;
-       u64 size;
-};
-
 void efi_printk(char *str)
 {
        char *s8;
@@ -77,369 +63,6 @@ void efi_printk(char *str)
        }
 }
 
-static inline bool mmap_has_headroom(unsigned long buff_size,
-                                    unsigned long map_size,
-                                    unsigned long desc_size)
-{
-       unsigned long slack = buff_size - map_size;
-
-       return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
-}
-
-efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
-{
-       efi_memory_desc_t *m = NULL;
-       efi_status_t status;
-       unsigned long key;
-       u32 desc_version;
-
-       *map->desc_size =       sizeof(*m);
-       *map->map_size =        *map->desc_size * 32;
-       *map->buff_size =       *map->map_size;
-again:
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
-                            *map->map_size, (void **)&m);
-       if (status != EFI_SUCCESS)
-               goto fail;
-
-       *map->desc_size = 0;
-       key = 0;
-       status = efi_bs_call(get_memory_map, map->map_size, m,
-                            &key, map->desc_size, &desc_version);
-       if (status == EFI_BUFFER_TOO_SMALL ||
-           !mmap_has_headroom(*map->buff_size, *map->map_size,
-                              *map->desc_size)) {
-               efi_bs_call(free_pool, m);
-               /*
-                * Make sure there is some entries of headroom so that the
-                * buffer can be reused for a new map after allocations are
-                * no longer permitted.  Its unlikely that the map will grow to
-                * exceed this headroom once we are ready to trigger
-                * ExitBootServices()
-                */
-               *map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
-               *map->buff_size = *map->map_size;
-               goto again;
-       }
-
-       if (status != EFI_SUCCESS)
-               efi_bs_call(free_pool, m);
-
-       if (map->key_ptr && status == EFI_SUCCESS)
-               *map->key_ptr = key;
-       if (map->desc_ver && status == EFI_SUCCESS)
-               *map->desc_ver = desc_version;
-
-fail:
-       *map->map = m;
-       return status;
-}
-
-
-unsigned long get_dram_base(void)
-{
-       efi_status_t status;
-       unsigned long map_size, buff_size;
-       unsigned long membase  = EFI_ERROR;
-       struct efi_memory_map map;
-       efi_memory_desc_t *md;
-       struct efi_boot_memmap boot_map;
-
-       boot_map.map =          (efi_memory_desc_t **)&map.map;
-       boot_map.map_size =     &map_size;
-       boot_map.desc_size =    &map.desc_size;
-       boot_map.desc_ver =     NULL;
-       boot_map.key_ptr =      NULL;
-       boot_map.buff_size =    &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               return membase;
-
-       map.map_end = map.map + map_size;
-
-       for_each_efi_memory_desc_in_map(&map, md) {
-               if (md->attribute & EFI_MEMORY_WB) {
-                       if (membase > md->phys_addr)
-                               membase = md->phys_addr;
-               }
-       }
-
-       efi_bs_call(free_pool, map.map);
-
-       return membase;
-}
-
-/*
- * Allocate at the highest possible address that is not above 'max'.
- */
-efi_status_t efi_high_alloc(unsigned long size, unsigned long align,
-                           unsigned long *addr, unsigned long max)
-{
-       unsigned long map_size, desc_size, buff_size;
-       efi_memory_desc_t *map;
-       efi_status_t status;
-       unsigned long nr_pages;
-       u64 max_addr = 0;
-       int i;
-       struct efi_boot_memmap boot_map;
-
-       boot_map.map =          &map;
-       boot_map.map_size =     &map_size;
-       boot_map.desc_size =    &desc_size;
-       boot_map.desc_ver =     NULL;
-       boot_map.key_ptr =      NULL;
-       boot_map.buff_size =    &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               goto fail;
-
-       /*
-        * Enforce minimum alignment that EFI or Linux requires when
-        * requesting a specific address.  We are doing page-based (or
-        * larger) allocations, and both the address and size must meet
-        * alignment constraints.
-        */
-       if (align < EFI_ALLOC_ALIGN)
-               align = EFI_ALLOC_ALIGN;
-
-       size = round_up(size, EFI_ALLOC_ALIGN);
-       nr_pages = size / EFI_PAGE_SIZE;
-again:
-       for (i = 0; i < map_size / desc_size; i++) {
-               efi_memory_desc_t *desc;
-               unsigned long m = (unsigned long)map;
-               u64 start, end;
-
-               desc = efi_early_memdesc_ptr(m, desc_size, i);
-               if (desc->type != EFI_CONVENTIONAL_MEMORY)
-                       continue;
-
-               if (efi_soft_reserve_enabled() &&
-                   (desc->attribute & EFI_MEMORY_SP))
-                       continue;
-
-               if (desc->num_pages < nr_pages)
-                       continue;
-
-               start = desc->phys_addr;
-               end = start + desc->num_pages * EFI_PAGE_SIZE;
-
-               if (end > max)
-                       end = max;
-
-               if ((start + size) > end)
-                       continue;
-
-               if (round_down(end - size, align) < start)
-                       continue;
-
-               start = round_down(end - size, align);
-
-               /*
-                * Don't allocate at 0x0. It will confuse code that
-                * checks pointers against NULL.
-                */
-               if (start == 0x0)
-                       continue;
-
-               if (start > max_addr)
-                       max_addr = start;
-       }
-
-       if (!max_addr)
-               status = EFI_NOT_FOUND;
-       else {
-               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                                    EFI_LOADER_DATA, nr_pages, &max_addr);
-               if (status != EFI_SUCCESS) {
-                       max = max_addr;
-                       max_addr = 0;
-                       goto again;
-               }
-
-               *addr = max_addr;
-       }
-
-       efi_bs_call(free_pool, map);
-fail:
-       return status;
-}
-
-/*
- * Allocate at the lowest possible address that is not below 'min'.
- */
-efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
-                                unsigned long *addr, unsigned long min)
-{
-       unsigned long map_size, desc_size, buff_size;
-       efi_memory_desc_t *map;
-       efi_status_t status;
-       unsigned long nr_pages;
-       int i;
-       struct efi_boot_memmap boot_map;
-
-       boot_map.map =          &map;
-       boot_map.map_size =     &map_size;
-       boot_map.desc_size =    &desc_size;
-       boot_map.desc_ver =     NULL;
-       boot_map.key_ptr =      NULL;
-       boot_map.buff_size =    &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               goto fail;
-
-       /*
-        * Enforce minimum alignment that EFI or Linux requires when
-        * requesting a specific address.  We are doing page-based (or
-        * larger) allocations, and both the address and size must meet
-        * alignment constraints.
-        */
-       if (align < EFI_ALLOC_ALIGN)
-               align = EFI_ALLOC_ALIGN;
-
-       size = round_up(size, EFI_ALLOC_ALIGN);
-       nr_pages = size / EFI_PAGE_SIZE;
-       for (i = 0; i < map_size / desc_size; i++) {
-               efi_memory_desc_t *desc;
-               unsigned long m = (unsigned long)map;
-               u64 start, end;
-
-               desc = efi_early_memdesc_ptr(m, desc_size, i);
-
-               if (desc->type != EFI_CONVENTIONAL_MEMORY)
-                       continue;
-
-               if (efi_soft_reserve_enabled() &&
-                   (desc->attribute & EFI_MEMORY_SP))
-                       continue;
-
-               if (desc->num_pages < nr_pages)
-                       continue;
-
-               start = desc->phys_addr;
-               end = start + desc->num_pages * EFI_PAGE_SIZE;
-
-               if (start < min)
-                       start = min;
-
-               start = round_up(start, align);
-               if ((start + size) > end)
-                       continue;
-
-               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                                    EFI_LOADER_DATA, nr_pages, &start);
-               if (status == EFI_SUCCESS) {
-                       *addr = start;
-                       break;
-               }
-       }
-
-       if (i == map_size / desc_size)
-               status = EFI_NOT_FOUND;
-
-       efi_bs_call(free_pool, map);
-fail:
-       return status;
-}
-
-void efi_free(unsigned long size, unsigned long addr)
-{
-       unsigned long nr_pages;
-
-       if (!size)
-               return;
-
-       nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
-       efi_bs_call(free_pages, addr, nr_pages);
-}
-
-static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,
-                                 void **handle, u64 *file_sz)
-{
-       efi_file_handle_t *h, *fh = __fh;
-       efi_file_info_t *info;
-       efi_status_t status;
-       efi_guid_t info_guid = EFI_FILE_INFO_ID;
-       unsigned long info_sz;
-
-       status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, 0);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to open file: ");
-               efi_char16_printk(filename_16);
-               efi_printk("\n");
-               return status;
-       }
-
-       *handle = h;
-
-       info_sz = 0;
-       status = h->get_info(h, &info_guid, &info_sz, NULL);
-       if (status != EFI_BUFFER_TOO_SMALL) {
-               efi_printk("Failed to get file info size\n");
-               return status;
-       }
-
-grow:
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, info_sz,
-                            (void **)&info);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to alloc mem for file info\n");
-               return status;
-       }
-
-       status = h->get_info(h, &info_guid, &info_sz, info);
-       if (status == EFI_BUFFER_TOO_SMALL) {
-               efi_bs_call(free_pool, info);
-               goto grow;
-       }
-
-       *file_sz = info->file_size;
-       efi_bs_call(free_pool, info);
-
-       if (status != EFI_SUCCESS)
-               efi_printk("Failed to get initrd info\n");
-
-       return status;
-}
-
-static efi_status_t efi_file_read(efi_file_handle_t *handle,
-                                 unsigned long *size, void *addr)
-{
-       return handle->read(handle, size, addr);
-}
-
-static efi_status_t efi_file_close(efi_file_handle_t *handle)
-{
-       return handle->close(handle);
-}
-
-static efi_status_t efi_open_volume(efi_loaded_image_t *image,
-                                   efi_file_handle_t **__fh)
-{
-       efi_file_io_interface_t *io;
-       efi_file_handle_t *fh;
-       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
-       efi_status_t status;
-       efi_handle_t handle = image->device_handle;
-
-       status = efi_bs_call(handle_protocol, handle, &fs_proto, (void **)&io);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to handle fs_proto\n");
-               return status;
-       }
-
-       status = io->open_volume(io, &fh);
-       if (status != EFI_SUCCESS)
-               efi_printk("Failed to open volume\n");
-       else
-               *__fh = fh;
-
-       return status;
-}
-
 /*
  * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
  * option, e.g. efi=nochunk.
@@ -450,316 +73,42 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,
  */
 efi_status_t efi_parse_options(char const *cmdline)
 {
-       char *str;
-
-       str = strstr(cmdline, "nokaslr");
-       if (str == cmdline || (str && str > cmdline && *(str - 1) == ' '))
-               efi_nokaslr = true;
-
-       str = strstr(cmdline, "quiet");
-       if (str == cmdline || (str && str > cmdline && *(str - 1) == ' '))
-               efi_quiet = true;
-
-       /*
-        * If no EFI parameters were specified on the cmdline we've got
-        * nothing to do.
-        */
-       str = strstr(cmdline, "efi=");
-       if (!str)
-               return EFI_SUCCESS;
-
-       /* Skip ahead to first argument */
-       str += strlen("efi=");
-
-       /*
-        * Remember, because efi= is also used by the kernel we need to
-        * skip over arguments we don't understand.
-        */
-       while (*str && *str != ' ') {
-               if (!strncmp(str, "nochunk", 7)) {
-                       str += strlen("nochunk");
-                       efi_chunk_size = -1UL;
-               }
-
-               if (!strncmp(str, "novamap", 7)) {
-                       str += strlen("novamap");
-                       efi_novamap = true;
-               }
-
-               if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
-                   !strncmp(str, "nosoftreserve", 7)) {
-                       str += strlen("nosoftreserve");
-                       efi_nosoftreserve = true;
-               }
-
-               if (!strncmp(str, "disable_early_pci_dma", 21)) {
-                       str += strlen("disable_early_pci_dma");
-                       efi_disable_pci_dma = true;
-               }
-
-               if (!strncmp(str, "no_disable_early_pci_dma", 24)) {
-                       str += strlen("no_disable_early_pci_dma");
-                       efi_disable_pci_dma = false;
-               }
-
-               /* Group words together, delimited by "," */
-               while (*str && *str != ' ' && *str != ',')
-                       str++;
-
-               if (*str == ',')
-                       str++;
-       }
-
-       return EFI_SUCCESS;
-}
-
-/*
- * Check the cmdline for a LILO-style file= arguments.
- *
- * We only support loading a file from the same filesystem as
- * the kernel image.
- */
-efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
-                                 char *cmd_line, char *option_string,
-                                 unsigned long max_addr,
-                                 unsigned long *load_addr,
-                                 unsigned long *load_size)
-{
-       struct file_info *files;
-       unsigned long file_addr;
-       u64 file_size_total;
-       efi_file_handle_t *fh = NULL;
+       size_t len = strlen(cmdline) + 1;
        efi_status_t status;
-       int nr_files;
-       char *str;
-       int i, j, k;
-
-       file_addr = 0;
-       file_size_total = 0;
-
-       str = cmd_line;
-
-       j = 0;                  /* See close_handles */
-
-       if (!load_addr || !load_size)
-               return EFI_INVALID_PARAMETER;
-
-       *load_addr = 0;
-       *load_size = 0;
-
-       if (!str || !*str)
-               return EFI_SUCCESS;
-
-       for (nr_files = 0; *str; nr_files++) {
-               str = strstr(str, option_string);
-               if (!str)
-                       break;
-
-               str += strlen(option_string);
-
-               /* Skip any leading slashes */
-               while (*str == '/' || *str == '\\')
-                       str++;
-
-               while (*str && *str != ' ' && *str != '\n')
-                       str++;
-       }
-
-       if (!nr_files)
-               return EFI_SUCCESS;
-
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
-                            nr_files * sizeof(*files), (void **)&files);
-       if (status != EFI_SUCCESS) {
-               pr_efi_err("Failed to alloc mem for file handle list\n");
-               goto fail;
-       }
-
-       str = cmd_line;
-       for (i = 0; i < nr_files; i++) {
-               struct file_info *file;
-               efi_char16_t filename_16[256];
-               efi_char16_t *p;
-
-               str = strstr(str, option_string);
-               if (!str)
-                       break;
-
-               str += strlen(option_string);
-
-               file = &files[i];
-               p = filename_16;
-
-               /* Skip any leading slashes */
-               while (*str == '/' || *str == '\\')
-                       str++;
-
-               while (*str && *str != ' ' && *str != '\n') {
-                       if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
-                               break;
-
-                       if (*str == '/') {
-                               *p++ = '\\';
-                               str++;
-                       } else {
-                               *p++ = *str++;
-                       }
-               }
-
-               *p = '\0';
+       char *str, *buf;
 
-               /* Only open the volume once. */
-               if (!i) {
-                       status = efi_open_volume(image, &fh);
-                       if (status != EFI_SUCCESS)
-                               goto free_files;
-               }
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
+       if (status != EFI_SUCCESS)
+               return status;
 
-               status = efi_file_size(fh, filename_16, (void **)&file->handle,
-                                      &file->size);
-               if (status != EFI_SUCCESS)
-                       goto close_handles;
+       str = skip_spaces(memcpy(buf, cmdline, len));
 
-               file_size_total += file->size;
-       }
+       while (*str) {
+               char *param, *val;
 
-       if (file_size_total) {
-               unsigned long addr;
+               str = next_arg(str, &param, &val);
 
-               /*
-                * Multiple files need to be at consecutive addresses in memory,
-                * so allocate enough memory for all the files.  This is used
-                * for loading multiple files.
-                */
-               status = efi_high_alloc(file_size_total, 0x1000, &file_addr,
-                                       max_addr);
-               if (status != EFI_SUCCESS) {
-                       pr_efi_err("Failed to alloc highmem for files\n");
-                       goto close_handles;
-               }
+               if (!strcmp(param, "nokaslr")) {
+                       efi_nokaslr = true;
+               } else if (!strcmp(param, "quiet")) {
+                       efi_quiet = true;
+               } else if (!strcmp(param, "noinitrd")) {
+                       efi_noinitrd = true;
+               } else if (!strcmp(param, "efi") && val) {
+                       efi_nochunk = parse_option_str(val, "nochunk");
+                       efi_novamap = parse_option_str(val, "novamap");
 
-               /* We've run out of free low memory. */
-               if (file_addr > max_addr) {
-                       pr_efi_err("We've run out of free low memory\n");
-                       status = EFI_INVALID_PARAMETER;
-                       goto free_file_total;
-               }
+                       efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
+                                           parse_option_str(val, "nosoftreserve");
 
-               addr = file_addr;
-               for (j = 0; j < nr_files; j++) {
-                       unsigned long size;
-
-                       size = files[j].size;
-                       while (size) {
-                               unsigned long chunksize;
-
-                               if (IS_ENABLED(CONFIG_X86) && size > efi_chunk_size)
-                                       chunksize = efi_chunk_size;
-                               else
-                                       chunksize = size;
-
-                               status = efi_file_read(files[j].handle,
-                                                      &chunksize,
-                                                      (void *)addr);
-                               if (status != EFI_SUCCESS) {
-                                       pr_efi_err("Failed to read file\n");
-                                       goto free_file_total;
-                               }
-                               addr += chunksize;
-                               size -= chunksize;
-                       }
-
-                       efi_file_close(files[j].handle);
+                       if (parse_option_str(val, "disable_early_pci_dma"))
+                               efi_disable_pci_dma = true;
+                       if (parse_option_str(val, "no_disable_early_pci_dma"))
+                               efi_disable_pci_dma = false;
                }
-
-       }
-
-       efi_bs_call(free_pool, files);
-
-       *load_addr = file_addr;
-       *load_size = file_size_total;
-
-       return status;
-
-free_file_total:
-       efi_free(file_size_total, file_addr);
-
-close_handles:
-       for (k = j; k < i; k++)
-               efi_file_close(files[k].handle);
-free_files:
-       efi_bs_call(free_pool, files);
-fail:
-       *load_addr = 0;
-       *load_size = 0;
-
-       return status;
-}
-/*
- * Relocate a kernel image, either compressed or uncompressed.
- * In the ARM64 case, all kernel images are currently
- * uncompressed, and as such when we relocate it we need to
- * allocate additional space for the BSS segment. Any low
- * memory that this function should avoid needs to be
- * unavailable in the EFI memory map, as if the preferred
- * address is not available the lowest available address will
- * be used.
- */
-efi_status_t efi_relocate_kernel(unsigned long *image_addr,
-                                unsigned long image_size,
-                                unsigned long alloc_size,
-                                unsigned long preferred_addr,
-                                unsigned long alignment,
-                                unsigned long min_addr)
-{
-       unsigned long cur_image_addr;
-       unsigned long new_addr = 0;
-       efi_status_t status;
-       unsigned long nr_pages;
-       efi_physical_addr_t efi_addr = preferred_addr;
-
-       if (!image_addr || !image_size || !alloc_size)
-               return EFI_INVALID_PARAMETER;
-       if (alloc_size < image_size)
-               return EFI_INVALID_PARAMETER;
-
-       cur_image_addr = *image_addr;
-
-       /*
-        * The EFI firmware loader could have placed the kernel image
-        * anywhere in memory, but the kernel has restrictions on the
-        * max physical address it can run at.  Some architectures
-        * also have a prefered address, so first try to relocate
-        * to the preferred address.  If that fails, allocate as low
-        * as possible while respecting the required alignment.
-        */
-       nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
-       status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                            EFI_LOADER_DATA, nr_pages, &efi_addr);
-       new_addr = efi_addr;
-       /*
-        * If preferred address allocation failed allocate as low as
-        * possible.
-        */
-       if (status != EFI_SUCCESS) {
-               status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
-                                            min_addr);
        }
-       if (status != EFI_SUCCESS) {
-               pr_efi_err("Failed to allocate usable memory for kernel.\n");
-               return status;
-       }
-
-       /*
-        * We know source/dest won't overlap since both memory ranges
-        * have been allocated by UEFI, so we can safely use memcpy.
-        */
-       memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
-
-       /* Return the new address of the relocated image. */
-       *image_addr = new_addr;
-
-       return status;
+       efi_bs_call(free_pool, buf);
+       return EFI_SUCCESS;
 }
 
 /*
@@ -811,23 +160,19 @@ static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
        return dst;
 }
 
-#ifndef MAX_CMDLINE_ADDRESS
-#define MAX_CMDLINE_ADDRESS    ULONG_MAX
-#endif
-
 /*
  * Convert the unicode UEFI command line to ASCII to pass to kernel.
  * Size of memory allocated return in *cmd_line_len.
  * Returns NULL on error.
  */
 char *efi_convert_cmdline(efi_loaded_image_t *image,
-                         int *cmd_line_len)
+                         int *cmd_line_len, unsigned long max_addr)
 {
        const u16 *s2;
        u8 *s1 = NULL;
        unsigned long cmdline_addr = 0;
-       int load_options_chars = image->load_options_size / 2; /* UTF-16 */
-       const u16 *options = image->load_options;
+       int load_options_chars = efi_table_attr(image, load_options_size) / 2;
+       const u16 *options = efi_table_attr(image, load_options);
        int options_bytes = 0;  /* UTF-8 bytes */
        int options_chars = 0;  /* UTF-16 chars */
        efi_status_t status;
@@ -849,8 +194,7 @@ char *efi_convert_cmdline(efi_loaded_image_t *image,
 
        options_bytes++;        /* NUL termination */
 
-       status = efi_high_alloc(options_bytes, 0, &cmdline_addr,
-                               MAX_CMDLINE_ADDRESS);
+       status = efi_allocate_pages(options_bytes, &cmdline_addr, max_addr);
        if (status != EFI_SUCCESS)
                return NULL;
 
@@ -962,3 +306,89 @@ void efi_char16_printk(efi_char16_t *str)
        efi_call_proto(efi_table_attr(efi_system_table(), con_out),
                       output_string, str);
 }
+
+/*
+ * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
+ * for the firmware or bootloader to expose the initrd data directly to the stub
+ * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is
+ * very easy to implement. It is a simple Linux initrd specific conduit between
+ * kernel and firmware, allowing us to put the EFI stub (being part of the
+ * kernel) in charge of where and when to load the initrd, while leaving it up
+ * to the firmware to decide whether it needs to expose its filesystem hierarchy
+ * via EFI protocols.
+ */
+static const struct {
+       struct efi_vendor_dev_path      vendor;
+       struct efi_generic_dev_path     end;
+} __packed initrd_dev_path = {
+       {
+               {
+                       EFI_DEV_MEDIA,
+                       EFI_DEV_MEDIA_VENDOR,
+                       sizeof(struct efi_vendor_dev_path),
+               },
+               LINUX_EFI_INITRD_MEDIA_GUID
+       }, {
+               EFI_DEV_END_PATH,
+               EFI_DEV_END_ENTIRE,
+               sizeof(struct efi_generic_dev_path)
+       }
+};
+
+/**
+ * efi_load_initrd_dev_path - load the initrd from the Linux initrd device path
+ * @load_addr: pointer to store the address where the initrd was loaded
+ * @load_size: pointer to store the size of the loaded initrd
+ * @max:       upper limit for the initrd memory allocation
+ * @return:    %EFI_SUCCESS if the initrd was loaded successfully, in which
+ *             case @load_addr and @load_size are assigned accordingly
+ *             %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd
+ *             device path
+ *             %EFI_INVALID_PARAMETER if load_addr == NULL or load_size == NULL
+ *             %EFI_OUT_OF_RESOURCES if memory allocation failed
+ *             %EFI_LOAD_ERROR in all other cases
+ */
+efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
+                                     unsigned long *load_size,
+                                     unsigned long max)
+{
+       efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
+       efi_device_path_protocol_t *dp;
+       efi_load_file2_protocol_t *lf2;
+       unsigned long initrd_addr;
+       unsigned long initrd_size;
+       efi_handle_t handle;
+       efi_status_t status;
+
+       if (!load_addr || !load_size)
+               return EFI_INVALID_PARAMETER;
+
+       dp = (efi_device_path_protocol_t *)&initrd_dev_path;
+       status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid,
+                            (void **)&lf2);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_proto(lf2, load_file, dp, false, &initrd_size, NULL);
+       if (status != EFI_BUFFER_TOO_SMALL)
+               return EFI_LOAD_ERROR;
+
+       status = efi_allocate_pages(initrd_size, &initrd_addr, max);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_proto(lf2, load_file, dp, false, &initrd_size,
+                               (void *)initrd_addr);
+       if (status != EFI_SUCCESS) {
+               efi_free(initrd_size, initrd_addr);
+               return EFI_LOAD_ERROR;
+       }
+
+       *load_addr = initrd_addr;
+       *load_size = initrd_size;
+       return EFI_SUCCESS;
+}
index c244b16..cc90a74 100644 (file)
@@ -31,7 +31,9 @@
 #define __efistub_global
 #endif
 
+extern bool __pure nochunk(void);
 extern bool __pure nokaslr(void);
+extern bool __pure noinitrd(void);
 extern bool __pure is_quiet(void);
 extern bool __pure novamap(void);
 
@@ -43,10 +45,549 @@ extern __pure efi_system_table_t  *efi_system_table(void);
 
 #define pr_efi_err(msg) efi_printk("EFI stub: ERROR: "msg)
 
-void efi_char16_printk(efi_char16_t *);
-void efi_char16_printk(efi_char16_t *);
+/* Helper macros for the usual case of using simple C variables: */
+#ifndef fdt_setprop_inplace_var
+#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
+       fdt_setprop_inplace((fdt), (node_offset), (name), &(var), sizeof(var))
+#endif
+
+#ifndef fdt_setprop_var
+#define fdt_setprop_var(fdt, node_offset, name, var) \
+       fdt_setprop((fdt), (node_offset), (name), &(var), sizeof(var))
+#endif
+
+#define get_efi_var(name, vendor, ...)                         \
+       efi_rt_call(get_variable, (efi_char16_t *)(name),       \
+                   (efi_guid_t *)(vendor), __VA_ARGS__)
+
+#define set_efi_var(name, vendor, ...)                         \
+       efi_rt_call(set_variable, (efi_char16_t *)(name),       \
+                   (efi_guid_t *)(vendor), __VA_ARGS__)
+
+#define efi_get_handle_at(array, idx)                                  \
+       (efi_is_native() ? (array)[idx]                                 \
+               : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
+
+#define efi_get_handle_num(size)                                       \
+       ((size) / (efi_is_native() ? sizeof(efi_handle_t) : sizeof(u32)))
+
+#define for_each_efi_handle(handle, array, size, i)                    \
+       for (i = 0;                                                     \
+            i < efi_get_handle_num(size) &&                            \
+               ((handle = efi_get_handle_at((array), i)) || true);     \
+            i++)
+
+/*
+ * Allocation types for calls to boottime->allocate_pages.
+ */
+#define EFI_ALLOCATE_ANY_PAGES         0
+#define EFI_ALLOCATE_MAX_ADDRESS       1
+#define EFI_ALLOCATE_ADDRESS           2
+#define EFI_MAX_ALLOCATE_TYPE          3
+
+/*
+ * The type of search to perform when calling boottime->locate_handle
+ */
+#define EFI_LOCATE_ALL_HANDLES                 0
+#define EFI_LOCATE_BY_REGISTER_NOTIFY          1
+#define EFI_LOCATE_BY_PROTOCOL                 2
+
+struct efi_boot_memmap {
+       efi_memory_desc_t       **map;
+       unsigned long           *map_size;
+       unsigned long           *desc_size;
+       u32                     *desc_ver;
+       unsigned long           *key_ptr;
+       unsigned long           *buff_size;
+};
+
+typedef struct efi_generic_dev_path efi_device_path_protocol_t;
+
+/*
+ * EFI Boot Services table
+ */
+union efi_boot_services {
+       struct {
+               efi_table_hdr_t hdr;
+               void *raise_tpl;
+               void *restore_tpl;
+               efi_status_t (__efiapi *allocate_pages)(int, int, unsigned long,
+                                                       efi_physical_addr_t *);
+               efi_status_t (__efiapi *free_pages)(efi_physical_addr_t,
+                                                   unsigned long);
+               efi_status_t (__efiapi *get_memory_map)(unsigned long *, void *,
+                                                       unsigned long *,
+                                                       unsigned long *, u32 *);
+               efi_status_t (__efiapi *allocate_pool)(int, unsigned long,
+                                                      void **);
+               efi_status_t (__efiapi *free_pool)(void *);
+               void *create_event;
+               void *set_timer;
+               void *wait_for_event;
+               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 *handle_protocol)(efi_handle_t,
+                                                        efi_guid_t *, void **);
+               void *__reserved;
+               void *register_protocol_notify;
+               efi_status_t (__efiapi *locate_handle)(int, efi_guid_t *,
+                                                      void *, unsigned long *,
+                                                      efi_handle_t *);
+               efi_status_t (__efiapi *locate_device_path)(efi_guid_t *,
+                                                           efi_device_path_protocol_t **,
+                                                           efi_handle_t *);
+               efi_status_t (__efiapi *install_configuration_table)(efi_guid_t *,
+                                                                    void *);
+               void *load_image;
+               void *start_image;
+               efi_status_t __noreturn (__efiapi *exit)(efi_handle_t,
+                                                        efi_status_t,
+                                                        unsigned long,
+                                                        efi_char16_t *);
+               void *unload_image;
+               efi_status_t (__efiapi *exit_boot_services)(efi_handle_t,
+                                                           unsigned long);
+               void *get_next_monotonic_count;
+               void *stall;
+               void *set_watchdog_timer;
+               void *connect_controller;
+               efi_status_t (__efiapi *disconnect_controller)(efi_handle_t,
+                                                              efi_handle_t,
+                                                              efi_handle_t);
+               void *open_protocol;
+               void *close_protocol;
+               void *open_protocol_information;
+               void *protocols_per_handle;
+               void *locate_handle_buffer;
+               efi_status_t (__efiapi *locate_protocol)(efi_guid_t *, void *,
+                                                        void **);
+               void *install_multiple_protocol_interfaces;
+               void *uninstall_multiple_protocol_interfaces;
+               void *calculate_crc32;
+               void *copy_mem;
+               void *set_mem;
+               void *create_event_ex;
+       };
+       struct {
+               efi_table_hdr_t hdr;
+               u32 raise_tpl;
+               u32 restore_tpl;
+               u32 allocate_pages;
+               u32 free_pages;
+               u32 get_memory_map;
+               u32 allocate_pool;
+               u32 free_pool;
+               u32 create_event;
+               u32 set_timer;
+               u32 wait_for_event;
+               u32 signal_event;
+               u32 close_event;
+               u32 check_event;
+               u32 install_protocol_interface;
+               u32 reinstall_protocol_interface;
+               u32 uninstall_protocol_interface;
+               u32 handle_protocol;
+               u32 __reserved;
+               u32 register_protocol_notify;
+               u32 locate_handle;
+               u32 locate_device_path;
+               u32 install_configuration_table;
+               u32 load_image;
+               u32 start_image;
+               u32 exit;
+               u32 unload_image;
+               u32 exit_boot_services;
+               u32 get_next_monotonic_count;
+               u32 stall;
+               u32 set_watchdog_timer;
+               u32 connect_controller;
+               u32 disconnect_controller;
+               u32 open_protocol;
+               u32 close_protocol;
+               u32 open_protocol_information;
+               u32 protocols_per_handle;
+               u32 locate_handle_buffer;
+               u32 locate_protocol;
+               u32 install_multiple_protocol_interfaces;
+               u32 uninstall_multiple_protocol_interfaces;
+               u32 calculate_crc32;
+               u32 copy_mem;
+               u32 set_mem;
+               u32 create_event_ex;
+       } mixed_mode;
+};
+
+typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t;
+
+union efi_uga_draw_protocol {
+       struct {
+               efi_status_t (__efiapi *get_mode)(efi_uga_draw_protocol_t *,
+                                                 u32*, u32*, u32*, u32*);
+               void *set_mode;
+               void *blt;
+       };
+       struct {
+               u32 get_mode;
+               u32 set_mode;
+               u32 blt;
+       } mixed_mode;
+};
+
+union efi_simple_text_output_protocol {
+       struct {
+               void *reset;
+               efi_status_t (__efiapi *output_string)(efi_simple_text_output_protocol_t *,
+                                                      efi_char16_t *);
+               void *test_string;
+       };
+       struct {
+               u32 reset;
+               u32 output_string;
+               u32 test_string;
+       } mixed_mode;
+};
+
+#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR              0
+#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR              1
+#define PIXEL_BIT_MASK                                 2
+#define PIXEL_BLT_ONLY                                 3
+#define PIXEL_FORMAT_MAX                               4
+
+typedef struct {
+       u32 red_mask;
+       u32 green_mask;
+       u32 blue_mask;
+       u32 reserved_mask;
+} efi_pixel_bitmask_t;
+
+typedef struct {
+       u32 version;
+       u32 horizontal_resolution;
+       u32 vertical_resolution;
+       int pixel_format;
+       efi_pixel_bitmask_t pixel_information;
+       u32 pixels_per_scan_line;
+} efi_graphics_output_mode_info_t;
+
+typedef union efi_graphics_output_protocol_mode efi_graphics_output_protocol_mode_t;
+
+union efi_graphics_output_protocol_mode {
+       struct {
+               u32 max_mode;
+               u32 mode;
+               efi_graphics_output_mode_info_t *info;
+               unsigned long size_of_info;
+               efi_physical_addr_t frame_buffer_base;
+               unsigned long frame_buffer_size;
+       };
+       struct {
+               u32 max_mode;
+               u32 mode;
+               u32 info;
+               u32 size_of_info;
+               u64 frame_buffer_base;
+               u32 frame_buffer_size;
+       } mixed_mode;
+};
+
+typedef union efi_graphics_output_protocol efi_graphics_output_protocol_t;
+
+union efi_graphics_output_protocol {
+       struct {
+               void *query_mode;
+               void *set_mode;
+               void *blt;
+               efi_graphics_output_protocol_mode_t *mode;
+       };
+       struct {
+               u32 query_mode;
+               u32 set_mode;
+               u32 blt;
+               u32 mode;
+       } mixed_mode;
+};
+
+typedef union {
+       struct {
+               u32                     revision;
+               efi_handle_t            parent_handle;
+               efi_system_table_t      *system_table;
+               efi_handle_t            device_handle;
+               void                    *file_path;
+               void                    *reserved;
+               u32                     load_options_size;
+               void                    *load_options;
+               void                    *image_base;
+               __aligned_u64           image_size;
+               unsigned int            image_code_type;
+               unsigned int            image_data_type;
+               efi_status_t            (__efiapi *unload)(efi_handle_t image_handle);
+       };
+       struct {
+               u32             revision;
+               u32             parent_handle;
+               u32             system_table;
+               u32             device_handle;
+               u32             file_path;
+               u32             reserved;
+               u32             load_options_size;
+               u32             load_options;
+               u32             image_base;
+               __aligned_u64   image_size;
+               u32             image_code_type;
+               u32             image_data_type;
+               u32             unload;
+       } mixed_mode;
+} efi_loaded_image_t;
+
+typedef struct {
+       u64                     size;
+       u64                     file_size;
+       u64                     phys_size;
+       efi_time_t              create_time;
+       efi_time_t              last_access_time;
+       efi_time_t              modification_time;
+       __aligned_u64           attribute;
+       efi_char16_t            filename[];
+} efi_file_info_t;
+
+typedef struct efi_file_protocol efi_file_protocol_t;
+
+struct efi_file_protocol {
+       u64             revision;
+       efi_status_t    (__efiapi *open)        (efi_file_protocol_t *,
+                                                efi_file_protocol_t **,
+                                                efi_char16_t *, u64, u64);
+       efi_status_t    (__efiapi *close)       (efi_file_protocol_t *);
+       efi_status_t    (__efiapi *delete)      (efi_file_protocol_t *);
+       efi_status_t    (__efiapi *read)        (efi_file_protocol_t *,
+                                                unsigned long *, void *);
+       efi_status_t    (__efiapi *write)       (efi_file_protocol_t *,
+                                                unsigned long, void *);
+       efi_status_t    (__efiapi *get_position)(efi_file_protocol_t *, u64 *);
+       efi_status_t    (__efiapi *set_position)(efi_file_protocol_t *, u64);
+       efi_status_t    (__efiapi *get_info)    (efi_file_protocol_t *,
+                                                efi_guid_t *, unsigned long *,
+                                                void *);
+       efi_status_t    (__efiapi *set_info)    (efi_file_protocol_t *,
+                                                efi_guid_t *, unsigned long,
+                                                void *);
+       efi_status_t    (__efiapi *flush)       (efi_file_protocol_t *);
+};
 
-unsigned long get_dram_base(void);
+typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
+
+struct efi_simple_file_system_protocol {
+       u64     revision;
+       int     (__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
+                                       efi_file_protocol_t **);
+};
+
+#define EFI_FILE_MODE_READ     0x0000000000000001
+#define EFI_FILE_MODE_WRITE    0x0000000000000002
+#define EFI_FILE_MODE_CREATE   0x8000000000000000
+
+typedef enum {
+       EfiPciIoWidthUint8,
+       EfiPciIoWidthUint16,
+       EfiPciIoWidthUint32,
+       EfiPciIoWidthUint64,
+       EfiPciIoWidthFifoUint8,
+       EfiPciIoWidthFifoUint16,
+       EfiPciIoWidthFifoUint32,
+       EfiPciIoWidthFifoUint64,
+       EfiPciIoWidthFillUint8,
+       EfiPciIoWidthFillUint16,
+       EfiPciIoWidthFillUint32,
+       EfiPciIoWidthFillUint64,
+       EfiPciIoWidthMaximum
+} EFI_PCI_IO_PROTOCOL_WIDTH;
+
+typedef enum {
+       EfiPciIoAttributeOperationGet,
+       EfiPciIoAttributeOperationSet,
+       EfiPciIoAttributeOperationEnable,
+       EfiPciIoAttributeOperationDisable,
+       EfiPciIoAttributeOperationSupported,
+    EfiPciIoAttributeOperationMaximum
+} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
+
+typedef struct {
+       u32 read;
+       u32 write;
+} efi_pci_io_protocol_access_32_t;
+
+typedef union efi_pci_io_protocol efi_pci_io_protocol_t;
+
+typedef
+efi_status_t (__efiapi *efi_pci_io_protocol_cfg_t)(efi_pci_io_protocol_t *,
+                                                  EFI_PCI_IO_PROTOCOL_WIDTH,
+                                                  u32 offset,
+                                                  unsigned long count,
+                                                  void *buffer);
+
+typedef struct {
+       void *read;
+       void *write;
+} efi_pci_io_protocol_access_t;
+
+typedef struct {
+       efi_pci_io_protocol_cfg_t read;
+       efi_pci_io_protocol_cfg_t write;
+} efi_pci_io_protocol_config_access_t;
+
+union efi_pci_io_protocol {
+       struct {
+               void *poll_mem;
+               void *poll_io;
+               efi_pci_io_protocol_access_t mem;
+               efi_pci_io_protocol_access_t io;
+               efi_pci_io_protocol_config_access_t pci;
+               void *copy_mem;
+               void *map;
+               void *unmap;
+               void *allocate_buffer;
+               void *free_buffer;
+               void *flush;
+               efi_status_t (__efiapi *get_location)(efi_pci_io_protocol_t *,
+                                                     unsigned long *segment_nr,
+                                                     unsigned long *bus_nr,
+                                                     unsigned long *device_nr,
+                                                     unsigned long *func_nr);
+               void *attributes;
+               void *get_bar_attributes;
+               void *set_bar_attributes;
+               uint64_t romsize;
+               void *romimage;
+       };
+       struct {
+               u32 poll_mem;
+               u32 poll_io;
+               efi_pci_io_protocol_access_32_t mem;
+               efi_pci_io_protocol_access_32_t io;
+               efi_pci_io_protocol_access_32_t pci;
+               u32 copy_mem;
+               u32 map;
+               u32 unmap;
+               u32 allocate_buffer;
+               u32 free_buffer;
+               u32 flush;
+               u32 get_location;
+               u32 attributes;
+               u32 get_bar_attributes;
+               u32 set_bar_attributes;
+               u64 romsize;
+               u32 romimage;
+       } mixed_mode;
+};
+
+#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004
+#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010
+#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
+#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
+#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200
+#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000
+#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000
+
+struct efi_dev_path;
+
+typedef union apple_properties_protocol apple_properties_protocol_t;
+
+union apple_properties_protocol {
+       struct {
+               unsigned long version;
+               efi_status_t (__efiapi *get)(apple_properties_protocol_t *,
+                                            struct efi_dev_path *,
+                                            efi_char16_t *, void *, u32 *);
+               efi_status_t (__efiapi *set)(apple_properties_protocol_t *,
+                                            struct efi_dev_path *,
+                                            efi_char16_t *, void *, u32);
+               efi_status_t (__efiapi *del)(apple_properties_protocol_t *,
+                                            struct efi_dev_path *,
+                                            efi_char16_t *);
+               efi_status_t (__efiapi *get_all)(apple_properties_protocol_t *,
+                                                void *buffer, u32 *);
+       };
+       struct {
+               u32 version;
+               u32 get;
+               u32 set;
+               u32 del;
+               u32 get_all;
+       } mixed_mode;
+};
+
+typedef u32 efi_tcg2_event_log_format;
+
+typedef union efi_tcg2_protocol efi_tcg2_protocol_t;
+
+union efi_tcg2_protocol {
+       struct {
+               void *get_capability;
+               efi_status_t (__efiapi *get_event_log)(efi_handle_t,
+                                                      efi_tcg2_event_log_format,
+                                                      efi_physical_addr_t *,
+                                                      efi_physical_addr_t *,
+                                                      efi_bool_t *);
+               void *hash_log_extend_event;
+               void *submit_command;
+               void *get_active_pcr_banks;
+               void *set_active_pcr_banks;
+               void *get_result_of_set_active_pcr_banks;
+       };
+       struct {
+               u32 get_capability;
+               u32 get_event_log;
+               u32 hash_log_extend_event;
+               u32 submit_command;
+               u32 get_active_pcr_banks;
+               u32 set_active_pcr_banks;
+               u32 get_result_of_set_active_pcr_banks;
+       } mixed_mode;
+};
+
+typedef union efi_load_file_protocol efi_load_file_protocol_t;
+typedef union efi_load_file_protocol efi_load_file2_protocol_t;
+
+union efi_load_file_protocol {
+       struct {
+               efi_status_t (__efiapi *load_file)(efi_load_file_protocol_t *,
+                                                  efi_device_path_protocol_t *,
+                                                  bool, unsigned long *, void *);
+       };
+       struct {
+               u32 load_file;
+       } mixed_mode;
+};
+
+void efi_pci_disable_bridge_busmaster(void);
+
+typedef efi_status_t (*efi_exit_boot_map_processing)(
+       struct efi_boot_memmap *map,
+       void *priv);
+
+efi_status_t efi_exit_boot_services(void *handle,
+                                   struct efi_boot_memmap *map,
+                                   void *priv,
+                                   efi_exit_boot_map_processing priv_func);
+
+void efi_char16_printk(efi_char16_t *);
 
 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                                            unsigned long *new_fdt_addr,
@@ -71,23 +612,57 @@ efi_status_t check_platform_features(void);
 
 void *get_efi_config_table(efi_guid_t guid);
 
-/* Helper macros for the usual case of using simple C variables: */
-#ifndef fdt_setprop_inplace_var
-#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
-       fdt_setprop_inplace((fdt), (node_offset), (name), &(var), sizeof(var))
-#endif
+void efi_printk(char *str);
 
-#ifndef fdt_setprop_var
-#define fdt_setprop_var(fdt, node_offset, name, var) \
-       fdt_setprop((fdt), (node_offset), (name), &(var), sizeof(var))
-#endif
+void efi_free(unsigned long size, unsigned long addr);
 
-#define get_efi_var(name, vendor, ...)                         \
-       efi_rt_call(get_variable, (efi_char16_t *)(name),       \
-                   (efi_guid_t *)(vendor), __VA_ARGS__)
+char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len,
+                         unsigned long max_addr);
 
-#define set_efi_var(name, vendor, ...)                         \
-       efi_rt_call(set_variable, (efi_char16_t *)(name),       \
-                   (efi_guid_t *)(vendor), __VA_ARGS__)
+efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
+
+efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
+                                unsigned long *addr, unsigned long min);
+
+static inline
+efi_status_t efi_low_alloc(unsigned long size, unsigned long align,
+                          unsigned long *addr)
+{
+       /*
+        * Don't allocate at 0x0. It will confuse code that
+        * checks pointers against NULL. Skip the first 8
+        * bytes so we start at a nice even number.
+        */
+       return efi_low_alloc_above(size, align, addr, 0x8);
+}
+
+efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
+                               unsigned long max);
+
+efi_status_t efi_relocate_kernel(unsigned long *image_addr,
+                                unsigned long image_size,
+                                unsigned long alloc_size,
+                                unsigned long preferred_addr,
+                                unsigned long alignment,
+                                unsigned long min_addr);
+
+efi_status_t efi_parse_options(char const *cmdline);
+
+efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
+                          unsigned long size);
+
+efi_status_t efi_load_dtb(efi_loaded_image_t *image,
+                         unsigned long *load_addr,
+                         unsigned long *load_size);
+
+efi_status_t efi_load_initrd(efi_loaded_image_t *image,
+                            unsigned long *load_addr,
+                            unsigned long *load_size,
+                            unsigned long soft_limit,
+                            unsigned long hard_limit);
+
+efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
+                                     unsigned long *load_size,
+                                     unsigned long max);
 
 #endif
index 0a91e52..46cffac 100644 (file)
@@ -199,10 +199,6 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
        return EFI_SUCCESS;
 }
 
-#ifndef EFI_FDT_ALIGN
-# define EFI_FDT_ALIGN EFI_PAGE_SIZE
-#endif
-
 struct exit_boot_struct {
        efi_memory_desc_t       *runtime_map;
        int                     *runtime_entry_count;
@@ -281,8 +277,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
        pr_efi("Exiting boot services and installing virtual address map...\n");
 
        map.map = &memory_map;
-       status = efi_high_alloc(MAX_FDT_SIZE, EFI_FDT_ALIGN,
-                               new_fdt_addr, max_addr);
+       status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, max_addr);
        if (status != EFI_SUCCESS) {
                pr_efi_err("Unable to allocate memory for new device tree.\n");
                goto fail;
diff --git a/drivers/firmware/efi/libstub/file.c b/drivers/firmware/efi/libstub/file.c
new file mode 100644 (file)
index 0000000..d4c7e5f
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Helper functions used by the EFI stub on multiple
+ * architectures. This should be #included by the EFI stub
+ * implementation files.
+ *
+ * Copyright 2011 Intel Corporation; author Matt Fleming
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+#define MAX_FILENAME_SIZE      256
+
+/*
+ * Some firmware implementations have problems reading files in one go.
+ * A read chunk size of 1MB seems to work for most platforms.
+ *
+ * Unfortunately, reading files in chunks triggers *other* bugs on some
+ * platforms, so we provide a way to disable this workaround, which can
+ * be done by passing "efi=nochunk" on the EFI boot stub command line.
+ *
+ * If you experience issues with initrd images being corrupt it's worth
+ * trying efi=nochunk, but chunking is enabled by default on x86 because
+ * there are far more machines that require the workaround than those that
+ * break with it enabled.
+ */
+#define EFI_READ_CHUNK_SIZE    SZ_1M
+
+static efi_status_t efi_open_file(efi_file_protocol_t *volume,
+                                 efi_char16_t *filename_16,
+                                 efi_file_protocol_t **handle,
+                                 unsigned long *file_size)
+{
+       struct {
+               efi_file_info_t info;
+               efi_char16_t    filename[MAX_FILENAME_SIZE];
+       } finfo;
+       efi_guid_t info_guid = EFI_FILE_INFO_ID;
+       efi_file_protocol_t *fh;
+       unsigned long info_sz;
+       efi_status_t status;
+
+       status = volume->open(volume, &fh, filename_16, EFI_FILE_MODE_READ, 0);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to open file: ");
+               efi_char16_printk(filename_16);
+               efi_printk("\n");
+               return status;
+       }
+
+       info_sz = sizeof(finfo);
+       status = fh->get_info(fh, &info_guid, &info_sz, &finfo);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to get file info\n");
+               fh->close(fh);
+               return status;
+       }
+
+       *handle = fh;
+       *file_size = finfo.info.file_size;
+       return EFI_SUCCESS;
+}
+
+static efi_status_t efi_open_volume(efi_loaded_image_t *image,
+                                   efi_file_protocol_t **fh)
+{
+       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+       efi_simple_file_system_protocol_t *io;
+       efi_status_t status;
+
+       status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,
+                            (void **)&io);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to handle fs_proto\n");
+               return status;
+       }
+
+       status = io->open_volume(io, fh);
+       if (status != EFI_SUCCESS)
+               pr_efi_err("Failed to open volume\n");
+
+       return status;
+}
+
+static int find_file_option(const efi_char16_t *cmdline, int cmdline_len,
+                           const efi_char16_t *prefix, int prefix_size,
+                           efi_char16_t *result, int result_len)
+{
+       int prefix_len = prefix_size / 2;
+       bool found = false;
+       int i;
+
+       for (i = prefix_len; i < cmdline_len; i++) {
+               if (!memcmp(&cmdline[i - prefix_len], prefix, prefix_size)) {
+                       found = true;
+                       break;
+               }
+       }
+
+       if (!found)
+               return 0;
+
+       while (--result_len > 0 && i < cmdline_len) {
+               if (cmdline[i] == L'\0' ||
+                   cmdline[i] == L'\n' ||
+                   cmdline[i] == L' ')
+                       break;
+               *result++ = cmdline[i++];
+       }
+       *result = L'\0';
+       return i;
+}
+
+/*
+ * Check the cmdline for a LILO-style file= arguments.
+ *
+ * We only support loading a file from the same filesystem as
+ * the kernel image.
+ */
+static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
+                                        const efi_char16_t *optstr,
+                                        int optstr_size,
+                                        unsigned long soft_limit,
+                                        unsigned long hard_limit,
+                                        unsigned long *load_addr,
+                                        unsigned long *load_size)
+{
+       const efi_char16_t *cmdline = image->load_options;
+       int cmdline_len = image->load_options_size / 2;
+       unsigned long efi_chunk_size = ULONG_MAX;
+       efi_file_protocol_t *volume = NULL;
+       efi_file_protocol_t *file;
+       unsigned long alloc_addr;
+       unsigned long alloc_size;
+       efi_status_t status;
+       int offset;
+
+       if (!load_addr || !load_size)
+               return EFI_INVALID_PARAMETER;
+
+       if (IS_ENABLED(CONFIG_X86) && !nochunk())
+               efi_chunk_size = EFI_READ_CHUNK_SIZE;
+
+       alloc_addr = alloc_size = 0;
+       do {
+               efi_char16_t filename[MAX_FILENAME_SIZE];
+               unsigned long size;
+               void *addr;
+
+               offset = find_file_option(cmdline, cmdline_len,
+                                         optstr, optstr_size,
+                                         filename, ARRAY_SIZE(filename));
+
+               if (!offset)
+                       break;
+
+               cmdline += offset;
+               cmdline_len -= offset;
+
+               if (!volume) {
+                       status = efi_open_volume(image, &volume);
+                       if (status != EFI_SUCCESS)
+                               return status;
+               }
+
+               status = efi_open_file(volume, filename, &file, &size);
+               if (status != EFI_SUCCESS)
+                       goto err_close_volume;
+
+               /*
+                * Check whether the existing allocation can contain the next
+                * file. This condition will also trigger naturally during the
+                * first (and typically only) iteration of the loop, given that
+                * alloc_size == 0 in that case.
+                */
+               if (round_up(alloc_size + size, EFI_ALLOC_ALIGN) >
+                   round_up(alloc_size, EFI_ALLOC_ALIGN)) {
+                       unsigned long old_addr = alloc_addr;
+
+                       status = EFI_OUT_OF_RESOURCES;
+                       if (soft_limit < hard_limit)
+                               status = efi_allocate_pages(alloc_size + size,
+                                                           &alloc_addr,
+                                                           soft_limit);
+                       if (status == EFI_OUT_OF_RESOURCES)
+                               status = efi_allocate_pages(alloc_size + size,
+                                                           &alloc_addr,
+                                                           hard_limit);
+                       if (status != EFI_SUCCESS) {
+                               pr_efi_err("Failed to allocate memory for files\n");
+                               goto err_close_file;
+                       }
+
+                       if (old_addr != 0) {
+                               /*
+                                * This is not the first time we've gone
+                                * around this loop, and so we are loading
+                                * multiple files that need to be concatenated
+                                * and returned in a single buffer.
+                                */
+                               memcpy((void *)alloc_addr, (void *)old_addr, alloc_size);
+                               efi_free(alloc_size, old_addr);
+                       }
+               }
+
+               addr = (void *)alloc_addr + alloc_size;
+               alloc_size += size;
+
+               while (size) {
+                       unsigned long chunksize = min(size, efi_chunk_size);
+
+                       status = file->read(file, &chunksize, addr);
+                       if (status != EFI_SUCCESS) {
+                               pr_efi_err("Failed to read file\n");
+                               goto err_close_file;
+                       }
+                       addr += chunksize;
+                       size -= chunksize;
+               }
+               file->close(file);
+       } while (offset > 0);
+
+       *load_addr = alloc_addr;
+       *load_size = alloc_size;
+
+       if (volume)
+               volume->close(volume);
+       return EFI_SUCCESS;
+
+err_close_file:
+       file->close(file);
+
+err_close_volume:
+       volume->close(volume);
+       efi_free(alloc_size, alloc_addr);
+       return status;
+}
+
+efi_status_t efi_load_dtb(efi_loaded_image_t *image,
+                         unsigned long *load_addr,
+                         unsigned long *load_size)
+{
+       return handle_cmdline_files(image, L"dtb=", sizeof(L"dtb=") - 2,
+                                   ULONG_MAX, ULONG_MAX, load_addr, load_size);
+}
+
+efi_status_t efi_load_initrd(efi_loaded_image_t *image,
+                            unsigned long *load_addr,
+                            unsigned long *load_size,
+                            unsigned long soft_limit,
+                            unsigned long hard_limit)
+{
+       return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
+                                   soft_limit, hard_limit, load_addr, load_size);
+}
diff --git a/drivers/firmware/efi/libstub/hidden.h b/drivers/firmware/efi/libstub/hidden.h
new file mode 100644 (file)
index 0000000..3493b04
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * To prevent the compiler from emitting GOT-indirected (and thus absolute)
+ * references to any global symbols, override their visibility as 'hidden'
+ */
+#pragma GCC visibility push(hidden)
diff --git a/drivers/firmware/efi/libstub/mem.c b/drivers/firmware/efi/libstub/mem.c
new file mode 100644 (file)
index 0000000..869a79c
--- /dev/null
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+#define EFI_MMAP_NR_SLACK_SLOTS        8
+
+static inline bool mmap_has_headroom(unsigned long buff_size,
+                                    unsigned long map_size,
+                                    unsigned long desc_size)
+{
+       unsigned long slack = buff_size - map_size;
+
+       return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
+}
+
+/**
+ * efi_get_memory_map() - get memory map
+ * @map:       on return pointer to memory map
+ *
+ * Retrieve the UEFI memory map. The allocated memory leaves room for
+ * up to EFI_MMAP_NR_SLACK_SLOTS additional memory map entries.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
+{
+       efi_memory_desc_t *m = NULL;
+       efi_status_t status;
+       unsigned long key;
+       u32 desc_version;
+
+       *map->desc_size =       sizeof(*m);
+       *map->map_size =        *map->desc_size * 32;
+       *map->buff_size =       *map->map_size;
+again:
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
+                            *map->map_size, (void **)&m);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       *map->desc_size = 0;
+       key = 0;
+       status = efi_bs_call(get_memory_map, map->map_size, m,
+                            &key, map->desc_size, &desc_version);
+       if (status == EFI_BUFFER_TOO_SMALL ||
+           !mmap_has_headroom(*map->buff_size, *map->map_size,
+                              *map->desc_size)) {
+               efi_bs_call(free_pool, m);
+               /*
+                * Make sure there is some entries of headroom so that the
+                * buffer can be reused for a new map after allocations are
+                * no longer permitted.  Its unlikely that the map will grow to
+                * exceed this headroom once we are ready to trigger
+                * ExitBootServices()
+                */
+               *map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
+               *map->buff_size = *map->map_size;
+               goto again;
+       }
+
+       if (status == EFI_SUCCESS) {
+               if (map->key_ptr)
+                       *map->key_ptr = key;
+               if (map->desc_ver)
+                       *map->desc_ver = desc_version;
+       } else {
+               efi_bs_call(free_pool, m);
+       }
+
+fail:
+       *map->map = m;
+       return status;
+}
+
+/**
+ * efi_allocate_pages() - Allocate memory pages
+ * @size:      minimum number of bytes to allocate
+ * @addr:      On return the address of the first allocated page. The first
+ *             allocated page has alignment EFI_ALLOC_ALIGN which is an
+ *             architecture dependent multiple of the page size.
+ * @max:       the address that the last allocated memory page shall not
+ *             exceed
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to EFI_ALLOC_ALIGN. The last allocated page will not exceed the address
+ * given by @max.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
+                               unsigned long max)
+{
+       efi_physical_addr_t alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
+       int slack = EFI_ALLOC_ALIGN / EFI_PAGE_SIZE - 1;
+       efi_status_t status;
+
+       size = round_up(size, EFI_ALLOC_ALIGN);
+       status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
+                            EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack,
+                            &alloc_addr);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       *addr = ALIGN((unsigned long)alloc_addr, EFI_ALLOC_ALIGN);
+
+       if (slack > 0) {
+               int l = (alloc_addr % EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
+
+               if (l) {
+                       efi_bs_call(free_pages, alloc_addr, slack - l + 1);
+                       slack = l - 1;
+               }
+               if (slack)
+                       efi_bs_call(free_pages, *addr + size, slack);
+       }
+       return EFI_SUCCESS;
+}
+/**
+ * efi_low_alloc_above() - allocate pages at or above given address
+ * @size:      size of the memory area to allocate
+ * @align:     minimum alignment of the allocated memory area. It should
+ *             a power of two.
+ * @addr:      on exit the address of the allocated memory
+ * @min:       minimum address to used for the memory allocation
+ *
+ * Allocate at the lowest possible address that is not below @min as
+ * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
+ * least EFI_ALLOC_ALIGN. The first allocated page will not below the address
+ * given by @min.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
+                                unsigned long *addr, unsigned long min)
+{
+       unsigned long map_size, desc_size, buff_size;
+       efi_memory_desc_t *map;
+       efi_status_t status;
+       unsigned long nr_pages;
+       int i;
+       struct efi_boot_memmap boot_map;
+
+       boot_map.map            = &map;
+       boot_map.map_size       = &map_size;
+       boot_map.desc_size      = &desc_size;
+       boot_map.desc_ver       = NULL;
+       boot_map.key_ptr        = NULL;
+       boot_map.buff_size      = &buff_size;
+
+       status = efi_get_memory_map(&boot_map);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       /*
+        * Enforce minimum alignment that EFI or Linux requires when
+        * requesting a specific address.  We are doing page-based (or
+        * larger) allocations, and both the address and size must meet
+        * alignment constraints.
+        */
+       if (align < EFI_ALLOC_ALIGN)
+               align = EFI_ALLOC_ALIGN;
+
+       size = round_up(size, EFI_ALLOC_ALIGN);
+       nr_pages = size / EFI_PAGE_SIZE;
+       for (i = 0; i < map_size / desc_size; i++) {
+               efi_memory_desc_t *desc;
+               unsigned long m = (unsigned long)map;
+               u64 start, end;
+
+               desc = efi_early_memdesc_ptr(m, desc_size, i);
+
+               if (desc->type != EFI_CONVENTIONAL_MEMORY)
+                       continue;
+
+               if (efi_soft_reserve_enabled() &&
+                   (desc->attribute & EFI_MEMORY_SP))
+                       continue;
+
+               if (desc->num_pages < nr_pages)
+                       continue;
+
+               start = desc->phys_addr;
+               end = start + desc->num_pages * EFI_PAGE_SIZE;
+
+               if (start < min)
+                       start = min;
+
+               start = round_up(start, align);
+               if ((start + size) > end)
+                       continue;
+
+               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
+                                    EFI_LOADER_DATA, nr_pages, &start);
+               if (status == EFI_SUCCESS) {
+                       *addr = start;
+                       break;
+               }
+       }
+
+       if (i == map_size / desc_size)
+               status = EFI_NOT_FOUND;
+
+       efi_bs_call(free_pool, map);
+fail:
+       return status;
+}
+
+/**
+ * efi_free() - free memory pages
+ * @size:      size of the memory area to free in bytes
+ * @addr:      start of the memory area to free (must be EFI_PAGE_SIZE
+ *             aligned)
+ *
+ * @size is rounded up to a multiple of EFI_ALLOC_ALIGN which is an
+ * architecture specific multiple of EFI_PAGE_SIZE. So this function should
+ * only be used to return pages allocated with efi_allocate_pages() or
+ * efi_low_alloc_above().
+ */
+void efi_free(unsigned long size, unsigned long addr)
+{
+       unsigned long nr_pages;
+
+       if (!size)
+               return;
+
+       nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
+       efi_bs_call(free_pages, addr, nr_pages);
+}
+
+/**
+ * efi_relocate_kernel() - copy memory area
+ * @image_addr:                pointer to address of memory area to copy
+ * @image_size:                size of memory area to copy
+ * @alloc_size:                minimum size of memory to allocate, must be greater or
+ *                     equal to image_size
+ * @preferred_addr:    preferred target address
+ * @alignment:         minimum alignment of the allocated memory area. It
+ *                     should be a power of two.
+ * @min_addr:          minimum target address
+ *
+ * Copy a memory area to a newly allocated memory area aligned according
+ * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
+ * is not available, the allocated address will not be below @min_addr.
+ * On exit, @image_addr is updated to the target copy address that was used.
+ *
+ * This function is used to copy the Linux kernel verbatim. It does not apply
+ * any relocation changes.
+ *
+ * Return:             status code
+ */
+efi_status_t efi_relocate_kernel(unsigned long *image_addr,
+                                unsigned long image_size,
+                                unsigned long alloc_size,
+                                unsigned long preferred_addr,
+                                unsigned long alignment,
+                                unsigned long min_addr)
+{
+       unsigned long cur_image_addr;
+       unsigned long new_addr = 0;
+       efi_status_t status;
+       unsigned long nr_pages;
+       efi_physical_addr_t efi_addr = preferred_addr;
+
+       if (!image_addr || !image_size || !alloc_size)
+               return EFI_INVALID_PARAMETER;
+       if (alloc_size < image_size)
+               return EFI_INVALID_PARAMETER;
+
+       cur_image_addr = *image_addr;
+
+       /*
+        * The EFI firmware loader could have placed the kernel image
+        * anywhere in memory, but the kernel has restrictions on the
+        * max physical address it can run at.  Some architectures
+        * also have a prefered address, so first try to relocate
+        * to the preferred address.  If that fails, allocate as low
+        * as possible while respecting the required alignment.
+        */
+       nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
+       status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
+                            EFI_LOADER_DATA, nr_pages, &efi_addr);
+       new_addr = efi_addr;
+       /*
+        * If preferred address allocation failed allocate as low as
+        * possible.
+        */
+       if (status != EFI_SUCCESS) {
+               status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
+                                            min_addr);
+       }
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to allocate usable memory for kernel.\n");
+               return status;
+       }
+
+       /*
+        * We know source/dest won't overlap since both memory ranges
+        * have been allocated by UEFI, so we can safely use memcpy.
+        */
+       memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
+
+       /* Return the new address of the relocated image. */
+       *image_addr = new_addr;
+
+       return status;
+}
index 316ce9f..24aa375 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 #include <linux/efi.h>
-#include <linux/log2.h>
 #include <asm/efi.h>
 
 #include "efistub.h"
@@ -26,6 +25,17 @@ union efi_rng_protocol {
        } mixed_mode;
 };
 
+/**
+ * efi_get_random_bytes() - fill a buffer with random bytes
+ * @size:      size of the buffer
+ * @out:       caller allocated buffer to receive the random bytes
+ *
+ * The call will fail if either the firmware does not implement the
+ * EFI_RNG_PROTOCOL or there are not enough random bytes available to fill
+ * the buffer.
+ *
+ * Return:     status code
+ */
 efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
 {
        efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
@@ -39,119 +49,19 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
        return efi_call_proto(rng, get_rng, NULL, size, out);
 }
 
-/*
- * Return the number of slots covered by this entry, i.e., the number of
- * addresses it covers that are suitably aligned and supply enough room
- * for the allocation.
+/**
+ * efi_random_get_seed() - provide random seed as configuration table
+ *
+ * The EFI_RNG_PROTOCOL is used to read random bytes. These random bytes are
+ * saved as a configuration table which can be used as entropy by the kernel
+ * for the initialization of its pseudo random number generator.
+ *
+ * If the EFI_RNG_PROTOCOL is not available or there are not enough random bytes
+ * available, the configuration table will not be installed and an error code
+ * will be returned.
+ *
+ * Return:     status code
  */
-static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
-                                        unsigned long size,
-                                        unsigned long align_shift)
-{
-       unsigned long align = 1UL << align_shift;
-       u64 first_slot, last_slot, region_end;
-
-       if (md->type != EFI_CONVENTIONAL_MEMORY)
-               return 0;
-
-       if (efi_soft_reserve_enabled() &&
-           (md->attribute & EFI_MEMORY_SP))
-               return 0;
-
-       region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1);
-
-       first_slot = round_up(md->phys_addr, align);
-       last_slot = round_down(region_end - size + 1, align);
-
-       if (first_slot > last_slot)
-               return 0;
-
-       return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1;
-}
-
-/*
- * The UEFI memory descriptors have a virtual address field that is only used
- * when installing the virtual mapping using SetVirtualAddressMap(). Since it
- * is unused here, we can reuse it to keep track of each descriptor's slot
- * count.
- */
-#define MD_NUM_SLOTS(md)       ((md)->virt_addr)
-
-efi_status_t efi_random_alloc(unsigned long size,
-                             unsigned long align,
-                             unsigned long *addr,
-                             unsigned long random_seed)
-{
-       unsigned long map_size, desc_size, total_slots = 0, target_slot;
-       unsigned long buff_size;
-       efi_status_t status;
-       efi_memory_desc_t *memory_map;
-       int map_offset;
-       struct efi_boot_memmap map;
-
-       map.map =       &memory_map;
-       map.map_size =  &map_size;
-       map.desc_size = &desc_size;
-       map.desc_ver =  NULL;
-       map.key_ptr =   NULL;
-       map.buff_size = &buff_size;
-
-       status = efi_get_memory_map(&map);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       if (align < EFI_ALLOC_ALIGN)
-               align = EFI_ALLOC_ALIGN;
-
-       /* count the suitable slots in each memory map entry */
-       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
-               efi_memory_desc_t *md = (void *)memory_map + map_offset;
-               unsigned long slots;
-
-               slots = get_entry_num_slots(md, size, ilog2(align));
-               MD_NUM_SLOTS(md) = slots;
-               total_slots += slots;
-       }
-
-       /* find a random number between 0 and total_slots */
-       target_slot = (total_slots * (u16)random_seed) >> 16;
-
-       /*
-        * target_slot is now a value in the range [0, total_slots), and so
-        * it corresponds with exactly one of the suitable slots we recorded
-        * when iterating over the memory map the first time around.
-        *
-        * So iterate over the memory map again, subtracting the number of
-        * slots of each entry at each iteration, until we have found the entry
-        * that covers our chosen slot. Use the residual value of target_slot
-        * to calculate the randomly chosen address, and allocate it directly
-        * using EFI_ALLOCATE_ADDRESS.
-        */
-       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
-               efi_memory_desc_t *md = (void *)memory_map + map_offset;
-               efi_physical_addr_t target;
-               unsigned long pages;
-
-               if (target_slot >= MD_NUM_SLOTS(md)) {
-                       target_slot -= MD_NUM_SLOTS(md);
-                       continue;
-               }
-
-               target = round_up(md->phys_addr, align) + target_slot * align;
-               pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
-
-               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                                    EFI_LOADER_DATA, pages, &target);
-               if (status == EFI_SUCCESS)
-                       *addr = target;
-               break;
-       }
-
-       efi_bs_call(free_pool, memory_map);
-
-       return status;
-}
-
 efi_status_t efi_random_get_seed(void)
 {
        efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c
new file mode 100644 (file)
index 0000000..4578f59
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 Linaro Ltd;  <ard.biesheuvel@linaro.org>
+ */
+
+#include <linux/efi.h>
+#include <linux/log2.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+/*
+ * Return the number of slots covered by this entry, i.e., the number of
+ * addresses it covers that are suitably aligned and supply enough room
+ * for the allocation.
+ */
+static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
+                                        unsigned long size,
+                                        unsigned long align_shift)
+{
+       unsigned long align = 1UL << align_shift;
+       u64 first_slot, last_slot, region_end;
+
+       if (md->type != EFI_CONVENTIONAL_MEMORY)
+               return 0;
+
+       if (efi_soft_reserve_enabled() &&
+           (md->attribute & EFI_MEMORY_SP))
+               return 0;
+
+       region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1,
+                        (u64)ULONG_MAX);
+
+       first_slot = round_up(md->phys_addr, align);
+       last_slot = round_down(region_end - size + 1, align);
+
+       if (first_slot > last_slot)
+               return 0;
+
+       return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1;
+}
+
+/*
+ * The UEFI memory descriptors have a virtual address field that is only used
+ * when installing the virtual mapping using SetVirtualAddressMap(). Since it
+ * is unused here, we can reuse it to keep track of each descriptor's slot
+ * count.
+ */
+#define MD_NUM_SLOTS(md)       ((md)->virt_addr)
+
+efi_status_t efi_random_alloc(unsigned long size,
+                             unsigned long align,
+                             unsigned long *addr,
+                             unsigned long random_seed)
+{
+       unsigned long map_size, desc_size, total_slots = 0, target_slot;
+       unsigned long buff_size;
+       efi_status_t status;
+       efi_memory_desc_t *memory_map;
+       int map_offset;
+       struct efi_boot_memmap map;
+
+       map.map =       &memory_map;
+       map.map_size =  &map_size;
+       map.desc_size = &desc_size;
+       map.desc_ver =  NULL;
+       map.key_ptr =   NULL;
+       map.buff_size = &buff_size;
+
+       status = efi_get_memory_map(&map);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       if (align < EFI_ALLOC_ALIGN)
+               align = EFI_ALLOC_ALIGN;
+
+       /* count the suitable slots in each memory map entry */
+       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+               efi_memory_desc_t *md = (void *)memory_map + map_offset;
+               unsigned long slots;
+
+               slots = get_entry_num_slots(md, size, ilog2(align));
+               MD_NUM_SLOTS(md) = slots;
+               total_slots += slots;
+       }
+
+       /* find a random number between 0 and total_slots */
+       target_slot = (total_slots * (u16)random_seed) >> 16;
+
+       /*
+        * target_slot is now a value in the range [0, total_slots), and so
+        * it corresponds with exactly one of the suitable slots we recorded
+        * when iterating over the memory map the first time around.
+        *
+        * So iterate over the memory map again, subtracting the number of
+        * slots of each entry at each iteration, until we have found the entry
+        * that covers our chosen slot. Use the residual value of target_slot
+        * to calculate the randomly chosen address, and allocate it directly
+        * using EFI_ALLOCATE_ADDRESS.
+        */
+       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+               efi_memory_desc_t *md = (void *)memory_map + map_offset;
+               efi_physical_addr_t target;
+               unsigned long pages;
+
+               if (target_slot >= MD_NUM_SLOTS(md)) {
+                       target_slot -= MD_NUM_SLOTS(md);
+                       continue;
+               }
+
+               target = round_up(md->phys_addr, align) + target_slot * align;
+               pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+
+               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
+                                    EFI_LOADER_DATA, pages, &target);
+               if (status == EFI_SUCCESS)
+                       *addr = target;
+               break;
+       }
+
+       efi_bs_call(free_pool, memory_map);
+
+       return status;
+}
diff --git a/drivers/firmware/efi/libstub/skip_spaces.c b/drivers/firmware/efi/libstub/skip_spaces.c
new file mode 100644 (file)
index 0000000..a700b3c
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/ctype.h>
+#include <linux/types.h>
+
+char *skip_spaces(const char *str)
+{
+       while (isspace(*str))
+               ++str;
+       return (char *)str;
+}
index ed10e3f..1ac2f87 100644 (file)
@@ -6,6 +6,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/ctype.h>
 #include <linux/types.h>
 #include <linux/string.h>
 
@@ -56,3 +57,58 @@ int strncmp(const char *cs, const char *ct, size_t count)
        return 0;
 }
 #endif
+
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
+static unsigned int simple_guess_base(const char *cp)
+{
+       if (cp[0] == '0') {
+               if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
+                       return 16;
+               else
+                       return 8;
+       } else {
+               return 10;
+       }
+}
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+
+unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
+{
+       unsigned long long result = 0;
+
+       if (!base)
+               base = simple_guess_base(cp);
+
+       if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
+               cp += 2;
+
+       while (isxdigit(*cp)) {
+               unsigned int value;
+
+               value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
+               if (value >= base)
+                       break;
+               result = result * base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+
+       return result;
+}
+
+long simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+       if (*cp == '-')
+               return -simple_strtoull(cp + 1, endp, base);
+
+       return simple_strtoull(cp, endp, base);
+}
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
new file mode 100644 (file)
index 0000000..9db9883
--- /dev/null
@@ -0,0 +1,807 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* -----------------------------------------------------------------------
+ *
+ *   Copyright 2011 Intel Corporation; author Matt Fleming
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <linux/efi.h>
+#include <linux/pci.h>
+
+#include <asm/efi.h>
+#include <asm/e820/types.h>
+#include <asm/setup.h>
+#include <asm/desc.h>
+#include <asm/boot.h>
+
+#include "efistub.h"
+
+static efi_system_table_t *sys_table;
+extern const bool efi_is64;
+
+__pure efi_system_table_t *efi_system_table(void)
+{
+       return sys_table;
+}
+
+__attribute_const__ bool efi_is_64bit(void)
+{
+       if (IS_ENABLED(CONFIG_EFI_MIXED))
+               return efi_is64;
+       return IS_ENABLED(CONFIG_X86_64);
+}
+
+static efi_status_t
+preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
+{
+       struct pci_setup_rom *rom = NULL;
+       efi_status_t status;
+       unsigned long size;
+       uint64_t romsize;
+       void *romimage;
+
+       /*
+        * Some firmware images contain EFI function pointers at the place where
+        * the romimage and romsize fields are supposed to be. Typically the EFI
+        * code is mapped at high addresses, translating to an unrealistically
+        * large romsize. The UEFI spec limits the size of option ROMs to 16
+        * MiB so we reject any ROMs over 16 MiB in size to catch this.
+        */
+       romimage = efi_table_attr(pci, romimage);
+       romsize = efi_table_attr(pci, romsize);
+       if (!romimage || !romsize || romsize > SZ_16M)
+               return EFI_INVALID_PARAMETER;
+
+       size = romsize + sizeof(*rom);
+
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
+                            (void **)&rom);
+       if (status != EFI_SUCCESS) {
+               efi_printk("Failed to allocate memory for 'rom'\n");
+               return status;
+       }
+
+       memset(rom, 0, sizeof(*rom));
+
+       rom->data.type  = SETUP_PCI;
+       rom->data.len   = size - sizeof(struct setup_data);
+       rom->data.next  = 0;
+       rom->pcilen     = pci->romsize;
+       *__rom = rom;
+
+       status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
+                               PCI_VENDOR_ID, 1, &rom->vendor);
+
+       if (status != EFI_SUCCESS) {
+               efi_printk("Failed to read rom->vendor\n");
+               goto free_struct;
+       }
+
+       status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
+                               PCI_DEVICE_ID, 1, &rom->devid);
+
+       if (status != EFI_SUCCESS) {
+               efi_printk("Failed to read rom->devid\n");
+               goto free_struct;
+       }
+
+       status = efi_call_proto(pci, get_location, &rom->segment, &rom->bus,
+                               &rom->device, &rom->function);
+
+       if (status != EFI_SUCCESS)
+               goto free_struct;
+
+       memcpy(rom->romdata, romimage, romsize);
+       return status;
+
+free_struct:
+       efi_bs_call(free_pool, rom);
+       return status;
+}
+
+/*
+ * There's no way to return an informative status from this function,
+ * because any analysis (and printing of error messages) needs to be
+ * done directly at the EFI function call-site.
+ *
+ * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we
+ * just didn't find any PCI devices, but there's no way to tell outside
+ * the context of the call.
+ */
+static void setup_efi_pci(struct boot_params *params)
+{
+       efi_status_t status;
+       void **pci_handle = NULL;
+       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+       unsigned long size = 0;
+       struct setup_data *data;
+       efi_handle_t h;
+       int i;
+
+       status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
+                            &pci_proto, NULL, &size, pci_handle);
+
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
+                                    (void **)&pci_handle);
+
+               if (status != EFI_SUCCESS) {
+                       efi_printk("Failed to allocate memory for 'pci_handle'\n");
+                       return;
+               }
+
+               status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
+                                    &pci_proto, NULL, &size, pci_handle);
+       }
+
+       if (status != EFI_SUCCESS)
+               goto free_handle;
+
+       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+       while (data && data->next)
+               data = (struct setup_data *)(unsigned long)data->next;
+
+       for_each_efi_handle(h, pci_handle, size, i) {
+               efi_pci_io_protocol_t *pci = NULL;
+               struct pci_setup_rom *rom;
+
+               status = efi_bs_call(handle_protocol, h, &pci_proto,
+                                    (void **)&pci);
+               if (status != EFI_SUCCESS || !pci)
+                       continue;
+
+               status = preserve_pci_rom_image(pci, &rom);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               if (data)
+                       data->next = (unsigned long)rom;
+               else
+                       params->hdr.setup_data = (unsigned long)rom;
+
+               data = (struct setup_data *)rom;
+       }
+
+free_handle:
+       efi_bs_call(free_pool, pci_handle);
+}
+
+static void retrieve_apple_device_properties(struct boot_params *boot_params)
+{
+       efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
+       struct setup_data *data, *new;
+       efi_status_t status;
+       u32 size = 0;
+       apple_properties_protocol_t *p;
+
+       status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&p);
+       if (status != EFI_SUCCESS)
+               return;
+
+       if (efi_table_attr(p, version) != 0x10000) {
+               efi_printk("Unsupported properties proto version\n");
+               return;
+       }
+
+       efi_call_proto(p, get_all, NULL, &size);
+       if (!size)
+               return;
+
+       do {
+               status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
+                                    size + sizeof(struct setup_data),
+                                    (void **)&new);
+               if (status != EFI_SUCCESS) {
+                       efi_printk("Failed to allocate memory for 'properties'\n");
+                       return;
+               }
+
+               status = efi_call_proto(p, get_all, new->data, &size);
+
+               if (status == EFI_BUFFER_TOO_SMALL)
+                       efi_bs_call(free_pool, new);
+       } while (status == EFI_BUFFER_TOO_SMALL);
+
+       new->type = SETUP_APPLE_PROPERTIES;
+       new->len  = size;
+       new->next = 0;
+
+       data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
+       if (!data) {
+               boot_params->hdr.setup_data = (unsigned long)new;
+       } else {
+               while (data->next)
+                       data = (struct setup_data *)(unsigned long)data->next;
+               data->next = (unsigned long)new;
+       }
+}
+
+static const efi_char16_t apple[] = L"Apple";
+
+static void setup_quirks(struct boot_params *boot_params)
+{
+       efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
+               efi_table_attr(efi_system_table(), fw_vendor);
+
+       if (!memcmp(fw_vendor, apple, sizeof(apple))) {
+               if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
+                       retrieve_apple_device_properties(boot_params);
+       }
+}
+
+/*
+ * See if we have Universal Graphics Adapter (UGA) protocol
+ */
+static efi_status_t
+setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size)
+{
+       efi_status_t status;
+       u32 width, height;
+       void **uga_handle = NULL;
+       efi_uga_draw_protocol_t *uga = NULL, *first_uga;
+       efi_handle_t handle;
+       int i;
+
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
+                            (void **)&uga_handle);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
+                            uga_proto, NULL, &size, uga_handle);
+       if (status != EFI_SUCCESS)
+               goto free_handle;
+
+       height = 0;
+       width = 0;
+
+       first_uga = NULL;
+       for_each_efi_handle(handle, uga_handle, size, i) {
+               efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
+               u32 w, h, depth, refresh;
+               void *pciio;
+
+               status = efi_bs_call(handle_protocol, handle, uga_proto,
+                                    (void **)&uga);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               pciio = NULL;
+               efi_bs_call(handle_protocol, handle, &pciio_proto, &pciio);
+
+               status = efi_call_proto(uga, get_mode, &w, &h, &depth, &refresh);
+               if (status == EFI_SUCCESS && (!first_uga || pciio)) {
+                       width = w;
+                       height = h;
+
+                       /*
+                        * Once we've found a UGA supporting PCIIO,
+                        * don't bother looking any further.
+                        */
+                       if (pciio)
+                               break;
+
+                       first_uga = uga;
+               }
+       }
+
+       if (!width && !height)
+               goto free_handle;
+
+       /* EFI framebuffer */
+       si->orig_video_isVGA    = VIDEO_TYPE_EFI;
+
+       si->lfb_depth           = 32;
+       si->lfb_width           = width;
+       si->lfb_height          = height;
+
+       si->red_size            = 8;
+       si->red_pos             = 16;
+       si->green_size          = 8;
+       si->green_pos           = 8;
+       si->blue_size           = 8;
+       si->blue_pos            = 0;
+       si->rsvd_size           = 8;
+       si->rsvd_pos            = 24;
+
+free_handle:
+       efi_bs_call(free_pool, uga_handle);
+
+       return status;
+}
+
+static void setup_graphics(struct boot_params *boot_params)
+{
+       efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+       struct screen_info *si;
+       efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+       efi_status_t status;
+       unsigned long size;
+       void **gop_handle = NULL;
+       void **uga_handle = NULL;
+
+       si = &boot_params->screen_info;
+       memset(si, 0, sizeof(*si));
+
+       size = 0;
+       status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
+                            &graphics_proto, NULL, &size, gop_handle);
+       if (status == EFI_BUFFER_TOO_SMALL)
+               status = efi_setup_gop(si, &graphics_proto, size);
+
+       if (status != EFI_SUCCESS) {
+               size = 0;
+               status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
+                                    &uga_proto, NULL, &size, uga_handle);
+               if (status == EFI_BUFFER_TOO_SMALL)
+                       setup_uga(si, &uga_proto, size);
+       }
+}
+
+
+static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)
+{
+       efi_bs_call(exit, handle, status, 0, NULL);
+       unreachable();
+}
+
+void startup_32(struct boot_params *boot_params);
+
+void __noreturn efi_stub_entry(efi_handle_t handle,
+                              efi_system_table_t *sys_table_arg,
+                              struct boot_params *boot_params);
+
+/*
+ * Because the x86 boot code expects to be passed a boot_params we
+ * need to create one ourselves (usually the bootloader would create
+ * one for us).
+ */
+efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
+                                  efi_system_table_t *sys_table_arg)
+{
+       struct boot_params *boot_params;
+       struct setup_header *hdr;
+       efi_loaded_image_t *image;
+       efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
+       int options_size = 0;
+       efi_status_t status;
+       char *cmdline_ptr;
+       unsigned long ramdisk_addr;
+       unsigned long ramdisk_size;
+       bool above4g;
+
+       sys_table = sys_table_arg;
+
+       /* Check if we were booted by the EFI firmware */
+       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+               efi_exit(handle, EFI_INVALID_PARAMETER);
+
+       status = efi_bs_call(handle_protocol, handle, &proto, (void *)&image);
+       if (status != EFI_SUCCESS) {
+               efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
+               efi_exit(handle, status);
+       }
+
+       hdr = &((struct boot_params *)efi_table_attr(image, image_base))->hdr;
+       above4g = hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G;
+
+       status = efi_allocate_pages(0x4000, (unsigned long *)&boot_params,
+                                   above4g ? ULONG_MAX : UINT_MAX);
+       if (status != EFI_SUCCESS) {
+               efi_printk("Failed to allocate lowmem for boot params\n");
+               efi_exit(handle, status);
+       }
+
+       memset(boot_params, 0x0, 0x4000);
+
+       hdr = &boot_params->hdr;
+
+       /* Copy the second sector to boot_params */
+       memcpy(&hdr->jump, efi_table_attr(image, image_base) + 512, 512);
+
+       /*
+        * Fill out some of the header fields ourselves because the
+        * EFI firmware loader doesn't load the first sector.
+        */
+       hdr->root_flags = 1;
+       hdr->vid_mode   = 0xffff;
+       hdr->boot_flag  = 0xAA55;
+
+       hdr->type_of_loader = 0x21;
+
+       /* Convert unicode cmdline to ascii */
+       cmdline_ptr = efi_convert_cmdline(image, &options_size,
+                                         above4g ? ULONG_MAX : UINT_MAX);
+       if (!cmdline_ptr)
+               goto fail;
+
+       hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
+       /* Fill in upper bits of command line address, NOP on 32 bit  */
+       boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
+
+       hdr->ramdisk_image = 0;
+       hdr->ramdisk_size = 0;
+
+       if (efi_is_native()) {
+               status = efi_parse_options(cmdline_ptr);
+               if (status != EFI_SUCCESS)
+                       goto fail2;
+
+               if (!noinitrd()) {
+                       status = efi_load_initrd(image, &ramdisk_addr,
+                                                &ramdisk_size,
+                                                hdr->initrd_addr_max,
+                                                above4g ? ULONG_MAX
+                                                        : hdr->initrd_addr_max);
+                       if (status != EFI_SUCCESS)
+                               goto fail2;
+                       hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
+                       hdr->ramdisk_size  = ramdisk_size & 0xffffffff;
+                       boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
+                       boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
+               }
+       }
+
+       efi_stub_entry(handle, sys_table, boot_params);
+       /* not reached */
+
+fail2:
+       efi_free(options_size, (unsigned long)cmdline_ptr);
+fail:
+       efi_free(0x4000, (unsigned long)boot_params);
+
+       efi_exit(handle, status);
+}
+
+static void add_e820ext(struct boot_params *params,
+                       struct setup_data *e820ext, u32 nr_entries)
+{
+       struct setup_data *data;
+
+       e820ext->type = SETUP_E820_EXT;
+       e820ext->len  = nr_entries * sizeof(struct boot_e820_entry);
+       e820ext->next = 0;
+
+       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+       while (data && data->next)
+               data = (struct setup_data *)(unsigned long)data->next;
+
+       if (data)
+               data->next = (unsigned long)e820ext;
+       else
+               params->hdr.setup_data = (unsigned long)e820ext;
+}
+
+static efi_status_t
+setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_size)
+{
+       struct boot_e820_entry *entry = params->e820_table;
+       struct efi_info *efi = &params->efi_info;
+       struct boot_e820_entry *prev = NULL;
+       u32 nr_entries;
+       u32 nr_desc;
+       int i;
+
+       nr_entries = 0;
+       nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
+
+       for (i = 0; i < nr_desc; i++) {
+               efi_memory_desc_t *d;
+               unsigned int e820_type = 0;
+               unsigned long m = efi->efi_memmap;
+
+#ifdef CONFIG_X86_64
+               m |= (u64)efi->efi_memmap_hi << 32;
+#endif
+
+               d = efi_early_memdesc_ptr(m, efi->efi_memdesc_size, i);
+               switch (d->type) {
+               case EFI_RESERVED_TYPE:
+               case EFI_RUNTIME_SERVICES_CODE:
+               case EFI_RUNTIME_SERVICES_DATA:
+               case EFI_MEMORY_MAPPED_IO:
+               case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+               case EFI_PAL_CODE:
+                       e820_type = E820_TYPE_RESERVED;
+                       break;
+
+               case EFI_UNUSABLE_MEMORY:
+                       e820_type = E820_TYPE_UNUSABLE;
+                       break;
+
+               case EFI_ACPI_RECLAIM_MEMORY:
+                       e820_type = E820_TYPE_ACPI;
+                       break;
+
+               case EFI_LOADER_CODE:
+               case EFI_LOADER_DATA:
+               case EFI_BOOT_SERVICES_CODE:
+               case EFI_BOOT_SERVICES_DATA:
+               case EFI_CONVENTIONAL_MEMORY:
+                       if (efi_soft_reserve_enabled() &&
+                           (d->attribute & EFI_MEMORY_SP))
+                               e820_type = E820_TYPE_SOFT_RESERVED;
+                       else
+                               e820_type = E820_TYPE_RAM;
+                       break;
+
+               case EFI_ACPI_MEMORY_NVS:
+                       e820_type = E820_TYPE_NVS;
+                       break;
+
+               case EFI_PERSISTENT_MEMORY:
+                       e820_type = E820_TYPE_PMEM;
+                       break;
+
+               default:
+                       continue;
+               }
+
+               /* Merge adjacent mappings */
+               if (prev && prev->type == e820_type &&
+                   (prev->addr + prev->size) == d->phys_addr) {
+                       prev->size += d->num_pages << 12;
+                       continue;
+               }
+
+               if (nr_entries == ARRAY_SIZE(params->e820_table)) {
+                       u32 need = (nr_desc - i) * sizeof(struct e820_entry) +
+                                  sizeof(struct setup_data);
+
+                       if (!e820ext || e820ext_size < need)
+                               return EFI_BUFFER_TOO_SMALL;
+
+                       /* boot_params map full, switch to e820 extended */
+                       entry = (struct boot_e820_entry *)e820ext->data;
+               }
+
+               entry->addr = d->phys_addr;
+               entry->size = d->num_pages << PAGE_SHIFT;
+               entry->type = e820_type;
+               prev = entry++;
+               nr_entries++;
+       }
+
+       if (nr_entries > ARRAY_SIZE(params->e820_table)) {
+               u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_table);
+
+               add_e820ext(params, e820ext, nr_e820ext);
+               nr_entries -= nr_e820ext;
+       }
+
+       params->e820_entries = (u8)nr_entries;
+
+       return EFI_SUCCESS;
+}
+
+static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
+                                 u32 *e820ext_size)
+{
+       efi_status_t status;
+       unsigned long size;
+
+       size = sizeof(struct setup_data) +
+               sizeof(struct e820_entry) * nr_desc;
+
+       if (*e820ext) {
+               efi_bs_call(free_pool, *e820ext);
+               *e820ext = NULL;
+               *e820ext_size = 0;
+       }
+
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
+                            (void **)e820ext);
+       if (status == EFI_SUCCESS)
+               *e820ext_size = size;
+
+       return status;
+}
+
+static efi_status_t allocate_e820(struct boot_params *params,
+                                 struct setup_data **e820ext,
+                                 u32 *e820ext_size)
+{
+       unsigned long map_size, desc_size, buff_size;
+       struct efi_boot_memmap boot_map;
+       efi_memory_desc_t *map;
+       efi_status_t status;
+       __u32 nr_desc;
+
+       boot_map.map            = &map;
+       boot_map.map_size       = &map_size;
+       boot_map.desc_size      = &desc_size;
+       boot_map.desc_ver       = NULL;
+       boot_map.key_ptr        = NULL;
+       boot_map.buff_size      = &buff_size;
+
+       status = efi_get_memory_map(&boot_map);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       nr_desc = buff_size / desc_size;
+
+       if (nr_desc > ARRAY_SIZE(params->e820_table)) {
+               u32 nr_e820ext = nr_desc - ARRAY_SIZE(params->e820_table);
+
+               status = alloc_e820ext(nr_e820ext, e820ext, e820ext_size);
+               if (status != EFI_SUCCESS)
+                       return status;
+       }
+
+       return EFI_SUCCESS;
+}
+
+struct exit_boot_struct {
+       struct boot_params      *boot_params;
+       struct efi_info         *efi;
+};
+
+static efi_status_t exit_boot_func(struct efi_boot_memmap *map,
+                                  void *priv)
+{
+       const char *signature;
+       struct exit_boot_struct *p = priv;
+
+       signature = efi_is_64bit() ? EFI64_LOADER_SIGNATURE
+                                  : EFI32_LOADER_SIGNATURE;
+       memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
+
+       p->efi->efi_systab              = (unsigned long)efi_system_table();
+       p->efi->efi_memdesc_size        = *map->desc_size;
+       p->efi->efi_memdesc_version     = *map->desc_ver;
+       p->efi->efi_memmap              = (unsigned long)*map->map;
+       p->efi->efi_memmap_size         = *map->map_size;
+
+#ifdef CONFIG_X86_64
+       p->efi->efi_systab_hi           = (unsigned long)efi_system_table() >> 32;
+       p->efi->efi_memmap_hi           = (unsigned long)*map->map >> 32;
+#endif
+
+       return EFI_SUCCESS;
+}
+
+static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
+{
+       unsigned long map_sz, key, desc_size, buff_size;
+       efi_memory_desc_t *mem_map;
+       struct setup_data *e820ext = NULL;
+       __u32 e820ext_size = 0;
+       efi_status_t status;
+       __u32 desc_version;
+       struct efi_boot_memmap map;
+       struct exit_boot_struct priv;
+
+       map.map                 = &mem_map;
+       map.map_size            = &map_sz;
+       map.desc_size           = &desc_size;
+       map.desc_ver            = &desc_version;
+       map.key_ptr             = &key;
+       map.buff_size           = &buff_size;
+       priv.boot_params        = boot_params;
+       priv.efi                = &boot_params->efi_info;
+
+       status = allocate_e820(boot_params, &e820ext, &e820ext_size);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       /* Might as well exit boot services now */
+       status = efi_exit_boot_services(handle, &map, &priv, exit_boot_func);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       /* Historic? */
+       boot_params->alt_mem_k  = 32 * 1024;
+
+       status = setup_e820(boot_params, e820ext, e820ext_size);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       return EFI_SUCCESS;
+}
+
+/*
+ * On success we return a pointer to a boot_params structure, and NULL
+ * on failure.
+ */
+struct boot_params *efi_main(efi_handle_t handle,
+                            efi_system_table_t *sys_table_arg,
+                            struct boot_params *boot_params)
+{
+       unsigned long bzimage_addr = (unsigned long)startup_32;
+       struct setup_header *hdr = &boot_params->hdr;
+       efi_status_t status;
+       unsigned long cmdline_paddr;
+
+       sys_table = sys_table_arg;
+
+       /* Check if we were booted by the EFI firmware */
+       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+               efi_exit(handle, EFI_INVALID_PARAMETER);
+
+       /*
+        * If the kernel isn't already loaded at the preferred load
+        * address, relocate it.
+        */
+       if (bzimage_addr != hdr->pref_address) {
+               status = efi_relocate_kernel(&bzimage_addr,
+                                            hdr->init_size, hdr->init_size,
+                                            hdr->pref_address,
+                                            hdr->kernel_alignment,
+                                            LOAD_PHYSICAL_ADDR);
+               if (status != EFI_SUCCESS) {
+                       efi_printk("efi_relocate_kernel() failed!\n");
+                       goto fail;
+               }
+       }
+       hdr->code32_start = (u32)bzimage_addr;
+
+       /*
+        * efi_pe_entry() may have been called before efi_main(), in which
+        * case this is the second time we parse the cmdline. This is ok,
+        * parsing the cmdline multiple times does not have side-effects.
+        */
+       cmdline_paddr = ((u64)hdr->cmd_line_ptr |
+                        ((u64)boot_params->ext_cmd_line_ptr << 32));
+       efi_parse_options((char *)cmdline_paddr);
+
+       /*
+        * At this point, an initrd may already have been loaded, either by
+        * the bootloader and passed via bootparams, or loaded from a initrd=
+        * command line option by efi_pe_entry() above. In either case, we
+        * permit an initrd loaded from the LINUX_EFI_INITRD_MEDIA_GUID device
+        * path to supersede it.
+        */
+       if (!noinitrd()) {
+               unsigned long addr, size;
+               unsigned long max_addr = hdr->initrd_addr_max;
+
+               if (hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G)
+                       max_addr = ULONG_MAX;
+
+               status = efi_load_initrd_dev_path(&addr, &size, max_addr);
+               if (status == EFI_SUCCESS) {
+                       hdr->ramdisk_image              = (u32)addr;
+                       hdr->ramdisk_size               = (u32)size;
+                       boot_params->ext_ramdisk_image  = (u64)addr >> 32;
+                       boot_params->ext_ramdisk_size   = (u64)size >> 32;
+               } else if (status != EFI_NOT_FOUND) {
+                       efi_printk("efi_load_initrd_dev_path() failed!\n");
+                       goto fail;
+               }
+       }
+
+       /*
+        * If the boot loader gave us a value for secure_boot then we use that,
+        * otherwise we ask the BIOS.
+        */
+       if (boot_params->secure_boot == efi_secureboot_mode_unset)
+               boot_params->secure_boot = efi_get_secureboot();
+
+       /* Ask the firmware to clear memory on unclean shutdown */
+       efi_enable_reset_attack_mitigation();
+
+       efi_random_get_seed();
+
+       efi_retrieve_tpm2_eventlog();
+
+       setup_graphics(boot_params);
+
+       setup_efi_pci(boot_params);
+
+       setup_quirks(boot_params);
+
+       status = exit_boot(boot_params, handle);
+       if (status != EFI_SUCCESS) {
+               efi_printk("exit_boot() failed!\n");
+               goto fail;
+       }
+
+       return boot_params;
+fail:
+       efi_printk("efi_main() failed!\n");
+
+       efi_exit(handle, status);
+}
index 58452fd..5737cb0 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/early_ioremap.h>
 
 static int __initdata tbl_size;
+unsigned long __ro_after_init efi_mem_attr_table = EFI_INVALID_TABLE_ADDR;
 
 /*
  * Reserve the memory associated with the Memory Attributes configuration
@@ -22,13 +23,13 @@ int __init efi_memattr_init(void)
 {
        efi_memory_attributes_table_t *tbl;
 
-       if (efi.mem_attr_table == EFI_INVALID_TABLE_ADDR)
+       if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR)
                return 0;
 
-       tbl = early_memremap(efi.mem_attr_table, sizeof(*tbl));
+       tbl = early_memremap(efi_mem_attr_table, sizeof(*tbl));
        if (!tbl) {
                pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
-                      efi.mem_attr_table);
+                      efi_mem_attr_table);
                return -ENOMEM;
        }
 
@@ -39,7 +40,7 @@ int __init efi_memattr_init(void)
        }
 
        tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size;
-       memblock_reserve(efi.mem_attr_table, tbl_size);
+       memblock_reserve(efi_mem_attr_table, tbl_size);
        set_bit(EFI_MEM_ATTR, &efi.flags);
 
 unmap:
@@ -147,10 +148,10 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
        if (WARN_ON(!efi_enabled(EFI_MEMMAP)))
                return 0;
 
-       tbl = memremap(efi.mem_attr_table, tbl_size, MEMREMAP_WB);
+       tbl = memremap(efi_mem_attr_table, tbl_size, MEMREMAP_WB);
        if (!tbl) {
                pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
-                      efi.mem_attr_table);
+                      efi_mem_attr_table);
                return -ENOMEM;
        }
 
index 7effff9..73089a2 100644 (file)
@@ -15,7 +15,7 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
        const char *str[] = { "cold", "warm", "shutdown", "platform" };
        int efi_mode, cap_reset_mode;
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
                return;
 
        switch (reboot_mode) {
@@ -64,7 +64,7 @@ static void efi_power_off(void)
 
 static int __init efi_shutdown_init(void)
 {
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
                return -ENODEV;
 
        if (efi_poweroff_required()) {
index 65fffaa..1410bea 100644 (file)
@@ -40,9 +40,9 @@
  * code doesn't get too cluttered:
  */
 #define efi_call_virt(f, args...)   \
-       efi_call_virt_pointer(efi.systab->runtime, f, args)
+       efi_call_virt_pointer(efi.runtime, f, args)
 #define __efi_call_virt(f, args...) \
-       __efi_call_virt_pointer(efi.systab->runtime, f, args)
+       __efi_call_virt_pointer(efi.runtime, f, args)
 
 struct efi_runtime_work efi_rts_work;
 
index 4adeb7a..715a454 100644 (file)
@@ -80,6 +80,8 @@ setup_vga_console(struct pcdp_device *dev)
 #endif
 }
 
+extern unsigned long hcdp_phys;
+
 int __init
 efi_setup_pcdp_console(char *cmdline)
 {
@@ -89,11 +91,11 @@ efi_setup_pcdp_console(char *cmdline)
        int i, serial = 0;
        int rc = -ENODEV;
 
-       if (efi.hcdp == EFI_INVALID_TABLE_ADDR)
+       if (hcdp_phys == EFI_INVALID_TABLE_ADDR)
                return -ENODEV;
 
-       pcdp = early_memremap(efi.hcdp, 4096);
-       printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, efi.hcdp);
+       pcdp = early_memremap(hcdp_phys, 4096);
+       printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, hcdp_phys);
 
        if (strstr(cmdline, "console=hcdp")) {
                if (pcdp->rev < 3)
index d106d23..c22ab7b 100644 (file)
@@ -78,7 +78,7 @@ static int read_efi_var(const char *name, unsigned long *size,
        *size = 0;
        *return_data = NULL;
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                return -EOPNOTSUPP;
 
        uni_name = kcalloc(strlen(name) + 1, sizeof(efi_char16_t), GFP_KERNEL);
index 4ac8f19..24c7dfa 100644 (file)
@@ -12,10 +12,6 @@ obj-$(CONFIG_RTC_CLASS)              += rtc-core.o
 obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
 rtc-core-y                     := class.o interface.o
 
-ifdef CONFIG_RTC_DRV_EFI
-rtc-core-y                     += rtc-efi-platform.o
-endif
-
 rtc-core-$(CONFIG_RTC_NVMEM)           += nvmem.o
 rtc-core-$(CONFIG_RTC_INTF_DEV)                += dev.o
 rtc-core-$(CONFIG_RTC_INTF_PROC)       += proc.o
diff --git a/drivers/rtc/rtc-efi-platform.c b/drivers/rtc/rtc-efi-platform.c
deleted file mode 100644 (file)
index 6c037dc..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Moved from arch/ia64/kernel/time.c
- *
- * Copyright (C) 1998-2003 Hewlett-Packard Co
- *     Stephane Eranian <eranian@hpl.hp.com>
- *     David Mosberger <davidm@hpl.hp.com>
- * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
- * Copyright (C) 1999-2000 VA Linux Systems
- * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/efi.h>
-#include <linux/platform_device.h>
-
-static struct platform_device rtc_efi_dev = {
-       .name = "rtc-efi",
-       .id = -1,
-};
-
-static int __init rtc_init(void)
-{
-       if (efi_enabled(EFI_RUNTIME_SERVICES))
-               if (platform_device_register(&rtc_efi_dev) < 0)
-                       pr_err("unable to register rtc device...\n");
-
-       /* not necessarily an error */
-       return 0;
-}
-module_init(rtc_init);
index b48aac8..974c3b9 100644 (file)
@@ -621,7 +621,7 @@ static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENOMEM;
        pci_set_drvdata(pdev, pci_info);
 
-       if (efi_enabled(EFI_RUNTIME_SERVICES))
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                orom = isci_get_efi_var(pdev);
 
        if (!orom)
index fa4f644..12c66f5 100644 (file)
@@ -252,7 +252,7 @@ static struct file_system_type efivarfs_type = {
 
 static __init int efivarfs_init(void)
 {
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
                return -ENODEV;
 
        if (!efivars_kobject())
index 7efd707..abfc98e 100644 (file)
@@ -56,19 +56,6 @@ typedef void *efi_handle_t;
 #define __efiapi
 #endif
 
-#define efi_get_handle_at(array, idx)                                  \
-       (efi_is_native() ? (array)[idx]                                 \
-               : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
-
-#define efi_get_handle_num(size)                                       \
-       ((size) / (efi_is_native() ? sizeof(efi_handle_t) : sizeof(u32)))
-
-#define for_each_efi_handle(handle, array, size, i)                    \
-       for (i = 0;                                                     \
-            i < efi_get_handle_num(size) &&                            \
-               ((handle = efi_get_handle_at((array), i)) || true);     \
-            i++)
-
 /*
  * The UEFI spec and EDK2 reference implementation both define EFI_GUID as
  * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment
@@ -157,15 +144,6 @@ typedef struct {
        u32 imagesize;
 } efi_capsule_header_t;
 
-struct efi_boot_memmap {
-       efi_memory_desc_t       **map;
-       unsigned long           *map_size;
-       unsigned long           *desc_size;
-       u32                     *desc_ver;
-       unsigned long           *key_ptr;
-       unsigned long           *buff_size;
-};
-
 /*
  * EFI capsule flags
  */
@@ -187,14 +165,6 @@ struct capsule_info {
 
 int __efi_capsule_setup_info(struct capsule_info *cap_info);
 
-/*
- * Allocation types for calls to boottime->allocate_pages.
- */
-#define EFI_ALLOCATE_ANY_PAGES         0
-#define EFI_ALLOCATE_MAX_ADDRESS       1
-#define EFI_ALLOCATE_ADDRESS           2
-#define EFI_MAX_ALLOCATE_TYPE          3
-
 typedef int (*efi_freemem_callback_t) (u64 start, u64 end, void *arg);
 
 /*
@@ -224,291 +194,7 @@ typedef struct {
        u8 sets_to_zero;
 } efi_time_cap_t;
 
-typedef struct {
-       efi_table_hdr_t hdr;
-       u32 raise_tpl;
-       u32 restore_tpl;
-       u32 allocate_pages;
-       u32 free_pages;
-       u32 get_memory_map;
-       u32 allocate_pool;
-       u32 free_pool;
-       u32 create_event;
-       u32 set_timer;
-       u32 wait_for_event;
-       u32 signal_event;
-       u32 close_event;
-       u32 check_event;
-       u32 install_protocol_interface;
-       u32 reinstall_protocol_interface;
-       u32 uninstall_protocol_interface;
-       u32 handle_protocol;
-       u32 __reserved;
-       u32 register_protocol_notify;
-       u32 locate_handle;
-       u32 locate_device_path;
-       u32 install_configuration_table;
-       u32 load_image;
-       u32 start_image;
-       u32 exit;
-       u32 unload_image;
-       u32 exit_boot_services;
-       u32 get_next_monotonic_count;
-       u32 stall;
-       u32 set_watchdog_timer;
-       u32 connect_controller;
-       u32 disconnect_controller;
-       u32 open_protocol;
-       u32 close_protocol;
-       u32 open_protocol_information;
-       u32 protocols_per_handle;
-       u32 locate_handle_buffer;
-       u32 locate_protocol;
-       u32 install_multiple_protocol_interfaces;
-       u32 uninstall_multiple_protocol_interfaces;
-       u32 calculate_crc32;
-       u32 copy_mem;
-       u32 set_mem;
-       u32 create_event_ex;
-} __packed efi_boot_services_32_t;
-
-/*
- * EFI Boot Services table
- */
-typedef union {
-       struct {
-               efi_table_hdr_t hdr;
-               void *raise_tpl;
-               void *restore_tpl;
-               efi_status_t (__efiapi *allocate_pages)(int, int, unsigned long,
-                                                       efi_physical_addr_t *);
-               efi_status_t (__efiapi *free_pages)(efi_physical_addr_t,
-                                                   unsigned long);
-               efi_status_t (__efiapi *get_memory_map)(unsigned long *, void *,
-                                                       unsigned long *,
-                                                       unsigned long *, u32 *);
-               efi_status_t (__efiapi *allocate_pool)(int, unsigned long,
-                                                      void **);
-               efi_status_t (__efiapi *free_pool)(void *);
-               void *create_event;
-               void *set_timer;
-               void *wait_for_event;
-               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 *handle_protocol)(efi_handle_t,
-                                                        efi_guid_t *, void **);
-               void *__reserved;
-               void *register_protocol_notify;
-               efi_status_t (__efiapi *locate_handle)(int, efi_guid_t *,
-                                                      void *, unsigned long *,
-                                                      efi_handle_t *);
-               void *locate_device_path;
-               efi_status_t (__efiapi *install_configuration_table)(efi_guid_t *,
-                                                                    void *);
-               void *load_image;
-               void *start_image;
-               void *exit;
-               void *unload_image;
-               efi_status_t (__efiapi *exit_boot_services)(efi_handle_t,
-                                                           unsigned long);
-               void *get_next_monotonic_count;
-               void *stall;
-               void *set_watchdog_timer;
-               void *connect_controller;
-               efi_status_t (__efiapi *disconnect_controller)(efi_handle_t,
-                                                              efi_handle_t,
-                                                              efi_handle_t);
-               void *open_protocol;
-               void *close_protocol;
-               void *open_protocol_information;
-               void *protocols_per_handle;
-               void *locate_handle_buffer;
-               efi_status_t (__efiapi *locate_protocol)(efi_guid_t *, void *,
-                                                        void **);
-               void *install_multiple_protocol_interfaces;
-               void *uninstall_multiple_protocol_interfaces;
-               void *calculate_crc32;
-               void *copy_mem;
-               void *set_mem;
-               void *create_event_ex;
-       };
-       efi_boot_services_32_t mixed_mode;
-} efi_boot_services_t;
-
-typedef enum {
-       EfiPciIoWidthUint8,
-       EfiPciIoWidthUint16,
-       EfiPciIoWidthUint32,
-       EfiPciIoWidthUint64,
-       EfiPciIoWidthFifoUint8,
-       EfiPciIoWidthFifoUint16,
-       EfiPciIoWidthFifoUint32,
-       EfiPciIoWidthFifoUint64,
-       EfiPciIoWidthFillUint8,
-       EfiPciIoWidthFillUint16,
-       EfiPciIoWidthFillUint32,
-       EfiPciIoWidthFillUint64,
-       EfiPciIoWidthMaximum
-} EFI_PCI_IO_PROTOCOL_WIDTH;
-
-typedef enum {
-       EfiPciIoAttributeOperationGet,
-       EfiPciIoAttributeOperationSet,
-       EfiPciIoAttributeOperationEnable,
-       EfiPciIoAttributeOperationDisable,
-       EfiPciIoAttributeOperationSupported,
-    EfiPciIoAttributeOperationMaximum
-} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
-
-typedef struct {
-       u32 read;
-       u32 write;
-} efi_pci_io_protocol_access_32_t;
-
-typedef union efi_pci_io_protocol efi_pci_io_protocol_t;
-
-typedef
-efi_status_t (__efiapi *efi_pci_io_protocol_cfg_t)(efi_pci_io_protocol_t *,
-                                                  EFI_PCI_IO_PROTOCOL_WIDTH,
-                                                  u32 offset,
-                                                  unsigned long count,
-                                                  void *buffer);
-
-typedef struct {
-       void *read;
-       void *write;
-} efi_pci_io_protocol_access_t;
-
-typedef struct {
-       efi_pci_io_protocol_cfg_t read;
-       efi_pci_io_protocol_cfg_t write;
-} efi_pci_io_protocol_config_access_t;
-
-union efi_pci_io_protocol {
-       struct {
-               void *poll_mem;
-               void *poll_io;
-               efi_pci_io_protocol_access_t mem;
-               efi_pci_io_protocol_access_t io;
-               efi_pci_io_protocol_config_access_t pci;
-               void *copy_mem;
-               void *map;
-               void *unmap;
-               void *allocate_buffer;
-               void *free_buffer;
-               void *flush;
-               efi_status_t (__efiapi *get_location)(efi_pci_io_protocol_t *,
-                                                     unsigned long *segment_nr,
-                                                     unsigned long *bus_nr,
-                                                     unsigned long *device_nr,
-                                                     unsigned long *func_nr);
-               void *attributes;
-               void *get_bar_attributes;
-               void *set_bar_attributes;
-               uint64_t romsize;
-               void *romimage;
-       };
-       struct {
-               u32 poll_mem;
-               u32 poll_io;
-               efi_pci_io_protocol_access_32_t mem;
-               efi_pci_io_protocol_access_32_t io;
-               efi_pci_io_protocol_access_32_t pci;
-               u32 copy_mem;
-               u32 map;
-               u32 unmap;
-               u32 allocate_buffer;
-               u32 free_buffer;
-               u32 flush;
-               u32 get_location;
-               u32 attributes;
-               u32 get_bar_attributes;
-               u32 set_bar_attributes;
-               u64 romsize;
-               u32 romimage;
-       } mixed_mode;
-};
-
-#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
-#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002
-#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004
-#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008
-#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010
-#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
-#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
-#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200
-#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000
-#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000
-#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000
-#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
-#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000
-#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000
-#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000
-
-struct efi_dev_path;
-
-typedef union apple_properties_protocol apple_properties_protocol_t;
-
-union apple_properties_protocol {
-       struct {
-               unsigned long version;
-               efi_status_t (__efiapi *get)(apple_properties_protocol_t *,
-                                            struct efi_dev_path *,
-                                            efi_char16_t *, void *, u32 *);
-               efi_status_t (__efiapi *set)(apple_properties_protocol_t *,
-                                            struct efi_dev_path *,
-                                            efi_char16_t *, void *, u32);
-               efi_status_t (__efiapi *del)(apple_properties_protocol_t *,
-                                            struct efi_dev_path *,
-                                            efi_char16_t *);
-               efi_status_t (__efiapi *get_all)(apple_properties_protocol_t *,
-                                                void *buffer, u32 *);
-       };
-       struct {
-               u32 version;
-               u32 get;
-               u32 set;
-               u32 del;
-               u32 get_all;
-       } mixed_mode;
-};
-
-typedef u32 efi_tcg2_event_log_format;
-
-typedef union efi_tcg2_protocol efi_tcg2_protocol_t;
-
-union efi_tcg2_protocol {
-       struct {
-               void *get_capability;
-               efi_status_t (__efiapi *get_event_log)(efi_handle_t,
-                                                      efi_tcg2_event_log_format,
-                                                      efi_physical_addr_t *,
-                                                      efi_physical_addr_t *,
-                                                      efi_bool_t *);
-               void *hash_log_extend_event;
-               void *submit_command;
-               void *get_active_pcr_banks;
-               void *set_active_pcr_banks;
-               void *get_result_of_set_active_pcr_banks;
-       };
-       struct {
-               u32 get_capability;
-               u32 get_event_log;
-               u32 hash_log_extend_event;
-               u32 submit_command;
-               u32 get_active_pcr_banks;
-               u32 set_active_pcr_banks;
-               u32 get_result_of_set_active_pcr_banks;
-       } mixed_mode;
-};
+typedef union efi_boot_services efi_boot_services_t;
 
 /*
  * Types and defines for EFI ResetSystem
@@ -646,6 +332,9 @@ void efi_native_runtime_setup(void);
 #define EFI_CONSOLE_OUT_DEVICE_GUID            EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4,  0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 #define APPLE_PROPERTIES_PROTOCOL_GUID         EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb,  0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
 #define EFI_TCG2_PROTOCOL_GUID                 EFI_GUID(0x607f766c, 0x7455, 0x42be,  0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
+#define EFI_LOAD_FILE_PROTOCOL_GUID            EFI_GUID(0x56ec3091, 0x954c, 0x11d2,  0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_LOAD_FILE2_PROTOCOL_GUID           EFI_GUID(0x4006c0c1, 0xfcb3, 0x403e,  0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d)
+#define EFI_RT_PROPERTIES_TABLE_GUID           EFI_GUID(0xeb66918a, 0x7eef, 0x402a,  0x84, 0x2e, 0x93, 0x1d, 0x21, 0xc3, 0x8a, 0xe9)
 
 #define EFI_IMAGE_SECURITY_DATABASE_GUID       EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596,  0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
 #define EFI_SHIM_LOCK_GUID                     EFI_GUID(0x605dab50, 0xe046, 0x4300,  0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
@@ -665,6 +354,7 @@ void efi_native_runtime_setup(void);
 #define LINUX_EFI_TPM_EVENT_LOG_GUID           EFI_GUID(0xb7799cb0, 0xeca2, 0x4943,  0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
 #define LINUX_EFI_TPM_FINAL_LOG_GUID           EFI_GUID(0x1e2ed096, 0x30e2, 0x4254,  0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
 #define LINUX_EFI_MEMRESERVE_TABLE_GUID                EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5,  0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
+#define LINUX_EFI_INITRD_MEDIA_GUID            EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
 
 /* OEM GUIDs */
 #define DELLEMC_EFI_RCI2_TABLE_GUID            EFI_GUID(0x2d9f28a2, 0xa886, 0x456a,  0x97, 0xa8, 0xf1, 0x1e, 0xf2, 0x4f, 0xf4, 0x55)
@@ -788,74 +478,6 @@ struct efi_mem_range {
        u64 attribute;
 };
 
-struct efi_fdt_params {
-       u64 system_table;
-       u64 mmap;
-       u32 mmap_size;
-       u32 desc_size;
-       u32 desc_ver;
-};
-
-typedef struct {
-       u32 revision;
-       efi_handle_t parent_handle;
-       efi_system_table_t *system_table;
-       efi_handle_t device_handle;
-       void *file_path;
-       void *reserved;
-       u32 load_options_size;
-       void *load_options;
-       void *image_base;
-       __aligned_u64 image_size;
-       unsigned int image_code_type;
-       unsigned int image_data_type;
-       efi_status_t ( __efiapi *unload)(efi_handle_t image_handle);
-} efi_loaded_image_t;
-
-typedef struct {
-       u64 size;
-       u64 file_size;
-       u64 phys_size;
-       efi_time_t create_time;
-       efi_time_t last_access_time;
-       efi_time_t modification_time;
-       __aligned_u64 attribute;
-       efi_char16_t filename[1];
-} efi_file_info_t;
-
-typedef struct efi_file_handle efi_file_handle_t;
-
-struct efi_file_handle {
-       u64 revision;
-       efi_status_t (__efiapi *open)(efi_file_handle_t *,
-                                     efi_file_handle_t **,
-                                     efi_char16_t *, u64, u64);
-       efi_status_t (__efiapi *close)(efi_file_handle_t *);
-       void *delete;
-       efi_status_t (__efiapi *read)(efi_file_handle_t *,
-                                     unsigned long *, void *);
-       void *write;
-       void *get_position;
-       void *set_position;
-       efi_status_t (__efiapi *get_info)(efi_file_handle_t *,
-                                         efi_guid_t *, unsigned long *,
-                                         void *);
-       void *set_info;
-       void *flush;
-};
-
-typedef struct efi_file_io_interface efi_file_io_interface_t;
-
-struct efi_file_io_interface {
-       u64 revision;
-       int (__efiapi *open_volume)(efi_file_io_interface_t *,
-                                   efi_file_handle_t **);
-};
-
-#define EFI_FILE_MODE_READ     0x0000000000000001
-#define EFI_FILE_MODE_WRITE    0x0000000000000002
-#define EFI_FILE_MODE_CREATE   0x8000000000000000
-
 typedef struct {
        u32 version;
        u32 length;
@@ -865,6 +487,14 @@ typedef struct {
 #define EFI_PROPERTIES_TABLE_VERSION   0x00010000
 #define EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA        0x1
 
+typedef struct {
+       u16 version;
+       u16 length;
+       u32 runtime_services_supported;
+} efi_rt_properties_table_t;
+
+#define EFI_RT_PROPERTIES_TABLE_VERSION        0x1
+
 #define EFI_INVALID_TABLE_ADDR         (~0UL)
 
 typedef struct {
@@ -896,48 +526,63 @@ typedef struct {
        efi_time_t time_of_revocation;
 } efi_cert_x509_sha256_t;
 
+extern unsigned long __ro_after_init efi_rng_seed;             /* RNG Seed table */
+
 /*
  * All runtime access to EFI goes through this structure:
  */
 extern struct efi {
-       efi_system_table_t *systab;     /* EFI system table */
-       unsigned int runtime_version;   /* Runtime services version */
-       unsigned long mps;              /* MPS table */
-       unsigned long acpi;             /* ACPI table  (IA64 ext 0.71) */
-       unsigned long acpi20;           /* ACPI table  (ACPI 2.0) */
-       unsigned long smbios;           /* SMBIOS table (32 bit entry point) */
-       unsigned long smbios3;          /* SMBIOS table (64 bit entry point) */
-       unsigned long boot_info;        /* boot info table */
-       unsigned long hcdp;             /* HCDP table */
-       unsigned long uga;              /* UGA table */
-       unsigned long fw_vendor;        /* fw_vendor */
-       unsigned long runtime;          /* runtime table */
-       unsigned long config_table;     /* config tables */
-       unsigned long esrt;             /* ESRT table */
-       unsigned long properties_table; /* properties table */
-       unsigned long mem_attr_table;   /* memory attributes table */
-       unsigned long rng_seed;         /* UEFI firmware random seed */
-       unsigned long tpm_log;          /* TPM2 Event Log table */
-       unsigned long tpm_final_log;    /* TPM2 Final Events Log table */
-       unsigned long mem_reserve;      /* Linux EFI memreserve table */
-       efi_get_time_t *get_time;
-       efi_set_time_t *set_time;
-       efi_get_wakeup_time_t *get_wakeup_time;
-       efi_set_wakeup_time_t *set_wakeup_time;
-       efi_get_variable_t *get_variable;
-       efi_get_next_variable_t *get_next_variable;
-       efi_set_variable_t *set_variable;
-       efi_set_variable_t *set_variable_nonblocking;
-       efi_query_variable_info_t *query_variable_info;
-       efi_query_variable_info_t *query_variable_info_nonblocking;
-       efi_update_capsule_t *update_capsule;
-       efi_query_capsule_caps_t *query_capsule_caps;
-       efi_get_next_high_mono_count_t *get_next_high_mono_count;
-       efi_reset_system_t *reset_system;
-       struct efi_memory_map memmap;
-       unsigned long flags;
+       const efi_runtime_services_t    *runtime;               /* EFI runtime services table */
+       unsigned int                    runtime_version;        /* Runtime services version */
+       unsigned int                    runtime_supported_mask;
+
+       unsigned long                   acpi;                   /* ACPI table  (IA64 ext 0.71) */
+       unsigned long                   acpi20;                 /* ACPI table  (ACPI 2.0) */
+       unsigned long                   smbios;                 /* SMBIOS table (32 bit entry point) */
+       unsigned long                   smbios3;                /* SMBIOS table (64 bit entry point) */
+       unsigned long                   esrt;                   /* ESRT table */
+       unsigned long                   tpm_log;                /* TPM2 Event Log table */
+       unsigned long                   tpm_final_log;          /* TPM2 Final Events Log table */
+
+       efi_get_time_t                  *get_time;
+       efi_set_time_t                  *set_time;
+       efi_get_wakeup_time_t           *get_wakeup_time;
+       efi_set_wakeup_time_t           *set_wakeup_time;
+       efi_get_variable_t              *get_variable;
+       efi_get_next_variable_t         *get_next_variable;
+       efi_set_variable_t              *set_variable;
+       efi_set_variable_t              *set_variable_nonblocking;
+       efi_query_variable_info_t       *query_variable_info;
+       efi_query_variable_info_t       *query_variable_info_nonblocking;
+       efi_update_capsule_t            *update_capsule;
+       efi_query_capsule_caps_t        *query_capsule_caps;
+       efi_get_next_high_mono_count_t  *get_next_high_mono_count;
+       efi_reset_system_t              *reset_system;
+
+       struct efi_memory_map           memmap;
+       unsigned long                   flags;
 } efi;
 
+#define EFI_RT_SUPPORTED_GET_TIME                              0x0001
+#define EFI_RT_SUPPORTED_SET_TIME                              0x0002
+#define EFI_RT_SUPPORTED_GET_WAKEUP_TIME                       0x0004
+#define EFI_RT_SUPPORTED_SET_WAKEUP_TIME                       0x0008
+#define EFI_RT_SUPPORTED_GET_VARIABLE                          0x0010
+#define EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME                        0x0020
+#define EFI_RT_SUPPORTED_SET_VARIABLE                          0x0040
+#define EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP               0x0080
+#define EFI_RT_SUPPORTED_CONVERT_POINTER                       0x0100
+#define EFI_RT_SUPPORTED_GET_NEXT_HIGH_MONOTONIC_COUNT         0x0200
+#define EFI_RT_SUPPORTED_RESET_SYSTEM                          0x0400
+#define EFI_RT_SUPPORTED_UPDATE_CAPSULE                                0x0800
+#define EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES            0x1000
+#define EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO                   0x2000
+
+#define EFI_RT_SUPPORTED_ALL                                   0x3fff
+
+#define EFI_RT_SUPPORTED_TIME_SERVICES                         0x000f
+#define EFI_RT_SUPPORTED_VARIABLE_SERVICES                     0x0070
+
 extern struct mm_struct efi_mm;
 
 static inline int
@@ -987,14 +632,18 @@ extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
 extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
                                     void *buf, struct efi_mem_range *mem);
 
-extern int efi_config_init(efi_config_table_type_t *arch_tables);
 #ifdef CONFIG_EFI_ESRT
 extern void __init efi_esrt_init(void);
 #else
 static inline void efi_esrt_init(void) { }
 #endif
-extern int efi_config_parse_tables(void *config_tables, int count, int sz,
-                                  efi_config_table_type_t *arch_tables);
+extern int efi_config_parse_tables(const efi_config_table_t *config_tables,
+                                  int count,
+                                  const efi_config_table_type_t *arch_tables);
+extern int efi_systab_check_header(const efi_table_hdr_t *systab_hdr,
+                                  int min_major_version);
+extern void efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
+                                    unsigned long fw_vendor);
 extern u64 efi_get_iobase (void);
 extern int efi_mem_type(unsigned long phys_addr);
 extern u64 efi_mem_attributes (unsigned long phys_addr);
@@ -1006,7 +655,7 @@ extern void efi_mem_reserve(phys_addr_t addr, u64 size);
 extern int efi_mem_reserve_persistent(phys_addr_t addr, u64 size);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
                struct resource *data_resource, struct resource *bss_resource);
-extern int efi_get_fdt_params(struct efi_fdt_params *params);
+extern u64 efi_get_fdt_params(struct efi_memory_map_data *data);
 extern struct kobject *efi_kobj;
 
 extern int efi_reboot_quirk_mode;
@@ -1018,6 +667,8 @@ extern void __init efi_fake_memmap(void);
 static inline void efi_fake_memmap(void) { }
 #endif
 
+extern unsigned long efi_mem_attr_table;
+
 /*
  * efi_memattr_perm_setter - arch specific callback function passed into
  *                           efi_memattr_apply_permissions() that updates the
@@ -1124,6 +775,7 @@ extern int __init efi_setup_pcdp_console(char *);
 #define EFI_NX_PE_DATA         9       /* Can runtime data regions be mapped non-executable? */
 #define EFI_MEM_ATTR           10      /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */
 #define EFI_MEM_NO_SOFT_RESERVE        11      /* Is the kernel configured to ignore soft reservations? */
+#define EFI_PRESERVE_BS_REGIONS        12      /* Are EFI boot-services memory segments available? */
 
 #ifdef CONFIG_EFI
 /*
@@ -1142,6 +794,11 @@ static inline bool __pure efi_soft_reserve_enabled(void)
        return IS_ENABLED(CONFIG_EFI_SOFT_RESERVE)
                && __efi_soft_reserve_enabled();
 }
+
+static inline bool efi_rt_services_supported(unsigned int mask)
+{
+       return (efi.runtime_supported_mask & mask) == mask;
+}
 #else
 static inline bool efi_enabled(int feature)
 {
@@ -1160,6 +817,11 @@ static inline bool efi_soft_reserve_enabled(void)
 {
        return false;
 }
+
+static inline bool efi_rt_services_supported(unsigned int mask)
+{
+       return false;
+}
 #endif
 
 extern int efi_status_to_err(efi_status_t status);
@@ -1188,13 +850,6 @@ extern int efi_status_to_err(efi_status_t status);
  */
 #define EFI_VARIABLE_GUID_LEN  UUID_STRING_LEN
 
-/*
- * The type of search to perform when calling boottime->locate_handle
- */
-#define EFI_LOCATE_ALL_HANDLES                 0
-#define EFI_LOCATE_BY_REGISTER_NOTIFY          1
-#define EFI_LOCATE_BY_PROTOCOL                 2
-
 /*
  * EFI Device Path information
  */
@@ -1234,30 +889,40 @@ extern int efi_status_to_err(efi_status_t status);
 #define   EFI_DEV_END_ENTIRE                   0xFF
 
 struct efi_generic_dev_path {
-       u8 type;
-       u8 sub_type;
-       u16 length;
-} __attribute ((packed));
+       u8                              type;
+       u8                              sub_type;
+       u16                             length;
+} __packed;
+
+struct efi_acpi_dev_path {
+       struct efi_generic_dev_path     header;
+       u32                             hid;
+       u32                             uid;
+} __packed;
+
+struct efi_pci_dev_path {
+       struct efi_generic_dev_path     header;
+       u8                              fn;
+       u8                              dev;
+} __packed;
+
+struct efi_vendor_dev_path {
+       struct efi_generic_dev_path     header;
+       efi_guid_t                      vendorguid;
+       u8                              vendordata[];
+} __packed;
 
 struct efi_dev_path {
-       u8 type;        /* can be replaced with unnamed */
-       u8 sub_type;    /* struct efi_generic_dev_path; */
-       u16 length;     /* once we've moved to -std=c11 */
        union {
-               struct {
-                       u32 hid;
-                       u32 uid;
-               } acpi;
-               struct {
-                       u8 fn;
-                       u8 dev;
-               } pci;
+               struct efi_generic_dev_path     header;
+               struct efi_acpi_dev_path        acpi;
+               struct efi_pci_dev_path         pci;
+               struct efi_vendor_dev_path      vendor;
        };
-} __attribute ((packed));
+} __packed;
 
-#if IS_ENABLED(CONFIG_EFI_DEV_PATH_PARSER)
-struct device *efi_get_device_by_path(struct efi_dev_path **node, size_t *len);
-#endif
+struct device *efi_get_device_by_path(const struct efi_dev_path **node,
+                                     size_t *len);
 
 static inline void memrange_efi_to_native(u64 *addr, u64 *npages)
 {
@@ -1312,80 +977,6 @@ struct efivar_entry {
        bool deleting;
 };
 
-union efi_simple_text_output_protocol {
-       struct {
-               void *reset;
-               efi_status_t (__efiapi *output_string)(efi_simple_text_output_protocol_t *,
-                                                      efi_char16_t *);
-               void *test_string;
-       };
-       struct {
-               u32 reset;
-               u32 output_string;
-               u32 test_string;
-       } mixed_mode;
-};
-
-#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR              0
-#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR              1
-#define PIXEL_BIT_MASK                                 2
-#define PIXEL_BLT_ONLY                                 3
-#define PIXEL_FORMAT_MAX                               4
-
-typedef struct {
-       u32 red_mask;
-       u32 green_mask;
-       u32 blue_mask;
-       u32 reserved_mask;
-} efi_pixel_bitmask_t;
-
-typedef struct {
-       u32 version;
-       u32 horizontal_resolution;
-       u32 vertical_resolution;
-       int pixel_format;
-       efi_pixel_bitmask_t pixel_information;
-       u32 pixels_per_scan_line;
-} efi_graphics_output_mode_info_t;
-
-typedef union efi_graphics_output_protocol_mode efi_graphics_output_protocol_mode_t;
-
-union efi_graphics_output_protocol_mode {
-       struct {
-               u32 max_mode;
-               u32 mode;
-               efi_graphics_output_mode_info_t *info;
-               unsigned long size_of_info;
-               efi_physical_addr_t frame_buffer_base;
-               unsigned long frame_buffer_size;
-       };
-       struct {
-               u32 max_mode;
-               u32 mode;
-               u32 info;
-               u32 size_of_info;
-               u64 frame_buffer_base;
-               u32 frame_buffer_size;
-       } mixed_mode;
-};
-
-typedef union efi_graphics_output_protocol efi_graphics_output_protocol_t;
-
-union efi_graphics_output_protocol {
-       struct {
-               void *query_mode;
-               void *set_mode;
-               void *blt;
-               efi_graphics_output_protocol_mode_t *mode;
-       };
-       struct {
-               u32 query_mode;
-               u32 set_mode;
-               u32 blt;
-               u32 mode;
-       } mixed_mode;
-};
-
 extern struct list_head efivar_sysfs_list;
 
 static inline void
@@ -1483,52 +1074,6 @@ static inline int efi_runtime_map_copy(void *buf, size_t bufsz)
 
 #endif
 
-/* prototypes shared between arch specific and generic stub code */
-
-void efi_printk(char *str);
-
-void efi_free(unsigned long size, unsigned long addr);
-
-char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
-
-efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
-
-efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
-                                unsigned long *addr, unsigned long min);
-
-static inline
-efi_status_t efi_low_alloc(unsigned long size, unsigned long align,
-                          unsigned long *addr)
-{
-       /*
-        * Don't allocate at 0x0. It will confuse code that
-        * checks pointers against NULL. Skip the first 8
-        * bytes so we start at a nice even number.
-        */
-       return efi_low_alloc_above(size, align, addr, 0x8);
-}
-
-efi_status_t efi_high_alloc(unsigned long size, unsigned long align,
-                           unsigned long *addr, unsigned long max);
-
-efi_status_t efi_relocate_kernel(unsigned long *image_addr,
-                                unsigned long image_size,
-                                unsigned long alloc_size,
-                                unsigned long preferred_addr,
-                                unsigned long alignment,
-                                unsigned long min_addr);
-
-efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
-                                 char *cmd_line, char *option_string,
-                                 unsigned long max_addr,
-                                 unsigned long *load_addr,
-                                 unsigned long *load_size);
-
-efi_status_t efi_parse_options(char const *cmdline);
-
-efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
-                          unsigned long size);
-
 #ifdef CONFIG_EFI
 extern bool efi_runtime_disabled(void);
 #else
@@ -1553,6 +1098,12 @@ static inline void
 efi_enable_reset_attack_mitigation(void) { }
 #endif
 
+#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
+void efi_check_for_embedded_firmwares(void);
+#else
+static inline void efi_check_for_embedded_firmwares(void) { }
+#endif
+
 efi_status_t efi_random_get_seed(void);
 
 void efi_retrieve_tpm2_eventlog(void);
@@ -1606,15 +1157,6 @@ void efi_retrieve_tpm2_eventlog(void);
        arch_efi_call_virt_teardown();                                  \
 })
 
-typedef efi_status_t (*efi_exit_boot_map_processing)(
-       struct efi_boot_memmap *map,
-       void *priv);
-
-efi_status_t efi_exit_boot_services(void *handle,
-                                   struct efi_boot_memmap *map,
-                                   void *priv,
-                                   efi_exit_boot_map_processing priv_func);
-
 #define EFI_RANDOM_SEED_SIZE           64U
 
 struct linux_efi_random_seed {
@@ -1701,6 +1243,4 @@ struct linux_efi_memreserve {
 #define EFI_MEMRESERVE_COUNT(size) (((size) - sizeof(struct linux_efi_memreserve)) \
        / sizeof(((struct linux_efi_memreserve *)0)->entry[0]))
 
-void efi_pci_disable_bridge_busmaster(void);
-
 #endif /* _LINUX_EFI_H */
diff --git a/include/linux/efi_embedded_fw.h b/include/linux/efi_embedded_fw.h
new file mode 100644 (file)
index 0000000..3d066c6
--- /dev/null
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_EFI_EMBEDDED_FW_H
+#define _LINUX_EFI_EMBEDDED_FW_H
+
+#include <linux/list.h>
+#include <linux/mod_devicetable.h>
+
+#define EFI_EMBEDDED_FW_PREFIX_LEN             8
+
+/*
+ * This struct and efi_embedded_fw_list are private to the efi-embedded fw
+ * implementation they are in this header for use by lib/test_firmware.c only!
+ */
+struct efi_embedded_fw {
+       struct list_head list;
+       const char *name;
+       const u8 *data;
+       size_t length;
+};
+
+extern struct list_head efi_embedded_fw_list;
+
+/**
+ * struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw
+ *                               code to search for embedded firmwares.
+ *
+ * @name:   Name to register the firmware with if found
+ * @prefix: First 8 bytes of the firmware
+ * @length: Length of the firmware in bytes including prefix
+ * @sha256: SHA256 of the firmware
+ */
+struct efi_embedded_fw_desc {
+       const char *name;
+       u8 prefix[EFI_EMBEDDED_FW_PREFIX_LEN];
+       u32 length;
+       u8 sha256[32];
+};
+
+int efi_get_embedded_fw(const char *name, const u8 **dat, size_t *sz);
+
+#endif
index c86bd3a..8ad71d7 100644 (file)
 
 #include <linux/types.h>
 
+/*
+ * Linux EFI stub v1.0 adds the following functionality:
+ * - Loading initrd from the LINUX_EFI_INITRD_MEDIA_GUID device path,
+ * - Loading/starting the kernel from firmware that targets a different
+ *   machine type, via the entrypoint exposed in the .compat PE/COFF section.
+ *
+ * The recommended way of loading and starting v1.0 or later kernels is to use
+ * the LoadImage() and StartImage() EFI boot services, and expose the initrd
+ * via the LINUX_EFI_INITRD_MEDIA_GUID device path.
+ *
+ * Versions older than v1.0 support initrd loading via the image load options
+ * (using initrd=, limited to the volume from which the kernel itself was
+ * loaded), or via arch specific means (bootparams, DT, etc).
+ *
+ * On x86, LoadImage() and StartImage() can be omitted if the EFI handover
+ * protocol is implemented, which can be inferred from the version,
+ * handover_offset and xloadflags fields in the bootparams structure.
+ */
+#define LINUX_EFISTUB_MAJOR_VERSION            0x1
+#define LINUX_EFISTUB_MINOR_VERSION            0x0
+
 #define MZ_MAGIC       0x5a4d  /* "MZ" */
 
 #define PE_MAGIC               0x00004550      /* "PE\0\0" */
index f0c9082..253fb9a 100644 (file)
@@ -79,7 +79,7 @@ static int __init load_uefi_certs(void)
        efi_status_t status;
        int rc = 0;
 
-       if (!efi.get_variable)
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                return false;
 
        /* Get db, MokListRT, and dbx.  They might not exist, so it isn't