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 | vmlinux-objs-$(CONFIG_UNACCEPTED_MEMORY) += $(obj)/mem.o | 106 | vmlinux-objs-$(CONFIG_UNACCEPTED_MEMORY) += $(obj)/mem.o |
| 107 | 107 | ||
| 108 | vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o | 108 | vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o |
| 109 | vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o | ||
| 110 | vmlinux-libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a | 109 | vmlinux-libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a |
| 111 | 110 | ||
| 112 | $(obj)/vmlinux: $(vmlinux-objs-y) $(vmlinux-libs-y) FORCE | 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 | * used to perform that far jump. | 263 | * used to perform that far jump. |
| 264 | */ | 264 | */ |
| 265 | leal rva(startup_64)(%ebp), %eax | 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 | pushl $__KERNEL_CS | 266 | pushl $__KERNEL_CS |
| 274 | pushl %eax | 267 | pushl %eax |
| 275 | 268 | ||
| @@ -47,7 +47,7 @@ static int efibc_reboot_notifier_call(struct notifier_block *notifier, · 46 unmodified lines | |||
| 47 | if (ret || !data) | 47 | if (ret || !data) |
| 48 | return NOTIFY_DONE; | 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 | if (!wdata) | 51 | if (!wdata) |
| 52 | return NOTIFY_DONE; | 52 | return NOTIFY_DONE; |
| 53 | 53 | ||
| @@ -62,6 +62,8 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS)) · 61 unmodified lines | |||
| 62 | # `-fdata-sections` flag from KBUILD_CFLAGS_KERNEL | 62 | # `-fdata-sections` flag from KBUILD_CFLAGS_KERNEL |
| 63 | KBUILD_CFLAGS_KERNEL := $(filter-out -fdata-sections, $(KBUILD_CFLAGS_KERNEL)) | 63 | KBUILD_CFLAGS_KERNEL := $(filter-out -fdata-sections, $(KBUILD_CFLAGS_KERNEL)) |
| 64 | 64 | ||
| 65 | KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ | ||
| 66 | |||
| 65 | lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ | 67 | lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ |
| 66 | file.o mem.o random.o randomalloc.o pci.o \ | 68 | file.o mem.o random.o randomalloc.o pci.o \ |
| 67 | skip_spaces.o lib-cmdline.o lib-ctype.o \ | 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 | lib-$(CONFIG_ARM) += arm32-stub.o | 85 | lib-$(CONFIG_ARM) += arm32-stub.o |
| 84 | lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o | 86 | lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o |
| 85 | lib-$(CONFIG_X86) += x86-stub.o smbios.o | 87 | lib-$(CONFIG_X86) += x86-stub.o smbios.o |
| 88 | lib-$(CONFIG_EFI_MIXED) += x86-mixed.o | ||
| 86 | lib-$(CONFIG_X86_64) += x86-5lvl.o | 89 | lib-$(CONFIG_X86_64) += x86-5lvl.o |
| 87 | lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o | 90 | lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o |
| 88 | lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o | 91 | lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o |
| 89 | 92 | ||
| 90 | CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | 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 | lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) | 101 | lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) |
| 94 | 102 | ||
| 95 | lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o | 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 | void accept_memory(phys_addr_t start, unsigned long size); | 1234 | void accept_memory(phys_addr_t start, unsigned long size); |
| 1235 | void arch_accept_memory(phys_addr_t start, phys_addr_t end); | 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 | #endif | 1240 | #endif |
| @@ -15,8 +15,31 @@ void *__memmove(void *__dest, const void *__src, size_t count) __alias(memmove); · 14 unmodified lines | |||
| 15 | void *__memset(void *s, int c, size_t count) __alias(memset); | 15 | void *__memset(void *s, int c, size_t count) __alias(memset); |
| 16 | #endif | 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 | void *memcpy(void *dst, const void *src, size_t len) | 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 | efi_bs_call(copy_mem, dst, src, len); | 43 | efi_bs_call(copy_mem, dst, src, len); |
| 21 | return dst; | 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 | void *memset(void *dst, int c, size_t len) | 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 | efi_bs_call(set_mem, dst, len, c & U8_MAX); | 54 | efi_bs_call(set_mem, dst, len, c & U8_MAX); |
| 29 | return dst; | 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 | asm("hlt"); | 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 | * Because the x86 boot code expects to be passed a boot_params we | 401 | * Because the x86 boot code expects to be passed a boot_params we |
| 406 | * need to create one ourselves (usually the bootloader would create | 402 | * need to create one ourselves (usually the bootloader would create |
| 407 | * one for us). | 403 | * one for us). |
| 408 | */ | 404 | */ |
| 409 | efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, | 405 | static efi_status_t efi_allocate_bootparams(efi_handle_t handle, |
| 410 | efi_system_table_t *sys_table_arg) | 406 | struct boot_params **bp) |
| 411 | { | 407 | { |
| 412 | efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; | 408 | efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; |
| 413 | struct boot_params *boot_params; | 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 | unsigned long alloc; | 412 | unsigned long alloc; |
| 417 | char *cmdline_ptr; | 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 | status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image); | 415 | status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image); |
| 426 | if (status != EFI_SUCCESS) { | 416 | if (status != EFI_SUCCESS) { |
| 427 | efi_err("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); | 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 | status = efi_allocate_pages(PARAM_SIZE, &alloc, ULONG_MAX); | 421 | status = efi_allocate_pages(PARAM_SIZE, &alloc, ULONG_MAX); |
| 432 | if (status != EFI_SUCCESS) | 422 | if (status != EFI_SUCCESS) |
| 433 | efi_exit(handle, status); | 423 | return status; |
| 434 | 424 | ||
| 435 | boot_params = memset((void *)alloc, 0x0, PARAM_SIZE); | 425 | boot_params = memset((void *)alloc, 0x0, PARAM_SIZE); |
| 436 | hdr = &boot_params->hdr; | 426 | hdr = &boot_params->hdr; |
| @@ -446,14 +436,14 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, · 9 unmodified lines | |||
| 446 | cmdline_ptr = efi_convert_cmdline(image); | 436 | cmdline_ptr = efi_convert_cmdline(image); |
| 447 | if (!cmdline_ptr) { | 437 | if (!cmdline_ptr) { |
| 448 | efi_free(PARAM_SIZE, alloc); | 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 | efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr, | 442 | efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr, |
| 453 | &boot_params->ext_cmd_line_ptr); | 443 | &boot_params->ext_cmd_line_ptr); |
| 454 | 444 | ||
| 455 | efi_stub_entry(handle, sys_table_arg, boot_params); | 445 | *bp = boot_params; |
| 456 | /* not reached */ | 446 | return EFI_SUCCESS; |
| 457 | } | 447 | } |
| 458 | 448 | ||
| 459 | static void add_e820ext(struct boot_params *params, | 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 | return efi_parse_options(cmdline); | 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 | unsigned long virt_addr = LOAD_PHYSICAL_ADDR; | 736 | unsigned long virt_addr = LOAD_PHYSICAL_ADDR; |
| 746 | unsigned long addr, alloc_size, entry; | 737 | unsigned long addr, alloc_size, entry; |
| 747 | efi_status_t status; | 738 | efi_status_t status; |
| 748 | u32 seed[2] = {}; | 739 | u32 seed[2] = {}; |
| 749 | 740 | ||
| 741 | boot_params_ptr = boot_params; | ||
| 742 | |||
| 750 | /* determine the required size of the allocation */ | 743 | /* determine the required size of the allocation */ |
| 751 | alloc_size = ALIGN(max_t(unsigned long, output_len, kernel_total_size), | 744 | alloc_size = ALIGN(max_t(unsigned long, output_len, kernel_total_size), |
| 752 | MIN_KERNEL_ALIGN); | 745 | MIN_KERNEL_ALIGN); |
| @@ -777,7 +770,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) · 24 unmodified lines | |||
| 777 | seed[0] = 0; | 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 | status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr, | 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 | void __noreturn efi_stub_entry(efi_handle_t handle, | 808 | void __noreturn efi_stub_entry(efi_handle_t handle, |
| 816 | efi_system_table_t *sys_table_arg, | 809 | efi_system_table_t *sys_table_arg, |
| 817 | struct boot_params *boot_params) | 810 | struct boot_params *boot_params) |
| 811 | |||
| 818 | { | 812 | { |
| 819 | efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; | 813 | efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; |
| 820 | struct setup_header *hdr = &boot_params->hdr; | ||
| 821 | const struct linux_efi_initrd *initrd = NULL; | 814 | const struct linux_efi_initrd *initrd = NULL; |
| 822 | unsigned long kernel_entry; | 815 | unsigned long kernel_entry; |
| 816 | struct setup_header *hdr; | ||
| 823 | efi_status_t status; | 817 | efi_status_t status; |
| 824 | 818 | ||
| 825 | boot_params_ptr = boot_params; | ||
| 826 | |||
| 827 | efi_system_table = sys_table_arg; | 819 | efi_system_table = sys_table_arg; |
| 828 | /* Check if we were booted by the EFI firmware */ | 820 | /* Check if we were booted by the EFI firmware */ |
| 829 | if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) | 821 | if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) |
| 830 | efi_exit(handle, EFI_INVALID_PARAMETER); | 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 | if (have_unsupported_snp_features()) | 832 | if (have_unsupported_snp_features()) |
| 833 | efi_exit(handle, EFI_UNSUPPORTED); | 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 | if (efi_mem_encrypt > 0) | 870 | if (efi_mem_encrypt > 0) |
| 871 | hdr->xloadflags |= XLF_MEM_ENCRYPTION; | 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 | if (status != EFI_SUCCESS) { | 874 | if (status != EFI_SUCCESS) { |
| 875 | efi_err("Failed to decompress kernel\n"); | 875 | efi_err("Failed to decompress kernel\n"); |
| 876 | goto fail; | 876 | goto fail; |
| @@ -940,6 +940,12 @@ fail: · 63 unmodified lines | |||
| 940 | efi_exit(handle, status); | 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 | #ifdef CONFIG_EFI_HANDOVER_PROTOCOL | 949 | #ifdef CONFIG_EFI_HANDOVER_PROTOCOL |
| 944 | void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg, | 950 | void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg, |
| 945 | struct boot_params *boot_params) | 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 | #include "efistub.h" | 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 | static unsigned long alloc_preferred_address(unsigned long alloc_size) | 10 | static unsigned long alloc_preferred_address(unsigned long alloc_size) |
| 41 | { | 11 | { |
| 42 | #ifdef EFI_KIMG_PREFERRED_ADDRESS | 12 | #ifdef EFI_KIMG_PREFERRED_ADDRESS |
| @@ -64,22 +34,17 @@ struct screen_info *alloc_screen_info(void) · 21 unmodified lines | |||
| 64 | asmlinkage efi_status_t __efiapi | 34 | asmlinkage efi_status_t __efiapi |
| 65 | efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) | 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 | unsigned long image_base, alloc_size; | 38 | unsigned long image_base, alloc_size; |
| 69 | efi_loaded_image_t *image; | 39 | efi_loaded_image_t *image; |
| 70 | efi_status_t status; | 40 | efi_status_t status; |
| 71 | char *cmdline_ptr; | ||
| 72 | int ret; | ||
| 73 | 41 | ||
| 74 | WRITE_ONCE(efi_system_table, systab); | 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 | status = efi_bs_call(handle_protocol, handle, | 44 | status = efi_bs_call(handle_protocol, handle, |
| 80 | &LOADED_IMAGE_PROTOCOL_GUID, (void **)&image); | 45 | &LOADED_IMAGE_PROTOCOL_GUID, (void **)&image); |
| 81 | if (status != EFI_SUCCESS) { | 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 | return status; | 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 | efi_info("Decompressing Linux Kernel...\n"); | 55 | efi_info("Decompressing Linux Kernel...\n"); |
| 91 | 56 | ||
| 92 | // SizeOfImage from the compressee's PE/COFF header | 57 | status = efi_zboot_decompress_init(&alloc_size); |
| 93 | alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4), | 58 | if (status != EFI_SUCCESS) |
| 94 | EFI_ALLOC_ALIGN); | 59 | return status; |
| 95 | 60 | ||
| 96 | // If the architecture has a preferred address for the image, | 61 | // If the architecture has a preferred address for the image, |
| 97 | // try that first. | 62 | // try that first. |
| @@ -122,26 +87,14 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) · 24 unmodified lines | |||
| 122 | seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT); | 87 | seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT); |
| 123 | if (status != EFI_SUCCESS) { | 88 | if (status != EFI_SUCCESS) { |
| 124 | efi_err("Failed to allocate memory\n"); | 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. | 94 | // Decompress the payload into the newly allocated buffer |
| 130 | ret = __decompress(_gzdata_start, compressed_size, NULL, NULL, | 95 | status = efi_zboot_decompress((void *)image_base, alloc_size) ?: |
| 131 | (void *)image_base, alloc_size, NULL, error); | 96 | efi_stub_common(handle, image, image_base, cmdline_ptr); |
| 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); | ||
| 141 | 97 | ||
| 142 | free_image: | ||
| 143 | efi_free(alloc_size, image_base); | 98 | efi_free(alloc_size, image_base); |
| 144 | free_cmdline: | ||
| 145 | efi_bs_call(free_pool, cmdline_ptr); | ||
| 146 | return status; | 99 | return status; |
| 147 | } | 100 | } |
| @@ -17,6 +17,7 @@ SECTIONS · 16 unmodified lines | |||
| 17 | .rodata : ALIGN(8) { | 17 | .rodata : ALIGN(8) { |
| 18 | __efistub__gzdata_start = .; | 18 | __efistub__gzdata_start = .; |
| 19 | *(.gzdata) | 19 | *(.gzdata) |
| 20 | __efistub_payload_size = . - 4; | ||
| 20 | __efistub__gzdata_end = .; | 21 | __efistub__gzdata_end = .; |
| 21 | *(.rodata* .init.rodata* .srodata*) | 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 | if (bytes == -ENOENT) { | 58 | if (bytes == -ENOENT) { |
| 59 | /* | 59 | /* |
| 60 | * FIXME: temporary workaround for fwupdate, signal | 60 | * zero size signals to release that the write deleted |
| 61 | * failed write with a 1 to keep created but not | 61 | * the variable |
| 62 | * written files | ||
| 63 | */ | 62 | */ |
| 64 | i_size_write(inode, 1); | 63 | i_size_write(inode, 0); |
| 65 | } else { | 64 | } else { |
| 66 | i_size_write(inode, datasize + sizeof(attributes)); | 65 | i_size_write(inode, datasize + sizeof(attributes)); |
| 67 | inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); | 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 | struct efivar_entry *var = inode->i_private; | 124 | struct efivar_entry *var = inode->i_private; |
| 126 | 125 | ||
| 127 | inode_lock(inode); | 126 | inode_lock(inode); |
| 128 | /* FIXME: temporary work around for fwupdate */ | 127 | var->removed = (--var->open_count == 0 && i_size_read(inode) == 0); |
| 129 | var->removed = (--var->open_count == 0 && i_size_read(inode) == 1); | ||
| 130 | inode_unlock(inode); | 128 | inode_unlock(inode); |
| 131 | 129 | ||
| 132 | if (var->removed) | 130 | if (var->removed) |