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

Configure Feed

Select the types of activity you want to include in your feed.

x86/decompressor: Call trampoline directly from C code

Instead of returning to the asm calling code to invoke the trampoline,
call it straight from the C code that sets it up. That way, the struct
return type is no longer needed for returning two values, and the call
can be made conditional more cleanly in a subsequent patch.

This means that all callee save 64-bit registers need to be preserved
and restored, as their contents may not survive the legacy mode switch.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Link: https://lore.kernel.org/r/20230807162720.545787-13-ardb@kernel.org

authored by

Ard Biesheuvel and committed by
Borislav Petkov (AMD)
64ef578b bd328aa0

+26 -37
+13 -18
arch/x86/boot/compressed/head_64.S
··· 430 430 #endif 431 431 432 432 /* 433 - * paging_prepare() sets up the trampoline and checks if we need to 434 - * enable 5-level paging. 435 - * 436 - * paging_prepare() returns a two-quadword structure which lands 437 - * into RDX:RAX: 438 - * - Address of the trampoline is returned in RAX. 439 - * - Non zero RDX means trampoline needs to enable 5-level 440 - * paging. 433 + * configure_5level_paging() updates the number of paging levels using 434 + * a trampoline in 32-bit addressable memory if the current number does 435 + * not match the desired number. 441 436 * 442 437 * Pass the boot_params pointer as the first argument. 443 438 */ 444 439 movq %r15, %rdi 445 - call paging_prepare 446 - 447 - /* Pass the trampoline address and boolean flag as args #1 and #2 */ 448 - movq %rax, %rdi 449 - movq %rdx, %rsi 450 - leaq TRAMPOLINE_32BIT_CODE_OFFSET(%rax), %rax 451 - call *%rax 440 + call configure_5level_paging 452 441 453 442 /* 454 443 * cleanup_trampoline() would restore trampoline memory. ··· 532 543 .section ".rodata", "a", @progbits 533 544 SYM_CODE_START(trampoline_32bit_src) 534 545 /* 535 - * Preserve live 64-bit registers on the stack: this is necessary 536 - * because the architecture does not guarantee that GPRs will retain 537 - * their full 64-bit values across a 32-bit mode switch. 546 + * Preserve callee save 64-bit registers on the stack: this is 547 + * necessary because the architecture does not guarantee that GPRs will 548 + * retain their full 64-bit values across a 32-bit mode switch. 538 549 */ 539 550 pushq %r15 551 + pushq %r14 552 + pushq %r13 553 + pushq %r12 540 554 pushq %rbp 541 555 pushq %rbx 542 556 ··· 566 574 /* Restore the preserved 64-bit registers */ 567 575 popq %rbx 568 576 popq %rbp 577 + popq %r12 578 + popq %r13 579 + popq %r14 569 580 popq %r15 570 581 retq 571 582
+13 -19
arch/x86/boot/compressed/pgtable_64.c
··· 16 16 unsigned int __section(".data") ptrs_per_p4d = 1; 17 17 #endif 18 18 19 - struct paging_config { 20 - unsigned long trampoline_start; 21 - unsigned long l5_required; 22 - }; 23 - 24 19 /* Buffer to preserve trampoline memory */ 25 20 static char trampoline_save[TRAMPOLINE_32BIT_SIZE]; 26 21 ··· 24 29 * purposes. 25 30 * 26 31 * Avoid putting the pointer into .bss as it will be cleared between 27 - * paging_prepare() and extract_kernel(). 32 + * configure_5level_paging() and extract_kernel(). 28 33 */ 29 34 unsigned long *trampoline_32bit __section(".data"); 30 35 ··· 101 106 return bios_start - TRAMPOLINE_32BIT_SIZE; 102 107 } 103 108 104 - struct paging_config paging_prepare(void *rmode) 109 + asmlinkage void configure_5level_paging(struct boot_params *bp) 105 110 { 106 - struct paging_config paging_config = {}; 107 - void *tramp_code; 111 + void (*toggle_la57)(void *trampoline, bool enable_5lvl); 112 + bool l5_required = false; 108 113 109 114 /* Initialize boot_params. Required for cmdline_find_option_bool(). */ 110 - boot_params = rmode; 115 + boot_params = bp; 111 116 112 117 /* 113 118 * Check if LA57 is desired and supported. ··· 125 130 !cmdline_find_option_bool("no5lvl") && 126 131 native_cpuid_eax(0) >= 7 && 127 132 (native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31)))) { 128 - paging_config.l5_required = 1; 133 + l5_required = true; 129 134 130 135 /* Initialize variables for 5-level paging */ 131 136 __pgtable_l5_enabled = 1; ··· 133 138 ptrs_per_p4d = 512; 134 139 } 135 140 136 - paging_config.trampoline_start = find_trampoline_placement(); 137 - 138 - trampoline_32bit = (unsigned long *)paging_config.trampoline_start; 141 + trampoline_32bit = (unsigned long *)find_trampoline_placement(); 139 142 140 143 /* Preserve trampoline memory */ 141 144 memcpy(trampoline_save, trampoline_32bit, TRAMPOLINE_32BIT_SIZE); ··· 142 149 memset(trampoline_32bit, 0, TRAMPOLINE_32BIT_SIZE); 143 150 144 151 /* Copy trampoline code in place */ 145 - tramp_code = memcpy(trampoline_32bit + 152 + toggle_la57 = memcpy(trampoline_32bit + 146 153 TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long), 147 154 &trampoline_32bit_src, TRAMPOLINE_32BIT_CODE_SIZE); 148 155 ··· 152 159 * immediate absolute address, which needs to be adjusted based on the 153 160 * placement of the trampoline. 154 161 */ 155 - *(u32 *)(tramp_code + trampoline_ljmp_imm_offset) += (unsigned long)tramp_code; 162 + *(u32 *)((u8 *)toggle_la57 + trampoline_ljmp_imm_offset) += 163 + (unsigned long)toggle_la57; 156 164 157 165 /* 158 166 * The code below prepares page table in trampoline memory. ··· 169 175 * We are not going to use the page table in trampoline memory if we 170 176 * are already in the desired paging mode. 171 177 */ 172 - if (paging_config.l5_required == !!(native_read_cr4() & X86_CR4_LA57)) 178 + if (l5_required == !!(native_read_cr4() & X86_CR4_LA57)) 173 179 goto out; 174 180 175 - if (paging_config.l5_required) { 181 + if (l5_required) { 176 182 /* 177 183 * For 4- to 5-level paging transition, set up current CR3 as 178 184 * the first and the only entry in a new top-level page table. ··· 195 201 } 196 202 197 203 out: 198 - return paging_config; 204 + toggle_la57(trampoline_32bit, l5_required); 199 205 } 200 206 201 207 void cleanup_trampoline(void *pgtable)