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

x86/kexec: Consolidate relocate_kernel() function parameters

During kexec, the kernel jumps to the new kernel in relocate_kernel(),
which is implemented in assembly and both 32-bit and 64-bit have their
own version.

Currently, for both 32-bit and 64-bit, the last two parameters of the
relocate_kernel() are both 'unsigned int' but actually they only convey
a boolean, i.e., one bit information. The 'unsigned int' has enough
space to carry two bits information therefore there's no need to pass
the two booleans in two separate 'unsigned int'.

Consolidate the last two function parameters of relocate_kernel() into a
single 'unsigned int' and pass flags instead.

Only consolidate the 64-bit version albeit the similar optimization can
be done for the 32-bit version too. Don't bother changing the 32-bit
version while it is working (since assembly code change is required).

Signed-off-by: Kai Huang <kai.huang@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Reviewed-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: David Woodhouse <dwmw@amazon.co.uk>
Link: https://lore.kernel.org/all/20250901160930.1785244-2-pbonzini%40redhat.com

authored by

Kai Huang and committed by
Dave Hansen
744b02f6 01fb93a3

+38 -21
+10 -2
arch/x86/include/asm/kexec.h
··· 13 13 # define KEXEC_DEBUG_EXC_HANDLER_SIZE 6 /* PUSHI, PUSHI, 2-byte JMP */ 14 14 #endif 15 15 16 + #ifdef CONFIG_X86_64 17 + 18 + #include <linux/bits.h> 19 + 20 + #define RELOC_KERNEL_PRESERVE_CONTEXT BIT(0) 21 + #define RELOC_KERNEL_HOST_MEM_ENC_ACTIVE BIT(1) 22 + 23 + #endif 24 + 16 25 # define KEXEC_CONTROL_PAGE_SIZE 4096 17 26 # define KEXEC_CONTROL_CODE_MAX_SIZE 2048 18 27 ··· 130 121 relocate_kernel_fn(unsigned long indirection_page, 131 122 unsigned long pa_control_page, 132 123 unsigned long start_address, 133 - unsigned int preserve_context, 134 - unsigned int host_mem_enc_active); 124 + unsigned int flags); 135 125 #endif 136 126 extern relocate_kernel_fn relocate_kernel; 137 127 #define ARCH_HAS_KIMAGE_ARCH
+13 -9
arch/x86/kernel/machine_kexec_64.c
··· 384 384 { 385 385 unsigned long reloc_start = (unsigned long)__relocate_kernel_start; 386 386 relocate_kernel_fn *relocate_kernel_ptr; 387 - unsigned int host_mem_enc_active; 387 + unsigned int relocate_kernel_flags; 388 388 int save_ftrace_enabled; 389 389 void *control_page; 390 - 391 - /* 392 - * This must be done before load_segments() since if call depth tracking 393 - * is used then GS must be valid to make any function calls. 394 - */ 395 - host_mem_enc_active = cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT); 396 390 397 391 #ifdef CONFIG_KEXEC_JUMP 398 392 if (image->preserve_context) ··· 421 427 */ 422 428 relocate_kernel_ptr = control_page + (unsigned long)relocate_kernel - reloc_start; 423 429 430 + relocate_kernel_flags = 0; 431 + if (image->preserve_context) 432 + relocate_kernel_flags |= RELOC_KERNEL_PRESERVE_CONTEXT; 433 + 434 + /* 435 + * This must be done before load_segments() since if call depth tracking 436 + * is used then GS must be valid to make any function calls. 437 + */ 438 + if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) 439 + relocate_kernel_flags |= RELOC_KERNEL_HOST_MEM_ENC_ACTIVE; 440 + 424 441 /* 425 442 * The segment registers are funny things, they have both a 426 443 * visible and an invisible part. Whenever the visible part is ··· 448 443 image->start = relocate_kernel_ptr((unsigned long)image->head, 449 444 virt_to_phys(control_page), 450 445 image->start, 451 - image->preserve_context, 452 - host_mem_enc_active); 446 + relocate_kernel_flags); 453 447 454 448 #ifdef CONFIG_KEXEC_JUMP 455 449 if (image->preserve_context)
+15 -10
arch/x86/kernel/relocate_kernel_64.S
··· 66 66 * %rdi indirection_page 67 67 * %rsi pa_control_page 68 68 * %rdx start address 69 - * %rcx preserve_context 70 - * %r8 host_mem_enc_active 69 + * %rcx flags: RELOC_KERNEL_* 71 70 */ 72 71 73 72 /* Save the CPU context, used for jumping back */ ··· 110 111 /* save indirection list for jumping back */ 111 112 movq %rdi, pa_backup_pages_map(%rip) 112 113 113 - /* Save the preserve_context to %r11 as swap_pages clobbers %rcx. */ 114 + /* Save the flags to %r11 as swap_pages clobbers %rcx. */ 114 115 movq %rcx, %r11 115 116 116 117 /* setup a new stack at the end of the physical control page */ ··· 128 129 /* 129 130 * %rdi indirection page 130 131 * %rdx start address 131 - * %r8 host_mem_enc_active 132 132 * %r9 page table page 133 - * %r11 preserve_context 133 + * %r11 flags: RELOC_KERNEL_* 134 134 * %r13 original CR4 when relocate_kernel() was invoked 135 135 */ 136 136 ··· 202 204 * entries that will conflict with the now unencrypted memory 203 205 * used by kexec. Flush the caches before copying the kernel. 204 206 */ 205 - testq %r8, %r8 207 + testb $RELOC_KERNEL_HOST_MEM_ENC_ACTIVE, %r11b 206 208 jz .Lsme_off 207 209 wbinvd 208 210 .Lsme_off: ··· 218 220 movq %cr3, %rax 219 221 movq %rax, %cr3 220 222 221 - testq %r11, %r11 /* preserve_context */ 223 + testb $RELOC_KERNEL_PRESERVE_CONTEXT, %r11b 222 224 jnz .Lrelocate 223 225 224 226 /* ··· 271 273 ANNOTATE_NOENDBR 272 274 andq $PAGE_MASK, %r8 273 275 lea PAGE_SIZE(%r8), %rsp 274 - movl $1, %r11d /* Ensure preserve_context flag is set */ 276 + /* 277 + * Ensure RELOC_KERNEL_PRESERVE_CONTEXT flag is set so that 278 + * swap_pages() can swap pages correctly. Note all other 279 + * RELOC_KERNEL_* flags passed to relocate_kernel() are not 280 + * restored. 281 + */ 282 + movl $RELOC_KERNEL_PRESERVE_CONTEXT, %r11d 275 283 call swap_pages 276 284 movq kexec_va_control_page(%rip), %rax 277 285 0: addq $virtual_mapped - 0b, %rax ··· 325 321 UNWIND_HINT_END_OF_STACK 326 322 /* 327 323 * %rdi indirection page 328 - * %r11 preserve_context 324 + * %r11 flags: RELOC_KERNEL_* 329 325 */ 330 326 movq %rdi, %rcx /* Put the indirection_page in %rcx */ 331 327 xorl %edi, %edi ··· 361 357 movq %rdi, %rdx /* Save destination page to %rdx */ 362 358 movq %rsi, %rax /* Save source page to %rax */ 363 359 364 - testq %r11, %r11 /* Only actually swap for ::preserve_context */ 360 + /* Only actually swap for ::preserve_context */ 361 + testb $RELOC_KERNEL_PRESERVE_CONTEXT, %r11b 365 362 jz .Lnoswap 366 363 367 364 /* copy source page to swap page */