Commit a776c270 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull EFI updates from Ingo Molnar:
 "The EFI changes in this cycle are much larger than usual, for two
  (positive) reasons:

   - The GRUB project is showing signs of life again, resulting in the
     introduction of the generic Linux/UEFI boot protocol, instead of
     x86 specific hacks which are increasingly difficult to maintain.
     There's hope that all future extensions will now go through that
     boot protocol.

   - Preparatory work for RISC-V EFI support.

  The main changes are:

   - Boot time GDT handling changes

   - Simplify handling of EFI properties table on arm64

   - Generic EFI stub cleanups, to improve command line handling, file
     I/O, memory allocation, etc.

   - Introduce a generic initrd loading method based on calling back
     into the firmware, instead of relying on the x86 EFI handover
     protocol or device tree.

   - Introduce a mixed mode boot method that does not rely on the x86
     EFI handover protocol either, and could potentially be adopted by
     other architectures (if another one ever surfaces where one
     execution mode is a superset of another)

   - Clean up the contents of 'struct efi', and move out everything that
     doesn't need to be stored there.

   - Incorporate support for UEFI spec v2.8A changes that permit
     firmware implementations to return EFI_UNSUPPORTED from UEFI
     runtime services at OS runtime, and expose a mask of which ones are
     supported or unsupported via a configuration table.

   - Partial fix for the lack of by-VA cache maintenance in the
     decompressor on 32-bit ARM.

   - Changes to load device firmware from EFI boot service memory
     regions

   - Various documentation updates and minor code cleanups and fixes"

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (114 commits)
  efi/libstub/arm: Fix spurious message that an initrd was loaded
  efi/libstub/arm64: Avoid image_base value from efi_loaded_image
  partitions/efi: Fix partition name parsing in GUID partition entry
  efi/x86: Fix cast of image argument
  efi/libstub/x86: Use ULONG_MAX as upper bound for all allocations
  efi: Fix a mistype in comments mentioning efivar_entry_iter_begin()
  efi/libstub: Avoid linking libstub/lib-ksyms.o into vmlinux
  efi/x86: Preserve %ebx correctly in efi_set_virtual_address_map()
  efi/x86: Ignore the memory attributes table on i386
  efi/x86: Don't relocate the kernel unless necessary
  efi/x86: Remove extra headroom for setup block
  efi/x86: Add kernel preferred address to PE header
  efi/x86: Decompress at start of PE image load address
  x86/boot/compressed/32: Save the output address instead of recalculating it
  efi/libstub/x86: Deal with exit() boot service returning
  x86/boot: Use unsigned comparison for addresses
  efi/x86: Avoid using code32_start
  efi/x86: Make efi32_pe_entry() more readable
  efi/x86: Respect 32-bit ABI in efi32_pe_entry()
  efi/x86: Annotate the LOADED_IMAGE_PROTOCOL_GUID with SYM_DATA
  ...
parents 7c4fa150 594e576d
.. SPDX-License-Identifier: GPL-2.0
============
UEFI Support
============
UEFI stub library functions
===========================
.. kernel-doc:: drivers/firmware/efi/libstub/mem.c
:internal:
...@@ -6,6 +6,7 @@ Linux Firmware API ...@@ -6,6 +6,7 @@ Linux Firmware API
introduction introduction
core core
efi/index
request_firmware request_firmware
other_interfaces other_interfaces
......
...@@ -490,15 +490,11 @@ Protocol: 2.00+ ...@@ -490,15 +490,11 @@ Protocol: 2.00+
kernel) to not write early messages that require kernel) to not write early messages that require
accessing the display hardware directly. accessing the display hardware directly.
Bit 6 (write): KEEP_SEGMENTS Bit 6 (obsolete): KEEP_SEGMENTS
Protocol: 2.07+ Protocol: 2.07+
- If 0, reload the segment registers in the 32bit entry point. - This flag is obsolete.
- 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).
Bit 7 (write): CAN_USE_HEAP Bit 7 (write): CAN_USE_HEAP
......
...@@ -6363,7 +6363,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git ...@@ -6363,7 +6363,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
S: Maintained S: Maintained
F: Documentation/admin-guide/efi-stub.rst F: Documentation/admin-guide/efi-stub.rst
F: arch/*/kernel/efi.c F: arch/*/kernel/efi.c
F: arch/x86/boot/compressed/eboot.[ch]
F: arch/*/include/asm/efi.h F: arch/*/include/asm/efi.h
F: arch/x86/platform/efi/ F: arch/x86/platform/efi/
F: drivers/firmware/efi/ F: drivers/firmware/efi/
......
...@@ -60,7 +60,7 @@ optional_header: ...@@ -60,7 +60,7 @@ optional_header:
.long __pecoff_code_size @ SizeOfCode .long __pecoff_code_size @ SizeOfCode
.long __pecoff_data_size @ SizeOfInitializedData .long __pecoff_data_size @ SizeOfInitializedData
.long 0 @ SizeOfUninitializedData .long 0 @ SizeOfUninitializedData
.long efi_stub_entry - start @ AddressOfEntryPoint .long efi_entry - start @ AddressOfEntryPoint
.long start_offset @ BaseOfCode .long start_offset @ BaseOfCode
.long __pecoff_data_start - start @ BaseOfData .long __pecoff_data_start - start @ BaseOfData
...@@ -70,8 +70,8 @@ extra_header_fields: ...@@ -70,8 +70,8 @@ extra_header_fields:
.long SZ_512 @ FileAlignment .long SZ_512 @ FileAlignment
.short 0 @ MajorOsVersion .short 0 @ MajorOsVersion
.short 0 @ MinorOsVersion .short 0 @ MinorOsVersion
.short 0 @ MajorImageVersion .short LINUX_EFISTUB_MAJOR_VERSION @ MajorImageVersion
.short 0 @ MinorImageVersion .short LINUX_EFISTUB_MINOR_VERSION @ MinorImageVersion
.short 0 @ MajorSubsystemVersion .short 0 @ MajorSubsystemVersion
.short 0 @ MinorSubsystemVersion .short 0 @ MinorSubsystemVersion
.long 0 @ Win32VersionValue .long 0 @ Win32VersionValue
......
...@@ -1437,29 +1437,25 @@ __enter_kernel: ...@@ -1437,29 +1437,25 @@ __enter_kernel:
reloc_code_end: reloc_code_end:
#ifdef CONFIG_EFI_STUB #ifdef CONFIG_EFI_STUB
.align 2 ENTRY(efi_enter_kernel)
_start: .long start - . mov r7, r0 @ preserve image base
mov r4, r1 @ preserve DT pointer
ENTRY(efi_stub_entry)
@ allocate space on stack for passing current zImage address mov r0, r4 @ DT start
@ and for the EFI stub to return of new entry point of add r1, r4, r2 @ DT end
@ zImage, as EFI stub may copy the kernel. Pointer address bl cache_clean_flush
@ is passed in r2. r0 and r1 are passed through from the
@ EFI firmware to efi_entry mov r0, r7 @ relocated zImage
adr ip, _start ldr r1, =_edata @ size of zImage
ldr r3, [ip] add r1, r1, r0 @ end of zImage
add r3, r3, ip bl cache_clean_flush
stmfd sp!, {r3, lr}
mov r2, sp @ pass zImage address in r2 @ The PE/COFF loader might not have cleaned the code we are
bl efi_entry @ running beyond the PoU, and so calling cache_off below from
@ inside the PE/COFF loader allocated region is unsafe unless
@ Check for error return from EFI stub. r0 has FDT address @ we explicitly clean it to the PoC.
@ or error code. adr r0, call_cache_fn @ region of code we will
cmn r0, #1 adr r1, 0f @ run with MMU off
beq efi_load_fail
@ Preserve return value of efi_entry() in r4
mov r4, r0
bl cache_clean_flush bl cache_clean_flush
bl cache_off bl cache_off
...@@ -1469,18 +1465,10 @@ ENTRY(efi_stub_entry) ...@@ -1469,18 +1465,10 @@ ENTRY(efi_stub_entry)
mov r0, #0 mov r0, #0
mov r1, #0xFFFFFFFF mov r1, #0xFFFFFFFF
mov r2, r4 mov r2, r4
add r7, r7, #(__efi_start - start)
@ Branch to (possibly) relocated zImage that is in [sp] mov pc, r7 @ no mode switch
ldr lr, [sp] ENDPROC(efi_enter_kernel)
ldr ip, =start_offset 0:
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)
#endif #endif
.align .align
......
...@@ -57,13 +57,6 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...); ...@@ -57,13 +57,6 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
/* arch specific definitions used by the stub code */ /* 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 * 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. * 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) ...@@ -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) static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
{ {
} }
......
...@@ -10,81 +10,35 @@ ...@@ -10,81 +10,35 @@
#include <asm/assembler.h> #include <asm/assembler.h>
#define EFI_LOAD_ERROR 0x8000000000000001
__INIT __INIT
/* SYM_CODE_START(efi_enter_kernel)
* 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
/* /*
* efi_entry() will have copied the kernel image if necessary and we * efi_entry() will have copied the kernel image if necessary and we
* return here with device tree address in x0 and the kernel entry * end up here with device tree address in x1 and the kernel entry
* point stored at *image_addr. Save those values in registers which * point stored in x0. Save those values in registers which are
* are callee preserved. * callee preserved.
*/ */
mov x20, x0 // DTB address ldr w2, =stext_offset
ldr x0, [sp, #16] // relocated _text address add x19, x0, x2 // relocated Image entrypoint
ldr w21, =stext_offset mov x20, x1 // DTB address
add x21, x0, x21
/* /*
* Calculate size of the kernel Image (same for original and copy). * Clean the copied Image to the PoC, and ensure it is not shadowed by
*/
adr_l x1, _text
adr_l x2, _edata
sub x1, x2, x1
/*
* Flush the copied Image to the PoC, and ensure it is not shadowed by
* stale icache entries from before relocation. * stale icache entries from before relocation.
*/ */
bl __flush_dcache_area ldr w1, =kernel_size
bl __clean_dcache_area_poc
ic ialluis ic ialluis
/* /*
* Ensure that the rest of this function (in the original Image) is * Clean the remainder of this routine to the PoC
* visible when the caches are disabled. The I-cache can't have stale * so that we can safely disable the MMU and caches.
* entries for the VA range of the current image, so no maintenance is
* necessary.
*/ */
adr x0, entry adr x0, 0f
adr x1, entry_end ldr w1, 3f
sub x1, x1, x0 bl __clean_dcache_area_poc
bl __flush_dcache_area 0:
/* Turn off Dcache and MMU */ /* Turn off Dcache and MMU */
mrs x0, CurrentEL mrs x0, CurrentEL
cmp x0, #CurrentEL_EL2 cmp x0, #CurrentEL_EL2
...@@ -109,12 +63,6 @@ ENTRY(entry) ...@@ -109,12 +63,6 @@ ENTRY(entry)
mov x1, xzr mov x1, xzr
mov x2, xzr mov x2, xzr
mov x3, xzr mov x3, xzr
br x21 br x19
SYM_CODE_END(efi_enter_kernel)
efi_load_fail: 3: .long . - 0b
mov x0, #EFI_LOAD_ERROR
ldp x29, x30, [sp], #32
ret
entry_end:
ENDPROC(entry)
...@@ -27,7 +27,7 @@ optional_header: ...@@ -27,7 +27,7 @@ optional_header:
.long __initdata_begin - efi_header_end // SizeOfCode .long __initdata_begin - efi_header_end // SizeOfCode
.long __pecoff_data_size // SizeOfInitializedData .long __pecoff_data_size // SizeOfInitializedData
.long 0 // SizeOfUninitializedData .long 0 // SizeOfUninitializedData
.long __efistub_entry - _head // AddressOfEntryPoint .long __efistub_efi_entry - _head // AddressOfEntryPoint
.long efi_header_end - _head // BaseOfCode .long efi_header_end - _head // BaseOfCode
extra_header_fields: extra_header_fields:
...@@ -36,8 +36,8 @@ extra_header_fields: ...@@ -36,8 +36,8 @@ extra_header_fields:
.long PECOFF_FILE_ALIGNMENT // FileAlignment .long PECOFF_FILE_ALIGNMENT // FileAlignment
.short 0 // MajorOperatingSystemVersion .short 0 // MajorOperatingSystemVersion
.short 0 // MinorOperatingSystemVersion .short 0 // MinorOperatingSystemVersion
.short 0 // MajorImageVersion .short LINUX_EFISTUB_MAJOR_VERSION // MajorImageVersion
.short 0 // MinorImageVersion .short LINUX_EFISTUB_MINOR_VERSION // MinorImageVersion
.short 0 // MajorSubsystemVersion .short 0 // MajorSubsystemVersion
.short 0 // MinorSubsystemVersion .short 0 // MinorSubsystemVersion
.long 0 // Win32VersionValue .long 0 // Win32VersionValue
......
...@@ -12,8 +12,10 @@ ...@@ -12,8 +12,10 @@
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
__efistub_kernel_size = _edata - _text;
__efistub_stext_offset = stext - _text; __efistub_stext_offset = stext - _text;
/* /*
* The EFI stub has its own symbol namespace prefixed by __efistub_, to * The EFI stub has its own symbol namespace prefixed by __efistub_, to
* isolate it from the kernel proper. The following symbols are legally * isolate it from the kernel proper. The following symbols are legally
...@@ -33,7 +35,7 @@ __efistub_strnlen = __pi_strnlen; ...@@ -33,7 +35,7 @@ __efistub_strnlen = __pi_strnlen;
__efistub_strcmp = __pi_strcmp; __efistub_strcmp = __pi_strcmp;
__efistub_strncmp = __pi_strncmp; __efistub_strncmp = __pi_strncmp;
__efistub_strrchr = __pi_strrchr; __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 #ifdef CONFIG_KASAN
__efistub___memcpy = __pi_memcpy; __efistub___memcpy = __pi_memcpy;
...@@ -45,6 +47,7 @@ __efistub__text = _text; ...@@ -45,6 +47,7 @@ __efistub__text = _text;
__efistub__end = _end; __efistub__end = _end;
__efistub__edata = _edata; __efistub__edata = _edata;
__efistub_screen_info = screen_info; __efistub_screen_info = screen_info;
__efistub__ctype = _ctype;
#endif #endif
......
...@@ -45,11 +45,21 @@ ...@@ -45,11 +45,21 @@
#define EFI_DEBUG 0 #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; 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; 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}, {PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys},
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &sal_systab_phys}, {SAL_SYSTEM_TABLE_GUID, "SALsystab", &sal_systab_phys},
{NULL_GUID, NULL, 0}, {NULL_GUID, NULL, 0},
...@@ -474,11 +484,10 @@ efi_map_pal_code (void) ...@@ -474,11 +484,10 @@ efi_map_pal_code (void)
void __init void __init
efi_init (void) efi_init (void)
{ {
const efi_system_table_t *efi_systab;
void *efi_map_start, *efi_map_end; void *efi_map_start, *efi_map_end;
efi_char16_t *c16;
u64 efi_desc_size; u64 efi_desc_size;
char *cp, vendor[100] = "unknown"; char *cp;
int i;
set_bit(EFI_BOOT, &efi.flags); set_bit(EFI_BOOT, &efi.flags);
set_bit(EFI_64BIT, &efi.flags); set_bit(EFI_64BIT, &efi.flags);
...@@ -508,42 +517,29 @@ efi_init (void) ...@@ -508,42 +517,29 @@ efi_init (void)
printk(KERN_INFO "Ignoring memory above %lluMB\n", printk(KERN_INFO "Ignoring memory above %lluMB\n",
max_addr >> 20); max_addr >> 20);
efi.systab = __va(ia64_boot_param->efi_systab); efi_systab = __va(ia64_boot_param->efi_systab);
/* /*
* Verify the EFI Table * Verify the EFI Table
*/ */
if (efi.systab == NULL) if (efi_systab == NULL)
panic("Whoa! Can't find EFI system table.\n"); 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"); 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_report_header(&efi_systab->hdr, efi_systab->fw_vendor);
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor);
palo_phys = EFI_INVALID_TABLE_ADDR; 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; return;
if (palo_phys != EFI_INVALID_TABLE_ADDR) if (palo_phys != EFI_INVALID_TABLE_ADDR)
handle_palo(palo_phys); handle_palo(palo_phys);
runtime = __va(efi.systab->runtime); runtime = __va(efi_systab->runtime);
efi.get_time = phys_get_time; efi.get_time = phys_get_time;
efi.set_time = phys_set_time; efi.set_time = phys_set_time;
efi.get_wakeup_time = phys_get_wakeup_time; efi.get_wakeup_time = phys_get_wakeup_time;
...@@ -1351,3 +1347,12 @@ vmcore_find_descriptor_size (unsigned long address) ...@@ -1351,3 +1347,12 @@ vmcore_find_descriptor_size (unsigned long address)
return ret; return ret;
} }
#endif #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;
}
...@@ -19,10 +19,6 @@ MODULE_LICENSE("GPL"); ...@@ -19,10 +19,6 @@ MODULE_LICENSE("GPL");
#define MODULE_NAME "esi" #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 { enum esi_systab_entry_type {
ESI_DESC_ENTRY_POINT = 0 ESI_DESC_ENTRY_POINT = 0
}; };
...@@ -48,27 +44,18 @@ struct pdesc { ...@@ -48,27 +44,18 @@ struct pdesc {
static struct ia64_sal_systab *esi_systab; static struct ia64_sal_systab *esi_systab;
extern unsigned long esi_phys;
static int __init esi_init (void) static int __init esi_init (void)
{ {
efi_config_table_t *config_tables;
struct ia64_sal_systab *systab; struct ia64_sal_systab *systab;
unsigned long esi = 0;
char *p; char *p;
int i; int i;
config_tables = __va(efi.systab->tables); if (esi_phys == EFI_INVALID_TABLE_ADDR)
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)
return -ENODEV; return -ENODEV;
systab = __va(esi); systab = __va(esi_phys);
if (strncmp(systab->signature, "ESIT", 4) != 0) { if (strncmp(systab->signature, "ESIT", 4) != 0) {
printk(KERN_ERR "bad signature in ESI system table!"); printk(KERN_ERR "bad signature in ESI system table!");
......
...@@ -88,7 +88,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE ...@@ -88,7 +88,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) 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 $@ quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@ cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
......
...@@ -87,10 +87,7 @@ endif ...@@ -87,10 +87,7 @@ endif
vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o \
$(objtree)/drivers/firmware/efi/libstub/lib.a
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
# The compressed kernel is built with -fPIC/-fPIE so that a boot loader # The compressed kernel is built with -fPIC/-fPIE so that a boot loader
......
/* 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 */
...@@ -54,11 +54,16 @@ SYM_FUNC_START(__efi64_thunk) ...@@ -54,11 +54,16 @@ SYM_FUNC_START(__efi64_thunk)
* Switch to gdt with 32-bit segments. This is the firmware GDT * Switch to gdt with 32-bit segments. This is the firmware GDT
* that was installed when the kernel started executing. This * that was installed when the kernel started executing. This
* pointer was saved at the EFI stub entry point in head_64.S. * 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 leaq efi32_boot_gdt(%rip), %rax
lgdt (%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 leaq efi_enter32(%rip), %rax
pushq %rax pushq %rax
lretq lretq
...@@ -73,6 +78,10 @@ SYM_FUNC_START(__efi64_thunk) ...@@ -73,6 +78,10 @@ SYM_FUNC_START(__efi64_thunk)
movl %ebx, %es movl %ebx, %es
pop %rbx pop %rbx
movl %ebx, %ds 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. * Convert 32-bit status code into 64-bit.
...@@ -92,10 +101,12 @@ SYM_FUNC_END(__efi64_thunk) ...@@ -92,10 +101,12 @@ SYM_FUNC_END(__efi64_thunk)
* The stack should represent the 32-bit calling convention. * The stack should represent the 32-bit calling convention.
*/ */
SYM_FUNC_START_LOCAL(efi_enter32) SYM_FUNC_START_LOCAL(efi_enter32)
movl $__KERNEL_DS, %eax /* Load firmware selector into data and stack segment registers */
movl %eax, %ds movl %edx, %ds
movl %eax, %es movl %edx, %es
movl %eax, %ss movl %edx, %fs
movl %edx, %gs
movl %edx, %ss
/* Reload pgtables */ /* Reload pgtables */
movl %cr3, %eax movl %cr3, %eax
...@@ -157,6 +168,14 @@ SYM_DATA_START(efi32_boot_gdt) ...@@ -157,6 +168,14 @@ SYM_DATA_START(efi32_boot_gdt)
.quad 0 .quad 0
SYM_DATA_END(efi32_boot_gdt) 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) SYM_DATA_START(efi_gdt64)
.word efi_gdt64_end - efi_gdt64 .word efi_gdt64_end - efi_gdt64
.long 0 /* Filled out by user */ .long 0 /* Filled out by user */
......
...@@ -63,21 +63,7 @@ ...@@ -63,21 +63,7 @@
__HEAD __HEAD
SYM_FUNC_START(startup_32) SYM_FUNC_START(startup_32)
cld 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 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 * Calculate the delta between where we were compiled to run
...@@ -89,32 +75,59 @@ SYM_FUNC_START(startup_32) ...@@ -89,32 +75,59 @@ SYM_FUNC_START(startup_32)
*/ */
leal (BP_scratch+4)(%esi), %esp leal (BP_scratch+4)(%esi), %esp
call 1f call 1f
1: popl %ebp 1: popl %edx
subl $1b, %ebp subl $1b, %edx
/* Load new GDT */
leal gdt(%edx), %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 * %edx contains the address we are loaded at by the boot loader and %ebx
* contains the address where we should move the kernel image temporarily * contains the address where we should move the kernel image temporarily
* for safe in-place decompression. * for safe in-place decompression. %ebp contains the address that the kernel
* will be decompressed to.
*/ */
#ifdef CONFIG_RELOCATABLE #ifdef CONFIG_RELOCATABLE
movl %ebp, %ebx movl %edx, %ebx
#ifdef CONFIG_EFI_STUB
/*
* If we were loaded via the EFI LoadImage service, startup_32() will be at an
* offset to the start of the space allocated for the image. efi_pe_entry() will
* set up image_offset to tell us where the image actually starts, so that we
* can use the full available buffer.
* image_offset = startup_32 - image_base
* Otherwise image_offset will be zero and has no effect on the calculations.
*/
subl image_offset(%edx), %ebx
#endif
movl BP_kernel_alignment(%esi), %eax movl BP_kernel_alignment(%esi), %eax
decl %eax decl %eax
addl %eax, %ebx addl %eax, %ebx
notl %eax notl %eax
andl %eax, %ebx andl %eax, %ebx
cmpl $LOAD_PHYSICAL_ADDR, %ebx cmpl $LOAD_PHYSICAL_ADDR, %ebx
jge 1f jae 1f
#endif #endif
movl $LOAD_PHYSICAL_ADDR, %ebx movl $LOAD_PHYSICAL_ADDR, %ebx
1: 1:
movl %ebx, %ebp // Save the output address for later
/* Target address to relocate to for decompression */ /* Target address to relocate to for decompression */
movl BP_init_size(%esi), %eax addl BP_init_size(%esi), %ebx
subl $_end, %eax subl $_end, %ebx
addl %eax, %ebx
/* Set up the stack */ /* Set up the stack */
leal boot_stack_end(%ebx), %esp leal boot_stack_end(%ebx), %esp
...@@ -128,7 +141,7 @@ SYM_FUNC_START(startup_32) ...@@ -128,7 +141,7 @@ SYM_FUNC_START(startup_32)
* where decompression in place becomes safe. * where decompression in place becomes safe.
*/ */
pushl %esi pushl %esi
leal (_bss-4)(%ebp), %esi leal (_bss-4)(%edx), %esi
leal (_bss-4)(%ebx), %edi leal (_bss-4)(%ebx), %edi
movl $(_bss - startup_32), %ecx movl $(_bss - startup_32), %ecx
shrl $2, %ecx shrl $2, %ecx
...@@ -137,6 +150,15 @@ SYM_FUNC_START(startup_32) ...@@ -137,6 +150,15 @@ SYM_FUNC_START(startup_32)
cld cld
popl %esi 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. * Jump to the relocated address.
*/ */
...@@ -148,9 +170,8 @@ SYM_FUNC_END(startup_32) ...@@ -148,9 +170,8 @@ SYM_FUNC_END(startup_32)
SYM_FUNC_START(efi32_stub_entry) SYM_FUNC_START(efi32_stub_entry)
SYM_FUNC_START_ALIAS(efi_stub_entry) SYM_FUNC_START_ALIAS(efi_stub_entry)
add $0x4, %esp add $0x4, %esp
movl 8(%esp), %esi /* save boot_params pointer */
call efi_main call efi_main
movl %eax, %esi
movl BP_code32_start(%esi), %eax
leal startup_32(%eax), %eax leal startup_32(%eax), %eax
jmp *%eax jmp *%eax
SYM_FUNC_END(efi32_stub_entry) SYM_FUNC_END(efi32_stub_entry)
...@@ -189,9 +210,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) ...@@ -189,9 +210,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
/* push arguments for extract_kernel: */ /* push arguments for extract_kernel: */
pushl $z_output_len /* decompressed length, end of relocs */ pushl $z_output_len /* decompressed length, end of relocs */
leal _end(%ebx), %eax pushl %ebp /* output address */
subl BP_init_size(%esi), %eax
pushl %eax /* output address */
pushl $z_input_len /* input_len */ pushl $z_input_len /* input_len */
leal input_data(%ebx), %eax leal input_data(%ebx), %eax
...@@ -209,6 +228,21 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) ...@@ -209,6 +228,21 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
jmp *%eax jmp *%eax
SYM_FUNC_END(.Lrelocated) 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)
#ifdef CONFIG_EFI_STUB
SYM_DATA(image_offset, .long 0)
#endif
/* /*
* Stack and heap for uncompression * Stack and heap for uncompression
*/ */
......
...@@ -53,19 +53,7 @@ SYM_FUNC_START(startup_32) ...@@ -53,19 +53,7 @@ SYM_FUNC_START(startup_32)
* all need to be under the 4G limit. * all need to be under the 4G limit.
*/ */
cld 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 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 * Calculate the delta between where we were compiled to run
...@@ -80,10 +68,21 @@ SYM_FUNC_START(startup_32) ...@@ -80,10 +68,21 @@ SYM_FUNC_START(startup_32)
1: popl %ebp 1: popl %ebp
subl $1b, %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. */ /* setup a stack and make sure cpu supports long mode. */
movl $boot_stack_end, %eax leal boot_stack_end(%ebp), %esp
addl %ebp, %eax
movl %eax, %esp
call verify_cpu call verify_cpu
testl %eax, %eax testl %eax, %eax
...@@ -100,30 +99,38 @@ SYM_FUNC_START(startup_32) ...@@ -100,30 +99,38 @@ SYM_FUNC_START(startup_32)
#ifdef CONFIG_RELOCATABLE #ifdef CONFIG_RELOCATABLE
movl %ebp, %ebx movl %ebp, %ebx
#ifdef CONFIG_EFI_STUB
/*
* If we were loaded via the EFI LoadImage service, startup_32 will be at an
* offset to the start of the space allocated for the image. efi_pe_entry will
* set up image_offset to tell us where the image actually starts, so that we
* can use the full available buffer.
* image_offset = startup_32 - image_base
* Otherwise image_offset will be zero and has no effect on the calculations.
*/
subl image_offset(%ebp), %ebx
#endif
movl BP_kernel_alignment(%esi), %eax movl BP_kernel_alignment(%esi), %eax
decl %eax decl %eax
addl %eax, %ebx addl %eax, %ebx
notl %eax notl %eax
andl %eax, %ebx andl %eax, %ebx
cmpl $LOAD_PHYSICAL_ADDR, %ebx cmpl $LOAD_PHYSICAL_ADDR, %ebx
jge 1f jae 1f
#endif #endif
movl $LOAD_PHYSICAL_ADDR, %ebx movl $LOAD_PHYSICAL_ADDR, %ebx
1: 1:
/* Target address to relocate to for decompression */ /* Target address to relocate to for decompression */
movl BP_init_size(%esi), %eax addl BP_init_size(%esi), %ebx
subl $_end, %eax subl $_end, %ebx
addl %eax, %ebx
/* /*
* Prepare for entering 64 bit mode * 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 */ /* Enable PAE mode */
movl %cr4, %eax movl %cr4, %eax
orl $X86_CR4_PAE, %eax orl $X86_CR4_PAE, %eax
...@@ -212,8 +219,13 @@ SYM_FUNC_START(startup_32) ...@@ -212,8 +219,13 @@ SYM_FUNC_START(startup_32)
cmp $0, %edi cmp $0, %edi
jz 1f jz 1f
leal efi64_stub_entry(%ebp), %eax leal efi64_stub_entry(%ebp), %eax
movl %esi, %edx
movl efi32_boot_args+4(%ebp), %esi 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: 1:
#endif #endif
pushl %eax pushl %eax
...@@ -238,11 +250,17 @@ SYM_FUNC_START(efi32_stub_entry) ...@@ -238,11 +250,17 @@ SYM_FUNC_START(efi32_stub_entry)
1: pop %ebp 1: pop %ebp
subl $1b, %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 %ecx, efi32_boot_args(%ebp)
movl %edx, efi32_boot_args+4(%ebp) movl %edx, efi32_boot_args+4(%ebp)
sgdtl efi32_boot_gdt(%ebp)
movb $0, efi_is64(%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 */ /* Disable paging */
movl %cr0, %eax movl %cr0, %eax
btrl $X86_CR0_PG_BIT, %eax btrl $X86_CR0_PG_BIT, %eax
...@@ -266,6 +284,9 @@ SYM_CODE_START(startup_64) ...@@ -266,6 +284,9 @@ SYM_CODE_START(startup_64)
* and command line. * and command line.
*/ */
cld
cli
/* Setup data segments. */ /* Setup data segments. */
xorl %eax, %eax xorl %eax, %eax
movl %eax, %ds movl %eax, %ds
...@@ -290,13 +311,27 @@ SYM_CODE_START(startup_64) ...@@ -290,13 +311,27 @@ SYM_CODE_START(startup_64)
/* Start with the delta to where the kernel will run at. */ /* Start with the delta to where the kernel will run at. */
#ifdef CONFIG_RELOCATABLE #ifdef CONFIG_RELOCATABLE
leaq startup_32(%rip) /* - $startup_32 */, %rbp leaq startup_32(%rip) /* - $startup_32 */, %rbp
#ifdef CONFIG_EFI_STUB
/*
* If we were loaded via the EFI LoadImage service, startup_32 will be at an
* offset to the start of the space allocated for the image. efi_pe_entry will
* set up image_offset to tell us where the image actually starts, so that we
* can use the full available buffer.
* image_offset = startup_32 - image_base
* Otherwise image_offset will be zero and has no effect on the calculations.
*/
movl image_offset(%rip), %eax
subq %rax, %rbp
#endif
movl BP_kernel_alignment(%rsi), %eax movl BP_kernel_alignment(%rsi), %eax
decl %eax decl %eax
addq %rax, %rbp addq %rax, %rbp
notq %rax notq %rax
andq %rax, %rbp andq %rax, %rbp
cmpq $LOAD_PHYSICAL_ADDR, %rbp cmpq $LOAD_PHYSICAL_ADDR, %rbp
jge 1f jae 1f
#endif #endif
movq $LOAD_PHYSICAL_ADDR, %rbp movq $LOAD_PHYSICAL_ADDR, %rbp
1: 1:
...@@ -354,9 +389,9 @@ SYM_CODE_START(startup_64) ...@@ -354,9 +389,9 @@ SYM_CODE_START(startup_64)
*/ */
/* Make sure we have GDT with 32-bit code segment */ /* Make sure we have GDT with 32-bit code segment */
leaq gdt(%rip), %rax leaq gdt64(%rip), %rax
movq %rax, gdt64+2(%rip) addq %rax, 2(%rax)
lgdt gdt64(%rip) lgdt (%rax)
/* /*
* paging_prepare() sets up the trampoline and checks if we need to * paging_prepare() sets up the trampoline and checks if we need to
...@@ -441,6 +476,16 @@ trampoline_return: ...@@ -441,6 +476,16 @@ trampoline_return:
cld cld
popq %rsi 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. * Jump to the relocated address.
*/ */
...@@ -453,9 +498,9 @@ SYM_CODE_END(startup_64) ...@@ -453,9 +498,9 @@ SYM_CODE_END(startup_64)
SYM_FUNC_START(efi64_stub_entry) SYM_FUNC_START(efi64_stub_entry)
SYM_FUNC_START_ALIAS(efi_stub_entry) SYM_FUNC_START_ALIAS(efi_stub_entry)
and $~0xf, %rsp /* realign the stack */ and $~0xf, %rsp /* realign the stack */
movq %rdx, %rbx /* save boot_params pointer */
call efi_main call efi_main
movq %rax,%rsi movq %rbx,%rsi
movl BP_code32_start(%esi), %eax
leaq startup_64(%rax), %rax leaq startup_64(%rax), %rax
jmp *%rax jmp *%rax
SYM_FUNC_END(efi64_stub_entry) SYM_FUNC_END(efi64_stub_entry)
...@@ -613,13 +658,13 @@ SYM_FUNC_END(.Lno_longmode) ...@@ -613,13 +658,13 @@ SYM_FUNC_END(.Lno_longmode)
.data .data
SYM_DATA_START_LOCAL(gdt64) SYM_DATA_START_LOCAL(gdt64)
.word gdt_end - gdt .word gdt_end - gdt - 1
.quad 0 .quad gdt - gdt64
SYM_DATA_END(gdt64) SYM_DATA_END(gdt64)
.balign 8 .balign 8
SYM_DATA_START_LOCAL(gdt) SYM_DATA_START_LOCAL(gdt)
.word gdt_end - gdt .word gdt_end - gdt - 1
.long gdt .long 0
.word 0 .word 0
.quad 0x00cf9a000000ffff /* __KERNEL32_CS */ .quad 0x00cf9a000000ffff /* __KERNEL32_CS */
.quad 0x00af9a000000ffff /* __KERNEL_CS */ .quad 0x00af9a000000ffff /* __KERNEL_CS */
...@@ -628,9 +673,97 @@ SYM_DATA_START_LOCAL(gdt) ...@@ -628,9 +673,97 @@ SYM_DATA_START_LOCAL(gdt)
.quad 0x0000000000000000 /* TS continued */ .quad 0x0000000000000000 /* TS continued */
SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end) SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
#ifdef CONFIG_EFI_STUB
SYM_DATA(image_offset, .long 0)
#endif
#ifdef CONFIG_EFI_MIXED #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) 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)
/*
* efi_status_t efi32_pe_entry(efi_handle_t image_handle,
* efi_system_table_32_t *sys_table)
*/
pushl %ebp
movl %esp, %ebp
pushl %eax // dummy push to allocate loaded_image
pushl %ebx // save callee-save registers
pushl %edi
call verify_cpu // check for long mode support
testl %eax, %eax
movl $0x80000003, %eax // EFI_UNSUPPORTED
jnz 2f
call 1f
1: pop %ebx
subl $1b, %ebx
/* Get the loaded image protocol pointer from the image handle */
leal -4(%ebp), %eax
pushl %eax // &loaded_image
leal loaded_image_proto(%ebx), %eax
pushl %eax // pass the GUID address
pushl 8(%ebp) // pass the image handle
/*
* Note the alignment of the stack frame.
* sys_table
* handle <-- 16-byte aligned on entry by ABI
* return address
* frame pointer
* loaded_image <-- local variable
* saved %ebx <-- 16-byte aligned here
* saved %edi
* &loaded_image
* &loaded_image_proto
* handle <-- 16-byte aligned for call to handle_protocol
*/
movl 12(%ebp), %eax // sys_table
movl ST32_boottime(%eax), %eax // sys_table->boottime
call *BS32_handle_protocol(%eax) // sys_table->boottime->handle_protocol
addl $12, %esp // restore argument space
testl %eax, %eax
jnz 2f
movl 8(%ebp), %ecx // image_handle
movl 12(%ebp), %edx // sys_table
movl -4(%ebp), %esi // loaded_image
movl LI32_image_base(%esi), %esi // loaded_image->image_base
movl %ebx, %ebp // startup_32 for efi32_pe_stub_entry
/*
* We need to set the image_offset variable here since startup_32() will
* use it before we get to the 64-bit efi_pe_entry() in C code.
*/
subl %esi, %ebx
movl %ebx, image_offset(%ebp) // save image_offset
jmp efi32_pe_stub_entry
2: popl %edi // restore callee-save registers
popl %ebx
leave
ret
SYM_FUNC_END(efi32_pe_entry)
.section ".rodata"
/* EFI loaded image protocol GUID */
.balign 4
SYM_DATA_START_LOCAL(loaded_image_proto)
.long 0x5b1b31a1
.word 0x9562, 0x11d2
.byte 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b
SYM_DATA_END(loaded_image_proto)
#endif #endif
/* /*
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* hex while segment addresses are written as segment:offset. * hex while segment addresses are written as segment:offset.
* *
*/ */
#include <linux/pe.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/boot.h> #include <asm/boot.h>
#include <asm/page_types.h> #include <asm/page_types.h>
...@@ -43,8 +43,7 @@ SYSSEG = 0x1000 /* historical load address >> 4 */ ...@@ -43,8 +43,7 @@ SYSSEG = 0x1000 /* historical load address >> 4 */
bootsect_start: bootsect_start:
#ifdef CONFIG_EFI_STUB #ifdef CONFIG_EFI_STUB
# "MZ", MS-DOS header # "MZ", MS-DOS header
.byte 0x4d .word MZ_MAGIC
.byte 0x5a
#endif #endif
# Normalize the start address # Normalize the start address
...@@ -97,39 +96,30 @@ bugger_off_msg: ...@@ -97,39 +96,30 @@ bugger_off_msg:
#ifdef CONFIG_EFI_STUB #ifdef CONFIG_EFI_STUB
pe_header: pe_header:
.ascii "PE" .long PE_MAGIC
.word 0
coff_header: coff_header:
#ifdef CONFIG_X86_32 #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 #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 #endif
.word 4 # nr_sections .word section_count # nr_sections
.long 0 # TimeDateStamp .long 0 # TimeDateStamp
.long 0 # PointerToSymbolTable .long 0 # PointerToSymbolTable
.long 1 # NumberOfSymbols .long 1 # NumberOfSymbols
.word section_table - optional_header # SizeOfOptionalHeader .word section_table - optional_header # SizeOfOptionalHeader
#ifdef CONFIG_X86_32 .word IMAGE_FILE_EXECUTABLE_IMAGE | \
.word 0x306 # Characteristics. image_file_add_flags | \
# IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_DEBUG_STRIPPED | \
# IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_LINE_NUMS_STRIPPED # Characteristics
# 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
optional_header: optional_header:
#ifdef CONFIG_X86_32 .word pe_opt_magic
.word 0x10b # PE32 format
#else
.word 0x20b # PE32+ format
#endif
.byte 0x02 # MajorLinkerVersion .byte 0x02 # MajorLinkerVersion
.byte 0x14 # MinorLinkerVersion .byte 0x14 # MinorLinkerVersion
...@@ -148,17 +138,19 @@ optional_header: ...@@ -148,17 +138,19 @@ optional_header:
#endif #endif
extra_header_fields: extra_header_fields:
# PE specification requires ImageBase to be 64k aligned
.set image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
.long 0 # ImageBase .long image_base # ImageBase
#else #else
.quad 0 # ImageBase .quad image_base # ImageBase
#endif #endif
.long 0x20 # SectionAlignment .long 0x20 # SectionAlignment
.long 0x20 # FileAlignment .long 0x20 # FileAlignment
.word 0 # MajorOperatingSystemVersion .word 0 # MajorOperatingSystemVersion
.word 0 # MinorOperatingSystemVersion .word 0 # MinorOperatingSystemVersion
.word 0 # MajorImageVersion .word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
.word 0 # MinorImageVersion .word LINUX_EFISTUB_MINOR_VERSION # MinorImageVersion
.word 0 # MajorSubsystemVersion .word 0 # MajorSubsystemVersion
.word 0 # MinorSubsystemVersion .word 0 # MinorSubsystemVersion
.long 0 # Win32VersionValue .long 0 # Win32VersionValue
...@@ -170,7 +162,7 @@ extra_header_fields: ...@@ -170,7 +162,7 @@ extra_header_fields:
.long 0x200 # SizeOfHeaders .long 0x200 # SizeOfHeaders
.long 0 # CheckSum .long 0 # CheckSum
.word 0xa # Subsystem (EFI application) .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
.word 0 # DllCharacteristics .word 0 # DllCharacteristics
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
.long 0 # SizeOfStackReserve .long 0 # SizeOfStackReserve
...@@ -184,7 +176,7 @@ extra_header_fields: ...@@ -184,7 +176,7 @@ extra_header_fields:
.quad 0 # SizeOfHeapCommit .quad 0 # SizeOfHeapCommit
#endif #endif
.long 0 # LoaderFlags .long 0 # LoaderFlags
.long 0x6 # NumberOfRvaAndSizes .long (section_table - .) / 8 # NumberOfRvaAndSizes
.quad 0 # ExportTable .quad 0 # ExportTable
.quad 0 # ImportTable .quad 0 # ImportTable
...@@ -210,7 +202,10 @@ section_table: ...@@ -210,7 +202,10 @@ section_table:
.long 0 # PointerToLineNumbers .long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations .word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers .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 # The EFI application loader requires a relocation section
...@@ -228,45 +223,53 @@ section_table: ...@@ -228,45 +223,53 @@ section_table:
.long 0 # PointerToLineNumbers .long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations .word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers .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. # The offset & size fields are filled in by build.c.
# #
.ascii ".text" .asciz ".compat"
.byte 0
.byte 0
.byte 0
.long 0 .long 0
.long 0x0 # startup_{32,64} .long 0x0
.long 0 # Size of initialized data .long 0 # Size of initialized data
# on disk # on disk
.long 0x0 # startup_{32,64} .long 0x0
.long 0 # PointerToRelocations .long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers .long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations .word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers .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. # The offset & size fields are filled in by build.c.
# #
.ascii ".bss" .ascii ".text"
.byte 0
.byte 0 .byte 0
.byte 0 .byte 0
.byte 0 .byte 0
.long 0 .long 0
.long 0x0 .long 0x0 # startup_{32,64}
.long 0 # Size of initialized data .long 0 # Size of initialized data
# on disk # on disk
.long 0x0 .long 0x0 # startup_{32,64}
.long 0 # PointerToRelocations .long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers .long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations .word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers .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 */ #endif /* CONFIG_EFI_STUB */
# Kernel attributes; used by setup. This is part 1 of the # Kernel attributes; used by setup. This is part 1 of the
......
...@@ -53,11 +53,20 @@ u8 buf[SETUP_SECT_MAX*512]; ...@@ -53,11 +53,20 @@ u8 buf[SETUP_SECT_MAX*512];
#define PECOFF_RELOC_RESERVE 0x20 #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 efi32_stub_entry;
unsigned long efi64_stub_entry; unsigned long efi64_stub_entry;
unsigned long efi_pe_entry; unsigned long efi_pe_entry;
unsigned long efi32_pe_entry;
unsigned long kernel_info; unsigned long kernel_info;
unsigned long startup_64; unsigned long startup_64;
unsigned long _ehead;
unsigned long _end;
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
...@@ -189,7 +198,10 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz ...@@ -189,7 +198,10 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz
static void update_pecoff_setup_and_reloc(unsigned int size) static void update_pecoff_setup_and_reloc(unsigned int size)
{ {
u32 setup_offset = 0x200; 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; u32 setup_size = reloc_offset - setup_offset;
update_pecoff_section_header(".setup", setup_offset, setup_size); update_pecoff_section_header(".setup", setup_offset, setup_size);
...@@ -201,43 +213,59 @@ static void update_pecoff_setup_and_reloc(unsigned int size) ...@@ -201,43 +213,59 @@ static void update_pecoff_setup_and_reloc(unsigned int size)
*/ */
put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
put_unaligned_le32(10, &buf[reloc_offset + 4]); 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 pe_header;
unsigned int text_sz = file_sz - text_start; unsigned int text_sz = file_sz - text_start;
unsigned int bss_sz = init_sz - file_sz;
pe_header = get_unaligned_le32(&buf[0x3c]); pe_header = get_unaligned_le32(&buf[0x3c]);
/*
* The PE/COFF loader may load the image at an address which is
* misaligned with respect to the kernel_alignment field in the setup
* header.
*
* In order to avoid relocating the kernel to correct the misalignment,
* add slack to allow the buffer to be aligned within the declared size
* of the image.
*/
bss_sz += CONFIG_PHYSICAL_ALIGN;
init_sz += CONFIG_PHYSICAL_ALIGN;
/* /*
* Size of code: Subtract the size of the first sector (512 bytes) * Size of code: Subtract the size of the first sector (512 bytes)
* which includes the header. * 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, &buf[pe_header + 0x50]);
/* /*
* Address of entry point for PE/COFF executable * Address of entry point for PE/COFF executable
*/ */
put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]); put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
update_pecoff_section_header(".text", text_start, text_sz); update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
} text_sz, text_start);
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);
} }
static int reserve_pecoff_reloc_section(int c) static int reserve_pecoff_reloc_section(int c)
...@@ -278,8 +306,7 @@ static void efi_stub_entry_update(void) ...@@ -278,8 +306,7 @@ static void efi_stub_entry_update(void)
static inline void update_pecoff_setup_and_reloc(unsigned int size) {} static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
static inline void update_pecoff_text(unsigned int text_start, static inline void update_pecoff_text(unsigned int text_start,
unsigned int file_sz) {} unsigned int file_sz,
static inline void update_pecoff_bss(unsigned int file_sz,
unsigned int init_sz) {} unsigned int init_sz) {}
static inline void efi_stub_defaults(void) {} static inline void efi_stub_defaults(void) {}
static inline void efi_stub_entry_update(void) {} static inline void efi_stub_entry_update(void) {}
...@@ -290,6 +317,12 @@ static inline int reserve_pecoff_reloc_section(int c) ...@@ -290,6 +317,12 @@ static inline int reserve_pecoff_reloc_section(int c)
} }
#endif /* CONFIG_EFI_STUB */ #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 * Parse zoffset.h and find the entry points. We could just #include zoffset.h
...@@ -322,8 +355,11 @@ static void parse_zoffset(char *fname) ...@@ -322,8 +355,11 @@ static void parse_zoffset(char *fname)
PARSE_ZOFS(p, efi32_stub_entry); PARSE_ZOFS(p, efi32_stub_entry);
PARSE_ZOFS(p, efi64_stub_entry); PARSE_ZOFS(p, efi64_stub_entry);
PARSE_ZOFS(p, efi_pe_entry); PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, efi32_pe_entry);
PARSE_ZOFS(p, kernel_info); PARSE_ZOFS(p, kernel_info);
PARSE_ZOFS(p, startup_64); PARSE_ZOFS(p, startup_64);
PARSE_ZOFS(p, _ehead);
PARSE_ZOFS(p, _end);
p = strchr(p, '\n'); p = strchr(p, '\n');
while (p && (*p == '\r' || *p == '\n')) while (p && (*p == '\r' || *p == '\n'))
...@@ -365,6 +401,7 @@ int main(int argc, char ** argv) ...@@ -365,6 +401,7 @@ int main(int argc, char ** argv)
die("Boot block hasn't got boot flag (0xAA55)"); die("Boot block hasn't got boot flag (0xAA55)");
fclose(file); fclose(file);
c += reserve_pecoff_compat_section(c);
c += reserve_pecoff_reloc_section(c); c += reserve_pecoff_reloc_section(c);
/* Pad unused space with zeros */ /* Pad unused space with zeros */
...@@ -406,9 +443,28 @@ int main(int argc, char ** argv) ...@@ -406,9 +443,28 @@ int main(int argc, char ** argv)
buf[0x1f1] = setup_sectors-1; buf[0x1f1] = setup_sectors-1;
put_unaligned_le32(sys_size, &buf[0x1f4]); put_unaligned_le32(sys_size, &buf[0x1f4]);
update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
init_sz = get_unaligned_le32(&buf[0x260]); init_sz = get_unaligned_le32(&buf[0x260]);
update_pecoff_bss(i + (sys_size * 16), init_sz); #ifdef CONFIG_EFI_STUB
/*
* The decompression buffer will start at ImageBase. When relocating
* the compressed kernel to its end, we must ensure that the head
* section does not get overwritten. The head section occupies
* [i, i + _ehead), and the destination is [init_sz - _end, init_sz).
*
* At present these should never overlap, because 'i' is at most 32k
* because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the
* calculation of INIT_SIZE in boot/header.S ensures that
* 'init_sz - _end' is at least 64k.
*
* For future-proofing, increase init_sz if necessary.
*/
if (init_sz - _end < i + _ehead) {
init_sz = (i + _ehead + _end + 4095) & ~4095;
put_unaligned_le32(init_sz, &buf[0x260]);
}
#endif
update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz);
efi_stub_entry_update(); efi_stub_entry_update();
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <linux/build_bug.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, * We map the EFI regions needed for runtime services non-contiguously,
* with preserved alignment on virtual addresses starting from -4G down * with preserved alignment on virtual addresses starting from -4G down
...@@ -34,8 +36,6 @@ static inline bool efi_have_uv1_memmap(void) ...@@ -34,8 +36,6 @@ static inline bool efi_have_uv1_memmap(void)
#define EFI32_LOADER_SIGNATURE "EL32" #define EFI32_LOADER_SIGNATURE "EL32"
#define EFI64_LOADER_SIGNATURE "EL64" #define EFI64_LOADER_SIGNATURE "EL64"
#define MAX_CMDLINE_ADDRESS UINT_MAX
#define ARCH_EFI_IRQ_FLAGS_MASK X86_EFLAGS_IF #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); ...@@ -180,7 +180,6 @@ extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
struct efi_setup_data { struct efi_setup_data {
u64 fw_vendor; u64 fw_vendor;
u64 runtime;
u64 tables; u64 tables;
u64 smbios; u64 smbios;
u64 reserved[8]; u64 reserved[8];
...@@ -219,7 +218,8 @@ extern void efi_thunk_runtime_setup(void); ...@@ -219,7 +218,8 @@ extern void efi_thunk_runtime_setup(void);
efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size, efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
unsigned long descriptor_size, unsigned long descriptor_size,
u32 descriptor_version, 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 */ /* arch specific definitions used by the stub code */
...@@ -270,6 +270,11 @@ static inline void *efi64_zero_upper(void *p) ...@@ -270,6 +270,11 @@ static inline void *efi64_zero_upper(void *p)
return 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) \ #define __efi64_argmap_free_pages(addr, size) \
((addr), 0, (size)) ((addr), 0, (size))
...@@ -285,11 +290,21 @@ static inline void *efi64_zero_upper(void *p) ...@@ -285,11 +290,21 @@ static inline void *efi64_zero_upper(void *p)
#define __efi64_argmap_locate_protocol(protocol, reg, interface) \ #define __efi64_argmap_locate_protocol(protocol, reg, interface) \
((protocol), (reg), efi64_zero_upper(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 */ /* PCI I/O */
#define __efi64_argmap_get_location(protocol, seg, bus, dev, func) \ #define __efi64_argmap_get_location(protocol, seg, bus, dev, func) \
((protocol), efi64_zero_upper(seg), efi64_zero_upper(bus), \ ((protocol), efi64_zero_upper(seg), efi64_zero_upper(bus), \
efi64_zero_upper(dev), efi64_zero_upper(func)) 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 * The macros below handle the plumbing for the argument mapping. To add a
* mapping for a specific EFI method, simply define a macro * mapping for a specific EFI method, simply define a macro
......
...@@ -88,7 +88,6 @@ static void __used common(void) ...@@ -88,7 +88,6 @@ static void __used common(void)
OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
OFFSET(BP_init_size, boot_params, hdr.init_size); OFFSET(BP_init_size, boot_params, hdr.init_size);
OFFSET(BP_pref_address, boot_params, hdr.pref_address); OFFSET(BP_pref_address, boot_params, hdr.pref_address);
OFFSET(BP_code32_start, boot_params, hdr.code32_start);
BLANK(); BLANK();
DEFINE(PTREGS_SIZE, sizeof(struct pt_regs)); DEFINE(PTREGS_SIZE, sizeof(struct pt_regs));
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# error "Please do not build this file directly, build asm-offsets.c instead" # error "Please do not build this file directly, build asm-offsets.c instead"
#endif #endif
#include <linux/efi.h>
#include <asm/ucontext.h> #include <asm/ucontext.h>
#define __SYSCALL_I386(nr, sym, qual) [nr] = 1, #define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
...@@ -64,4 +66,7 @@ void foo(void) ...@@ -64,4 +66,7 @@ void foo(void)
BLANK(); BLANK();
DEFINE(__NR_syscall_max, sizeof(syscalls) - 1); DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
DEFINE(NR_syscalls, sizeof(syscalls)); DEFINE(NR_syscalls, sizeof(syscalls));
BLANK();
DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
} }
...@@ -67,11 +67,6 @@ __HEAD ...@@ -67,11 +67,6 @@ __HEAD
SYM_CODE_START(startup_32) SYM_CODE_START(startup_32)
movl pa(initial_stack),%ecx 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. * Set segments to known values.
*/ */
...@@ -82,7 +77,6 @@ SYM_CODE_START(startup_32) ...@@ -82,7 +77,6 @@ SYM_CODE_START(startup_32)
movl %eax,%fs movl %eax,%fs
movl %eax,%gs movl %eax,%gs
movl %eax,%ss movl %eax,%ss
2:
leal -__PAGE_OFFSET(%ecx),%esp leal -__PAGE_OFFSET(%ecx),%esp
/* /*
......
...@@ -17,7 +17,7 @@ static enum efi_secureboot_mode get_sb_mode(void) ...@@ -17,7 +17,7 @@ static enum efi_secureboot_mode get_sb_mode(void)
size = sizeof(secboot); 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"); pr_info("ima: secureboot mode unknown, no efi\n");
return efi_secureboot_mode_unknown; return efi_secureboot_mode_unknown;
} }
......
...@@ -141,9 +141,8 @@ prepare_add_efi_setup_data(struct boot_params *params, ...@@ -141,9 +141,8 @@ prepare_add_efi_setup_data(struct boot_params *params,
struct setup_data *sd = (void *)params + efi_setup_data_offset; struct setup_data *sd = (void *)params + efi_setup_data_offset;
struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data); struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data);
esd->fw_vendor = efi.fw_vendor; esd->fw_vendor = efi_fw_vendor;
esd->runtime = efi.runtime; esd->tables = efi_config_table;
esd->tables = efi.config_table;
esd->smbios = efi.smbios; esd->smbios = efi.smbios;
sd->type = SETUP_EFI; sd->type = SETUP_EFI;
......
This diff is collapsed.
...@@ -66,14 +66,16 @@ void __init efi_map_region(efi_memory_desc_t *md) ...@@ -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 efi_map_region_fixed(efi_memory_desc_t *md) {}
void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
efi_status_t efi_call_svam(efi_set_virtual_address_map_t *__efiapi *, efi_status_t efi_call_svam(efi_runtime_services_t * const *,
u32, u32, u32, void *); u32, u32, u32, void *, u32);
efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size, efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
unsigned long descriptor_size, unsigned long descriptor_size,
u32 descriptor_version, 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; struct desc_ptr gdt_descr;
efi_status_t status; efi_status_t status;
unsigned long flags; unsigned long flags;
...@@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size, ...@@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
/* Disable interrupts around EFI calls: */ /* Disable interrupts around EFI calls: */
local_irq_save(flags); 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, memory_map_size, descriptor_size,
descriptor_version, virtual_map); descriptor_version, virtual_map,
__pa(&efi.runtime));
local_irq_restore(flags); local_irq_restore(flags);
load_fixmap_gdt(0); load_fixmap_gdt(0);
......
...@@ -497,12 +497,9 @@ static DEFINE_SPINLOCK(efi_runtime_lock); ...@@ -497,12 +497,9 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
*/ */
#define __efi_thunk(func, ...) \ #define __efi_thunk(func, ...) \
({ \ ({ \
efi_runtime_services_32_t *__rt; \
unsigned short __ds, __es; \ unsigned short __ds, __es; \
efi_status_t ____s; \ efi_status_t ____s; \
\ \
__rt = (void *)(unsigned long)efi.systab->mixed_mode.runtime; \
\
savesegment(ds, __ds); \ savesegment(ds, __ds); \
savesegment(es, __es); \ savesegment(es, __es); \
\ \
...@@ -510,7 +507,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock); ...@@ -510,7 +507,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
loadsegment(ds, __KERNEL_DS); \ loadsegment(ds, __KERNEL_DS); \
loadsegment(es, __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(ds, __ds); \
loadsegment(es, __es); \ loadsegment(es, __es); \
...@@ -839,8 +836,10 @@ efi_status_t __init __no_sanitize_address ...@@ -839,8 +836,10 @@ efi_status_t __init __no_sanitize_address
efi_set_virtual_address_map(unsigned long memory_map_size, efi_set_virtual_address_map(unsigned long memory_map_size,
unsigned long descriptor_size, unsigned long descriptor_size,
u32 descriptor_version, 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; efi_status_t status;
unsigned long flags; unsigned long flags;
pgd_t *save_pgd = NULL; pgd_t *save_pgd = NULL;
...@@ -863,13 +862,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size, ...@@ -863,13 +862,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size,
/* Disable interrupts around EFI calls: */ /* Disable interrupts around EFI calls: */
local_irq_save(flags); 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, memory_map_size, descriptor_size,
descriptor_version, virtual_map); descriptor_version, virtual_map);
local_irq_restore(flags); local_irq_restore(flags);
kernel_fpu_end(); kernel_fpu_end();
/* grab the virtually remapped EFI runtime services table pointer */
efi.runtime = READ_ONCE(systab->runtime);
if (save_pgd) if (save_pgd)
efi_uv1_memmap_phys_epilog(save_pgd); efi_uv1_memmap_phys_epilog(save_pgd);
else else
......
...@@ -8,14 +8,20 @@ ...@@ -8,14 +8,20 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/asm-offsets.h>
#include <asm/page_types.h> #include <asm/page_types.h>
__INIT __INIT
SYM_FUNC_START(efi_call_svam) SYM_FUNC_START(efi_call_svam)
push 8(%esp) push %ebp
push 8(%esp) movl %esp, %ebp
push %ebx
push 16(%esp)
push 16(%esp)
push %ecx push %ecx
push %edx push %edx
movl %eax, %ebx // &systab_phys->runtime
/* /*
* Switch to the flat mapped alias of this routine, by jumping to the * Switch to the flat mapped alias of this routine, by jumping to the
...@@ -35,15 +41,20 @@ SYM_FUNC_START(efi_call_svam) ...@@ -35,15 +41,20 @@ SYM_FUNC_START(efi_call_svam)
subl $__PAGE_OFFSET, %esp subl $__PAGE_OFFSET, %esp
/* call the EFI routine */ /* 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 */ /* grab the virtually remapped EFI runtime services table pointer */
addl $__PAGE_OFFSET + 16, %esp movl (%ebx), %ecx
movl 36(%esp), %edx // &efi.runtime
movl %ecx, (%edx)
/* re-enable paging */ /* re-enable paging */
movl %cr0, %edx movl %cr0, %edx
orl $0x80000000, %edx orl $0x80000000, %edx
movl %edx, %cr0 movl %edx, %cr0
movl 16(%esp), %ebx
leave
ret ret
SYM_FUNC_END(efi_call_svam) SYM_FUNC_END(efi_call_svam)
...@@ -541,7 +541,7 @@ int __init efi_reuse_config(u64 tables, int nr_tables) ...@@ -541,7 +541,7 @@ int __init efi_reuse_config(u64 tables, int nr_tables)
goto out_memremap; goto out_memremap;
} }
for (i = 0; i < efi.systab->nr_tables; i++) { for (i = 0; i < nr_tables; i++) {
efi_guid_t guid; efi_guid_t guid;
guid = ((efi_config_table_64_t *)p)->guid; guid = ((efi_config_table_64_t *)p)->guid;
......
...@@ -656,6 +656,31 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, ...@@ -656,6 +656,31 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
return 0; return 0;
} }
/**
* utf16_le_to_7bit(): Naively converts a UTF-16LE string to 7-bit ASCII characters
* @in: input UTF-16LE string
* @size: size of the input string
* @out: output string ptr, should be capable to store @size+1 characters
*
* Description: Converts @size UTF16-LE symbols from @in string to 7-bit
* ASCII characters and stores them to @out. Adds trailing zero to @out array.
*/
static void utf16_le_to_7bit(const __le16 *in, unsigned int size, u8 *out)
{
unsigned int i = 0;
out[size] = 0;
while (i < size) {
u8 c = le16_to_cpu(in[i]) & 0xff;
if (c && !isprint(c))
c = '!';
out[i] = c;
i++;
}
}
/** /**
* efi_partition(struct parsed_partitions *state) * efi_partition(struct parsed_partitions *state)
* @state: disk parsed partitions * @state: disk parsed partitions
...@@ -692,7 +717,6 @@ int efi_partition(struct parsed_partitions *state) ...@@ -692,7 +717,6 @@ int efi_partition(struct parsed_partitions *state)
for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
struct partition_meta_info *info; struct partition_meta_info *info;
unsigned label_count = 0;
unsigned label_max; unsigned label_max;
u64 start = le64_to_cpu(ptes[i].starting_lba); u64 start = le64_to_cpu(ptes[i].starting_lba);
u64 size = le64_to_cpu(ptes[i].ending_lba) - u64 size = le64_to_cpu(ptes[i].ending_lba) -
...@@ -713,14 +737,7 @@ int efi_partition(struct parsed_partitions *state) ...@@ -713,14 +737,7 @@ int efi_partition(struct parsed_partitions *state)
/* Naively convert UTF16-LE to 7 bits. */ /* Naively convert UTF16-LE to 7 bits. */
label_max = min(ARRAY_SIZE(info->volname) - 1, label_max = min(ARRAY_SIZE(info->volname) - 1,
ARRAY_SIZE(ptes[i].partition_name)); ARRAY_SIZE(ptes[i].partition_name));
info->volname[label_max] = 0; utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname);
while (label_count < label_max) {
u8 c = ptes[i].partition_name[label_count] & 0xff;
if (c && !isprint(c))
c = '!';
info->volname[label_count] = c;
label_count++;
}
state->parts[i + 1].has_info = true; state->parts[i + 1].has_info = true;
} }
kfree(ptes); kfree(ptes);
......
...@@ -88,7 +88,7 @@ typedef struct _gpt_entry { ...@@ -88,7 +88,7 @@ typedef struct _gpt_entry {
__le64 starting_lba; __le64 starting_lba;
__le64 ending_lba; __le64 ending_lba;
gpt_entry_attributes attributes; gpt_entry_attributes attributes;
efi_char16_t partition_name[72 / sizeof (efi_char16_t)]; __le16 partition_name[72/sizeof(__le16)];
} __packed gpt_entry; } __packed gpt_entry;
typedef struct _gpt_mbr_record { typedef struct _gpt_mbr_record {
......
...@@ -13,13 +13,14 @@ KASAN_SANITIZE_runtime-wrappers.o := n ...@@ -13,13 +13,14 @@ KASAN_SANITIZE_runtime-wrappers.o := n
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o tpm.o obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o tpm.o
obj-$(CONFIG_EFI) += capsule.o memmap.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_VARS) += efivars.o
obj-$(CONFIG_EFI_ESRT) += esrt.o obj-$(CONFIG_EFI_ESRT) += esrt.o
obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
obj-$(CONFIG_UEFI_CPER) += cper.o obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
obj-$(CONFIG_EFI_STUB) += libstub/ subdir-$(CONFIG_EFI_STUB) += libstub
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_map.o obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_map.o
obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
obj-$(CONFIG_EFI_TEST) += test/ obj-$(CONFIG_EFI_TEST) += test/
......
...@@ -31,7 +31,7 @@ __setup("dump_apple_properties", dump_properties_enable); ...@@ -31,7 +31,7 @@ __setup("dump_apple_properties", dump_properties_enable);
struct dev_header { struct dev_header {
u32 len; u32 len;
u32 prop_count; 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, * 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) * len includes itself, value may be empty (in which case its len is 4)
...@@ -42,11 +42,11 @@ struct properties_header { ...@@ -42,11 +42,11 @@ struct properties_header {
u32 len; u32 len;
u32 version; u32 version;
u32 dev_count; 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, 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[]) struct property_entry entry[])
{ {
int i; int i;
...@@ -117,10 +117,10 @@ static int __init unmarshal_devices(struct properties_header *properties) ...@@ -117,10 +117,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
while (offset + sizeof(struct dev_header) < properties->len) { while (offset + sizeof(struct dev_header) < properties->len) {
struct dev_header *dev_header = (void *)properties + offset; struct dev_header *dev_header = (void *)properties + offset;
struct property_entry *entry = NULL; struct property_entry *entry = NULL;
const struct efi_dev_path *ptr;
struct device *dev; struct device *dev;
size_t len; size_t len;
int ret, i; int ret, i;
void *ptr;
if (offset + dev_header->len > properties->len || if (offset + dev_header->len > properties->len ||
dev_header->len <= sizeof(*dev_header)) { dev_header->len <= sizeof(*dev_header)) {
...@@ -131,10 +131,10 @@ static int __init unmarshal_devices(struct properties_header *properties) ...@@ -131,10 +131,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
ptr = dev_header->path; ptr = dev_header->path;
len = dev_header->len - sizeof(*dev_header); 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)) { if (IS_ERR(dev)) {
pr_err("device path parse error %ld at %#zx:\n", 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, print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, dev_header, dev_header->len, true); 16, 1, dev_header, dev_header->len, true);
dev = NULL; dev = NULL;
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#include <asm/efi.h> #include <asm/efi.h>
u64 efi_system_table;
static int __init is_memory(efi_memory_desc_t *md) static int __init is_memory(efi_memory_desc_t *md)
{ {
if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC)) 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) ...@@ -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 * as some data members of the EFI system table are virtually remapped after
* SetVirtualAddressMap() has been called. * 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; efi_memory_desc_t *md;
...@@ -55,7 +53,7 @@ static phys_addr_t efi_to_phys(unsigned long addr) ...@@ -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 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}, {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, NULL, &screen_info_table},
{NULL_GUID, NULL, NULL} {NULL_GUID, NULL, NULL}
}; };
...@@ -83,17 +81,15 @@ static void __init init_screen_info(void) ...@@ -83,17 +81,15 @@ static void __init init_screen_info(void)
memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size); 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; efi_config_table_t *config_tables;
void *config_tables; efi_system_table_t *systab;
size_t table_size; size_t table_size;
char vendor[100] = "unknown"; int retval;
int i, retval;
efi.systab = early_memremap_ro(efi_system_table, systab = early_memremap_ro(efi_system_table, sizeof(efi_system_table_t));
sizeof(efi_system_table_t)); if (systab == NULL) {
if (efi.systab == NULL) {
pr_warn("Unable to map EFI system table.\n"); pr_warn("Unable to map EFI system table.\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -102,53 +98,29 @@ static int __init uefi_init(void) ...@@ -102,53 +98,29 @@ static int __init uefi_init(void)
if (IS_ENABLED(CONFIG_64BIT)) if (IS_ENABLED(CONFIG_64BIT))
set_bit(EFI_64BIT, &efi.flags); set_bit(EFI_64BIT, &efi.flags);
/* retval = efi_systab_check_header(&systab->hdr, 2);
* Verify the EFI Table if (retval)
*/
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
pr_err("System table signature incorrect\n");
retval = -EINVAL;
goto out; 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.runtime = systab->runtime;
efi.systab->hdr.revision >> 16, efi.runtime_version = systab->hdr.revision;
efi.systab->hdr.revision & 0xffff, vendor);
table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; efi_systab_report_header(&systab->hdr, efi_to_phys(systab->fw_vendor));
config_tables = early_memremap_ro(efi_to_phys(efi.systab->tables),
table_size = sizeof(efi_config_table_t) * systab->nr_tables;
config_tables = early_memremap_ro(efi_to_phys(systab->tables),
table_size); table_size);
if (config_tables == NULL) { if (config_tables == NULL) {
pr_warn("Unable to map EFI config table array.\n"); pr_warn("Unable to map EFI config table array.\n");
retval = -ENOMEM; retval = -ENOMEM;
goto out; goto out;
} }
retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, retval = efi_config_parse_tables(config_tables, systab->nr_tables,
sizeof(efi_config_table_t),
arch_tables); arch_tables);
if (!retval)
efi.config_table = (unsigned long)efi.systab->tables;
early_memunmap(config_tables, table_size); early_memunmap(config_tables, table_size);
out: out:
early_memunmap(efi.systab, sizeof(efi_system_table_t)); early_memunmap(systab, sizeof(efi_system_table_t));
return retval; return retval;
} }
...@@ -233,19 +205,13 @@ static __init void reserve_regions(void) ...@@ -233,19 +205,13 @@ static __init void reserve_regions(void)
void __init efi_init(void) void __init efi_init(void)
{ {
struct efi_memory_map_data data; struct efi_memory_map_data data;
struct efi_fdt_params params; u64 efi_system_table;
/* Grab UEFI information placed in FDT by stub */ /* 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; 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 (efi_memmap_init_early(&data) < 0) {
/* /*
* If we are booting via UEFI, the UEFI memory map is the only * If we are booting via UEFI, the UEFI memory map is the only
...@@ -259,7 +225,7 @@ void __init efi_init(void) ...@@ -259,7 +225,7 @@ void __init efi_init(void)
"Unexpected EFI_MEMORY_DESCRIPTOR version %ld", "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
efi.memmap.desc_version); efi.memmap.desc_version);
if (uefi_init() < 0) { if (uefi_init(efi_system_table) < 0) {
efi_memmap_unmap(); efi_memmap_unmap();
return; return;
} }
...@@ -267,9 +233,8 @@ void __init efi_init(void) ...@@ -267,9 +233,8 @@ void __init efi_init(void)
reserve_regions(); reserve_regions();
efi_esrt_init(); efi_esrt_init();
memblock_reserve(params.mmap & PAGE_MASK, memblock_reserve(data.phys_map & PAGE_MASK,
PAGE_ALIGN(params.mmap_size + PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
(params.mmap & ~PAGE_MASK)));
init_screen_info(); init_screen_info();
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
extern u64 efi_system_table;
#if defined(CONFIG_PTDUMP_DEBUGFS) && defined(CONFIG_ARM64) #if defined(CONFIG_PTDUMP_DEBUGFS) && defined(CONFIG_ARM64)
#include <asm/ptdump.h> #include <asm/ptdump.h>
...@@ -54,13 +52,11 @@ device_initcall(ptdump_init); ...@@ -54,13 +52,11 @@ device_initcall(ptdump_init);
static bool __init efi_virtmap_init(void) static bool __init efi_virtmap_init(void)
{ {
efi_memory_desc_t *md; efi_memory_desc_t *md;
bool systab_found;
efi_mm.pgd = pgd_alloc(&efi_mm); efi_mm.pgd = pgd_alloc(&efi_mm);
mm_init_cpumask(&efi_mm); mm_init_cpumask(&efi_mm);
init_new_context(NULL, &efi_mm); init_new_context(NULL, &efi_mm);
systab_found = false;
for_each_efi_memory_desc(md) { for_each_efi_memory_desc(md) {
phys_addr_t phys = md->phys_addr; phys_addr_t phys = md->phys_addr;
int ret; int ret;
...@@ -76,20 +72,6 @@ static bool __init efi_virtmap_init(void) ...@@ -76,20 +72,6 @@ static bool __init efi_virtmap_init(void)
&phys, ret); &phys, ret);
return false; 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)) if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
......
...@@ -168,7 +168,7 @@ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) ...@@ -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, static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
size_t count, loff_t *offp) size_t count, loff_t *offp)
{ {
int ret = 0; int ret;
struct capsule_info *cap_info = file->private_data; struct capsule_info *cap_info = file->private_data;
struct page *page; struct page *page;
void *kbuff = NULL; void *kbuff = NULL;
......
...@@ -31,13 +31,13 @@ static int __init match_acpi_dev(struct device *dev, const void *data) ...@@ -31,13 +31,13 @@ static int __init match_acpi_dev(struct device *dev, const void *data)
return !strcmp("0", hid_uid.uid); 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 device *parent, struct device **child)
{ {
struct acpi_hid_uid hid_uid = {}; struct acpi_hid_uid hid_uid = {};
struct device *phys_dev; struct device *phys_dev;
if (node->length != 12) if (node->header.length != 12)
return -EINVAL; return -EINVAL;
sprintf(hid_uid.hid[0].id, "%c%c%c%04X", 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) ...@@ -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; 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) struct device *parent, struct device **child)
{ {
unsigned int devfn; unsigned int devfn;
if (node->length != 6) if (node->header.length != 6)
return -EINVAL; return -EINVAL;
if (!parent) if (!parent)
return -EINVAL; return -EINVAL;
...@@ -105,19 +105,19 @@ static long __init parse_pci_path(struct efi_dev_path *node, ...@@ -105,19 +105,19 @@ static long __init parse_pci_path(struct efi_dev_path *node,
* search for a device. * 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) struct device *parent, struct device **child)
{ {
if (node->length != 4) if (node->header.length != 4)
return -EINVAL; return -EINVAL;
if (node->sub_type != EFI_DEV_END_INSTANCE && if (node->header.sub_type != EFI_DEV_END_INSTANCE &&
node->sub_type != EFI_DEV_END_ENTIRE) node->header.sub_type != EFI_DEV_END_ENTIRE)
return -EINVAL; return -EINVAL;
if (!parent) if (!parent)
return -ENODEV; return -ENODEV;
*child = get_device(parent); *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, ...@@ -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(-EINVAL) if a node is malformed or exceeds @len,
* %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented. * %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) size_t *len)
{ {
struct device *parent = NULL, *child; struct device *parent = NULL, *child;
...@@ -166,16 +166,16 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node, ...@@ -166,16 +166,16 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
return NULL; return NULL;
while (!ret) { while (!ret) {
if (*len < 4 || *len < (*node)->length) if (*len < 4 || *len < (*node)->header.length)
ret = -EINVAL; ret = -EINVAL;
else if ((*node)->type == EFI_DEV_ACPI && else if ((*node)->header.type == EFI_DEV_ACPI &&
(*node)->sub_type == EFI_DEV_BASIC_ACPI) (*node)->header.sub_type == EFI_DEV_BASIC_ACPI)
ret = parse_acpi_path(*node, parent, &child); ret = parse_acpi_path(*node, parent, &child);
else if ((*node)->type == EFI_DEV_HW && else if ((*node)->header.type == EFI_DEV_HW &&
(*node)->sub_type == EFI_DEV_PCI) (*node)->header.sub_type == EFI_DEV_PCI)
ret = parse_pci_path(*node, parent, &child); ret = parse_pci_path(*node, parent, &child);
else if (((*node)->type == EFI_DEV_END_PATH || else if (((*node)->header.type == EFI_DEV_END_PATH ||
(*node)->type == EFI_DEV_END_PATH2)) (*node)->header.type == EFI_DEV_END_PATH2))
ret = parse_end_path(*node, parent, &child); ret = parse_end_path(*node, parent, &child);
else else
ret = -ENOTSUPP; ret = -ENOTSUPP;
...@@ -185,8 +185,8 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node, ...@@ -185,8 +185,8 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
return ERR_PTR(ret); return ERR_PTR(ret);
parent = child; parent = child;
*node = (void *)*node + (*node)->length; *node = (void *)*node + (*node)->header.length;
*len -= (*node)->length; *len -= (*node)->header.length;
} }
if (ret == EFI_DEV_END_ENTIRE) if (ret == EFI_DEV_END_ENTIRE)
......
...@@ -42,7 +42,12 @@ void __init efi_bgrt_init(struct acpi_table_header *table) ...@@ -42,7 +42,12 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
return; return;
} }
*bgrt = *(struct acpi_table_bgrt *)table; *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", pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n",
bgrt->version); bgrt->version);
goto out; goto out;
......
...@@ -161,7 +161,7 @@ static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos, ...@@ -161,7 +161,7 @@ static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
* *
* @record: pstore record to pass to callback * @record: pstore record to pass to callback
* *
* You MUST call efivar_enter_iter_begin() before this function, and * You MUST call efivar_entry_iter_begin() before this function, and
* efivar_entry_iter_end() afterwards. * efivar_entry_iter_end() afterwards.
* *
*/ */
...@@ -356,7 +356,7 @@ static struct pstore_info efi_pstore_info = { ...@@ -356,7 +356,7 @@ static struct pstore_info efi_pstore_info = {
static __init int efivars_pstore_init(void) 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; return 0;
if (!efivars_kobject()) if (!efivars_kobject())
......
This diff is collapsed.
...@@ -678,7 +678,7 @@ int efivars_sysfs_init(void) ...@@ -678,7 +678,7 @@ int efivars_sysfs_init(void)
struct kobject *parent_kobj = efivars_kobject(); struct kobject *parent_kobj = efivars_kobject();
int error = 0; int error = 0;
if (!efi_enabled(EFI_RUNTIME_SERVICES)) if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
return -ENODEV; return -ENODEV;
/* No efivars has been registered yet */ /* No efivars has been registered yet */
......
...@@ -240,7 +240,6 @@ void __init efi_esrt_init(void) ...@@ -240,7 +240,6 @@ void __init efi_esrt_init(void)
{ {
void *va; void *va;
struct efi_system_resource_table tmpesrt; struct efi_system_resource_table tmpesrt;
struct efi_system_resource_entry_v1 *v1_entries;
size_t size, max, entry_size, entries_size; size_t size, max, entry_size, entries_size;
efi_memory_desc_t md; efi_memory_desc_t md;
int rc; int rc;
...@@ -288,14 +287,13 @@ void __init efi_esrt_init(void) ...@@ -288,14 +287,13 @@ void __init efi_esrt_init(void)
memcpy(&tmpesrt, va, sizeof(tmpesrt)); memcpy(&tmpesrt, va, sizeof(tmpesrt));
early_memunmap(va, size); early_memunmap(va, size);
if (tmpesrt.fw_resource_version == 1) { if (tmpesrt.fw_resource_version != 1) {
entry_size = sizeof (*v1_entries);
} else {
pr_err("Unsupported ESRT version %lld.\n", pr_err("Unsupported ESRT version %lld.\n",
tmpesrt.fw_resource_version); tmpesrt.fw_resource_version);
return; return;
} }
entry_size = sizeof(struct efi_system_resource_entry_v1);
if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) { 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", pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n",
max - size, entry_size); max - size, entry_size);
......
// 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;
}
...@@ -25,6 +25,7 @@ cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ ...@@ -25,6 +25,7 @@ cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \ KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
-include $(srctree)/drivers/firmware/efi/libstub/hidden.h \
-D__NO_FORTIFY \ -D__NO_FORTIFY \
$(call cc-option,-ffreestanding) \ $(call cc-option,-ffreestanding) \
$(call cc-option,-fno-stack-protector) \ $(call cc-option,-fno-stack-protector) \
...@@ -39,11 +40,11 @@ OBJECT_FILES_NON_STANDARD := y ...@@ -39,11 +40,11 @@ OBJECT_FILES_NON_STANDARD := y
KCOV_INSTRUMENT := n KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ 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 # 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-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 $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
$(call if_changed_rule,cc_o_c) $(call if_changed_rule,cc_o_c)
...@@ -53,6 +54,7 @@ lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ ...@@ -53,6 +54,7 @@ lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \
lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o
lib-$(CONFIG_X86) += x86-stub.o
CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
......
This diff is collapsed.
...@@ -227,6 +227,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, ...@@ -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 * Relocate the zImage, so that it appears in the lowest 128 MB
* memory window. * memory window.
*/ */
*image_addr = (unsigned long)image->image_base;
*image_size = image->image_size; *image_size = image->image_size;
status = efi_relocate_kernel(image_addr, *image_size, *image_size, status = efi_relocate_kernel(image_addr, *image_size, *image_size,
kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0); kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
......
...@@ -6,17 +6,11 @@ ...@@ -6,17 +6,11 @@
* Adapted from ARM version by Mark Salter <msalter@redhat.com> * 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 <linux/efi.h>
#include <asm/efi.h> #include <asm/efi.h>
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/sections.h>
#include <asm/sysreg.h> #include <asm/sysreg.h>
#include "efistub.h" #include "efistub.h"
...@@ -49,7 +43,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, ...@@ -49,7 +43,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
{ {
efi_status_t status; efi_status_t status;
unsigned long kernel_size, kernel_memsize = 0; unsigned long kernel_size, kernel_memsize = 0;
void *old_image_addr = (void *)*image_addr;
unsigned long preferred_offset; unsigned long preferred_offset;
u64 phys_seed = 0; u64 phys_seed = 0;
...@@ -123,6 +116,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, ...@@ -123,6 +116,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
* Mustang), we can still place the kernel at the address * Mustang), we can still place the kernel at the address
* 'dram_base + TEXT_OFFSET'. * 'dram_base + TEXT_OFFSET'.
*/ */
*image_addr = (unsigned long)_text;
if (*image_addr == preferred_offset) if (*image_addr == preferred_offset)
return EFI_SUCCESS; return EFI_SUCCESS;
...@@ -147,7 +141,11 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, ...@@ -147,7 +141,11 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
} }
*image_addr = *reserve_addr + TEXT_OFFSET; *image_addr = *reserve_addr + TEXT_OFFSET;
} }
memcpy((void *)*image_addr, old_image_addr, kernel_size);
if (image->image_base != _text)
pr_efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
memcpy((void *)*image_addr, _text, kernel_size);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
This diff is collapsed.
...@@ -199,10 +199,6 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map) ...@@ -199,10 +199,6 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
#ifndef EFI_FDT_ALIGN
# define EFI_FDT_ALIGN EFI_PAGE_SIZE
#endif
struct exit_boot_struct { struct exit_boot_struct {
efi_memory_desc_t *runtime_map; efi_memory_desc_t *runtime_map;
int *runtime_entry_count; int *runtime_entry_count;
...@@ -281,8 +277,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle, ...@@ -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"); pr_efi("Exiting boot services and installing virtual address map...\n");
map.map = &memory_map; map.map = &memory_map;
status = efi_high_alloc(MAX_FDT_SIZE, EFI_FDT_ALIGN, status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, max_addr);
new_fdt_addr, max_addr);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
pr_efi_err("Unable to allocate memory for new device tree.\n"); pr_efi_err("Unable to allocate memory for new device tree.\n");
goto fail; goto fail;
......
// 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);
}
/* 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)
This diff is collapsed.
This diff is collapsed.
// 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;
}
// 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;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment