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
introduction
core
efi/index
request_firmware
other_interfaces
......
......@@ -490,15 +490,11 @@ Protocol: 2.00+
kernel) to not write early messages that require
accessing the display hardware directly.
Bit 6 (write): KEEP_SEGMENTS
Bit 6 (obsolete): KEEP_SEGMENTS
Protocol: 2.07+
- If 0, reload the segment registers in the 32bit entry point.
- If 1, do not reload the segment registers in the 32bit entry point.
Assume that %cs %ds %ss %es are all set to flat segments with
a base of 0 (or the equivalent for their environment).
- This flag is obsolete.
Bit 7 (write): CAN_USE_HEAP
......
......@@ -6363,7 +6363,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
S: Maintained
F: Documentation/admin-guide/efi-stub.rst
F: arch/*/kernel/efi.c
F: arch/x86/boot/compressed/eboot.[ch]
F: arch/*/include/asm/efi.h
F: arch/x86/platform/efi/
F: drivers/firmware/efi/
......
......@@ -60,7 +60,7 @@ optional_header:
.long __pecoff_code_size @ SizeOfCode
.long __pecoff_data_size @ SizeOfInitializedData
.long 0 @ SizeOfUninitializedData
.long efi_stub_entry - start @ AddressOfEntryPoint
.long efi_entry - start @ AddressOfEntryPoint
.long start_offset @ BaseOfCode
.long __pecoff_data_start - start @ BaseOfData
......@@ -70,8 +70,8 @@ extra_header_fields:
.long SZ_512 @ FileAlignment
.short 0 @ MajorOsVersion
.short 0 @ MinorOsVersion
.short 0 @ MajorImageVersion
.short 0 @ MinorImageVersion
.short LINUX_EFISTUB_MAJOR_VERSION @ MajorImageVersion
.short LINUX_EFISTUB_MINOR_VERSION @ MinorImageVersion
.short 0 @ MajorSubsystemVersion
.short 0 @ MinorSubsystemVersion
.long 0 @ Win32VersionValue
......
......@@ -1437,29 +1437,25 @@ __enter_kernel:
reloc_code_end:
#ifdef CONFIG_EFI_STUB
.align 2
_start: .long start - .
ENTRY(efi_stub_entry)
@ allocate space on stack for passing current zImage address
@ and for the EFI stub to return of new entry point of
@ zImage, as EFI stub may copy the kernel. Pointer address
@ is passed in r2. r0 and r1 are passed through from the
@ EFI firmware to efi_entry
adr ip, _start
ldr r3, [ip]
add r3, r3, ip
stmfd sp!, {r3, lr}
mov r2, sp @ pass zImage address in r2
bl efi_entry
@ Check for error return from EFI stub. r0 has FDT address
@ or error code.
cmn r0, #1
beq efi_load_fail
@ Preserve return value of efi_entry() in r4
mov r4, r0
ENTRY(efi_enter_kernel)
mov r7, r0 @ preserve image base
mov r4, r1 @ preserve DT pointer
mov r0, r4 @ DT start
add r1, r4, r2 @ DT end
bl cache_clean_flush
mov r0, r7 @ relocated zImage
ldr r1, =_edata @ size of zImage
add r1, r1, r0 @ end of zImage
bl cache_clean_flush
@ The PE/COFF loader might not have cleaned the code we are
@ running beyond the PoU, and so calling cache_off below from
@ inside the PE/COFF loader allocated region is unsafe unless
@ we explicitly clean it to the PoC.
adr r0, call_cache_fn @ region of code we will
adr r1, 0f @ run with MMU off
bl cache_clean_flush
bl cache_off
......@@ -1469,18 +1465,10 @@ ENTRY(efi_stub_entry)
mov r0, #0
mov r1, #0xFFFFFFFF
mov r2, r4
@ Branch to (possibly) relocated zImage that is in [sp]
ldr lr, [sp]
ldr ip, =start_offset
add lr, lr, ip
mov pc, lr @ no mode switch
efi_load_fail:
@ Return EFI_LOAD_ERROR to EFI firmware on error.
ldr r0, =0x80000001
ldmfd sp!, {ip, pc}
ENDPROC(efi_stub_entry)
add r7, r7, #(__efi_start - start)
mov pc, r7 @ no mode switch
ENDPROC(efi_enter_kernel)
0:
#endif
.align
......
......@@ -57,13 +57,6 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
/* arch specific definitions used by the stub code */
/*
* AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
* start of kernel and may not cross a 2MiB boundary. We set alignment to
* 2MiB so we know it won't cross a 2MiB boundary.
*/
#define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */
/*
* In some configurations (e.g. VMAP_STACK && 64K pages), stacks built into the
* kernel need greater alignment than we require the segments to be padded to.
......@@ -107,9 +100,6 @@ static inline void free_screen_info(struct screen_info *si)
{
}
/* redeclare as 'hidden' so the compiler will generate relative references */
extern struct screen_info screen_info __attribute__((__visibility__("hidden")));
static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
{
}
......
......@@ -10,81 +10,35 @@
#include <asm/assembler.h>
#define EFI_LOAD_ERROR 0x8000000000000001
__INIT
/*
* We arrive here from the EFI boot manager with:
*
* * CPU in little-endian mode
* * MMU on with identity-mapped RAM
* * Icache and Dcache on
*
* We will most likely be running from some place other than where
* we want to be. The kernel image wants to be placed at TEXT_OFFSET
* from start of RAM.
*/
ENTRY(entry)
/*
* Create a stack frame to save FP/LR with extra space
* for image_addr variable passed to efi_entry().
*/
stp x29, x30, [sp, #-32]!
mov x29, sp
/*
* Call efi_entry to do the real work.
* x0 and x1 are already set up by firmware. Current runtime
* address of image is calculated and passed via *image_addr.
*
* unsigned long efi_entry(void *handle,
* efi_system_table_t *sys_table,
* unsigned long *image_addr) ;
*/
adr_l x8, _text
add x2, sp, 16
str x8, [x2]
bl efi_entry
cmn x0, #1
b.eq efi_load_fail
SYM_CODE_START(efi_enter_kernel)
/*
* efi_entry() will have copied the kernel image if necessary and we
* return here with device tree address in x0 and the kernel entry
* point stored at *image_addr. Save those values in registers which
* are callee preserved.
*/
mov x20, x0 // DTB address
ldr x0, [sp, #16] // relocated _text address
ldr w21, =stext_offset
add x21, x0, x21
/*
* Calculate size of the kernel Image (same for original and copy).
* end up here with device tree address in x1 and the kernel entry
* point stored in x0. Save those values in registers which are
* callee preserved.
*/
adr_l x1, _text
adr_l x2, _edata
sub x1, x2, x1
ldr w2, =stext_offset
add x19, x0, x2 // relocated Image entrypoint
mov x20, x1 // DTB address
/*
* Flush the copied Image to the PoC, and ensure it is not shadowed by
* Clean the copied Image to the PoC, and ensure it is not shadowed by
* stale icache entries from before relocation.
*/
bl __flush_dcache_area
ldr w1, =kernel_size
bl __clean_dcache_area_poc
ic ialluis
/*
* Ensure that the rest of this function (in the original Image) is
* visible when the caches are disabled. The I-cache can't have stale
* entries for the VA range of the current image, so no maintenance is
* necessary.
* Clean the remainder of this routine to the PoC
* so that we can safely disable the MMU and caches.
*/
adr x0, entry
adr x1, entry_end
sub x1, x1, x0
bl __flush_dcache_area
adr x0, 0f
ldr w1, 3f
bl __clean_dcache_area_poc
0:
/* Turn off Dcache and MMU */
mrs x0, CurrentEL
cmp x0, #CurrentEL_EL2
......@@ -109,12 +63,6 @@ ENTRY(entry)
mov x1, xzr
mov x2, xzr
mov x3, xzr
br x21
efi_load_fail:
mov x0, #EFI_LOAD_ERROR
ldp x29, x30, [sp], #32
ret
entry_end:
ENDPROC(entry)
br x19
SYM_CODE_END(efi_enter_kernel)
3: .long . - 0b
......@@ -27,7 +27,7 @@ optional_header:
.long __initdata_begin - efi_header_end // SizeOfCode
.long __pecoff_data_size // SizeOfInitializedData
.long 0 // SizeOfUninitializedData
.long __efistub_entry - _head // AddressOfEntryPoint
.long __efistub_efi_entry - _head // AddressOfEntryPoint
.long efi_header_end - _head // BaseOfCode
extra_header_fields:
......@@ -36,8 +36,8 @@ extra_header_fields:
.long PECOFF_FILE_ALIGNMENT // FileAlignment
.short 0 // MajorOperatingSystemVersion
.short 0 // MinorOperatingSystemVersion
.short 0 // MajorImageVersion
.short 0 // MinorImageVersion
.short LINUX_EFISTUB_MAJOR_VERSION // MajorImageVersion
.short LINUX_EFISTUB_MINOR_VERSION // MinorImageVersion
.short 0 // MajorSubsystemVersion
.short 0 // MinorSubsystemVersion
.long 0 // Win32VersionValue
......
......@@ -12,7 +12,9 @@
#ifdef CONFIG_EFI
__efistub_stext_offset = stext - _text;
__efistub_kernel_size = _edata - _text;
__efistub_stext_offset = stext - _text;
/*
* The EFI stub has its own symbol namespace prefixed by __efistub_, to
......@@ -33,7 +35,7 @@ __efistub_strnlen = __pi_strnlen;
__efistub_strcmp = __pi_strcmp;
__efistub_strncmp = __pi_strncmp;
__efistub_strrchr = __pi_strrchr;
__efistub___flush_dcache_area = __pi___flush_dcache_area;
__efistub___clean_dcache_area_poc = __pi___clean_dcache_area_poc;
#ifdef CONFIG_KASAN
__efistub___memcpy = __pi_memcpy;
......@@ -45,6 +47,7 @@ __efistub__text = _text;
__efistub__end = _end;
__efistub__edata = _edata;
__efistub_screen_info = screen_info;
__efistub__ctype = _ctype;
#endif
......
......@@ -45,11 +45,21 @@
#define EFI_DEBUG 0
#define ESI_TABLE_GUID \
EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3, \
0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
static unsigned long mps_phys = EFI_INVALID_TABLE_ADDR;
static __initdata unsigned long palo_phys;
unsigned long __initdata esi_phys = EFI_INVALID_TABLE_ADDR;
unsigned long hcdp_phys = EFI_INVALID_TABLE_ADDR;
unsigned long sal_systab_phys = EFI_INVALID_TABLE_ADDR;
static __initdata efi_config_table_type_t arch_tables[] = {
static const efi_config_table_type_t arch_tables[] __initconst = {
{ESI_TABLE_GUID, "ESI", &esi_phys},
{HCDP_TABLE_GUID, "HCDP", &hcdp_phys},
{MPS_TABLE_GUID, "MPS", &mps_phys},
{PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys},
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &sal_systab_phys},
{NULL_GUID, NULL, 0},
......@@ -474,11 +484,10 @@ efi_map_pal_code (void)
void __init
efi_init (void)
{
const efi_system_table_t *efi_systab;
void *efi_map_start, *efi_map_end;
efi_char16_t *c16;
u64 efi_desc_size;
char *cp, vendor[100] = "unknown";
int i;
char *cp;
set_bit(EFI_BOOT, &efi.flags);
set_bit(EFI_64BIT, &efi.flags);
......@@ -508,42 +517,29 @@ efi_init (void)
printk(KERN_INFO "Ignoring memory above %lluMB\n",
max_addr >> 20);
efi.systab = __va(ia64_boot_param->efi_systab);
efi_systab = __va(ia64_boot_param->efi_systab);
/*
* Verify the EFI Table
*/
if (efi.systab == NULL)
if (efi_systab == NULL)
panic("Whoa! Can't find EFI system table.\n");
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
if (efi_systab_check_header(&efi_systab->hdr, 1))
panic("Whoa! EFI system table signature incorrect\n");
if ((efi.systab->hdr.revision >> 16) == 0)
printk(KERN_WARNING "Warning: EFI system table version "
"%d.%02d, expected 1.00 or greater\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff);
/* Show what we know for posterity */
c16 = __va(efi.systab->fw_vendor);
if (c16) {
for (i = 0;i < (int) sizeof(vendor) - 1 && *c16; ++i)
vendor[i] = *c16++;
vendor[i] = '\0';
}
printk(KERN_INFO "EFI v%u.%.02u by %s:",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor);
efi_systab_report_header(&efi_systab->hdr, efi_systab->fw_vendor);
palo_phys = EFI_INVALID_TABLE_ADDR;
if (efi_config_init(arch_tables) != 0)
if (efi_config_parse_tables(__va(efi_systab->tables),
efi_systab->nr_tables,
arch_tables) != 0)
return;
if (palo_phys != EFI_INVALID_TABLE_ADDR)
handle_palo(palo_phys);
runtime = __va(efi.systab->runtime);
runtime = __va(efi_systab->runtime);
efi.get_time = phys_get_time;
efi.set_time = phys_set_time;
efi.get_wakeup_time = phys_get_wakeup_time;
......@@ -1351,3 +1347,12 @@ vmcore_find_descriptor_size (unsigned long address)
return ret;
}
#endif
char *efi_systab_show_arch(char *str)
{
if (mps_phys != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "MPS=0x%lx\n", mps_phys);
if (hcdp_phys != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "HCDP=0x%lx\n", hcdp_phys);
return str;
}
......@@ -19,10 +19,6 @@ MODULE_LICENSE("GPL");
#define MODULE_NAME "esi"
#define ESI_TABLE_GUID \
EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3, \
0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
enum esi_systab_entry_type {
ESI_DESC_ENTRY_POINT = 0
};
......@@ -48,27 +44,18 @@ struct pdesc {
static struct ia64_sal_systab *esi_systab;
extern unsigned long esi_phys;
static int __init esi_init (void)
{
efi_config_table_t *config_tables;
struct ia64_sal_systab *systab;
unsigned long esi = 0;
char *p;
int i;
config_tables = __va(efi.systab->tables);
for (i = 0; i < (int) efi.systab->nr_tables; ++i) {
if (efi_guidcmp(config_tables[i].guid, ESI_TABLE_GUID) == 0) {
esi = config_tables[i].table;
break;
}
}
if (!esi)
if (esi_phys == EFI_INVALID_TABLE_ADDR)
return -ENODEV;
systab = __va(esi);
systab = __va(esi_phys);
if (strncmp(systab->signature, "ESIT", 4) != 0) {
printk(KERN_ERR "bad signature in ESI system table!");
......
......@@ -88,7 +88,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
......
......@@ -87,10 +87,7 @@ endif
vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o \
$(objtree)/drivers/firmware/efi/libstub/lib.a
vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
# The compressed kernel is built with -fPIC/-fPIE so that a boot loader
......
/* 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)
* Switch to gdt with 32-bit segments. This is the firmware GDT
* that was installed when the kernel started executing. This
* pointer was saved at the EFI stub entry point in head_64.S.
*
* Pass the saved DS selector to the 32-bit code, and use far return to
* restore the saved CS selector.
*/
leaq efi32_boot_gdt(%rip), %rax
lgdt (%rax)
pushq $__KERNEL_CS
movzwl efi32_boot_ds(%rip), %edx
movzwq efi32_boot_cs(%rip), %rax
pushq %rax
leaq efi_enter32(%rip), %rax
pushq %rax
lretq
......@@ -73,6 +78,10 @@ SYM_FUNC_START(__efi64_thunk)
movl %ebx, %es
pop %rbx
movl %ebx, %ds
/* Clear out 32-bit selector from FS and GS */
xorl %ebx, %ebx
movl %ebx, %fs
movl %ebx, %gs
/*
* Convert 32-bit status code into 64-bit.
......@@ -92,10 +101,12 @@ SYM_FUNC_END(__efi64_thunk)
* The stack should represent the 32-bit calling convention.
*/
SYM_FUNC_START_LOCAL(efi_enter32)
movl $__KERNEL_DS, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
/* Load firmware selector into data and stack segment registers */
movl %edx, %ds
movl %edx, %es
movl %edx, %fs
movl %edx, %gs
movl %edx, %ss
/* Reload pgtables */
movl %cr3, %eax
......@@ -157,6 +168,14 @@ SYM_DATA_START(efi32_boot_gdt)
.quad 0
SYM_DATA_END(efi32_boot_gdt)
SYM_DATA_START(efi32_boot_cs)
.word 0
SYM_DATA_END(efi32_boot_cs)
SYM_DATA_START(efi32_boot_ds)
.word 0
SYM_DATA_END(efi32_boot_ds)
SYM_DATA_START(efi_gdt64)
.word efi_gdt64_end - efi_gdt64
.long 0 /* Filled out by user */
......
......@@ -63,21 +63,7 @@
__HEAD
SYM_FUNC_START(startup_32)
cld
/*
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
* us to not reload segments
*/
testb $KEEP_SEGMENTS, BP_loadflags(%esi)
jnz 1f
cli
movl $__BOOT_DS, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
movl %eax, %ss
1:
/*
* Calculate the delta between where we were compiled to run
......@@ -89,32 +75,59 @@ SYM_FUNC_START(startup_32)
*/
leal (BP_scratch+4)(%esi), %esp
call 1f
1: popl %ebp
subl $1b, %ebp
1: popl %edx
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
* for safe in-place decompression.
* for safe in-place decompression. %ebp contains the address that the kernel
* will be decompressed to.
*/
#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
decl %eax
addl %eax, %ebx
notl %eax
andl %eax, %ebx
cmpl $LOAD_PHYSICAL_ADDR, %ebx
jge 1f
jae 1f
#endif
movl $LOAD_PHYSICAL_ADDR, %ebx
1:
movl %ebx, %ebp // Save the output address for later
/* Target address to relocate to for decompression */
movl BP_init_size(%esi), %eax
subl $_end, %eax
addl %eax, %ebx
addl BP_init_size(%esi), %ebx
subl $_end, %ebx
/* Set up the stack */
leal boot_stack_end(%ebx), %esp
......@@ -128,7 +141,7 @@ SYM_FUNC_START(startup_32)
* where decompression in place becomes safe.
*/
pushl %esi
leal (_bss-4)(%ebp), %esi
leal (_bss-4)(%edx), %esi
leal (_bss-4)(%ebx), %edi
movl $(_bss - startup_32), %ecx
shrl $2, %ecx
......@@ -137,6 +150,15 @@ SYM_FUNC_START(startup_32)
cld
popl %esi
/*
* The GDT may get overwritten either during the copy we just did or
* during extract_kernel below. To avoid any issues, repoint the GDTR
* to the new copy of the GDT.
*/
leal gdt(%ebx), %eax
movl %eax, 2(%eax)
lgdt (%eax)
/*
* Jump to the relocated address.
*/
......@@ -148,9 +170,8 @@ SYM_FUNC_END(startup_32)
SYM_FUNC_START(efi32_stub_entry)
SYM_FUNC_START_ALIAS(efi_stub_entry)
add $0x4, %esp
movl 8(%esp), %esi /* save boot_params pointer */
call efi_main
movl %eax, %esi
movl BP_code32_start(%esi), %eax
leal startup_32(%eax), %eax
jmp *%eax
SYM_FUNC_END(efi32_stub_entry)
......@@ -189,9 +210,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
/* push arguments for extract_kernel: */
pushl $z_output_len /* decompressed length, end of relocs */
leal _end(%ebx), %eax
subl BP_init_size(%esi), %eax
pushl %eax /* output address */
pushl %ebp /* output address */
pushl $z_input_len /* input_len */
leal input_data(%ebx), %eax
......@@ -209,6 +228,21 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
jmp *%eax
SYM_FUNC_END(.Lrelocated)
.data
.balign 8
SYM_DATA_START_LOCAL(gdt)
.word gdt_end - gdt - 1
.long 0
.word 0
.quad 0x0000000000000000 /* Reserved */
.quad 0x00cf9a000000ffff /* __KERNEL_CS */
.quad 0x00cf92000000ffff /* __KERNEL_DS */
SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
#ifdef CONFIG_EFI_STUB
SYM_DATA(image_offset, .long 0)
#endif
/*
* Stack and heap for uncompression
*/
......
......@@ -53,19 +53,7 @@ SYM_FUNC_START(startup_32)
* all need to be under the 4G limit.
*/
cld
/*
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
* us to not reload segments
*/
testb $KEEP_SEGMENTS, BP_loadflags(%esi)
jnz 1f
cli
movl $(__BOOT_DS), %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
1:
/*
* Calculate the delta between where we were compiled to run
......@@ -80,10 +68,21 @@ SYM_FUNC_START(startup_32)
1: popl %ebp
subl $1b, %ebp
/* Load new GDT with the 64bit segments using 32bit descriptor */
leal gdt(%ebp), %eax
movl %eax, 2(%eax)
lgdt (%eax)
/* Load segment registers with our descriptors */
movl $__BOOT_DS, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
movl %eax, %ss
/* setup a stack and make sure cpu supports long mode. */
movl $boot_stack_end, %eax
addl %ebp, %eax
movl %eax, %esp
leal boot_stack_end(%ebp), %esp
call verify_cpu
testl %eax, %eax
......@@ -100,30 +99,38 @@ SYM_FUNC_START(startup_32)
#ifdef CONFIG_RELOCATABLE
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
decl %eax
addl %eax, %ebx
notl %eax
andl %eax, %ebx
cmpl $LOAD_PHYSICAL_ADDR, %ebx
jge 1f
jae 1f
#endif
movl $LOAD_PHYSICAL_ADDR, %ebx
1:
/* Target address to relocate to for decompression */
movl BP_init_size(%esi), %eax
subl $_end, %eax
addl %eax, %ebx
addl BP_init_size(%esi), %ebx
subl $_end, %ebx
/*
* Prepare for entering 64 bit mode
*/
/* Load new GDT with the 64bit segments using 32bit descriptor */
addl %ebp, gdt+2(%ebp)
lgdt gdt(%ebp)
/* Enable PAE mode */
movl %cr4, %eax
orl $X86_CR4_PAE, %eax
......@@ -212,8 +219,13 @@ SYM_FUNC_START(startup_32)
cmp $0, %edi
jz 1f
leal efi64_stub_entry(%ebp), %eax
movl %esi, %edx
movl efi32_boot_args+4(%ebp), %esi
movl efi32_boot_args+8(%ebp), %edx // saved bootparams pointer
cmpl $0, %edx
jnz 1f
leal efi_pe_entry(%ebp), %eax
movl %edi, %ecx // MS calling convention
movl %esi, %edx
1:
#endif
pushl %eax
......@@ -238,11 +250,17 @@ SYM_FUNC_START(efi32_stub_entry)
1: pop %ebp
subl $1b, %ebp
movl %esi, efi32_boot_args+8(%ebp)
SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
movl %ecx, efi32_boot_args(%ebp)
movl %edx, efi32_boot_args+4(%ebp)
sgdtl efi32_boot_gdt(%ebp)
movb $0, efi_is64(%ebp)
/* Save firmware GDTR and code/data selectors */
sgdtl efi32_boot_gdt(%ebp)
movw %cs, efi32_boot_cs(%ebp)
movw %ds, efi32_boot_ds(%ebp)
/* Disable paging */
movl %cr0, %eax
btrl $X86_CR0_PG_BIT, %eax
......@@ -266,6 +284,9 @@ SYM_CODE_START(startup_64)
* and command line.
*/
cld
cli
/* Setup data segments. */
xorl %eax, %eax
movl %eax, %ds
......@@ -290,13 +311,27 @@ SYM_CODE_START(startup_64)
/* Start with the delta to where the kernel will run at. */
#ifdef CONFIG_RELOCATABLE
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
decl %eax
addq %rax, %rbp
notq %rax
andq %rax, %rbp
cmpq $LOAD_PHYSICAL_ADDR, %rbp
jge 1f
jae 1f
#endif
movq $LOAD_PHYSICAL_ADDR, %rbp
1:
......@@ -354,9 +389,9 @@ SYM_CODE_START(startup_64)
*/
/* Make sure we have GDT with 32-bit code segment */
leaq gdt(%rip), %rax
movq %rax, gdt64+2(%rip)
lgdt gdt64(%rip)
leaq gdt64(%rip), %rax
addq %rax, 2(%rax)
lgdt (%rax)
/*
* paging_prepare() sets up the trampoline and checks if we need to
......@@ -441,6 +476,16 @@ trampoline_return:
cld
popq %rsi
/*
* The GDT may get overwritten either during the copy we just did or
* during extract_kernel below. To avoid any issues, repoint the GDTR
* to the new copy of the GDT.
*/
leaq gdt64(%rbx), %rax
leaq gdt(%rbx), %rdx
movq %rdx, 2(%rax)
lgdt (%rax)
/*
* Jump to the relocated address.
*/
......@@ -453,9 +498,9 @@ SYM_CODE_END(startup_64)
SYM_FUNC_START(efi64_stub_entry)
SYM_FUNC_START_ALIAS(efi_stub_entry)
and $~0xf, %rsp /* realign the stack */
movq %rdx, %rbx /* save boot_params pointer */
call efi_main
movq %rax,%rsi
movl BP_code32_start(%esi), %eax
movq %rbx,%rsi
leaq startup_64(%rax), %rax
jmp *%rax
SYM_FUNC_END(efi64_stub_entry)
......@@ -613,13 +658,13 @@ SYM_FUNC_END(.Lno_longmode)
.data
SYM_DATA_START_LOCAL(gdt64)
.word gdt_end - gdt
.quad 0
.word gdt_end - gdt - 1
.quad gdt - gdt64
SYM_DATA_END(gdt64)
.balign 8
SYM_DATA_START_LOCAL(gdt)
.word gdt_end - gdt
.long gdt
.word gdt_end - gdt - 1
.long 0
.word 0
.quad 0x00cf9a000000ffff /* __KERNEL32_CS */
.quad 0x00af9a000000ffff /* __KERNEL_CS */
......@@ -628,9 +673,97 @@ SYM_DATA_START_LOCAL(gdt)
.quad 0x0000000000000000 /* TS continued */
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
SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0)
SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
SYM_DATA(efi_is64, .byte 1)
#define ST32_boottime 60 // offsetof(efi_system_table_32_t, boottime)
#define BS32_handle_protocol 88 // offsetof(efi_boot_services_32_t, handle_protocol)
#define LI32_image_base 32 // offsetof(efi_loaded_image_32_t, image_base)
.text
.code32
SYM_FUNC_START(efi32_pe_entry)
/*
* 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
/*
......
......@@ -15,7 +15,7 @@
* hex while segment addresses are written as segment:offset.
*
*/
#include <linux/pe.h>
#include <asm/segment.h>
#include <asm/boot.h>
#include <asm/page_types.h>
......@@ -43,8 +43,7 @@ SYSSEG = 0x1000 /* historical load address >> 4 */
bootsect_start:
#ifdef CONFIG_EFI_STUB
# "MZ", MS-DOS header
.byte 0x4d
.byte 0x5a
.word MZ_MAGIC
#endif
# Normalize the start address
......@@ -97,39 +96,30 @@ bugger_off_msg:
#ifdef CONFIG_EFI_STUB
pe_header:
.ascii "PE"
.word 0
.long PE_MAGIC
coff_header:
#ifdef CONFIG_X86_32
.word 0x14c # i386
.set image_file_add_flags, IMAGE_FILE_32BIT_MACHINE
.set pe_opt_magic, PE_OPT_MAGIC_PE32
.word IMAGE_FILE_MACHINE_I386
#else
.word 0x8664 # x86-64
.set image_file_add_flags, 0
.set pe_opt_magic, PE_OPT_MAGIC_PE32PLUS
.word IMAGE_FILE_MACHINE_AMD64
#endif
.word 4 # nr_sections
.word section_count # nr_sections
.long 0 # TimeDateStamp
.long 0 # PointerToSymbolTable
.long 1 # NumberOfSymbols
.word section_table - optional_header # SizeOfOptionalHeader
#ifdef CONFIG_X86_32
.word 0x306 # Characteristics.
# IMAGE_FILE_32BIT_MACHINE |
# IMAGE_FILE_DEBUG_STRIPPED |
# IMAGE_FILE_EXECUTABLE_IMAGE |
# IMAGE_FILE_LINE_NUMS_STRIPPED
#else
.word 0x206 # Characteristics
# IMAGE_FILE_DEBUG_STRIPPED |
# IMAGE_FILE_EXECUTABLE_IMAGE |
# IMAGE_FILE_LINE_NUMS_STRIPPED
#endif
.word IMAGE_FILE_EXECUTABLE_IMAGE | \
image_file_add_flags | \
IMAGE_FILE_DEBUG_STRIPPED | \
IMAGE_FILE_LINE_NUMS_STRIPPED # Characteristics
optional_header:
#ifdef CONFIG_X86_32
.word 0x10b # PE32 format
#else
.word 0x20b # PE32+ format
#endif
.word pe_opt_magic
.byte 0x02 # MajorLinkerVersion
.byte 0x14 # MinorLinkerVersion
......@@ -148,17 +138,19 @@ optional_header:
#endif
extra_header_fields:
# PE specification requires ImageBase to be 64k aligned
.set image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff
#ifdef CONFIG_X86_32
.long 0 # ImageBase
.long image_base # ImageBase
#else
.quad 0 # ImageBase
.quad image_base # ImageBase
#endif
.long 0x20 # SectionAlignment
.long 0x20 # FileAlignment
.word 0 # MajorOperatingSystemVersion
.word 0 # MinorOperatingSystemVersion
.word 0 # MajorImageVersion
.word 0 # MinorImageVersion
.word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
.word LINUX_EFISTUB_MINOR_VERSION # MinorImageVersion
.word 0 # MajorSubsystemVersion
.word 0 # MinorSubsystemVersion
.long 0 # Win32VersionValue
......@@ -170,7 +162,7 @@ extra_header_fields:
.long 0x200 # SizeOfHeaders
.long 0 # CheckSum
.word 0xa # Subsystem (EFI application)
.word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
.word 0 # DllCharacteristics
#ifdef CONFIG_X86_32
.long 0 # SizeOfStackReserve
......@@ -184,7 +176,7 @@ extra_header_fields:
.quad 0 # SizeOfHeapCommit
#endif
.long 0 # LoaderFlags
.long 0x6 # NumberOfRvaAndSizes
.long (section_table - .) / 8 # NumberOfRvaAndSizes
.quad 0 # ExportTable
.quad 0 # ImportTable
......@@ -210,7 +202,10 @@ section_table:
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers
.long 0x60500020 # Characteristics (section flags)
.long IMAGE_SCN_CNT_CODE | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_EXECUTE | \
IMAGE_SCN_ALIGN_16BYTES # Characteristics
#
# The EFI application loader requires a relocation section
......@@ -228,45 +223,53 @@ section_table:
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers
.long 0x42100040 # Characteristics (section flags)
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_DISCARDABLE | \
IMAGE_SCN_ALIGN_1BYTES # Characteristics
#ifdef CONFIG_EFI_MIXED
#
# The offset & size fields are filled in by build.c.
#
.ascii ".text"
.byte 0
.byte 0
.byte 0
.asciz ".compat"
.long 0
.long 0x0 # startup_{32,64}
.long 0x0
.long 0 # Size of initialized data
# on disk
.long 0x0 # startup_{32,64}
.long 0x0
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers
.long 0x60500020 # Characteristics (section flags)
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_DISCARDABLE | \
IMAGE_SCN_ALIGN_1BYTES # Characteristics
#endif
#
# The offset & size fields are filled in by build.c.
#
.ascii ".bss"
.byte 0
.ascii ".text"
.byte 0
.byte 0
.byte 0
.long 0
.long 0x0
.long 0x0 # startup_{32,64}
.long 0 # Size of initialized data
# on disk
.long 0x0
.long 0x0 # startup_{32,64}
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
.word 0 # NumberOfLineNumbers
.long 0xc8000080 # Characteristics (section flags)
.long IMAGE_SCN_CNT_CODE | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_EXECUTE | \
IMAGE_SCN_ALIGN_16BYTES # Characteristics
.set section_count, (. - section_table) / 40
#endif /* CONFIG_EFI_STUB */
# Kernel attributes; used by setup. This is part 1 of the
......
......@@ -53,11 +53,20 @@ u8 buf[SETUP_SECT_MAX*512];
#define PECOFF_RELOC_RESERVE 0x20
#ifdef CONFIG_EFI_MIXED
#define PECOFF_COMPAT_RESERVE 0x20
#else
#define PECOFF_COMPAT_RESERVE 0x0
#endif
unsigned long efi32_stub_entry;
unsigned long efi64_stub_entry;
unsigned long efi_pe_entry;
unsigned long efi32_pe_entry;
unsigned long kernel_info;
unsigned long startup_64;
unsigned long _ehead;
unsigned long _end;
/*----------------------------------------------------------------------*/
......@@ -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)
{
u32 setup_offset = 0x200;
u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
#ifdef CONFIG_EFI_MIXED
u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
#endif
u32 setup_size = reloc_offset - setup_offset;
update_pecoff_section_header(".setup", setup_offset, setup_size);
......@@ -201,43 +213,59 @@ static void update_pecoff_setup_and_reloc(unsigned int size)
*/
put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
put_unaligned_le32(10, &buf[reloc_offset + 4]);
#ifdef CONFIG_EFI_MIXED
update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
/*
* Put the IA-32 machine type (0x14c) and the associated entry point
* address in the .compat section, so loaders can figure out which other
* execution modes this image supports.
*/
buf[compat_offset] = 0x1;
buf[compat_offset + 1] = 0x8;
put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
#endif
}
static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
static void update_pecoff_text(unsigned int text_start, unsigned int file_sz,
unsigned int init_sz)
{
unsigned int pe_header;
unsigned int text_sz = file_sz - text_start;
unsigned int bss_sz = init_sz - file_sz;
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)
* 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
*/
put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
update_pecoff_section_header(".text", text_start, text_sz);
}
static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz)
{
unsigned int pe_header;
unsigned int bss_sz = init_sz - file_sz;
pe_header = get_unaligned_le32(&buf[0x3c]);
/* Size of uninitialized data */
put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]);
/* Size of image */
put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0);
update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
text_sz, text_start);
}
static int reserve_pecoff_reloc_section(int c)
......@@ -278,9 +306,8 @@ static void efi_stub_entry_update(void)
static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
static inline void update_pecoff_text(unsigned int text_start,
unsigned int file_sz) {}
static inline void update_pecoff_bss(unsigned int file_sz,
unsigned int init_sz) {}
unsigned int file_sz,
unsigned int init_sz) {}
static inline void efi_stub_defaults(void) {}
static inline void efi_stub_entry_update(void) {}
......@@ -290,6 +317,12 @@ static inline int reserve_pecoff_reloc_section(int c)
}
#endif /* CONFIG_EFI_STUB */
static int reserve_pecoff_compat_section(int c)
{
/* Reserve 0x20 bytes for .compat section */
memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
return PECOFF_COMPAT_RESERVE;
}
/*
* Parse zoffset.h and find the entry points. We could just #include zoffset.h
......@@ -322,8 +355,11 @@ static void parse_zoffset(char *fname)
PARSE_ZOFS(p, efi32_stub_entry);
PARSE_ZOFS(p, efi64_stub_entry);
PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, efi32_pe_entry);
PARSE_ZOFS(p, kernel_info);
PARSE_ZOFS(p, startup_64);
PARSE_ZOFS(p, _ehead);
PARSE_ZOFS(p, _end);
p = strchr(p, '\n');
while (p && (*p == '\r' || *p == '\n'))
......@@ -365,6 +401,7 @@ int main(int argc, char ** argv)
die("Boot block hasn't got boot flag (0xAA55)");
fclose(file);
c += reserve_pecoff_compat_section(c);
c += reserve_pecoff_reloc_section(c);
/* Pad unused space with zeros */
......@@ -406,9 +443,28 @@ int main(int argc, char ** argv)
buf[0x1f1] = setup_sectors-1;
put_unaligned_le32(sys_size, &buf[0x1f4]);
update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
init_sz = get_unaligned_le32(&buf[0x260]);
update_pecoff_bss(i + (sys_size * 16), init_sz);
#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();
......
......@@ -10,6 +10,8 @@
#include <asm/mmu_context.h>
#include <linux/build_bug.h>
extern unsigned long efi_fw_vendor, efi_config_table;
/*
* We map the EFI regions needed for runtime services non-contiguously,
* with preserved alignment on virtual addresses starting from -4G down
......@@ -34,8 +36,6 @@ static inline bool efi_have_uv1_memmap(void)
#define EFI32_LOADER_SIGNATURE "EL32"
#define EFI64_LOADER_SIGNATURE "EL64"
#define MAX_CMDLINE_ADDRESS UINT_MAX
#define ARCH_EFI_IRQ_FLAGS_MASK X86_EFLAGS_IF
/*
......@@ -180,7 +180,6 @@ extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
struct efi_setup_data {
u64 fw_vendor;
u64 runtime;
u64 tables;
u64 smbios;
u64 reserved[8];
......@@ -219,7 +218,8 @@ extern void efi_thunk_runtime_setup(void);
efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
unsigned long descriptor_size,
u32 descriptor_version,
efi_memory_desc_t *virtual_map);
efi_memory_desc_t *virtual_map,
unsigned long systab_phys);
/* arch specific definitions used by the stub code */
......@@ -270,6 +270,11 @@ static inline void *efi64_zero_upper(void *p)
return p;
}
static inline u32 efi64_convert_status(efi_status_t status)
{
return (u32)(status | (u64)status >> 32);
}
#define __efi64_argmap_free_pages(addr, size) \
((addr), 0, (size))
......@@ -285,11 +290,21 @@ static inline void *efi64_zero_upper(void *p)
#define __efi64_argmap_locate_protocol(protocol, reg, interface) \
((protocol), (reg), efi64_zero_upper(interface))
#define __efi64_argmap_locate_device_path(protocol, path, handle) \
((protocol), (path), efi64_zero_upper(handle))
#define __efi64_argmap_exit(handle, status, size, data) \
((handle), efi64_convert_status(status), (size), (data))
/* PCI I/O */
#define __efi64_argmap_get_location(protocol, seg, bus, dev, func) \
((protocol), efi64_zero_upper(seg), efi64_zero_upper(bus), \
efi64_zero_upper(dev), efi64_zero_upper(func))
/* LoadFile */
#define __efi64_argmap_load_file(protocol, path, policy, bufsize, buf) \
((protocol), (path), (policy), efi64_zero_upper(bufsize), (buf))
/*
* The macros below handle the plumbing for the argument mapping. To add a
* mapping for a specific EFI method, simply define a macro
......
......@@ -88,7 +88,6 @@ static void __used common(void)
OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
OFFSET(BP_init_size, boot_params, hdr.init_size);
OFFSET(BP_pref_address, boot_params, hdr.pref_address);
OFFSET(BP_code32_start, boot_params, hdr.code32_start);
BLANK();
DEFINE(PTREGS_SIZE, sizeof(struct pt_regs));
......
......@@ -3,6 +3,8 @@
# error "Please do not build this file directly, build asm-offsets.c instead"
#endif
#include <linux/efi.h>
#include <asm/ucontext.h>
#define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
......@@ -64,4 +66,7 @@ void foo(void)
BLANK();
DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
DEFINE(NR_syscalls, sizeof(syscalls));
BLANK();
DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
}
......@@ -67,11 +67,6 @@ __HEAD
SYM_CODE_START(startup_32)
movl pa(initial_stack),%ecx
/* test KEEP_SEGMENTS flag to see if the bootloader is asking
us to not reload segments */
testb $KEEP_SEGMENTS, BP_loadflags(%esi)
jnz 2f
/*
* Set segments to known values.
*/
......@@ -82,7 +77,6 @@ SYM_CODE_START(startup_32)
movl %eax,%fs
movl %eax,%gs
movl %eax,%ss
2:
leal -__PAGE_OFFSET(%ecx),%esp
/*
......
......@@ -17,7 +17,7 @@ static enum efi_secureboot_mode get_sb_mode(void)
size = sizeof(secboot);
if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
pr_info("ima: secureboot mode unknown, no efi\n");
return efi_secureboot_mode_unknown;
}
......
......@@ -141,9 +141,8 @@ prepare_add_efi_setup_data(struct boot_params *params,
struct setup_data *sd = (void *)params + efi_setup_data_offset;
struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data);
esd->fw_vendor = efi.fw_vendor;
esd->runtime = efi.runtime;
esd->tables = efi.config_table;
esd->fw_vendor = efi_fw_vendor;
esd->tables = efi_config_table;
esd->smbios = efi.smbios;
sd->type = SETUP_EFI;
......
This diff is collapsed.
......@@ -66,14 +66,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
efi_status_t efi_call_svam(efi_set_virtual_address_map_t *__efiapi *,
u32, u32, u32, void *);
efi_status_t efi_call_svam(efi_runtime_services_t * const *,
u32, u32, u32, void *, u32);
efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
unsigned long descriptor_size,
u32 descriptor_version,
efi_memory_desc_t *virtual_map)
efi_memory_desc_t *virtual_map,
unsigned long systab_phys)
{
const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
struct desc_ptr gdt_descr;
efi_status_t status;
unsigned long flags;
......@@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
/* Disable interrupts around EFI calls: */
local_irq_save(flags);
status = efi_call_svam(&efi.systab->runtime->set_virtual_address_map,
status = efi_call_svam(&systab->runtime,
memory_map_size, descriptor_size,
descriptor_version, virtual_map);
descriptor_version, virtual_map,
__pa(&efi.runtime));
local_irq_restore(flags);
load_fixmap_gdt(0);
......
......@@ -497,12 +497,9 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
*/
#define __efi_thunk(func, ...) \
({ \
efi_runtime_services_32_t *__rt; \
unsigned short __ds, __es; \
efi_status_t ____s; \
\
__rt = (void *)(unsigned long)efi.systab->mixed_mode.runtime; \
\
savesegment(ds, __ds); \
savesegment(es, __es); \
\
......@@ -510,7 +507,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
loadsegment(ds, __KERNEL_DS); \
loadsegment(es, __KERNEL_DS); \
\
____s = efi64_thunk(__rt->func, __VA_ARGS__); \
____s = efi64_thunk(efi.runtime->mixed_mode.func, __VA_ARGS__); \
\
loadsegment(ds, __ds); \
loadsegment(es, __es); \
......@@ -839,8 +836,10 @@ efi_status_t __init __no_sanitize_address
efi_set_virtual_address_map(unsigned long memory_map_size,
unsigned long descriptor_size,
u32 descriptor_version,
efi_memory_desc_t *virtual_map)
efi_memory_desc_t *virtual_map,
unsigned long systab_phys)
{
const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
efi_status_t status;
unsigned long flags;
pgd_t *save_pgd = NULL;
......@@ -863,13 +862,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size,
/* Disable interrupts around EFI calls: */
local_irq_save(flags);
status = efi_call(efi.systab->runtime->set_virtual_address_map,
status = efi_call(efi.runtime->set_virtual_address_map,
memory_map_size, descriptor_size,
descriptor_version, virtual_map);
local_irq_restore(flags);
kernel_fpu_end();
/* grab the virtually remapped EFI runtime services table pointer */
efi.runtime = READ_ONCE(systab->runtime);
if (save_pgd)
efi_uv1_memmap_phys_epilog(save_pgd);
else
......
......@@ -8,14 +8,20 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/asm-offsets.h>
#include <asm/page_types.h>
__INIT
SYM_FUNC_START(efi_call_svam)
push 8(%esp)
push 8(%esp)
push %ebp
movl %esp, %ebp
push %ebx
push 16(%esp)
push 16(%esp)
push %ecx
push %edx
movl %eax, %ebx // &systab_phys->runtime
/*
* Switch to the flat mapped alias of this routine, by jumping to the
......@@ -35,15 +41,20 @@ SYM_FUNC_START(efi_call_svam)
subl $__PAGE_OFFSET, %esp
/* call the EFI routine */
call *(%eax)
movl (%eax), %eax
call *EFI_svam(%eax)
/* convert ESP back to a kernel VA, and pop the outgoing args */
addl $__PAGE_OFFSET + 16, %esp
/* grab the virtually remapped EFI runtime services table pointer */
movl (%ebx), %ecx
movl 36(%esp), %edx // &efi.runtime
movl %ecx, (%edx)
/* re-enable paging */
movl %cr0, %edx
orl $0x80000000, %edx
movl %edx, %cr0
movl 16(%esp), %ebx
leave
ret
SYM_FUNC_END(efi_call_svam)
......@@ -541,7 +541,7 @@ int __init efi_reuse_config(u64 tables, int nr_tables)
goto out_memremap;
}
for (i = 0; i < efi.systab->nr_tables; i++) {
for (i = 0; i < nr_tables; i++) {
efi_guid_t guid;
guid = ((efi_config_table_64_t *)p)->guid;
......
......@@ -656,6 +656,31 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
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)
* @state: disk parsed partitions
......@@ -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++) {
struct partition_meta_info *info;
unsigned label_count = 0;
unsigned label_max;
u64 start = le64_to_cpu(ptes[i].starting_lba);
u64 size = le64_to_cpu(ptes[i].ending_lba) -
......@@ -713,14 +737,7 @@ int efi_partition(struct parsed_partitions *state)
/* Naively convert UTF16-LE to 7 bits. */
label_max = min(ARRAY_SIZE(info->volname) - 1,
ARRAY_SIZE(ptes[i].partition_name));
info->volname[label_max] = 0;
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++;
}
utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname);
state->parts[i + 1].has_info = true;
}
kfree(ptes);
......
......@@ -88,7 +88,7 @@ typedef struct _gpt_entry {
__le64 starting_lba;
__le64 ending_lba;
gpt_entry_attributes attributes;
efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
__le16 partition_name[72/sizeof(__le16)];
} __packed gpt_entry;
typedef struct _gpt_mbr_record {
......
......@@ -13,13 +13,14 @@ KASAN_SANITIZE_runtime-wrappers.o := n
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o tpm.o
obj-$(CONFIG_EFI) += capsule.o memmap.o
obj-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdtparams.o
obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_ESRT) += esrt.o
obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.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_BOOTLOADER_CONTROL) += efibc.o
obj-$(CONFIG_EFI_TEST) += test/
......
......@@ -31,7 +31,7 @@ __setup("dump_apple_properties", dump_properties_enable);
struct dev_header {
u32 len;
u32 prop_count;
struct efi_dev_path path[0];
struct efi_dev_path path[];
/*
* followed by key/value pairs, each key and value preceded by u32 len,
* len includes itself, value may be empty (in which case its len is 4)
......@@ -42,11 +42,11 @@ struct properties_header {
u32 len;
u32 version;
u32 dev_count;
struct dev_header dev_header[0];
struct dev_header dev_header[];
};
static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
struct device *dev, void *ptr,
struct device *dev, const void *ptr,
struct property_entry entry[])
{
int i;
......@@ -117,10 +117,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
while (offset + sizeof(struct dev_header) < properties->len) {
struct dev_header *dev_header = (void *)properties + offset;
struct property_entry *entry = NULL;
const struct efi_dev_path *ptr;
struct device *dev;
size_t len;
int ret, i;
void *ptr;
if (offset + dev_header->len > properties->len ||
dev_header->len <= sizeof(*dev_header)) {
......@@ -131,10 +131,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
ptr = dev_header->path;
len = dev_header->len - sizeof(*dev_header);
dev = efi_get_device_by_path((struct efi_dev_path **)&ptr, &len);
dev = efi_get_device_by_path(&ptr, &len);
if (IS_ERR(dev)) {
pr_err("device path parse error %ld at %#zx:\n",
PTR_ERR(dev), ptr - (void *)dev_header);
PTR_ERR(dev), (void *)ptr - (void *)dev_header);
print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, dev_header, dev_header->len, true);
dev = NULL;
......
......@@ -22,8 +22,6 @@
#include <asm/efi.h>
u64 efi_system_table;
static int __init is_memory(efi_memory_desc_t *md)
{
if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC))
......@@ -36,7 +34,7 @@ static int __init is_memory(efi_memory_desc_t *md)
* as some data members of the EFI system table are virtually remapped after
* SetVirtualAddressMap() has been called.
*/
static phys_addr_t efi_to_phys(unsigned long addr)
static phys_addr_t __init efi_to_phys(unsigned long addr)
{
efi_memory_desc_t *md;
......@@ -55,7 +53,7 @@ static phys_addr_t efi_to_phys(unsigned long addr)
static __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR;
static __initdata efi_config_table_type_t arch_tables[] = {
static const efi_config_table_type_t arch_tables[] __initconst = {
{LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, NULL, &screen_info_table},
{NULL_GUID, NULL, NULL}
};
......@@ -83,17 +81,15 @@ static void __init init_screen_info(void)
memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size);
}
static int __init uefi_init(void)
static int __init uefi_init(u64 efi_system_table)
{
efi_char16_t *c16;
void *config_tables;
efi_config_table_t *config_tables;
efi_system_table_t *systab;
size_t table_size;
char vendor[100] = "unknown";
int i, retval;
int retval;
efi.systab = early_memremap_ro(efi_system_table,
sizeof(efi_system_table_t));
if (efi.systab == NULL) {
systab = early_memremap_ro(efi_system_table, sizeof(efi_system_table_t));
if (systab == NULL) {
pr_warn("Unable to map EFI system table.\n");
return -ENOMEM;
}
......@@ -102,53 +98,29 @@ static int __init uefi_init(void)
if (IS_ENABLED(CONFIG_64BIT))
set_bit(EFI_64BIT, &efi.flags);
/*
* Verify the EFI Table
*/
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
pr_err("System table signature incorrect\n");
retval = -EINVAL;
retval = efi_systab_check_header(&systab->hdr, 2);
if (retval)
goto out;
}
if ((efi.systab->hdr.revision >> 16) < 2)
pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff);
efi.runtime_version = efi.systab->hdr.revision;
/* Show what we know for posterity */
c16 = early_memremap_ro(efi_to_phys(efi.systab->fw_vendor),
sizeof(vendor) * sizeof(efi_char16_t));
if (c16) {
for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
vendor[i] = c16[i];
vendor[i] = '\0';
early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
}
pr_info("EFI v%u.%.02u by %s\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor);
efi.runtime = systab->runtime;
efi.runtime_version = systab->hdr.revision;
table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
config_tables = early_memremap_ro(efi_to_phys(efi.systab->tables),
efi_systab_report_header(&systab->hdr, efi_to_phys(systab->fw_vendor));
table_size = sizeof(efi_config_table_t) * systab->nr_tables;
config_tables = early_memremap_ro(efi_to_phys(systab->tables),
table_size);
if (config_tables == NULL) {
pr_warn("Unable to map EFI config table array.\n");
retval = -ENOMEM;
goto out;
}
retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
sizeof(efi_config_table_t),
retval = efi_config_parse_tables(config_tables, systab->nr_tables,
arch_tables);
if (!retval)
efi.config_table = (unsigned long)efi.systab->tables;
early_memunmap(config_tables, table_size);
out:
early_memunmap(efi.systab, sizeof(efi_system_table_t));
early_memunmap(systab, sizeof(efi_system_table_t));
return retval;
}
......@@ -233,19 +205,13 @@ static __init void reserve_regions(void)
void __init efi_init(void)
{
struct efi_memory_map_data data;
struct efi_fdt_params params;
u64 efi_system_table;
/* Grab UEFI information placed in FDT by stub */
if (!efi_get_fdt_params(&params))
efi_system_table = efi_get_fdt_params(&data);
if (!efi_system_table)
return;
efi_system_table = params.system_table;
data.desc_version = params.desc_ver;
data.desc_size = params.desc_size;
data.size = params.mmap_size;
data.phys_map = params.mmap;
if (efi_memmap_init_early(&data) < 0) {
/*
* If we are booting via UEFI, the UEFI memory map is the only
......@@ -259,7 +225,7 @@ void __init efi_init(void)
"Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
efi.memmap.desc_version);
if (uefi_init() < 0) {
if (uefi_init(efi_system_table) < 0) {
efi_memmap_unmap();
return;
}
......@@ -267,9 +233,8 @@ void __init efi_init(void)
reserve_regions();
efi_esrt_init();
memblock_reserve(params.mmap & PAGE_MASK,
PAGE_ALIGN(params.mmap_size +
(params.mmap & ~PAGE_MASK)));
memblock_reserve(data.phys_map & PAGE_MASK,
PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
init_screen_info();
......
......@@ -25,8 +25,6 @@
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
extern u64 efi_system_table;
#if defined(CONFIG_PTDUMP_DEBUGFS) && defined(CONFIG_ARM64)
#include <asm/ptdump.h>
......@@ -54,13 +52,11 @@ device_initcall(ptdump_init);
static bool __init efi_virtmap_init(void)
{
efi_memory_desc_t *md;
bool systab_found;
efi_mm.pgd = pgd_alloc(&efi_mm);
mm_init_cpumask(&efi_mm);
init_new_context(NULL, &efi_mm);
systab_found = false;
for_each_efi_memory_desc(md) {
phys_addr_t phys = md->phys_addr;
int ret;
......@@ -76,20 +72,6 @@ static bool __init efi_virtmap_init(void)
&phys, ret);
return false;
}
/*
* If this entry covers the address of the UEFI system table,
* calculate and record its virtual address.
*/
if (efi_system_table >= phys &&
efi_system_table < phys + (md->num_pages * EFI_PAGE_SIZE)) {
efi.systab = (void *)(unsigned long)(efi_system_table -
phys + md->virt_addr);
systab_found = true;
}
}
if (!systab_found) {
pr_err("No virtual mapping found for the UEFI System Table\n");
return false;
}
if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
......
......@@ -168,7 +168,7 @@ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info)
static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
size_t count, loff_t *offp)
{
int ret = 0;
int ret;
struct capsule_info *cap_info = file->private_data;
struct page *page;
void *kbuff = NULL;
......
......@@ -31,13 +31,13 @@ static int __init match_acpi_dev(struct device *dev, const void *data)
return !strcmp("0", hid_uid.uid);
}
static long __init parse_acpi_path(struct efi_dev_path *node,
static long __init parse_acpi_path(const struct efi_dev_path *node,
struct device *parent, struct device **child)
{
struct acpi_hid_uid hid_uid = {};
struct device *phys_dev;
if (node->length != 12)
if (node->header.length != 12)
return -EINVAL;
sprintf(hid_uid.hid[0].id, "%c%c%c%04X",
......@@ -69,12 +69,12 @@ static int __init match_pci_dev(struct device *dev, void *data)
return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn;
}
static long __init parse_pci_path(struct efi_dev_path *node,
static long __init parse_pci_path(const struct efi_dev_path *node,
struct device *parent, struct device **child)
{
unsigned int devfn;
if (node->length != 6)
if (node->header.length != 6)
return -EINVAL;
if (!parent)
return -EINVAL;
......@@ -105,19 +105,19 @@ static long __init parse_pci_path(struct efi_dev_path *node,
* search for a device.
*/
static long __init parse_end_path(struct efi_dev_path *node,
static long __init parse_end_path(const struct efi_dev_path *node,
struct device *parent, struct device **child)
{
if (node->length != 4)
if (node->header.length != 4)
return -EINVAL;
if (node->sub_type != EFI_DEV_END_INSTANCE &&
node->sub_type != EFI_DEV_END_ENTIRE)
if (node->header.sub_type != EFI_DEV_END_INSTANCE &&
node->header.sub_type != EFI_DEV_END_ENTIRE)
return -EINVAL;
if (!parent)
return -ENODEV;
*child = get_device(parent);
return node->sub_type;
return node->header.sub_type;
}
/**
......@@ -156,7 +156,7 @@ static long __init parse_end_path(struct efi_dev_path *node,
* %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len,
* %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented.
*/
struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
struct device * __init efi_get_device_by_path(const struct efi_dev_path **node,
size_t *len)
{
struct device *parent = NULL, *child;
......@@ -166,16 +166,16 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
return NULL;
while (!ret) {
if (*len < 4 || *len < (*node)->length)
if (*len < 4 || *len < (*node)->header.length)
ret = -EINVAL;
else if ((*node)->type == EFI_DEV_ACPI &&
(*node)->sub_type == EFI_DEV_BASIC_ACPI)
else if ((*node)->header.type == EFI_DEV_ACPI &&
(*node)->header.sub_type == EFI_DEV_BASIC_ACPI)
ret = parse_acpi_path(*node, parent, &child);
else if ((*node)->type == EFI_DEV_HW &&
(*node)->sub_type == EFI_DEV_PCI)
else if ((*node)->header.type == EFI_DEV_HW &&
(*node)->header.sub_type == EFI_DEV_PCI)
ret = parse_pci_path(*node, parent, &child);
else if (((*node)->type == EFI_DEV_END_PATH ||
(*node)->type == EFI_DEV_END_PATH2))
else if (((*node)->header.type == EFI_DEV_END_PATH ||
(*node)->header.type == EFI_DEV_END_PATH2))
ret = parse_end_path(*node, parent, &child);
else
ret = -ENOTSUPP;
......@@ -185,8 +185,8 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
return ERR_PTR(ret);
parent = child;
*node = (void *)*node + (*node)->length;
*len -= (*node)->length;
*node = (void *)*node + (*node)->header.length;
*len -= (*node)->header.length;
}
if (ret == EFI_DEV_END_ENTIRE)
......
......@@ -42,7 +42,12 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
return;
}
*bgrt = *(struct acpi_table_bgrt *)table;
if (bgrt->version != 1) {
/*
* Only version 1 is defined but some older laptops (seen on Lenovo
* Ivy Bridge models) have a correct version 1 BGRT table with the
* version set to 0, so we accept version 0 and 1.
*/
if (bgrt->version > 1) {
pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n",
bgrt->version);
goto out;
......
......@@ -161,7 +161,7 @@ static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
*
* @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.
*
*/
......@@ -356,7 +356,7 @@ static struct pstore_info efi_pstore_info = {
static __init int efivars_pstore_init(void)
{
if (!efi_enabled(EFI_RUNTIME_SERVICES))
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
return 0;
if (!efivars_kobject())
......
This diff is collapsed.
......@@ -678,7 +678,7 @@ int efivars_sysfs_init(void)
struct kobject *parent_kobj = efivars_kobject();
int error = 0;
if (!efi_enabled(EFI_RUNTIME_SERVICES))
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
return -ENODEV;
/* No efivars has been registered yet */
......
......@@ -240,7 +240,6 @@ void __init efi_esrt_init(void)
{
void *va;
struct efi_system_resource_table tmpesrt;
struct efi_system_resource_entry_v1 *v1_entries;
size_t size, max, entry_size, entries_size;
efi_memory_desc_t md;
int rc;
......@@ -288,14 +287,13 @@ void __init efi_esrt_init(void)
memcpy(&tmpesrt, va, sizeof(tmpesrt));
early_memunmap(va, size);
if (tmpesrt.fw_resource_version == 1) {
entry_size = sizeof (*v1_entries);
} else {
if (tmpesrt.fw_resource_version != 1) {
pr_err("Unsupported ESRT version %lld.\n",
tmpesrt.fw_resource_version);
return;
}
entry_size = sizeof(struct efi_system_resource_entry_v1);
if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) {
pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n",
max - size, entry_size);
......
// 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)) \
cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
-include $(srctree)/drivers/firmware/efi/libstub/hidden.h \
-D__NO_FORTIFY \
$(call cc-option,-ffreestanding) \
$(call cc-option,-fno-stack-protector) \
......@@ -39,11 +40,11 @@ OBJECT_FILES_NON_STANDARD := y
KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
random.o pci.o
file.o mem.o random.o randomalloc.o pci.o \
skip_spaces.o lib-cmdline.o lib-ctype.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
arm-deps-$(CONFIG_ARM64) += sort.c
$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
$(call if_changed_rule,cc_o_c)
......@@ -53,6 +54,7 @@ lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \
lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64-stub.o
lib-$(CONFIG_X86) += x86-stub.o
CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
......
This diff is collapsed.
......@@ -227,6 +227,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
* Relocate the zImage, so that it appears in the lowest 128 MB
* memory window.
*/
*image_addr = (unsigned long)image->image_base;
*image_size = image->image_size;
status = efi_relocate_kernel(image_addr, *image_size, *image_size,
kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
......
......@@ -6,17 +6,11 @@
* Adapted from ARM version by Mark Salter <msalter@redhat.com>
*/
/*
* To prevent the compiler from emitting GOT-indirected (and thus absolute)
* references to the section markers, override their visibility as 'hidden'
*/
#pragma GCC visibility push(hidden)
#include <asm/sections.h>
#pragma GCC visibility pop
#include <linux/efi.h>
#include <asm/efi.h>
#include <asm/memory.h>
#include <asm/sections.h>
#include <asm/sysreg.h>
#include "efistub.h"
......@@ -49,7 +43,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
{
efi_status_t status;
unsigned long kernel_size, kernel_memsize = 0;
void *old_image_addr = (void *)*image_addr;
unsigned long preferred_offset;
u64 phys_seed = 0;
......@@ -123,6 +116,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
* Mustang), we can still place the kernel at the address
* 'dram_base + TEXT_OFFSET'.
*/
*image_addr = (unsigned long)_text;
if (*image_addr == preferred_offset)
return EFI_SUCCESS;
......@@ -147,7 +141,11 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
}
*image_addr = *reserve_addr + TEXT_OFFSET;
}
memcpy((void *)*image_addr, old_image_addr, kernel_size);
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;
}
This diff is collapsed.
......@@ -199,10 +199,6 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
return EFI_SUCCESS;
}
#ifndef EFI_FDT_ALIGN
# define EFI_FDT_ALIGN EFI_PAGE_SIZE
#endif
struct exit_boot_struct {
efi_memory_desc_t *runtime_map;
int *runtime_entry_count;
......@@ -281,8 +277,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
pr_efi("Exiting boot services and installing virtual address map...\n");
map.map = &memory_map;
status = efi_high_alloc(MAX_FDT_SIZE, EFI_FDT_ALIGN,
new_fdt_addr, max_addr);
status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, max_addr);
if (status != EFI_SUCCESS) {
pr_efi_err("Unable to allocate memory for new device tree.\n");
goto fail;
......
// 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.
This diff is collapsed.
// 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;
}
......@@ -6,6 +6,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/ctype.h>
#include <linux/types.h>
#include <linux/string.h>
......@@ -56,3 +57,58 @@ int strncmp(const char *cs, const char *ct, size_t count)
return 0;
}
#endif
/* Works only for digits and letters, but small and fast */
#define TOLOWER(x) ((x) | 0x20)
static unsigned int simple_guess_base(const char *cp)
{
if (cp[0] == '0') {
if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
return 16;
else
return 8;
} else {
return 10;
}
}
/**
* simple_strtoull - convert a string to an unsigned long long
* @cp: The start of the string
* @endp: A pointer to the end of the parsed string will be placed here
* @base: The number base to use
*/
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
{
unsigned long long result = 0;
if (!base)
base = simple_guess_base(cp);
if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
cp += 2;
while (isxdigit(*cp)) {
unsigned int value;
value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
if (value >= base)
break;
result = result * base + value;
cp++;
}
if (endp)
*endp = (char *)cp;
return result;
}
long simple_strtol(const char *cp, char **endp, unsigned int base)
{
if (*cp == '-')
return -simple_strtoull(cp + 1, endp, base);
return simple_strtoull(cp, endp, base);
}
This diff is collapsed.
......@@ -15,7 +15,7 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
const char *str[] = { "cold", "warm", "shutdown", "platform" };
int efi_mode, cap_reset_mode;
if (!efi_enabled(EFI_RUNTIME_SERVICES))
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
return;
switch (reboot_mode) {
......@@ -64,7 +64,7 @@ static void efi_power_off(void)
static int __init efi_shutdown_init(void)
{
if (!efi_enabled(EFI_RUNTIME_SERVICES))
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
return -ENODEV;
if (efi_poweroff_required()) {
......
This diff is collapsed.
......@@ -1071,7 +1071,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
* entry on the list. It is safe for @func to remove entries in the
* list via efivar_entry_delete().
*
* 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.
*
* It is possible to begin iteration from an arbitrary entry within
......
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