mirror of
https://github.com/torvalds/linux.git
synced 2025-04-09 14:45:27 +00:00
EFI updates for v6.15
- Decouple mixed mode startup code from the traditional x86 decompressor - Revert zero-length file hack in efivarfs - Prevent EFI zboot from using the CopyMem/SetMem boot services after ExitBootServices() - Update EFI zboot to use the ZLIB/ZSTD library interfaces directly -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQQm/3uucuRGn1Dmh0wbglWLn0tXAUCZ9vAPwAKCRAwbglWLn0t XNsFAQCq4zXmbHnFl8gR3rq06f2gR3DKPfUBGVnyfaP/77ag0AD6Alzm4Pg014cL GsZPQf38uGnygMTGYsU1HdE8EugFFQY= =UXC0 -----END PGP SIGNATURE----- Merge tag 'efi-next-for-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi Pull EFI updates from Ard Biesheuvel: - Decouple mixed mode startup code from the traditional x86 decompressor - Revert zero-length file hack in efivarfs - Prevent EFI zboot from using the CopyMem/SetMem boot services after ExitBootServices() - Update EFI zboot to use the ZLIB/ZSTD library interfaces directly * tag 'efi-next-for-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: efi/libstub: Avoid legacy decompressor zlib/zstd wrappers efi/libstub: Avoid CopyMem/SetMem EFI services after ExitBootServices efi: efibc: change kmalloc(size * count, ...) to kmalloc_array() efivarfs: Revert "allow creation of zero length files" x86/efi/mixed: Move mixed mode startup code into libstub x86/efi/mixed: Simplify and document thunking logic x86/efi/mixed: Remove dependency on legacy startup_32 code x86/efi/mixed: Set up 1:1 mapping of lower 4GiB in the stub x86/efi/mixed: Factor out and clean up long mode entry x86/efi/mixed: Check CPU compatibility without relying on verify_cpu() x86/efistub: Merge PE and handover entrypoints
This commit is contained in:
commit
1fa753c7b5
@ -106,7 +106,6 @@ vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o $(obj)/tdcall.o $(obj)/td
|
||||
vmlinux-objs-$(CONFIG_UNACCEPTED_MEMORY) += $(obj)/mem.o
|
||||
|
||||
vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
|
||||
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
|
||||
vmlinux-libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
|
||||
|
||||
$(obj)/vmlinux: $(vmlinux-objs-y) $(vmlinux-libs-y) FORCE
|
||||
|
@ -1,341 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
|
||||
*
|
||||
* Early support for invoking 32-bit EFI services from a 64-bit kernel.
|
||||
*
|
||||
* Because this thunking occurs before ExitBootServices() we have to
|
||||
* restore the firmware's 32-bit GDT and IDT before we make EFI service
|
||||
* calls.
|
||||
*
|
||||
* On the plus side, we don't have to worry about mangling 64-bit
|
||||
* addresses into 32-bits because we're executing with an identity
|
||||
* mapped pagetable and haven't transitioned to 64-bit virtual addresses
|
||||
* yet.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/page_types.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
.code64
|
||||
.text
|
||||
/*
|
||||
* When booting in 64-bit mode on 32-bit EFI firmware, startup_64_mixed_mode()
|
||||
* is the first thing that runs after switching to long mode. Depending on
|
||||
* whether the EFI handover protocol or the compat entry point was used to
|
||||
* enter the kernel, it will either branch to the common 64-bit EFI stub
|
||||
* entrypoint efi_stub_entry() directly, or via the 64-bit EFI PE/COFF
|
||||
* entrypoint efi_pe_entry(). In the former case, the bootloader must provide a
|
||||
* struct bootparams pointer as the third argument, so the presence of such a
|
||||
* pointer is used to disambiguate.
|
||||
*
|
||||
* +--------------+
|
||||
* +------------------+ +------------+ +------>| efi_pe_entry |
|
||||
* | efi32_pe_entry |---->| | | +-----------+--+
|
||||
* +------------------+ | | +------+----------------+ |
|
||||
* | startup_32 |---->| startup_64_mixed_mode | |
|
||||
* +------------------+ | | +------+----------------+ |
|
||||
* | efi32_stub_entry |---->| | | |
|
||||
* +------------------+ +------------+ | |
|
||||
* V |
|
||||
* +------------+ +----------------+ |
|
||||
* | startup_64 |<----| efi_stub_entry |<--------+
|
||||
* +------------+ +----------------+
|
||||
*/
|
||||
SYM_FUNC_START(startup_64_mixed_mode)
|
||||
lea efi32_boot_args(%rip), %rdx
|
||||
mov 0(%rdx), %edi
|
||||
mov 4(%rdx), %esi
|
||||
|
||||
/* Switch to the firmware's stack */
|
||||
movl efi32_boot_sp(%rip), %esp
|
||||
andl $~7, %esp
|
||||
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
mov 8(%rdx), %edx // saved bootparams pointer
|
||||
test %edx, %edx
|
||||
jnz efi_stub_entry
|
||||
#endif
|
||||
/*
|
||||
* efi_pe_entry uses MS calling convention, which requires 32 bytes of
|
||||
* shadow space on the stack even if all arguments are passed in
|
||||
* registers. We also need an additional 8 bytes for the space that
|
||||
* would be occupied by the return address, and this also results in
|
||||
* the correct stack alignment for entry.
|
||||
*/
|
||||
sub $40, %rsp
|
||||
mov %rdi, %rcx // MS calling convention
|
||||
mov %rsi, %rdx
|
||||
jmp efi_pe_entry
|
||||
SYM_FUNC_END(startup_64_mixed_mode)
|
||||
|
||||
SYM_FUNC_START(__efi64_thunk)
|
||||
push %rbp
|
||||
push %rbx
|
||||
|
||||
movl %ds, %eax
|
||||
push %rax
|
||||
movl %es, %eax
|
||||
push %rax
|
||||
movl %ss, %eax
|
||||
push %rax
|
||||
|
||||
/* Copy args passed on stack */
|
||||
movq 0x30(%rsp), %rbp
|
||||
movq 0x38(%rsp), %rbx
|
||||
movq 0x40(%rsp), %rax
|
||||
|
||||
/*
|
||||
* Convert x86-64 ABI params to i386 ABI
|
||||
*/
|
||||
subq $64, %rsp
|
||||
movl %esi, 0x0(%rsp)
|
||||
movl %edx, 0x4(%rsp)
|
||||
movl %ecx, 0x8(%rsp)
|
||||
movl %r8d, 0xc(%rsp)
|
||||
movl %r9d, 0x10(%rsp)
|
||||
movl %ebp, 0x14(%rsp)
|
||||
movl %ebx, 0x18(%rsp)
|
||||
movl %eax, 0x1c(%rsp)
|
||||
|
||||
leaq 0x20(%rsp), %rbx
|
||||
sgdt (%rbx)
|
||||
sidt 16(%rbx)
|
||||
|
||||
leaq 1f(%rip), %rbp
|
||||
|
||||
/*
|
||||
* Switch to IDT and GDT with 32-bit segments. These are the firmware
|
||||
* GDT and IDT that were installed when the kernel started executing.
|
||||
* The pointers were saved by the efi32_entry() routine below.
|
||||
*
|
||||
* Pass the saved DS selector to the 32-bit code, and use far return to
|
||||
* restore the saved CS selector.
|
||||
*/
|
||||
lidt efi32_boot_idt(%rip)
|
||||
lgdt efi32_boot_gdt(%rip)
|
||||
|
||||
movzwl efi32_boot_ds(%rip), %edx
|
||||
movzwq efi32_boot_cs(%rip), %rax
|
||||
pushq %rax
|
||||
leaq efi_enter32(%rip), %rax
|
||||
pushq %rax
|
||||
lretq
|
||||
|
||||
1: addq $64, %rsp
|
||||
movq %rdi, %rax
|
||||
|
||||
pop %rbx
|
||||
movl %ebx, %ss
|
||||
pop %rbx
|
||||
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
|
||||
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
RET
|
||||
SYM_FUNC_END(__efi64_thunk)
|
||||
|
||||
.code32
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
SYM_FUNC_START(efi32_stub_entry)
|
||||
call 1f
|
||||
1: popl %ecx
|
||||
leal (efi32_boot_args - 1b)(%ecx), %ebx
|
||||
|
||||
/* Clear BSS */
|
||||
xorl %eax, %eax
|
||||
leal (_bss - 1b)(%ecx), %edi
|
||||
leal (_ebss - 1b)(%ecx), %ecx
|
||||
subl %edi, %ecx
|
||||
shrl $2, %ecx
|
||||
cld
|
||||
rep stosl
|
||||
|
||||
add $0x4, %esp /* Discard return address */
|
||||
popl %ecx
|
||||
popl %edx
|
||||
popl %esi
|
||||
movl %esi, 8(%ebx)
|
||||
jmp efi32_entry
|
||||
SYM_FUNC_END(efi32_stub_entry)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* EFI service pointer must be in %edi.
|
||||
*
|
||||
* The stack should represent the 32-bit calling convention.
|
||||
*/
|
||||
SYM_FUNC_START_LOCAL(efi_enter32)
|
||||
/* 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
|
||||
movl %eax, %cr3
|
||||
|
||||
/* Disable paging */
|
||||
movl %cr0, %eax
|
||||
btrl $X86_CR0_PG_BIT, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Disable long mode via EFER */
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
btrl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
call *%edi
|
||||
|
||||
/* We must preserve return value */
|
||||
movl %eax, %edi
|
||||
|
||||
/*
|
||||
* Some firmware will return with interrupts enabled. Be sure to
|
||||
* disable them before we switch GDTs and IDTs.
|
||||
*/
|
||||
cli
|
||||
|
||||
lidtl 16(%ebx)
|
||||
lgdtl (%ebx)
|
||||
|
||||
movl %cr4, %eax
|
||||
btsl $(X86_CR4_PAE_BIT), %eax
|
||||
movl %eax, %cr4
|
||||
|
||||
movl %cr3, %eax
|
||||
movl %eax, %cr3
|
||||
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
btsl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
xorl %eax, %eax
|
||||
lldt %ax
|
||||
|
||||
pushl $__KERNEL_CS
|
||||
pushl %ebp
|
||||
|
||||
/* Enable paging */
|
||||
movl %cr0, %eax
|
||||
btsl $X86_CR0_PG_BIT, %eax
|
||||
movl %eax, %cr0
|
||||
lret
|
||||
SYM_FUNC_END(efi_enter32)
|
||||
|
||||
/*
|
||||
* This is the common EFI stub entry point for mixed mode.
|
||||
*
|
||||
* Arguments: %ecx image handle
|
||||
* %edx EFI system table pointer
|
||||
*
|
||||
* Since this is the point of no return for ordinary execution, no registers
|
||||
* are considered live except for the function parameters. [Note that the EFI
|
||||
* stub may still exit and return to the firmware using the Exit() EFI boot
|
||||
* service.]
|
||||
*/
|
||||
SYM_FUNC_START_LOCAL(efi32_entry)
|
||||
call 1f
|
||||
1: pop %ebx
|
||||
|
||||
/* Save firmware GDTR and code/data selectors */
|
||||
sgdtl (efi32_boot_gdt - 1b)(%ebx)
|
||||
movw %cs, (efi32_boot_cs - 1b)(%ebx)
|
||||
movw %ds, (efi32_boot_ds - 1b)(%ebx)
|
||||
|
||||
/* Store firmware IDT descriptor */
|
||||
sidtl (efi32_boot_idt - 1b)(%ebx)
|
||||
|
||||
/* Store firmware stack pointer */
|
||||
movl %esp, (efi32_boot_sp - 1b)(%ebx)
|
||||
|
||||
/* Store boot arguments */
|
||||
leal (efi32_boot_args - 1b)(%ebx), %ebx
|
||||
movl %ecx, 0(%ebx)
|
||||
movl %edx, 4(%ebx)
|
||||
movb $0x0, 12(%ebx) // efi_is64
|
||||
|
||||
/*
|
||||
* Allocate some memory for a temporary struct boot_params, which only
|
||||
* needs the minimal pieces that startup_32() relies on.
|
||||
*/
|
||||
subl $PARAM_SIZE, %esp
|
||||
movl %esp, %esi
|
||||
movl $PAGE_SIZE, BP_kernel_alignment(%esi)
|
||||
movl $_end - 1b, BP_init_size(%esi)
|
||||
subl $startup_32 - 1b, BP_init_size(%esi)
|
||||
|
||||
/* Disable paging */
|
||||
movl %cr0, %eax
|
||||
btrl $X86_CR0_PG_BIT, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
jmp startup_32
|
||||
SYM_FUNC_END(efi32_entry)
|
||||
|
||||
/*
|
||||
* efi_status_t efi32_pe_entry(efi_handle_t image_handle,
|
||||
* efi_system_table_32_t *sys_table)
|
||||
*/
|
||||
SYM_FUNC_START(efi32_pe_entry)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
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
|
||||
|
||||
movl 8(%ebp), %ecx // image_handle
|
||||
movl 12(%ebp), %edx // sys_table
|
||||
jmp efi32_entry // pass %ecx, %edx
|
||||
// no other registers remain live
|
||||
|
||||
2: popl %edi // restore callee-save registers
|
||||
popl %ebx
|
||||
leave
|
||||
RET
|
||||
SYM_FUNC_END(efi32_pe_entry)
|
||||
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
.org efi32_stub_entry + 0x200
|
||||
.code64
|
||||
SYM_FUNC_START_NOALIGN(efi64_stub_entry)
|
||||
jmp efi_handover_entry
|
||||
SYM_FUNC_END(efi64_stub_entry)
|
||||
#endif
|
||||
|
||||
.data
|
||||
.balign 8
|
||||
SYM_DATA_START_LOCAL(efi32_boot_gdt)
|
||||
.word 0
|
||||
.quad 0
|
||||
SYM_DATA_END(efi32_boot_gdt)
|
||||
|
||||
SYM_DATA_START_LOCAL(efi32_boot_idt)
|
||||
.word 0
|
||||
.quad 0
|
||||
SYM_DATA_END(efi32_boot_idt)
|
||||
|
||||
SYM_DATA_LOCAL(efi32_boot_cs, .word 0)
|
||||
SYM_DATA_LOCAL(efi32_boot_ds, .word 0)
|
||||
SYM_DATA_LOCAL(efi32_boot_sp, .long 0)
|
||||
SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
|
||||
SYM_DATA(efi_is64, .byte 1)
|
@ -263,13 +263,6 @@ SYM_FUNC_START(startup_32)
|
||||
* used to perform that far jump.
|
||||
*/
|
||||
leal rva(startup_64)(%ebp), %eax
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
cmpb $1, rva(efi_is64)(%ebp)
|
||||
je 1f
|
||||
leal rva(startup_64_mixed_mode)(%ebp), %eax
|
||||
1:
|
||||
#endif
|
||||
|
||||
pushl $__KERNEL_CS
|
||||
pushl %eax
|
||||
|
||||
|
@ -47,7 +47,7 @@ static int efibc_reboot_notifier_call(struct notifier_block *notifier,
|
||||
if (ret || !data)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
wdata = kmalloc(MAX_DATA_LEN * sizeof(efi_char16_t), GFP_KERNEL);
|
||||
wdata = kmalloc_array(MAX_DATA_LEN, sizeof(efi_char16_t), GFP_KERNEL);
|
||||
if (!wdata)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
|
@ -62,6 +62,8 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS))
|
||||
# `-fdata-sections` flag from KBUILD_CFLAGS_KERNEL
|
||||
KBUILD_CFLAGS_KERNEL := $(filter-out -fdata-sections, $(KBUILD_CFLAGS_KERNEL))
|
||||
|
||||
KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
|
||||
|
||||
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
|
||||
file.o mem.o random.o randomalloc.o pci.o \
|
||||
skip_spaces.o lib-cmdline.o lib-ctype.o \
|
||||
@ -83,13 +85,19 @@ lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \
|
||||
lib-$(CONFIG_ARM) += arm32-stub.o
|
||||
lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o
|
||||
lib-$(CONFIG_X86) += x86-stub.o smbios.o
|
||||
lib-$(CONFIG_EFI_MIXED) += x86-mixed.o
|
||||
lib-$(CONFIG_X86_64) += x86-5lvl.o
|
||||
lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o
|
||||
lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o
|
||||
|
||||
CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
|
||||
zboot-obj-$(CONFIG_RISCV) := lib-clz_ctz.o lib-ashldi3.o
|
||||
zboot-obj-y := zboot-decompress-gzip.o
|
||||
CFLAGS_zboot-decompress-gzip.o += -I$(srctree)/lib/zlib_inflate
|
||||
zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o
|
||||
CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd
|
||||
|
||||
zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o
|
||||
lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y)
|
||||
|
||||
lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o
|
||||
|
@ -1234,4 +1234,7 @@ void process_unaccepted_memory(u64 start, u64 end);
|
||||
void accept_memory(phys_addr_t start, unsigned long size);
|
||||
void arch_accept_memory(phys_addr_t start, phys_addr_t end);
|
||||
|
||||
efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size);
|
||||
efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen);
|
||||
|
||||
#endif
|
||||
|
@ -15,8 +15,31 @@ void *__memmove(void *__dest, const void *__src, size_t count) __alias(memmove);
|
||||
void *__memset(void *s, int c, size_t count) __alias(memset);
|
||||
#endif
|
||||
|
||||
static void *efistub_memmove(u8 *dst, const u8 *src, size_t len)
|
||||
{
|
||||
if (src > dst || dst >= (src + len))
|
||||
for (size_t i = 0; i < len; i++)
|
||||
dst[i] = src[i];
|
||||
else
|
||||
for (ssize_t i = len - 1; i >= 0; i--)
|
||||
dst[i] = src[i];
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void *efistub_memset(void *dst, int c, size_t len)
|
||||
{
|
||||
for (u8 *d = dst; len--; d++)
|
||||
*d = c;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
if (efi_table_attr(efi_system_table, boottime) == NULL)
|
||||
return efistub_memmove(dst, src, len);
|
||||
|
||||
efi_bs_call(copy_mem, dst, src, len);
|
||||
return dst;
|
||||
}
|
||||
@ -25,6 +48,9 @@ extern void *memmove(void *dst, const void *src, size_t len) __alias(memcpy);
|
||||
|
||||
void *memset(void *dst, int c, size_t len)
|
||||
{
|
||||
if (efi_table_attr(efi_system_table, boottime) == NULL)
|
||||
return efistub_memset(dst, c, len);
|
||||
|
||||
efi_bs_call(set_mem, dst, len, c & U8_MAX);
|
||||
return dst;
|
||||
}
|
||||
|
253
drivers/firmware/efi/libstub/x86-mixed.S
Normal file
253
drivers/firmware/efi/libstub/x86-mixed.S
Normal file
@ -0,0 +1,253 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
|
||||
*
|
||||
* Early support for invoking 32-bit EFI services from a 64-bit kernel.
|
||||
*
|
||||
* Because this thunking occurs before ExitBootServices() we have to
|
||||
* restore the firmware's 32-bit GDT and IDT before we make EFI service
|
||||
* calls.
|
||||
*
|
||||
* On the plus side, we don't have to worry about mangling 64-bit
|
||||
* addresses into 32-bits because we're executing with an identity
|
||||
* mapped pagetable and haven't transitioned to 64-bit virtual addresses
|
||||
* yet.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/desc_defs.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/page_types.h>
|
||||
#include <asm/pgtable_types.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
.text
|
||||
.code32
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
SYM_FUNC_START(efi32_stub_entry)
|
||||
call 1f
|
||||
1: popl %ecx
|
||||
|
||||
/* Clear BSS */
|
||||
xorl %eax, %eax
|
||||
leal (_bss - 1b)(%ecx), %edi
|
||||
leal (_ebss - 1b)(%ecx), %ecx
|
||||
subl %edi, %ecx
|
||||
shrl $2, %ecx
|
||||
cld
|
||||
rep stosl
|
||||
|
||||
add $0x4, %esp /* Discard return address */
|
||||
movl 8(%esp), %ebx /* struct boot_params pointer */
|
||||
jmp efi32_startup
|
||||
SYM_FUNC_END(efi32_stub_entry)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Called using a far call from __efi64_thunk() below, using the x86_64 SysV
|
||||
* ABI (except for R8/R9 which are inaccessible to 32-bit code - EAX/EBX are
|
||||
* used instead). EBP+16 points to the arguments passed via the stack.
|
||||
*
|
||||
* The first argument (EDI) is a pointer to the boot service or protocol, to
|
||||
* which the remaining arguments are passed, each truncated to 32 bits.
|
||||
*/
|
||||
SYM_FUNC_START_LOCAL(efi_enter32)
|
||||
/*
|
||||
* Convert x86-64 SysV ABI params to i386 ABI
|
||||
*/
|
||||
pushl 32(%ebp) /* Up to 3 args passed via the stack */
|
||||
pushl 24(%ebp)
|
||||
pushl 16(%ebp)
|
||||
pushl %ebx /* R9 */
|
||||
pushl %eax /* R8 */
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
|
||||
/* Disable paging */
|
||||
movl %cr0, %eax
|
||||
btrl $X86_CR0_PG_BIT, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Disable long mode via EFER */
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
btrl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
call *%edi
|
||||
|
||||
/* We must preserve return value */
|
||||
movl %eax, %edi
|
||||
|
||||
call efi32_enable_long_mode
|
||||
|
||||
addl $32, %esp
|
||||
movl %edi, %eax
|
||||
lret
|
||||
SYM_FUNC_END(efi_enter32)
|
||||
|
||||
.code64
|
||||
SYM_FUNC_START(__efi64_thunk)
|
||||
push %rbp
|
||||
movl %esp, %ebp
|
||||
push %rbx
|
||||
|
||||
/* Move args #5 and #6 into 32-bit accessible registers */
|
||||
movl %r8d, %eax
|
||||
movl %r9d, %ebx
|
||||
|
||||
lcalll *efi32_call(%rip)
|
||||
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
RET
|
||||
SYM_FUNC_END(__efi64_thunk)
|
||||
|
||||
.code32
|
||||
SYM_FUNC_START_LOCAL(efi32_enable_long_mode)
|
||||
movl %cr4, %eax
|
||||
btsl $(X86_CR4_PAE_BIT), %eax
|
||||
movl %eax, %cr4
|
||||
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
btsl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
/* Disable interrupts - the firmware's IDT does not work in long mode */
|
||||
cli
|
||||
|
||||
/* Enable paging */
|
||||
movl %cr0, %eax
|
||||
btsl $X86_CR0_PG_BIT, %eax
|
||||
movl %eax, %cr0
|
||||
ret
|
||||
SYM_FUNC_END(efi32_enable_long_mode)
|
||||
|
||||
/*
|
||||
* This is the common EFI stub entry point for mixed mode. It sets up the GDT
|
||||
* and page tables needed for 64-bit execution, after which it calls the
|
||||
* common 64-bit EFI entrypoint efi_stub_entry().
|
||||
*
|
||||
* Arguments: 0(%esp) image handle
|
||||
* 4(%esp) EFI system table pointer
|
||||
* %ebx struct boot_params pointer (or NULL)
|
||||
*
|
||||
* Since this is the point of no return for ordinary execution, no registers
|
||||
* are considered live except for the function parameters. [Note that the EFI
|
||||
* stub may still exit and return to the firmware using the Exit() EFI boot
|
||||
* service.]
|
||||
*/
|
||||
SYM_FUNC_START_LOCAL(efi32_startup)
|
||||
movl %esp, %ebp
|
||||
|
||||
subl $8, %esp
|
||||
sgdtl (%esp) /* Save GDT descriptor to the stack */
|
||||
movl 2(%esp), %esi /* Existing GDT pointer */
|
||||
movzwl (%esp), %ecx /* Existing GDT limit */
|
||||
inc %ecx /* Existing GDT size */
|
||||
andl $~7, %ecx /* Ensure size is multiple of 8 */
|
||||
|
||||
subl %ecx, %esp /* Allocate new GDT */
|
||||
andl $~15, %esp /* Realign the stack */
|
||||
movl %esp, %edi /* New GDT address */
|
||||
leal 7(%ecx), %eax /* New GDT limit */
|
||||
pushw %cx /* Push 64-bit CS (for LJMP below) */
|
||||
pushl %edi /* Push new GDT address */
|
||||
pushw %ax /* Push new GDT limit */
|
||||
|
||||
/* Copy GDT to the stack and add a 64-bit code segment at the end */
|
||||
movl $GDT_ENTRY(DESC_CODE64, 0, 0xfffff) & 0xffffffff, (%edi,%ecx)
|
||||
movl $GDT_ENTRY(DESC_CODE64, 0, 0xfffff) >> 32, 4(%edi,%ecx)
|
||||
shrl $2, %ecx
|
||||
cld
|
||||
rep movsl /* Copy the firmware GDT */
|
||||
lgdtl (%esp) /* Switch to the new GDT */
|
||||
|
||||
call 1f
|
||||
1: pop %edi
|
||||
|
||||
/* Record mixed mode entry */
|
||||
movb $0x0, (efi_is64 - 1b)(%edi)
|
||||
|
||||
/* Set up indirect far call to re-enter 32-bit mode */
|
||||
leal (efi32_call - 1b)(%edi), %eax
|
||||
addl %eax, (%eax)
|
||||
movw %cs, 4(%eax)
|
||||
|
||||
/* Disable paging */
|
||||
movl %cr0, %eax
|
||||
btrl $X86_CR0_PG_BIT, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Set up 1:1 mapping */
|
||||
leal (pte - 1b)(%edi), %eax
|
||||
movl $_PAGE_PRESENT | _PAGE_RW | _PAGE_PSE, %ecx
|
||||
leal (_PAGE_PRESENT | _PAGE_RW)(%eax), %edx
|
||||
2: movl %ecx, (%eax)
|
||||
addl $8, %eax
|
||||
addl $PMD_SIZE, %ecx
|
||||
jnc 2b
|
||||
|
||||
movl $PAGE_SIZE, %ecx
|
||||
.irpc l, 0123
|
||||
movl %edx, \l * 8(%eax)
|
||||
addl %ecx, %edx
|
||||
.endr
|
||||
addl %ecx, %eax
|
||||
movl %edx, (%eax)
|
||||
movl %eax, %cr3
|
||||
|
||||
call efi32_enable_long_mode
|
||||
|
||||
/* Set up far jump to 64-bit mode (CS is already on the stack) */
|
||||
leal (efi_stub_entry - 1b)(%edi), %eax
|
||||
movl %eax, 2(%esp)
|
||||
|
||||
movl 0(%ebp), %edi
|
||||
movl 4(%ebp), %esi
|
||||
movl %ebx, %edx
|
||||
ljmpl *2(%esp)
|
||||
SYM_FUNC_END(efi32_startup)
|
||||
|
||||
/*
|
||||
* efi_status_t efi32_pe_entry(efi_handle_t image_handle,
|
||||
* efi_system_table_32_t *sys_table)
|
||||
*/
|
||||
SYM_FUNC_START(efi32_pe_entry)
|
||||
pushl %ebx // save callee-save registers
|
||||
|
||||
/* Check whether the CPU supports long mode */
|
||||
movl $0x80000001, %eax // assume extended info support
|
||||
cpuid
|
||||
btl $29, %edx // check long mode bit
|
||||
jnc 1f
|
||||
leal 8(%esp), %esp // preserve stack alignment
|
||||
xor %ebx, %ebx // no struct boot_params pointer
|
||||
jmp efi32_startup // only ESP and EBX remain live
|
||||
1: movl $0x80000003, %eax // EFI_UNSUPPORTED
|
||||
popl %ebx
|
||||
RET
|
||||
SYM_FUNC_END(efi32_pe_entry)
|
||||
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
.org efi32_stub_entry + 0x200
|
||||
.code64
|
||||
SYM_FUNC_START_NOALIGN(efi64_stub_entry)
|
||||
jmp efi_handover_entry
|
||||
SYM_FUNC_END(efi64_stub_entry)
|
||||
#endif
|
||||
|
||||
.data
|
||||
.balign 8
|
||||
SYM_DATA_START_LOCAL(efi32_call)
|
||||
.long efi_enter32 - .
|
||||
.word 0x0
|
||||
SYM_DATA_END(efi32_call)
|
||||
SYM_DATA(efi_is64, .byte 1)
|
||||
|
||||
.bss
|
||||
.balign PAGE_SIZE
|
||||
SYM_DATA_LOCAL(pte, .fill 6 * PAGE_SIZE, 1, 0)
|
@ -397,17 +397,13 @@ static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
void __noreturn efi_stub_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg,
|
||||
struct boot_params *boot_params);
|
||||
|
||||
/*
|
||||
* Because the x86 boot code expects to be passed a boot_params we
|
||||
* need to create one ourselves (usually the bootloader would create
|
||||
* one for us).
|
||||
*/
|
||||
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg)
|
||||
static efi_status_t efi_allocate_bootparams(efi_handle_t handle,
|
||||
struct boot_params **bp)
|
||||
{
|
||||
efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
struct boot_params *boot_params;
|
||||
@ -416,21 +412,15 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
unsigned long alloc;
|
||||
char *cmdline_ptr;
|
||||
|
||||
efi_system_table = sys_table_arg;
|
||||
|
||||
/* Check if we were booted by the EFI firmware */
|
||||
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
|
||||
efi_exit(handle, EFI_INVALID_PARAMETER);
|
||||
|
||||
status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
|
||||
efi_exit(handle, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = efi_allocate_pages(PARAM_SIZE, &alloc, ULONG_MAX);
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_exit(handle, status);
|
||||
return status;
|
||||
|
||||
boot_params = memset((void *)alloc, 0x0, PARAM_SIZE);
|
||||
hdr = &boot_params->hdr;
|
||||
@ -446,14 +436,14 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
cmdline_ptr = efi_convert_cmdline(image);
|
||||
if (!cmdline_ptr) {
|
||||
efi_free(PARAM_SIZE, alloc);
|
||||
efi_exit(handle, EFI_OUT_OF_RESOURCES);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr,
|
||||
&boot_params->ext_cmd_line_ptr);
|
||||
|
||||
efi_stub_entry(handle, sys_table_arg, boot_params);
|
||||
/* not reached */
|
||||
*bp = boot_params;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static void add_e820ext(struct boot_params *params,
|
||||
@ -740,13 +730,16 @@ static efi_status_t parse_options(const char *cmdline)
|
||||
return efi_parse_options(cmdline);
|
||||
}
|
||||
|
||||
static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
|
||||
static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry,
|
||||
struct boot_params *boot_params)
|
||||
{
|
||||
unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
|
||||
unsigned long addr, alloc_size, entry;
|
||||
efi_status_t status;
|
||||
u32 seed[2] = {};
|
||||
|
||||
boot_params_ptr = boot_params;
|
||||
|
||||
/* determine the required size of the allocation */
|
||||
alloc_size = ALIGN(max_t(unsigned long, output_len, kernel_total_size),
|
||||
MIN_KERNEL_ALIGN);
|
||||
@ -777,7 +770,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
|
||||
seed[0] = 0;
|
||||
}
|
||||
|
||||
boot_params_ptr->hdr.loadflags |= KASLR_FLAG;
|
||||
boot_params->hdr.loadflags |= KASLR_FLAG;
|
||||
}
|
||||
|
||||
status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr,
|
||||
@ -815,20 +808,27 @@ static void __noreturn enter_kernel(unsigned long kernel_addr,
|
||||
void __noreturn efi_stub_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg,
|
||||
struct boot_params *boot_params)
|
||||
|
||||
{
|
||||
efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
|
||||
struct setup_header *hdr = &boot_params->hdr;
|
||||
const struct linux_efi_initrd *initrd = NULL;
|
||||
unsigned long kernel_entry;
|
||||
struct setup_header *hdr;
|
||||
efi_status_t status;
|
||||
|
||||
boot_params_ptr = boot_params;
|
||||
|
||||
efi_system_table = sys_table_arg;
|
||||
/* Check if we were booted by the EFI firmware */
|
||||
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
|
||||
efi_exit(handle, EFI_INVALID_PARAMETER);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_EFI_HANDOVER_PROTOCOL) || !boot_params) {
|
||||
status = efi_allocate_bootparams(handle, &boot_params);
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
||||
hdr = &boot_params->hdr;
|
||||
|
||||
if (have_unsupported_snp_features())
|
||||
efi_exit(handle, EFI_UNSUPPORTED);
|
||||
|
||||
@ -870,7 +870,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
|
||||
if (efi_mem_encrypt > 0)
|
||||
hdr->xloadflags |= XLF_MEM_ENCRYPTION;
|
||||
|
||||
status = efi_decompress_kernel(&kernel_entry);
|
||||
status = efi_decompress_kernel(&kernel_entry, boot_params);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to decompress kernel\n");
|
||||
goto fail;
|
||||
@ -940,6 +940,12 @@ fail:
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
||||
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg)
|
||||
{
|
||||
efi_stub_entry(handle, sys_table_arg, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg,
|
||||
struct boot_params *boot_params)
|
||||
|
68
drivers/firmware/efi/libstub/zboot-decompress-gzip.c
Normal file
68
drivers/firmware/efi/libstub/zboot-decompress-gzip.c
Normal file
@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include <asm/efi.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
#include "inftrees.c"
|
||||
#include "inffast.c"
|
||||
#include "inflate.c"
|
||||
|
||||
extern unsigned char _gzdata_start[], _gzdata_end[];
|
||||
extern u32 __aligned(1) payload_size;
|
||||
|
||||
static struct z_stream_s stream;
|
||||
|
||||
efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size)
|
||||
{
|
||||
efi_status_t status;
|
||||
int rc;
|
||||
|
||||
/* skip the 10 byte header, assume no recorded filename */
|
||||
stream.next_in = _gzdata_start + 10;
|
||||
stream.avail_in = _gzdata_end - stream.next_in;
|
||||
|
||||
status = efi_allocate_pages(zlib_inflate_workspacesize(),
|
||||
(unsigned long *)&stream.workspace,
|
||||
ULONG_MAX);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
rc = zlib_inflateInit2(&stream, -MAX_WBITS);
|
||||
if (rc != Z_OK) {
|
||||
efi_err("failed to initialize GZIP decompressor: %d\n", rc);
|
||||
status = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*alloc_size = payload_size;
|
||||
return EFI_SUCCESS;
|
||||
out:
|
||||
efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);
|
||||
return status;
|
||||
}
|
||||
|
||||
efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
|
||||
{
|
||||
int rc;
|
||||
|
||||
stream.next_out = out;
|
||||
stream.avail_out = outlen;
|
||||
|
||||
rc = zlib_inflate(&stream, 0);
|
||||
zlib_inflateEnd(&stream);
|
||||
|
||||
efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);
|
||||
|
||||
if (rc != Z_STREAM_END) {
|
||||
efi_err("GZIP decompression failed with status %d\n", rc);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
efi_cache_sync_image((unsigned long)out, outlen);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
49
drivers/firmware/efi/libstub/zboot-decompress-zstd.c
Normal file
49
drivers/firmware/efi/libstub/zboot-decompress-zstd.c
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/zstd.h>
|
||||
|
||||
#include <asm/efi.h>
|
||||
|
||||
#include "decompress_sources.h"
|
||||
#include "efistub.h"
|
||||
|
||||
extern unsigned char _gzdata_start[], _gzdata_end[];
|
||||
extern u32 __aligned(1) payload_size;
|
||||
|
||||
static size_t wksp_size;
|
||||
static void *wksp;
|
||||
|
||||
efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size)
|
||||
{
|
||||
efi_status_t status;
|
||||
|
||||
wksp_size = zstd_dctx_workspace_bound();
|
||||
status = efi_allocate_pages(wksp_size, (unsigned long *)&wksp, ULONG_MAX);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
*alloc_size = payload_size;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
|
||||
{
|
||||
zstd_dctx *dctx = zstd_init_dctx(wksp, wksp_size);
|
||||
size_t ret;
|
||||
int retval;
|
||||
|
||||
ret = zstd_decompress_dctx(dctx, out, outlen, _gzdata_start,
|
||||
_gzdata_end - _gzdata_start - 4);
|
||||
efi_free(wksp_size, (unsigned long)wksp);
|
||||
|
||||
retval = zstd_get_error_code(ret);
|
||||
if (retval) {
|
||||
efi_err("ZSTD-decompression failed with status %d\n", retval);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
efi_cache_sync_image((unsigned long)out, outlen);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
@ -7,36 +7,6 @@
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
static unsigned char zboot_heap[SZ_256K] __aligned(64);
|
||||
static unsigned long free_mem_ptr, free_mem_end_ptr;
|
||||
|
||||
#define STATIC static
|
||||
#if defined(CONFIG_KERNEL_GZIP)
|
||||
#include "../../../../lib/decompress_inflate.c"
|
||||
#elif defined(CONFIG_KERNEL_LZ4)
|
||||
#include "../../../../lib/decompress_unlz4.c"
|
||||
#elif defined(CONFIG_KERNEL_LZMA)
|
||||
#include "../../../../lib/decompress_unlzma.c"
|
||||
#elif defined(CONFIG_KERNEL_LZO)
|
||||
#include "../../../../lib/decompress_unlzo.c"
|
||||
#elif defined(CONFIG_KERNEL_XZ)
|
||||
#undef memcpy
|
||||
#define memcpy memcpy
|
||||
#undef memmove
|
||||
#define memmove memmove
|
||||
#include "../../../../lib/decompress_unxz.c"
|
||||
#elif defined(CONFIG_KERNEL_ZSTD)
|
||||
#include "../../../../lib/decompress_unzstd.c"
|
||||
#endif
|
||||
|
||||
extern char efi_zboot_header[];
|
||||
extern char _gzdata_start[], _gzdata_end[];
|
||||
|
||||
static void error(char *x)
|
||||
{
|
||||
efi_err("EFI decompressor: %s\n", x);
|
||||
}
|
||||
|
||||
static unsigned long alloc_preferred_address(unsigned long alloc_size)
|
||||
{
|
||||
#ifdef EFI_KIMG_PREFERRED_ADDRESS
|
||||
@ -64,22 +34,17 @@ struct screen_info *alloc_screen_info(void)
|
||||
asmlinkage efi_status_t __efiapi
|
||||
efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
||||
{
|
||||
unsigned long compressed_size = _gzdata_end - _gzdata_start;
|
||||
char *cmdline_ptr __free(efi_pool) = NULL;
|
||||
unsigned long image_base, alloc_size;
|
||||
efi_loaded_image_t *image;
|
||||
efi_status_t status;
|
||||
char *cmdline_ptr;
|
||||
int ret;
|
||||
|
||||
WRITE_ONCE(efi_system_table, systab);
|
||||
|
||||
free_mem_ptr = (unsigned long)&zboot_heap;
|
||||
free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap);
|
||||
|
||||
status = efi_bs_call(handle_protocol, handle,
|
||||
&LOADED_IMAGE_PROTOCOL_GUID, (void **)&image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
error("Failed to locate parent's loaded image protocol");
|
||||
efi_err("Failed to locate parent's loaded image protocol\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -89,9 +54,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
||||
|
||||
efi_info("Decompressing Linux Kernel...\n");
|
||||
|
||||
// SizeOfImage from the compressee's PE/COFF header
|
||||
alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4),
|
||||
EFI_ALLOC_ALIGN);
|
||||
status = efi_zboot_decompress_init(&alloc_size);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
// If the architecture has a preferred address for the image,
|
||||
// try that first.
|
||||
@ -122,26 +87,14 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
||||
seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to allocate memory\n");
|
||||
goto free_cmdline;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Decompress the payload into the newly allocated buffer.
|
||||
ret = __decompress(_gzdata_start, compressed_size, NULL, NULL,
|
||||
(void *)image_base, alloc_size, NULL, error);
|
||||
if (ret < 0) {
|
||||
error("Decompression failed");
|
||||
status = EFI_DEVICE_ERROR;
|
||||
goto free_image;
|
||||
}
|
||||
// Decompress the payload into the newly allocated buffer
|
||||
status = efi_zboot_decompress((void *)image_base, alloc_size) ?:
|
||||
efi_stub_common(handle, image, image_base, cmdline_ptr);
|
||||
|
||||
efi_cache_sync_image(image_base, alloc_size);
|
||||
|
||||
status = efi_stub_common(handle, image, image_base, cmdline_ptr);
|
||||
|
||||
free_image:
|
||||
efi_free(alloc_size, image_base);
|
||||
free_cmdline:
|
||||
efi_bs_call(free_pool, cmdline_ptr);
|
||||
return status;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ SECTIONS
|
||||
.rodata : ALIGN(8) {
|
||||
__efistub__gzdata_start = .;
|
||||
*(.gzdata)
|
||||
__efistub_payload_size = . - 4;
|
||||
__efistub__gzdata_end = .;
|
||||
*(.rodata* .init.rodata* .srodata*)
|
||||
|
||||
|
@ -57,11 +57,10 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
|
||||
if (bytes == -ENOENT) {
|
||||
/*
|
||||
* FIXME: temporary workaround for fwupdate, signal
|
||||
* failed write with a 1 to keep created but not
|
||||
* written files
|
||||
* zero size signals to release that the write deleted
|
||||
* the variable
|
||||
*/
|
||||
i_size_write(inode, 1);
|
||||
i_size_write(inode, 0);
|
||||
} else {
|
||||
i_size_write(inode, datasize + sizeof(attributes));
|
||||
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||
@ -125,8 +124,7 @@ static int efivarfs_file_release(struct inode *inode, struct file *file)
|
||||
struct efivar_entry *var = inode->i_private;
|
||||
|
||||
inode_lock(inode);
|
||||
/* FIXME: temporary work around for fwupdate */
|
||||
var->removed = (--var->open_count == 0 && i_size_read(inode) == 1);
|
||||
var->removed = (--var->open_count == 0 && i_size_read(inode) == 0);
|
||||
inode_unlock(inode);
|
||||
|
||||
if (var->removed)
|
||||
|
Loading…
x
Reference in New Issue
Block a user