Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'efi-next-for-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi

Pull EFI updates from Ard Biesheuvel:

- Decouple mixed mode startup code from the traditional x86
decompressor

- Revert zero-length file hack in efivarfs

- Prevent EFI zboot from using the CopyMem/SetMem boot services after
ExitBootServices()

- Update EFI zboot to use the ZLIB/ZSTD library interfaces directly

* tag 'efi-next-for-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
efi/libstub: Avoid legacy decompressor zlib/zstd wrappers
efi/libstub: Avoid CopyMem/SetMem EFI services after ExitBootServices
efi: efibc: change kmalloc(size * count, ...) to kmalloc_array()
efivarfs: Revert "allow creation of zero length files"
x86/efi/mixed: Move mixed mode startup code into libstub
x86/efi/mixed: Simplify and document thunking logic
x86/efi/mixed: Remove dependency on legacy startup_32 code
x86/efi/mixed: Set up 1:1 mapping of lower 4GiB in the stub
x86/efi/mixed: Factor out and clean up long mode entry
x86/efi/mixed: Check CPU compatibility without relying on verify_cpu()
x86/efistub: Merge PE and handover entrypoints

+452 -436
-1
arch/x86/boot/compressed/Makefile
··· 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
-341
arch/x86/boot/compressed/efi_mixed.S
··· 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)
-7
arch/x86/boot/compressed/head_64.S
··· 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
+1 -1
drivers/firmware/efi/efibc.c
··· 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
+9 -1
drivers/firmware/efi/libstub/Makefile
··· 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 \ ··· 85 83 lib-$(CONFIG_ARM) += arm32-stub.o 86 84 lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o 87 85 lib-$(CONFIG_X86) += x86-stub.o smbios.o 86 + lib-$(CONFIG_EFI_MIXED) += x86-mixed.o 88 87 lib-$(CONFIG_X86_64) += x86-5lvl.o 89 88 lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o 90 89 lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o 91 90 92 91 CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) 93 92 94 - zboot-obj-$(CONFIG_RISCV) := lib-clz_ctz.o lib-ashldi3.o 93 + zboot-obj-y := zboot-decompress-gzip.o 94 + CFLAGS_zboot-decompress-gzip.o += -I$(srctree)/lib/zlib_inflate 95 + zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o 96 + CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd 97 + 98 + zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o 95 99 lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) 96 100 97 101 lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o
+3
drivers/firmware/efi/libstub/efistub.h
··· 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
+26
drivers/firmware/efi/libstub/intrinsics.c
··· 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 } ··· 48 25 49 26 void *memset(void *dst, int c, size_t len) 50 27 { 28 + if (efi_table_attr(efi_system_table, boottime) == NULL) 29 + return efistub_memset(dst, c, len); 30 + 51 31 efi_bs_call(set_mem, dst, len, c & U8_MAX); 52 32 return dst; 53 33 }
+253
drivers/firmware/efi/libstub/x86-mixed.S
··· 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)
+29 -23
drivers/firmware/efi/libstub/x86-stub.c
··· 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; ··· 412 416 unsigned long alloc; 413 417 char *cmdline_ptr; 414 418 415 - efi_system_table = sys_table_arg; 416 - 417 - /* Check if we were booted by the EFI firmware */ 418 - if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) 419 - efi_exit(handle, EFI_INVALID_PARAMETER); 420 - 421 419 status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image); 422 420 if (status != EFI_SUCCESS) { 423 421 efi_err("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); 424 - efi_exit(handle, status); 422 + return status; 425 423 } 426 424 427 425 status = efi_allocate_pages(PARAM_SIZE, &alloc, ULONG_MAX); 428 426 if (status != EFI_SUCCESS) 429 - efi_exit(handle, status); 427 + return status; 430 428 431 429 boot_params = memset((void *)alloc, 0x0, PARAM_SIZE); 432 430 hdr = &boot_params->hdr; ··· 436 446 cmdline_ptr = efi_convert_cmdline(image); 437 447 if (!cmdline_ptr) { 438 448 efi_free(PARAM_SIZE, alloc); 439 - efi_exit(handle, EFI_OUT_OF_RESOURCES); 449 + return EFI_OUT_OF_RESOURCES; 440 450 } 441 451 442 452 efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr, 443 453 &boot_params->ext_cmd_line_ptr); 444 454 445 - efi_stub_entry(handle, sys_table_arg, boot_params); 446 - /* not reached */ 455 + *bp = boot_params; 456 + return EFI_SUCCESS; 447 457 } 448 458 449 459 static void add_e820ext(struct boot_params *params, ··· 730 740 return efi_parse_options(cmdline); 731 741 } 732 742 733 - static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) 743 + static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry, 744 + struct boot_params *boot_params) 734 745 { 735 746 unsigned long virt_addr = LOAD_PHYSICAL_ADDR; 736 747 unsigned long addr, alloc_size, entry; 737 748 efi_status_t status; 738 749 u32 seed[2] = {}; 750 + 751 + boot_params_ptr = boot_params; 739 752 740 753 /* determine the required size of the allocation */ 741 754 alloc_size = ALIGN(max_t(unsigned long, output_len, kernel_total_size), ··· 770 777 seed[0] = 0; 771 778 } 772 779 773 - boot_params_ptr->hdr.loadflags |= KASLR_FLAG; 780 + boot_params->hdr.loadflags |= KASLR_FLAG; 774 781 } 775 782 776 783 status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr, ··· 808 815 void __noreturn efi_stub_entry(efi_handle_t handle, 809 816 efi_system_table_t *sys_table_arg, 810 817 struct boot_params *boot_params) 818 + 811 819 { 812 820 efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; 813 - struct setup_header *hdr = &boot_params->hdr; 814 821 const struct linux_efi_initrd *initrd = NULL; 815 822 unsigned long kernel_entry; 823 + struct setup_header *hdr; 816 824 efi_status_t status; 817 - 818 - boot_params_ptr = boot_params; 819 825 820 826 efi_system_table = sys_table_arg; 821 827 /* Check if we were booted by the EFI firmware */ 822 828 if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) 823 829 efi_exit(handle, EFI_INVALID_PARAMETER); 830 + 831 + if (!IS_ENABLED(CONFIG_EFI_HANDOVER_PROTOCOL) || !boot_params) { 832 + status = efi_allocate_bootparams(handle, &boot_params); 833 + if (status != EFI_SUCCESS) 834 + efi_exit(handle, status); 835 + } 836 + 837 + hdr = &boot_params->hdr; 824 838 825 839 if (have_unsupported_snp_features()) 826 840 efi_exit(handle, EFI_UNSUPPORTED); ··· 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; ··· 938 938 efi_err("efi_stub_entry() failed!\n"); 939 939 940 940 efi_exit(handle, status); 941 + } 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); 941 947 } 942 948 943 949 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
+68
drivers/firmware/efi/libstub/zboot-decompress-gzip.c
··· 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 + }
+49
drivers/firmware/efi/libstub/zboot-decompress-zstd.c
··· 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 + }
+9 -56
drivers/firmware/efi/libstub/zboot.c
··· 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 ··· 34 64 asmlinkage efi_status_t __efiapi 35 65 efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) 36 66 { 37 - unsigned long compressed_size = _gzdata_end - _gzdata_start; 67 + char *cmdline_ptr __free(efi_pool) = NULL; 38 68 unsigned long image_base, alloc_size; 39 69 efi_loaded_image_t *image; 40 70 efi_status_t status; 41 - char *cmdline_ptr; 42 - int ret; 43 71 44 72 WRITE_ONCE(efi_system_table, systab); 45 - 46 - free_mem_ptr = (unsigned long)&zboot_heap; 47 - free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap); 48 73 49 74 status = efi_bs_call(handle_protocol, handle, 50 75 &LOADED_IMAGE_PROTOCOL_GUID, (void **)&image); 51 76 if (status != EFI_SUCCESS) { 52 - error("Failed to locate parent's loaded image protocol"); 77 + efi_err("Failed to locate parent's loaded image protocol\n"); 53 78 return status; 54 79 } 55 80 ··· 54 89 55 90 efi_info("Decompressing Linux Kernel...\n"); 56 91 57 - // SizeOfImage from the compressee's PE/COFF header 58 - alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4), 59 - EFI_ALLOC_ALIGN); 92 + status = efi_zboot_decompress_init(&alloc_size); 93 + if (status != EFI_SUCCESS) 94 + return status; 60 95 61 96 // If the architecture has a preferred address for the image, 62 97 // try that first. ··· 87 122 seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT); 88 123 if (status != EFI_SUCCESS) { 89 124 efi_err("Failed to allocate memory\n"); 90 - goto free_cmdline; 125 + return status; 91 126 } 92 127 } 93 128 94 - // Decompress the payload into the newly allocated buffer. 95 - ret = __decompress(_gzdata_start, compressed_size, NULL, NULL, 96 - (void *)image_base, alloc_size, NULL, error); 97 - if (ret < 0) { 98 - error("Decompression failed"); 99 - status = EFI_DEVICE_ERROR; 100 - goto free_image; 101 - } 129 + // Decompress the payload into the newly allocated buffer 130 + status = efi_zboot_decompress((void *)image_base, alloc_size) ?: 131 + efi_stub_common(handle, image, image_base, cmdline_ptr); 102 132 103 - efi_cache_sync_image(image_base, alloc_size); 104 - 105 - status = efi_stub_common(handle, image, image_base, cmdline_ptr); 106 - 107 - free_image: 108 133 efi_free(alloc_size, image_base); 109 - free_cmdline: 110 - efi_bs_call(free_pool, cmdline_ptr); 111 134 return status; 112 135 }
+1
drivers/firmware/efi/libstub/zboot.lds
··· 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
+4 -6
fs/efivarfs/file.c
··· 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)); ··· 124 125 struct efivar_entry *var = inode->i_private; 125 126 126 127 inode_lock(inode); 127 - /* FIXME: temporary work around for fwupdate */ 128 - var->removed = (--var->open_count == 0 && i_size_read(inode) == 1); 128 + var->removed = (--var->open_count == 0 && i_size_read(inode) == 0); 129 129 inode_unlock(inode); 130 130 131 131 if (var->removed)