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
Unified · Split
| @@ -106,7 +106,6 @@ vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o $(obj)/tdcall.o $(obj)/td · 105 unmodified lines | ||
| 106 | 106 | vmlinux-objs-$(CONFIG_UNACCEPTED_MEMORY) += $(obj)/mem.o |
| 107 | 107 | |
| 108 | 108 | vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o |
| 109 | −vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o | |
| 110 | 109 | vmlinux-libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a |
| 111 | 110 | |
| 112 | 111 | $(obj)/vmlinux: $(vmlinux-objs-y) $(vmlinux-libs-y) FORCE |
| @@ -1,341 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −/* | |
| 3 | − * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming | |
| 4 | − * | |
| 5 | − * Early support for invoking 32-bit EFI services from a 64-bit kernel. | |
| 6 | − * | |
| 7 | − * Because this thunking occurs before ExitBootServices() we have to | |
| 8 | − * restore the firmware's 32-bit GDT and IDT before we make EFI service | |
| 9 | − * calls. | |
| 10 | − * | |
| 11 | − * On the plus side, we don't have to worry about mangling 64-bit | |
| 12 | − * addresses into 32-bits because we're executing with an identity | |
| 13 | − * mapped pagetable and haven't transitioned to 64-bit virtual addresses | |
| 14 | − * yet. | |
| 15 | − */ | |
| 16 | − | |
| 17 | −#include <linux/linkage.h> | |
| 18 | −#include <asm/asm-offsets.h> | |
| 19 | −#include <asm/msr.h> | |
| 20 | −#include <asm/page_types.h> | |
| 21 | −#include <asm/processor-flags.h> | |
| 22 | −#include <asm/segment.h> | |
| 23 | −#include <asm/setup.h> | |
| 24 | − | |
| 25 | − .code64 | |
| 26 | − .text | |
| 27 | −/* | |
| 28 | − * When booting in 64-bit mode on 32-bit EFI firmware, startup_64_mixed_mode() | |
| 29 | − * is the first thing that runs after switching to long mode. Depending on | |
| 30 | − * whether the EFI handover protocol or the compat entry point was used to | |
| 31 | − * enter the kernel, it will either branch to the common 64-bit EFI stub | |
| 32 | − * entrypoint efi_stub_entry() directly, or via the 64-bit EFI PE/COFF | |
| 33 | − * entrypoint efi_pe_entry(). In the former case, the bootloader must provide a | |
| 34 | − * struct bootparams pointer as the third argument, so the presence of such a | |
| 35 | − * pointer is used to disambiguate. | |
| 36 | − * | |
| 37 | − * +--------------+ | |
| 38 | − * +------------------+ +------------+ +------>| efi_pe_entry | | |
| 39 | − * | efi32_pe_entry |---->| | | +-----------+--+ | |
| 40 | − * +------------------+ | | +------+----------------+ | | |
| 41 | − * | startup_32 |---->| startup_64_mixed_mode | | | |
| 42 | − * +------------------+ | | +------+----------------+ | | |
| 43 | − * | efi32_stub_entry |---->| | | | | |
| 44 | − * +------------------+ +------------+ | | | |
| 45 | − * V | | |
| 46 | − * +------------+ +----------------+ | | |
| 47 | − * | startup_64 |<----| efi_stub_entry |<--------+ | |
| 48 | − * +------------+ +----------------+ | |
| 49 | − */ | |
| 50 | −SYM_FUNC_START(startup_64_mixed_mode) | |
| 51 | − lea efi32_boot_args(%rip), %rdx | |
| 52 | − mov 0(%rdx), %edi | |
| 53 | − mov 4(%rdx), %esi | |
| 54 | − | |
| 55 | − /* Switch to the firmware's stack */ | |
| 56 | − movl efi32_boot_sp(%rip), %esp | |
| 57 | − andl $~7, %esp | |
| 58 | − | |
| 59 | −#ifdef CONFIG_EFI_HANDOVER_PROTOCOL | |
| 60 | − mov 8(%rdx), %edx // saved bootparams pointer | |
| 61 | − test %edx, %edx | |
| 62 | − jnz efi_stub_entry | |
| 63 | −#endif | |
| 64 | − /* | |
| 65 | − * efi_pe_entry uses MS calling convention, which requires 32 bytes of | |
| 66 | − * shadow space on the stack even if all arguments are passed in | |
| 67 | − * registers. We also need an additional 8 bytes for the space that | |
| 68 | − * would be occupied by the return address, and this also results in | |
| 69 | − * the correct stack alignment for entry. | |
| 70 | − */ | |
| 71 | − sub $40, %rsp | |
| 72 | − mov %rdi, %rcx // MS calling convention | |
| 73 | − mov %rsi, %rdx | |
| 74 | − jmp efi_pe_entry | |
| 75 | −SYM_FUNC_END(startup_64_mixed_mode) | |
| 76 | − | |
| 77 | −SYM_FUNC_START(__efi64_thunk) | |
| 78 | − push %rbp | |
| 79 | − push %rbx | |
| 80 | − | |
| 81 | − movl %ds, %eax | |
| 82 | − push %rax | |
| 83 | − movl %es, %eax | |
| 84 | − push %rax | |
| 85 | − movl %ss, %eax | |
| 86 | − push %rax | |
| 87 | − | |
| 88 | − /* Copy args passed on stack */ | |
| 89 | − movq 0x30(%rsp), %rbp | |
| 90 | − movq 0x38(%rsp), %rbx | |
| 91 | − movq 0x40(%rsp), %rax | |
| 92 | − | |
| 93 | − /* | |
| 94 | − * Convert x86-64 ABI params to i386 ABI | |
| 95 | − */ | |
| 96 | − subq $64, %rsp | |
| 97 | − movl %esi, 0x0(%rsp) | |
| 98 | − movl %edx, 0x4(%rsp) | |
| 99 | − movl %ecx, 0x8(%rsp) | |
| 100 | − movl %r8d, 0xc(%rsp) | |
| 101 | − movl %r9d, 0x10(%rsp) | |
| 102 | − movl %ebp, 0x14(%rsp) | |
| 103 | − movl %ebx, 0x18(%rsp) | |
| 104 | − movl %eax, 0x1c(%rsp) | |
| 105 | − | |
| 106 | − leaq 0x20(%rsp), %rbx | |
| 107 | − sgdt (%rbx) | |
| 108 | − sidt 16(%rbx) | |
| 109 | − | |
| 110 | − leaq 1f(%rip), %rbp | |
| 111 | − | |
| 112 | − /* | |
| 113 | − * Switch to IDT and GDT with 32-bit segments. These are the firmware | |
| 114 | − * GDT and IDT that were installed when the kernel started executing. | |
| 115 | − * The pointers were saved by the efi32_entry() routine below. | |
| 116 | − * | |
| 117 | − * Pass the saved DS selector to the 32-bit code, and use far return to | |
| 118 | − * restore the saved CS selector. | |
| 119 | − */ | |
| 120 | − lidt efi32_boot_idt(%rip) | |
| 121 | − lgdt efi32_boot_gdt(%rip) | |
| 122 | − | |
| 123 | − movzwl efi32_boot_ds(%rip), %edx | |
| 124 | − movzwq efi32_boot_cs(%rip), %rax | |
| 125 | − pushq %rax | |
| 126 | − leaq efi_enter32(%rip), %rax | |
| 127 | − pushq %rax | |
| 128 | − lretq | |
| 129 | − | |
| 130 | −1: addq $64, %rsp | |
| 131 | − movq %rdi, %rax | |
| 132 | − | |
| 133 | − pop %rbx | |
| 134 | − movl %ebx, %ss | |
| 135 | − pop %rbx | |
| 136 | − movl %ebx, %es | |
| 137 | − pop %rbx | |
| 138 | − movl %ebx, %ds | |
| 139 | − /* Clear out 32-bit selector from FS and GS */ | |
| 140 | − xorl %ebx, %ebx | |
| 141 | − movl %ebx, %fs | |
| 142 | − movl %ebx, %gs | |
| 143 | − | |
| 144 | − pop %rbx | |
| 145 | − pop %rbp | |
| 146 | − RET | |
| 147 | −SYM_FUNC_END(__efi64_thunk) | |
| 148 | − | |
| 149 | − .code32 | |
| 150 | −#ifdef CONFIG_EFI_HANDOVER_PROTOCOL | |
| 151 | −SYM_FUNC_START(efi32_stub_entry) | |
| 152 | − call 1f | |
| 153 | −1: popl %ecx | |
| 154 | − leal (efi32_boot_args - 1b)(%ecx), %ebx | |
| 155 | − | |
| 156 | − /* Clear BSS */ | |
| 157 | − xorl %eax, %eax | |
| 158 | − leal (_bss - 1b)(%ecx), %edi | |
| 159 | − leal (_ebss - 1b)(%ecx), %ecx | |
| 160 | − subl %edi, %ecx | |
| 161 | − shrl $2, %ecx | |
| 162 | − cld | |
| 163 | − rep stosl | |
| 164 | − | |
| 165 | − add $0x4, %esp /* Discard return address */ | |
| 166 | − popl %ecx | |
| 167 | − popl %edx | |
| 168 | − popl %esi | |
| 169 | − movl %esi, 8(%ebx) | |
| 170 | − jmp efi32_entry | |
| 171 | −SYM_FUNC_END(efi32_stub_entry) | |
| 172 | −#endif | |
| 173 | − | |
| 174 | −/* | |
| 175 | − * EFI service pointer must be in %edi. | |
| 176 | − * | |
| 177 | − * The stack should represent the 32-bit calling convention. | |
| 178 | − */ | |
| 179 | −SYM_FUNC_START_LOCAL(efi_enter32) | |
| 180 | − /* Load firmware selector into data and stack segment registers */ | |
| 181 | − movl %edx, %ds | |
| 182 | − movl %edx, %es | |
| 183 | − movl %edx, %fs | |
| 184 | − movl %edx, %gs | |
| 185 | − movl %edx, %ss | |
| 186 | − | |
| 187 | − /* Reload pgtables */ | |
| 188 | − movl %cr3, %eax | |
| 189 | − movl %eax, %cr3 | |
| 190 | − | |
| 191 | − /* Disable paging */ | |
| 192 | − movl %cr0, %eax | |
| 193 | − btrl $X86_CR0_PG_BIT, %eax | |
| 194 | − movl %eax, %cr0 | |
| 195 | − | |
| 196 | − /* Disable long mode via EFER */ | |
| 197 | − movl $MSR_EFER, %ecx | |
| 198 | − rdmsr | |
| 199 | − btrl $_EFER_LME, %eax | |
| 200 | − wrmsr | |
| 201 | − | |
| 202 | − call *%edi | |
| 203 | − | |
| 204 | − /* We must preserve return value */ | |
| 205 | − movl %eax, %edi | |
| 206 | − | |
| 207 | − /* | |
| 208 | − * Some firmware will return with interrupts enabled. Be sure to | |
| 209 | − * disable them before we switch GDTs and IDTs. | |
| 210 | − */ | |
| 211 | − cli | |
| 212 | − | |
| 213 | − lidtl 16(%ebx) | |
| 214 | − lgdtl (%ebx) | |
| 215 | − | |
| 216 | − movl %cr4, %eax | |
| 217 | − btsl $(X86_CR4_PAE_BIT), %eax | |
| 218 | − movl %eax, %cr4 | |
| 219 | − | |
| 220 | − movl %cr3, %eax | |
| 221 | − movl %eax, %cr3 | |
| 222 | − | |
| 223 | − movl $MSR_EFER, %ecx | |
| 224 | − rdmsr | |
| 225 | − btsl $_EFER_LME, %eax | |
| 226 | − wrmsr | |
| 227 | − | |
| 228 | − xorl %eax, %eax | |
| 229 | − lldt %ax | |
| 230 | − | |
| 231 | − pushl $__KERNEL_CS | |
| 232 | − pushl %ebp | |
| 233 | − | |
| 234 | − /* Enable paging */ | |
| 235 | − movl %cr0, %eax | |
| 236 | − btsl $X86_CR0_PG_BIT, %eax | |
| 237 | − movl %eax, %cr0 | |
| 238 | − lret | |
| 239 | −SYM_FUNC_END(efi_enter32) | |
| 240 | − | |
| 241 | −/* | |
| 242 | − * This is the common EFI stub entry point for mixed mode. | |
| 243 | − * | |
| 244 | − * Arguments: %ecx image handle | |
| 245 | − * %edx EFI system table pointer | |
| 246 | − * | |
| 247 | − * Since this is the point of no return for ordinary execution, no registers | |
| 248 | − * are considered live except for the function parameters. [Note that the EFI | |
| 249 | − * stub may still exit and return to the firmware using the Exit() EFI boot | |
| 250 | − * service.] | |
| 251 | − */ | |
| 252 | −SYM_FUNC_START_LOCAL(efi32_entry) | |
| 253 | − call 1f | |
| 254 | −1: pop %ebx | |
| 255 | − | |
| 256 | − /* Save firmware GDTR and code/data selectors */ | |
| 257 | − sgdtl (efi32_boot_gdt - 1b)(%ebx) | |
| 258 | − movw %cs, (efi32_boot_cs - 1b)(%ebx) | |
| 259 | − movw %ds, (efi32_boot_ds - 1b)(%ebx) | |
| 260 | − | |
| 261 | − /* Store firmware IDT descriptor */ | |
| 262 | − sidtl (efi32_boot_idt - 1b)(%ebx) | |
| 263 | − | |
| 264 | − /* Store firmware stack pointer */ | |
| 265 | − movl %esp, (efi32_boot_sp - 1b)(%ebx) | |
| 266 | − | |
| 267 | − /* Store boot arguments */ | |
| 268 | − leal (efi32_boot_args - 1b)(%ebx), %ebx | |
| 269 | − movl %ecx, 0(%ebx) | |
| 270 | − movl %edx, 4(%ebx) | |
| 271 | − movb $0x0, 12(%ebx) // efi_is64 | |
| 272 | − | |
| 273 | − /* | |
| 274 | − * Allocate some memory for a temporary struct boot_params, which only | |
| 275 | − * needs the minimal pieces that startup_32() relies on. | |
| 276 | − */ | |
| 277 | − subl $PARAM_SIZE, %esp | |
| 278 | − movl %esp, %esi | |
| 279 | − movl $PAGE_SIZE, BP_kernel_alignment(%esi) | |
| 280 | − movl $_end - 1b, BP_init_size(%esi) | |
| 281 | − subl $startup_32 - 1b, BP_init_size(%esi) | |
| 282 | − | |
| 283 | − /* Disable paging */ | |
| 284 | − movl %cr0, %eax | |
| 285 | − btrl $X86_CR0_PG_BIT, %eax | |
| 286 | − movl %eax, %cr0 | |
| 287 | − | |
| 288 | − jmp startup_32 | |
| 289 | −SYM_FUNC_END(efi32_entry) | |
| 290 | − | |
| 291 | −/* | |
| 292 | − * efi_status_t efi32_pe_entry(efi_handle_t image_handle, | |
| 293 | − * efi_system_table_32_t *sys_table) | |
| 294 | − */ | |
| 295 | −SYM_FUNC_START(efi32_pe_entry) | |
| 296 | − pushl %ebp | |
| 297 | − movl %esp, %ebp | |
| 298 | − pushl %ebx // save callee-save registers | |
| 299 | − pushl %edi | |
| 300 | − | |
| 301 | − call verify_cpu // check for long mode support | |
| 302 | − testl %eax, %eax | |
| 303 | − movl $0x80000003, %eax // EFI_UNSUPPORTED | |
| 304 | − jnz 2f | |
| 305 | − | |
| 306 | − movl 8(%ebp), %ecx // image_handle | |
| 307 | − movl 12(%ebp), %edx // sys_table | |
| 308 | − jmp efi32_entry // pass %ecx, %edx | |
| 309 | − // no other registers remain live | |
| 310 | − | |
| 311 | −2: popl %edi // restore callee-save registers | |
| 312 | − popl %ebx | |
| 313 | − leave | |
| 314 | − RET | |
| 315 | −SYM_FUNC_END(efi32_pe_entry) | |
| 316 | − | |
| 317 | −#ifdef CONFIG_EFI_HANDOVER_PROTOCOL | |
| 318 | − .org efi32_stub_entry + 0x200 | |
| 319 | − .code64 | |
| 320 | −SYM_FUNC_START_NOALIGN(efi64_stub_entry) | |
| 321 | − jmp efi_handover_entry | |
| 322 | −SYM_FUNC_END(efi64_stub_entry) | |
| 323 | −#endif | |
| 324 | − | |
| 325 | − .data | |
| 326 | − .balign 8 | |
| 327 | −SYM_DATA_START_LOCAL(efi32_boot_gdt) | |
| 328 | − .word 0 | |
| 329 | − .quad 0 | |
| 330 | −SYM_DATA_END(efi32_boot_gdt) | |
| 331 | − | |
| 332 | −SYM_DATA_START_LOCAL(efi32_boot_idt) | |
| 333 | − .word 0 | |
| 334 | − .quad 0 | |
| 335 | −SYM_DATA_END(efi32_boot_idt) | |
| 336 | − | |
| 337 | −SYM_DATA_LOCAL(efi32_boot_cs, .word 0) | |
| 338 | −SYM_DATA_LOCAL(efi32_boot_ds, .word 0) | |
| 339 | −SYM_DATA_LOCAL(efi32_boot_sp, .long 0) | |
| 340 | −SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0) | |
| 341 | −SYM_DATA(efi_is64, .byte 1) | |
| @@ -263,13 +263,6 @@ SYM_FUNC_START(startup_32) · 262 unmodified lines | ||
| 263 | 263 | * used to perform that far jump. |
| 264 | 264 | */ |
| 265 | 265 | leal rva(startup_64)(%ebp), %eax |
| 266 | −#ifdef CONFIG_EFI_MIXED | |
| 267 | − cmpb $1, rva(efi_is64)(%ebp) | |
| 268 | − je 1f | |
| 269 | − leal rva(startup_64_mixed_mode)(%ebp), %eax | |
| 270 | −1: | |
| 271 | −#endif | |
| 272 | − | |
| 273 | 266 | pushl $__KERNEL_CS |
| 274 | 267 | pushl %eax |
| 275 | 268 | |
| @@ -47,7 +47,7 @@ static int efibc_reboot_notifier_call(struct notifier_block *notifier, · 46 unmodified lines | ||
| 47 | 47 | if (ret || !data) |
| 48 | 48 | return NOTIFY_DONE; |
| 49 | 49 | |
| 50 | − wdata = kmalloc(MAX_DATA_LEN * sizeof(efi_char16_t), GFP_KERNEL); | |
| 50 | + wdata = kmalloc_array(MAX_DATA_LEN, sizeof(efi_char16_t), GFP_KERNEL); | |
| 51 | 51 | if (!wdata) |
| 52 | 52 | return NOTIFY_DONE; |
| 53 | 53 | |
| @@ -62,6 +62,8 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS)) · 61 unmodified lines | ||
| 62 | 62 | # `-fdata-sections` flag from KBUILD_CFLAGS_KERNEL |
| 63 | 63 | KBUILD_CFLAGS_KERNEL := $(filter-out -fdata-sections, $(KBUILD_CFLAGS_KERNEL)) |
| 64 | 64 | |
| 65 | +KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ | |
| 66 | + | |
| 65 | 67 | lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ |
| 66 | 68 | file.o mem.o random.o randomalloc.o pci.o \ |
| 67 | 69 | 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 \ · 15 unmodified lines | ||
| 83 | 85 | lib-$(CONFIG_ARM) += arm32-stub.o |
| 84 | 86 | lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o |
| 85 | 87 | lib-$(CONFIG_X86) += x86-stub.o smbios.o |
| 88 | +lib-$(CONFIG_EFI_MIXED) += x86-mixed.o | |
| 86 | 89 | lib-$(CONFIG_X86_64) += x86-5lvl.o |
| 87 | 90 | lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o |
| 88 | 91 | lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o |
| 89 | 92 | |
| 90 | 93 | CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) |
| 91 | 94 | |
| 92 | −zboot-obj-$(CONFIG_RISCV) := lib-clz_ctz.o lib-ashldi3.o | |
| 95 | +zboot-obj-y := zboot-decompress-gzip.o | |
| 96 | +CFLAGS_zboot-decompress-gzip.o += -I$(srctree)/lib/zlib_inflate | |
| 97 | +zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o | |
| 98 | +CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd | |
| 99 | + | |
| 100 | +zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o | |
| 93 | 101 | lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) |
| 94 | 102 | |
| 95 | 103 | lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o |
| @@ -1234,4 +1234,7 @@ void process_unaccepted_memory(u64 start, u64 end); · 1233 unmodified lines | ||
| 1234 | 1234 | void accept_memory(phys_addr_t start, unsigned long size); |
| 1235 | 1235 | void arch_accept_memory(phys_addr_t start, phys_addr_t end); |
| 1236 | 1236 | |
| 1237 | +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size); | |
| 1238 | +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen); | |
| 1239 | + | |
| 1237 | 1240 | #endif |
| @@ -15,8 +15,31 @@ void *__memmove(void *__dest, const void *__src, size_t count) __alias(memmove); · 14 unmodified lines | ||
| 15 | 15 | void *__memset(void *s, int c, size_t count) __alias(memset); |
| 16 | 16 | #endif |
| 17 | 17 | |
| 18 | +static void *efistub_memmove(u8 *dst, const u8 *src, size_t len) | |
| 19 | +{ | |
| 20 | + if (src > dst || dst >= (src + len)) | |
| 21 | + for (size_t i = 0; i < len; i++) | |
| 22 | + dst[i] = src[i]; | |
| 23 | + else | |
| 24 | + for (ssize_t i = len - 1; i >= 0; i--) | |
| 25 | + dst[i] = src[i]; | |
| 26 | + | |
| 27 | + return dst; | |
| 28 | +} | |
| 29 | + | |
| 30 | +static void *efistub_memset(void *dst, int c, size_t len) | |
| 31 | +{ | |
| 32 | + for (u8 *d = dst; len--; d++) | |
| 33 | + *d = c; | |
| 34 | + | |
| 35 | + return dst; | |
| 36 | +} | |
| 37 | + | |
| 18 | 38 | void *memcpy(void *dst, const void *src, size_t len) |
| 19 | 39 | { |
| 40 | + if (efi_table_attr(efi_system_table, boottime) == NULL) | |
| 41 | + return efistub_memmove(dst, src, len); | |
| 42 | + | |
| 20 | 43 | efi_bs_call(copy_mem, dst, src, len); |
| 21 | 44 | return dst; |
| 22 | 45 | } |
| @@ -25,6 +48,9 @@ extern void *memmove(void *dst, const void *src, size_t len) __alias(memcpy); · 2 unmodified lines | ||
| 25 | 48 | |
| 26 | 49 | void *memset(void *dst, int c, size_t len) |
| 27 | 50 | { |
| 51 | + if (efi_table_attr(efi_system_table, boottime) == NULL) | |
| 52 | + return efistub_memset(dst, c, len); | |
| 53 | + | |
| 28 | 54 | efi_bs_call(set_mem, dst, len, c & U8_MAX); |
| 29 | 55 | return dst; |
| 30 | 56 | } |
| @@ -0,0 +1,253 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming | |
| 4 | + * | |
| 5 | + * Early support for invoking 32-bit EFI services from a 64-bit kernel. | |
| 6 | + * | |
| 7 | + * Because this thunking occurs before ExitBootServices() we have to | |
| 8 | + * restore the firmware's 32-bit GDT and IDT before we make EFI service | |
| 9 | + * calls. | |
| 10 | + * | |
| 11 | + * On the plus side, we don't have to worry about mangling 64-bit | |
| 12 | + * addresses into 32-bits because we're executing with an identity | |
| 13 | + * mapped pagetable and haven't transitioned to 64-bit virtual addresses | |
| 14 | + * yet. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/linkage.h> | |
| 18 | +#include <asm/desc_defs.h> | |
| 19 | +#include <asm/msr.h> | |
| 20 | +#include <asm/page_types.h> | |
| 21 | +#include <asm/pgtable_types.h> | |
| 22 | +#include <asm/processor-flags.h> | |
| 23 | +#include <asm/segment.h> | |
| 24 | + | |
| 25 | + .text | |
| 26 | + .code32 | |
| 27 | +#ifdef CONFIG_EFI_HANDOVER_PROTOCOL | |
| 28 | +SYM_FUNC_START(efi32_stub_entry) | |
| 29 | + call 1f | |
| 30 | +1: popl %ecx | |
| 31 | + | |
| 32 | + /* Clear BSS */ | |
| 33 | + xorl %eax, %eax | |
| 34 | + leal (_bss - 1b)(%ecx), %edi | |
| 35 | + leal (_ebss - 1b)(%ecx), %ecx | |
| 36 | + subl %edi, %ecx | |
| 37 | + shrl $2, %ecx | |
| 38 | + cld | |
| 39 | + rep stosl | |
| 40 | + | |
| 41 | + add $0x4, %esp /* Discard return address */ | |
| 42 | + movl 8(%esp), %ebx /* struct boot_params pointer */ | |
| 43 | + jmp efi32_startup | |
| 44 | +SYM_FUNC_END(efi32_stub_entry) | |
| 45 | +#endif | |
| 46 | + | |
| 47 | +/* | |
| 48 | + * Called using a far call from __efi64_thunk() below, using the x86_64 SysV | |
| 49 | + * ABI (except for R8/R9 which are inaccessible to 32-bit code - EAX/EBX are | |
| 50 | + * used instead). EBP+16 points to the arguments passed via the stack. | |
| 51 | + * | |
| 52 | + * The first argument (EDI) is a pointer to the boot service or protocol, to | |
| 53 | + * which the remaining arguments are passed, each truncated to 32 bits. | |
| 54 | + */ | |
| 55 | +SYM_FUNC_START_LOCAL(efi_enter32) | |
| 56 | + /* | |
| 57 | + * Convert x86-64 SysV ABI params to i386 ABI | |
| 58 | + */ | |
| 59 | + pushl 32(%ebp) /* Up to 3 args passed via the stack */ | |
| 60 | + pushl 24(%ebp) | |
| 61 | + pushl 16(%ebp) | |
| 62 | + pushl %ebx /* R9 */ | |
| 63 | + pushl %eax /* R8 */ | |
| 64 | + pushl %ecx | |
| 65 | + pushl %edx | |
| 66 | + pushl %esi | |
| 67 | + | |
| 68 | + /* Disable paging */ | |
| 69 | + movl %cr0, %eax | |
| 70 | + btrl $X86_CR0_PG_BIT, %eax | |
| 71 | + movl %eax, %cr0 | |
| 72 | + | |
| 73 | + /* Disable long mode via EFER */ | |
| 74 | + movl $MSR_EFER, %ecx | |
| 75 | + rdmsr | |
| 76 | + btrl $_EFER_LME, %eax | |
| 77 | + wrmsr | |
| 78 | + | |
| 79 | + call *%edi | |
| 80 | + | |
| 81 | + /* We must preserve return value */ | |
| 82 | + movl %eax, %edi | |
| 83 | + | |
| 84 | + call efi32_enable_long_mode | |
| 85 | + | |
| 86 | + addl $32, %esp | |
| 87 | + movl %edi, %eax | |
| 88 | + lret | |
| 89 | +SYM_FUNC_END(efi_enter32) | |
| 90 | + | |
| 91 | + .code64 | |
| 92 | +SYM_FUNC_START(__efi64_thunk) | |
| 93 | + push %rbp | |
| 94 | + movl %esp, %ebp | |
| 95 | + push %rbx | |
| 96 | + | |
| 97 | + /* Move args #5 and #6 into 32-bit accessible registers */ | |
| 98 | + movl %r8d, %eax | |
| 99 | + movl %r9d, %ebx | |
| 100 | + | |
| 101 | + lcalll *efi32_call(%rip) | |
| 102 | + | |
| 103 | + pop %rbx | |
| 104 | + pop %rbp | |
| 105 | + RET | |
| 106 | +SYM_FUNC_END(__efi64_thunk) | |
| 107 | + | |
| 108 | + .code32 | |
| 109 | +SYM_FUNC_START_LOCAL(efi32_enable_long_mode) | |
| 110 | + movl %cr4, %eax | |
| 111 | + btsl $(X86_CR4_PAE_BIT), %eax | |
| 112 | + movl %eax, %cr4 | |
| 113 | + | |
| 114 | + movl $MSR_EFER, %ecx | |
| 115 | + rdmsr | |
| 116 | + btsl $_EFER_LME, %eax | |
| 117 | + wrmsr | |
| 118 | + | |
| 119 | + /* Disable interrupts - the firmware's IDT does not work in long mode */ | |
| 120 | + cli | |
| 121 | + | |
| 122 | + /* Enable paging */ | |
| 123 | + movl %cr0, %eax | |
| 124 | + btsl $X86_CR0_PG_BIT, %eax | |
| 125 | + movl %eax, %cr0 | |
| 126 | + ret | |
| 127 | +SYM_FUNC_END(efi32_enable_long_mode) | |
| 128 | + | |
| 129 | +/* | |
| 130 | + * This is the common EFI stub entry point for mixed mode. It sets up the GDT | |
| 131 | + * and page tables needed for 64-bit execution, after which it calls the | |
| 132 | + * common 64-bit EFI entrypoint efi_stub_entry(). | |
| 133 | + * | |
| 134 | + * Arguments: 0(%esp) image handle | |
| 135 | + * 4(%esp) EFI system table pointer | |
| 136 | + * %ebx struct boot_params pointer (or NULL) | |
| 137 | + * | |
| 138 | + * Since this is the point of no return for ordinary execution, no registers | |
| 139 | + * are considered live except for the function parameters. [Note that the EFI | |
| 140 | + * stub may still exit and return to the firmware using the Exit() EFI boot | |
| 141 | + * service.] | |
| 142 | + */ | |
| 143 | +SYM_FUNC_START_LOCAL(efi32_startup) | |
| 144 | + movl %esp, %ebp | |
| 145 | + | |
| 146 | + subl $8, %esp | |
| 147 | + sgdtl (%esp) /* Save GDT descriptor to the stack */ | |
| 148 | + movl 2(%esp), %esi /* Existing GDT pointer */ | |
| 149 | + movzwl (%esp), %ecx /* Existing GDT limit */ | |
| 150 | + inc %ecx /* Existing GDT size */ | |
| 151 | + andl $~7, %ecx /* Ensure size is multiple of 8 */ | |
| 152 | + | |
| 153 | + subl %ecx, %esp /* Allocate new GDT */ | |
| 154 | + andl $~15, %esp /* Realign the stack */ | |
| 155 | + movl %esp, %edi /* New GDT address */ | |
| 156 | + leal 7(%ecx), %eax /* New GDT limit */ | |
| 157 | + pushw %cx /* Push 64-bit CS (for LJMP below) */ | |
| 158 | + pushl %edi /* Push new GDT address */ | |
| 159 | + pushw %ax /* Push new GDT limit */ | |
| 160 | + | |
| 161 | + /* Copy GDT to the stack and add a 64-bit code segment at the end */ | |
| 162 | + movl $GDT_ENTRY(DESC_CODE64, 0, 0xfffff) & 0xffffffff, (%edi,%ecx) | |
| 163 | + movl $GDT_ENTRY(DESC_CODE64, 0, 0xfffff) >> 32, 4(%edi,%ecx) | |
| 164 | + shrl $2, %ecx | |
| 165 | + cld | |
| 166 | + rep movsl /* Copy the firmware GDT */ | |
| 167 | + lgdtl (%esp) /* Switch to the new GDT */ | |
| 168 | + | |
| 169 | + call 1f | |
| 170 | +1: pop %edi | |
| 171 | + | |
| 172 | + /* Record mixed mode entry */ | |
| 173 | + movb $0x0, (efi_is64 - 1b)(%edi) | |
| 174 | + | |
| 175 | + /* Set up indirect far call to re-enter 32-bit mode */ | |
| 176 | + leal (efi32_call - 1b)(%edi), %eax | |
| 177 | + addl %eax, (%eax) | |
| 178 | + movw %cs, 4(%eax) | |
| 179 | + | |
| 180 | + /* Disable paging */ | |
| 181 | + movl %cr0, %eax | |
| 182 | + btrl $X86_CR0_PG_BIT, %eax | |
| 183 | + movl %eax, %cr0 | |
| 184 | + | |
| 185 | + /* Set up 1:1 mapping */ | |
| 186 | + leal (pte - 1b)(%edi), %eax | |
| 187 | + movl $_PAGE_PRESENT | _PAGE_RW | _PAGE_PSE, %ecx | |
| 188 | + leal (_PAGE_PRESENT | _PAGE_RW)(%eax), %edx | |
| 189 | +2: movl %ecx, (%eax) | |
| 190 | + addl $8, %eax | |
| 191 | + addl $PMD_SIZE, %ecx | |
| 192 | + jnc 2b | |
| 193 | + | |
| 194 | + movl $PAGE_SIZE, %ecx | |
| 195 | + .irpc l, 0123 | |
| 196 | + movl %edx, \l * 8(%eax) | |
| 197 | + addl %ecx, %edx | |
| 198 | + .endr | |
| 199 | + addl %ecx, %eax | |
| 200 | + movl %edx, (%eax) | |
| 201 | + movl %eax, %cr3 | |
| 202 | + | |
| 203 | + call efi32_enable_long_mode | |
| 204 | + | |
| 205 | + /* Set up far jump to 64-bit mode (CS is already on the stack) */ | |
| 206 | + leal (efi_stub_entry - 1b)(%edi), %eax | |
| 207 | + movl %eax, 2(%esp) | |
| 208 | + | |
| 209 | + movl 0(%ebp), %edi | |
| 210 | + movl 4(%ebp), %esi | |
| 211 | + movl %ebx, %edx | |
| 212 | + ljmpl *2(%esp) | |
| 213 | +SYM_FUNC_END(efi32_startup) | |
| 214 | + | |
| 215 | +/* | |
| 216 | + * efi_status_t efi32_pe_entry(efi_handle_t image_handle, | |
| 217 | + * efi_system_table_32_t *sys_table) | |
| 218 | + */ | |
| 219 | +SYM_FUNC_START(efi32_pe_entry) | |
| 220 | + pushl %ebx // save callee-save registers | |
| 221 | + | |
| 222 | + /* Check whether the CPU supports long mode */ | |
| 223 | + movl $0x80000001, %eax // assume extended info support | |
| 224 | + cpuid | |
| 225 | + btl $29, %edx // check long mode bit | |
| 226 | + jnc 1f | |
| 227 | + leal 8(%esp), %esp // preserve stack alignment | |
| 228 | + xor %ebx, %ebx // no struct boot_params pointer | |
| 229 | + jmp efi32_startup // only ESP and EBX remain live | |
| 230 | +1: movl $0x80000003, %eax // EFI_UNSUPPORTED | |
| 231 | + popl %ebx | |
| 232 | + RET | |
| 233 | +SYM_FUNC_END(efi32_pe_entry) | |
| 234 | + | |
| 235 | +#ifdef CONFIG_EFI_HANDOVER_PROTOCOL | |
| 236 | + .org efi32_stub_entry + 0x200 | |
| 237 | + .code64 | |
| 238 | +SYM_FUNC_START_NOALIGN(efi64_stub_entry) | |
| 239 | + jmp efi_handover_entry | |
| 240 | +SYM_FUNC_END(efi64_stub_entry) | |
| 241 | +#endif | |
| 242 | + | |
| 243 | + .data | |
| 244 | + .balign 8 | |
| 245 | +SYM_DATA_START_LOCAL(efi32_call) | |
| 246 | + .long efi_enter32 - . | |
| 247 | + .word 0x0 | |
| 248 | +SYM_DATA_END(efi32_call) | |
| 249 | +SYM_DATA(efi_is64, .byte 1) | |
| 250 | + | |
| 251 | + .bss | |
| 252 | + .balign PAGE_SIZE | |
| 253 | +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) · 396 unmodified lines | ||
| 397 | 397 | asm("hlt"); |
| 398 | 398 | } |
| 399 | 399 | |
| 400 | −void __noreturn efi_stub_entry(efi_handle_t handle, | |
| 401 | − efi_system_table_t *sys_table_arg, | |
| 402 | − struct boot_params *boot_params); | |
| 403 | − | |
| 404 | 400 | /* |
| 405 | 401 | * Because the x86 boot code expects to be passed a boot_params we |
| 406 | 402 | * need to create one ourselves (usually the bootloader would create |
| 407 | 403 | * one for us). |
| 408 | 404 | */ |
| 409 | −efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, | |
| 410 | − efi_system_table_t *sys_table_arg) | |
| 405 | +static efi_status_t efi_allocate_bootparams(efi_handle_t handle, | |
| 406 | + struct boot_params **bp) | |
| 411 | 407 | { |
| 412 | 408 | efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; |
| 413 | 409 | struct boot_params *boot_params; |
| @@ -416,21 +412,15 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, · 2 unmodified lines | ||
| 416 | 412 | unsigned long alloc; |
| 417 | 413 | char *cmdline_ptr; |
| 418 | 414 | |
| 419 | − efi_system_table = sys_table_arg; | |
| 420 | − | |
| 421 | − /* Check if we were booted by the EFI firmware */ | |
| 422 | − if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) | |
| 423 | − efi_exit(handle, EFI_INVALID_PARAMETER); | |
| 424 | − | |
| 425 | 415 | status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image); |
| 426 | 416 | if (status != EFI_SUCCESS) { |
| 427 | 417 | efi_err("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); |
| 428 | − efi_exit(handle, status); | |
| 418 | + return status; | |
| 429 | 419 | } |
| 430 | 420 | |
| 431 | 421 | status = efi_allocate_pages(PARAM_SIZE, &alloc, ULONG_MAX); |
| 432 | 422 | if (status != EFI_SUCCESS) |
| 433 | − efi_exit(handle, status); | |
| 423 | + return status; | |
| 434 | 424 | |
| 435 | 425 | boot_params = memset((void *)alloc, 0x0, PARAM_SIZE); |
| 436 | 426 | hdr = &boot_params->hdr; |
| @@ -446,14 +436,14 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, · 9 unmodified lines | ||
| 446 | 436 | cmdline_ptr = efi_convert_cmdline(image); |
| 447 | 437 | if (!cmdline_ptr) { |
| 448 | 438 | efi_free(PARAM_SIZE, alloc); |
| 449 | − efi_exit(handle, EFI_OUT_OF_RESOURCES); | |
| 439 | + return EFI_OUT_OF_RESOURCES; | |
| 450 | 440 | } |
| 451 | 441 | |
| 452 | 442 | efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr, |
| 453 | 443 | &boot_params->ext_cmd_line_ptr); |
| 454 | 444 | |
| 455 | − efi_stub_entry(handle, sys_table_arg, boot_params); | |
| 456 | − /* not reached */ | |
| 445 | + *bp = boot_params; | |
| 446 | + return EFI_SUCCESS; | |
| 457 | 447 | } |
| 458 | 448 | |
| 459 | 449 | static void add_e820ext(struct boot_params *params, |
| @@ -740,13 +730,16 @@ static efi_status_t parse_options(const char *cmdline) · 280 unmodified lines | ||
| 740 | 730 | return efi_parse_options(cmdline); |
| 741 | 731 | } |
| 742 | 732 | |
| 743 | −static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) | |
| 733 | +static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry, | |
| 734 | + struct boot_params *boot_params) | |
| 744 | 735 | { |
| 745 | 736 | unsigned long virt_addr = LOAD_PHYSICAL_ADDR; |
| 746 | 737 | unsigned long addr, alloc_size, entry; |
| 747 | 738 | efi_status_t status; |
| 748 | 739 | u32 seed[2] = {}; |
| 749 | 740 | |
| 741 | + boot_params_ptr = boot_params; | |
| 742 | + | |
| 750 | 743 | /* determine the required size of the allocation */ |
| 751 | 744 | alloc_size = ALIGN(max_t(unsigned long, output_len, kernel_total_size), |
| 752 | 745 | MIN_KERNEL_ALIGN); |
| @@ -777,7 +770,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) · 24 unmodified lines | ||
| 777 | 770 | seed[0] = 0; |
| 778 | 771 | } |
| 779 | 772 | |
| 780 | − boot_params_ptr->hdr.loadflags |= KASLR_FLAG; | |
| 773 | + boot_params->hdr.loadflags |= KASLR_FLAG; | |
| 781 | 774 | } |
| 782 | 775 | |
| 783 | 776 | status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr, |
| @@ -815,20 +808,27 @@ static void __noreturn enter_kernel(unsigned long kernel_addr, · 31 unmodified lines | ||
| 815 | 808 | void __noreturn efi_stub_entry(efi_handle_t handle, |
| 816 | 809 | efi_system_table_t *sys_table_arg, |
| 817 | 810 | struct boot_params *boot_params) |
| 811 | + | |
| 818 | 812 | { |
| 819 | 813 | efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; |
| 820 | − struct setup_header *hdr = &boot_params->hdr; | |
| 821 | 814 | const struct linux_efi_initrd *initrd = NULL; |
| 822 | 815 | unsigned long kernel_entry; |
| 816 | + struct setup_header *hdr; | |
| 823 | 817 | efi_status_t status; |
| 824 | 818 | |
| 825 | − boot_params_ptr = boot_params; | |
| 826 | − | |
| 827 | 819 | efi_system_table = sys_table_arg; |
| 828 | 820 | /* Check if we were booted by the EFI firmware */ |
| 829 | 821 | if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) |
| 830 | 822 | efi_exit(handle, EFI_INVALID_PARAMETER); |
| 831 | 823 | |
| 824 | + if (!IS_ENABLED(CONFIG_EFI_HANDOVER_PROTOCOL) || !boot_params) { | |
| 825 | + status = efi_allocate_bootparams(handle, &boot_params); | |
| 826 | + if (status != EFI_SUCCESS) | |
| 827 | + efi_exit(handle, status); | |
| 828 | + } | |
| 829 | + | |
| 830 | + hdr = &boot_params->hdr; | |
| 831 | + | |
| 832 | 832 | if (have_unsupported_snp_features()) |
| 833 | 833 | efi_exit(handle, EFI_UNSUPPORTED); |
| 834 | 834 | |
| @@ -870,7 +870,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, · 35 unmodified lines | ||
| 870 | 870 | if (efi_mem_encrypt > 0) |
| 871 | 871 | hdr->xloadflags |= XLF_MEM_ENCRYPTION; |
| 872 | 872 | |
| 873 | − status = efi_decompress_kernel(&kernel_entry); | |
| 873 | + status = efi_decompress_kernel(&kernel_entry, boot_params); | |
| 874 | 874 | if (status != EFI_SUCCESS) { |
| 875 | 875 | efi_err("Failed to decompress kernel\n"); |
| 876 | 876 | goto fail; |
| @@ -940,6 +940,12 @@ fail: · 63 unmodified lines | ||
| 940 | 940 | efi_exit(handle, status); |
| 941 | 941 | } |
| 942 | 942 | |
| 943 | +efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, | |
| 944 | + efi_system_table_t *sys_table_arg) | |
| 945 | +{ | |
| 946 | + efi_stub_entry(handle, sys_table_arg, NULL); | |
| 947 | +} | |
| 948 | + | |
| 943 | 949 | #ifdef CONFIG_EFI_HANDOVER_PROTOCOL |
| 944 | 950 | void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg, |
| 945 | 951 | struct boot_params *boot_params) |
| @@ -0,0 +1,68 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +#include <linux/efi.h> | |
| 4 | +#include <linux/zlib.h> | |
| 5 | + | |
| 6 | +#include <asm/efi.h> | |
| 7 | + | |
| 8 | +#include "efistub.h" | |
| 9 | + | |
| 10 | +#include "inftrees.c" | |
| 11 | +#include "inffast.c" | |
| 12 | +#include "inflate.c" | |
| 13 | + | |
| 14 | +extern unsigned char _gzdata_start[], _gzdata_end[]; | |
| 15 | +extern u32 __aligned(1) payload_size; | |
| 16 | + | |
| 17 | +static struct z_stream_s stream; | |
| 18 | + | |
| 19 | +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) | |
| 20 | +{ | |
| 21 | + efi_status_t status; | |
| 22 | + int rc; | |
| 23 | + | |
| 24 | + /* skip the 10 byte header, assume no recorded filename */ | |
| 25 | + stream.next_in = _gzdata_start + 10; | |
| 26 | + stream.avail_in = _gzdata_end - stream.next_in; | |
| 27 | + | |
| 28 | + status = efi_allocate_pages(zlib_inflate_workspacesize(), | |
| 29 | + (unsigned long *)&stream.workspace, | |
| 30 | + ULONG_MAX); | |
| 31 | + if (status != EFI_SUCCESS) | |
| 32 | + return status; | |
| 33 | + | |
| 34 | + rc = zlib_inflateInit2(&stream, -MAX_WBITS); | |
| 35 | + if (rc != Z_OK) { | |
| 36 | + efi_err("failed to initialize GZIP decompressor: %d\n", rc); | |
| 37 | + status = EFI_LOAD_ERROR; | |
| 38 | + goto out; | |
| 39 | + } | |
| 40 | + | |
| 41 | + *alloc_size = payload_size; | |
| 42 | + return EFI_SUCCESS; | |
| 43 | +out: | |
| 44 | + efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace); | |
| 45 | + return status; | |
| 46 | +} | |
| 47 | + | |
| 48 | +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) | |
| 49 | +{ | |
| 50 | + int rc; | |
| 51 | + | |
| 52 | + stream.next_out = out; | |
| 53 | + stream.avail_out = outlen; | |
| 54 | + | |
| 55 | + rc = zlib_inflate(&stream, 0); | |
| 56 | + zlib_inflateEnd(&stream); | |
| 57 | + | |
| 58 | + efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace); | |
| 59 | + | |
| 60 | + if (rc != Z_STREAM_END) { | |
| 61 | + efi_err("GZIP decompression failed with status %d\n", rc); | |
| 62 | + return EFI_LOAD_ERROR; | |
| 63 | + } | |
| 64 | + | |
| 65 | + efi_cache_sync_image((unsigned long)out, outlen); | |
| 66 | + | |
| 67 | + return EFI_SUCCESS; | |
| 68 | +} | |
| @@ -0,0 +1,49 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +#include <linux/efi.h> | |
| 4 | +#include <linux/zstd.h> | |
| 5 | + | |
| 6 | +#include <asm/efi.h> | |
| 7 | + | |
| 8 | +#include "decompress_sources.h" | |
| 9 | +#include "efistub.h" | |
| 10 | + | |
| 11 | +extern unsigned char _gzdata_start[], _gzdata_end[]; | |
| 12 | +extern u32 __aligned(1) payload_size; | |
| 13 | + | |
| 14 | +static size_t wksp_size; | |
| 15 | +static void *wksp; | |
| 16 | + | |
| 17 | +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) | |
| 18 | +{ | |
| 19 | + efi_status_t status; | |
| 20 | + | |
| 21 | + wksp_size = zstd_dctx_workspace_bound(); | |
| 22 | + status = efi_allocate_pages(wksp_size, (unsigned long *)&wksp, ULONG_MAX); | |
| 23 | + if (status != EFI_SUCCESS) | |
| 24 | + return status; | |
| 25 | + | |
| 26 | + *alloc_size = payload_size; | |
| 27 | + return EFI_SUCCESS; | |
| 28 | +} | |
| 29 | + | |
| 30 | +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) | |
| 31 | +{ | |
| 32 | + zstd_dctx *dctx = zstd_init_dctx(wksp, wksp_size); | |
| 33 | + size_t ret; | |
| 34 | + int retval; | |
| 35 | + | |
| 36 | + ret = zstd_decompress_dctx(dctx, out, outlen, _gzdata_start, | |
| 37 | + _gzdata_end - _gzdata_start - 4); | |
| 38 | + efi_free(wksp_size, (unsigned long)wksp); | |
| 39 | + | |
| 40 | + retval = zstd_get_error_code(ret); | |
| 41 | + if (retval) { | |
| 42 | + efi_err("ZSTD-decompression failed with status %d\n", retval); | |
| 43 | + return EFI_LOAD_ERROR; | |
| 44 | + } | |
| 45 | + | |
| 46 | + efi_cache_sync_image((unsigned long)out, outlen); | |
| 47 | + | |
| 48 | + return EFI_SUCCESS; | |
| 49 | +} | |
| @@ -7,36 +7,6 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | #include "efistub.h" |
| 9 | 9 | |
| 10 | −static unsigned char zboot_heap[SZ_256K] __aligned(64); | |
| 11 | −static unsigned long free_mem_ptr, free_mem_end_ptr; | |
| 12 | − | |
| 13 | −#define STATIC static | |
| 14 | −#if defined(CONFIG_KERNEL_GZIP) | |
| 15 | −#include "../../../../lib/decompress_inflate.c" | |
| 16 | −#elif defined(CONFIG_KERNEL_LZ4) | |
| 17 | −#include "../../../../lib/decompress_unlz4.c" | |
| 18 | −#elif defined(CONFIG_KERNEL_LZMA) | |
| 19 | −#include "../../../../lib/decompress_unlzma.c" | |
| 20 | −#elif defined(CONFIG_KERNEL_LZO) | |
| 21 | −#include "../../../../lib/decompress_unlzo.c" | |
| 22 | −#elif defined(CONFIG_KERNEL_XZ) | |
| 23 | −#undef memcpy | |
| 24 | −#define memcpy memcpy | |
| 25 | −#undef memmove | |
| 26 | −#define memmove memmove | |
| 27 | −#include "../../../../lib/decompress_unxz.c" | |
| 28 | −#elif defined(CONFIG_KERNEL_ZSTD) | |
| 29 | −#include "../../../../lib/decompress_unzstd.c" | |
| 30 | −#endif | |
| 31 | − | |
| 32 | −extern char efi_zboot_header[]; | |
| 33 | −extern char _gzdata_start[], _gzdata_end[]; | |
| 34 | − | |
| 35 | −static void error(char *x) | |
| 36 | −{ | |
| 37 | − efi_err("EFI decompressor: %s\n", x); | |
| 38 | −} | |
| 39 | − | |
| 40 | 10 | static unsigned long alloc_preferred_address(unsigned long alloc_size) |
| 41 | 11 | { |
| 42 | 12 | #ifdef EFI_KIMG_PREFERRED_ADDRESS |
| @@ -64,22 +34,17 @@ struct screen_info *alloc_screen_info(void) · 21 unmodified lines | ||
| 64 | 34 | asmlinkage efi_status_t __efiapi |
| 65 | 35 | efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) |
| 66 | 36 | { |
| 67 | − unsigned long compressed_size = _gzdata_end - _gzdata_start; | |
| 37 | + char *cmdline_ptr __free(efi_pool) = NULL; | |
| 68 | 38 | unsigned long image_base, alloc_size; |
| 69 | 39 | efi_loaded_image_t *image; |
| 70 | 40 | efi_status_t status; |
| 71 | − char *cmdline_ptr; | |
| 72 | − int ret; | |
| 73 | 41 | |
| 74 | 42 | WRITE_ONCE(efi_system_table, systab); |
| 75 | 43 | |
| 76 | − free_mem_ptr = (unsigned long)&zboot_heap; | |
| 77 | − free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap); | |
| 78 | − | |
| 79 | 44 | status = efi_bs_call(handle_protocol, handle, |
| 80 | 45 | &LOADED_IMAGE_PROTOCOL_GUID, (void **)&image); |
| 81 | 46 | if (status != EFI_SUCCESS) { |
| 82 | − error("Failed to locate parent's loaded image protocol"); | |
| 47 | + efi_err("Failed to locate parent's loaded image protocol\n"); | |
| 83 | 48 | return status; |
| 84 | 49 | } |
| 85 | 50 | |
| @@ -89,9 +54,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) · 3 unmodified lines | ||
| 89 | 54 | |
| 90 | 55 | efi_info("Decompressing Linux Kernel...\n"); |
| 91 | 56 | |
| 92 | − // SizeOfImage from the compressee's PE/COFF header | |
| 93 | − alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4), | |
| 94 | − EFI_ALLOC_ALIGN); | |
| 57 | + status = efi_zboot_decompress_init(&alloc_size); | |
| 58 | + if (status != EFI_SUCCESS) | |
| 59 | + return status; | |
| 95 | 60 | |
| 96 | 61 | // If the architecture has a preferred address for the image, |
| 97 | 62 | // try that first. |
| @@ -122,26 +87,14 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) · 24 unmodified lines | ||
| 122 | 87 | seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT); |
| 123 | 88 | if (status != EFI_SUCCESS) { |
| 124 | 89 | efi_err("Failed to allocate memory\n"); |
| 125 | − goto free_cmdline; | |
| 90 | + return status; | |
| 126 | 91 | } |
| 127 | 92 | } |
| 128 | 93 | |
| 129 | − // Decompress the payload into the newly allocated buffer. | |
| 130 | − ret = __decompress(_gzdata_start, compressed_size, NULL, NULL, | |
| 131 | − (void *)image_base, alloc_size, NULL, error); | |
| 132 | − if (ret < 0) { | |
| 133 | − error("Decompression failed"); | |
| 134 | − status = EFI_DEVICE_ERROR; | |
| 135 | − goto free_image; | |
| 136 | − } | |
| 137 | − | |
| 138 | − efi_cache_sync_image(image_base, alloc_size); | |
| 139 | − | |
| 140 | − status = efi_stub_common(handle, image, image_base, cmdline_ptr); | |
| 94 | + // Decompress the payload into the newly allocated buffer | |
| 95 | + status = efi_zboot_decompress((void *)image_base, alloc_size) ?: | |
| 96 | + efi_stub_common(handle, image, image_base, cmdline_ptr); | |
| 141 | 97 | |
| 142 | −free_image: | |
| 143 | 98 | efi_free(alloc_size, image_base); |
| 144 | −free_cmdline: | |
| 145 | − efi_bs_call(free_pool, cmdline_ptr); | |
| 146 | 99 | return status; |
| 147 | 100 | } |
| @@ -17,6 +17,7 @@ SECTIONS · 16 unmodified lines | ||
| 17 | 17 | .rodata : ALIGN(8) { |
| 18 | 18 | __efistub__gzdata_start = .; |
| 19 | 19 | *(.gzdata) |
| 20 | + __efistub_payload_size = . - 4; | |
| 20 | 21 | __efistub__gzdata_end = .; |
| 21 | 22 | *(.rodata* .init.rodata* .srodata*) |
| 22 | 23 | |
| @@ -57,11 +57,10 @@ static ssize_t efivarfs_file_write(struct file *file, · 56 unmodified lines | ||
| 57 | 57 | |
| 58 | 58 | if (bytes == -ENOENT) { |
| 59 | 59 | /* |
| 60 | − * FIXME: temporary workaround for fwupdate, signal | |
| 61 | − * failed write with a 1 to keep created but not | |
| 62 | − * written files | |
| 60 | + * zero size signals to release that the write deleted | |
| 61 | + * the variable | |
| 63 | 62 | */ |
| 64 | − i_size_write(inode, 1); | |
| 63 | + i_size_write(inode, 0); | |
| 65 | 64 | } else { |
| 66 | 65 | i_size_write(inode, datasize + sizeof(attributes)); |
| 67 | 66 | 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) · 57 unmodified lines | ||
| 125 | 124 | struct efivar_entry *var = inode->i_private; |
| 126 | 125 | |
| 127 | 126 | inode_lock(inode); |
| 128 | − /* FIXME: temporary work around for fwupdate */ | |
| 129 | − var->removed = (--var->open_count == 0 && i_size_read(inode) == 1); | |
| 127 | + var->removed = (--var->open_count == 0 && i_size_read(inode) == 0); | |
| 130 | 128 | inode_unlock(inode); |
| 131 | 129 | |
| 132 | 130 | if (var->removed) |