]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
x86/kexec: Consolidate relocate_kernel() function parameters
authorKai Huang <kai.huang@intel.com>
Mon, 1 Sep 2025 16:09:24 +0000 (18:09 +0200)
committerDave Hansen <dave.hansen@linux.intel.com>
Fri, 5 Sep 2025 17:40:40 +0000 (10:40 -0700)
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
arch/x86/include/asm/kexec.h
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/relocate_kernel_64.S

index f2ad77929d6efe07f0911262477ef667e83523af..12cebbcdb6c82456744ce116efec070b99c4a66a 100644 (file)
 # define KEXEC_DEBUG_EXC_HANDLER_SIZE  6 /* PUSHI, PUSHI, 2-byte JMP */
 #endif
 
+#ifdef CONFIG_X86_64
+
+#include <linux/bits.h>
+
+#define RELOC_KERNEL_PRESERVE_CONTEXT          BIT(0)
+#define RELOC_KERNEL_HOST_MEM_ENC_ACTIVE       BIT(1)
+
+#endif
+
 # define KEXEC_CONTROL_PAGE_SIZE       4096
 # define KEXEC_CONTROL_CODE_MAX_SIZE   2048
 
@@ -121,8 +130,7 @@ typedef unsigned long
 relocate_kernel_fn(unsigned long indirection_page,
                   unsigned long pa_control_page,
                   unsigned long start_address,
-                  unsigned int preserve_context,
-                  unsigned int host_mem_enc_active);
+                  unsigned int flags);
 #endif
 extern relocate_kernel_fn relocate_kernel;
 #define ARCH_HAS_KIMAGE_ARCH
index 697fb99406e6bcc3bac726c29f01bd334bbad911..5cda8d8d8b137da4df8e73e7db3bfea4c4af638f 100644 (file)
@@ -384,16 +384,10 @@ void __nocfi machine_kexec(struct kimage *image)
 {
        unsigned long reloc_start = (unsigned long)__relocate_kernel_start;
        relocate_kernel_fn *relocate_kernel_ptr;
-       unsigned int host_mem_enc_active;
+       unsigned int relocate_kernel_flags;
        int save_ftrace_enabled;
        void *control_page;
 
-       /*
-        * This must be done before load_segments() since if call depth tracking
-        * is used then GS must be valid to make any function calls.
-        */
-       host_mem_enc_active = cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT);
-
 #ifdef CONFIG_KEXEC_JUMP
        if (image->preserve_context)
                save_processor_state();
@@ -427,6 +421,17 @@ void __nocfi machine_kexec(struct kimage *image)
         */
        relocate_kernel_ptr = control_page + (unsigned long)relocate_kernel - reloc_start;
 
+       relocate_kernel_flags = 0;
+       if (image->preserve_context)
+               relocate_kernel_flags |= RELOC_KERNEL_PRESERVE_CONTEXT;
+
+       /*
+        * This must be done before load_segments() since if call depth tracking
+        * is used then GS must be valid to make any function calls.
+        */
+       if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT))
+               relocate_kernel_flags |= RELOC_KERNEL_HOST_MEM_ENC_ACTIVE;
+
        /*
         * The segment registers are funny things, they have both a
         * visible and an invisible part.  Whenever the visible part is
@@ -443,8 +448,7 @@ void __nocfi machine_kexec(struct kimage *image)
        image->start = relocate_kernel_ptr((unsigned long)image->head,
                                           virt_to_phys(control_page),
                                           image->start,
-                                          image->preserve_context,
-                                          host_mem_enc_active);
+                                          relocate_kernel_flags);
 
 #ifdef CONFIG_KEXEC_JUMP
        if (image->preserve_context)
index ea604f4d0b52bd879ba594adf96154182cecb191..26e945f85d19ac31e43aa500d34e457bfd1f75ea 100644 (file)
@@ -66,8 +66,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
         * %rdi indirection_page
         * %rsi pa_control_page
         * %rdx start address
-        * %rcx preserve_context
-        * %r8  host_mem_enc_active
+        * %rcx flags: RELOC_KERNEL_*
         */
 
        /* Save the CPU context, used for jumping back */
@@ -111,7 +110,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
        /* save indirection list for jumping back */
        movq    %rdi, pa_backup_pages_map(%rip)
 
-       /* Save the preserve_context to %r11 as swap_pages clobbers %rcx. */
+       /* Save the flags to %r11 as swap_pages clobbers %rcx. */
        movq    %rcx, %r11
 
        /* setup a new stack at the end of the physical control page */
@@ -129,9 +128,8 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        /*
         * %rdi indirection page
         * %rdx start address
-        * %r8 host_mem_enc_active
         * %r9 page table page
-        * %r11 preserve_context
+        * %r11 flags: RELOC_KERNEL_*
         * %r13 original CR4 when relocate_kernel() was invoked
         */
 
@@ -204,7 +202,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
         * entries that will conflict with the now unencrypted memory
         * used by kexec. Flush the caches before copying the kernel.
         */
-       testq   %r8, %r8
+       testb   $RELOC_KERNEL_HOST_MEM_ENC_ACTIVE, %r11b
        jz .Lsme_off
        wbinvd
 .Lsme_off:
@@ -220,7 +218,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        movq    %cr3, %rax
        movq    %rax, %cr3
 
-       testq   %r11, %r11      /* preserve_context */
+       testb   $RELOC_KERNEL_PRESERVE_CONTEXT, %r11b
        jnz .Lrelocate
 
        /*
@@ -273,7 +271,13 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        ANNOTATE_NOENDBR
        andq    $PAGE_MASK, %r8
        lea     PAGE_SIZE(%r8), %rsp
-       movl    $1, %r11d       /* Ensure preserve_context flag is set */
+       /*
+        * Ensure RELOC_KERNEL_PRESERVE_CONTEXT flag is set so that
+        * swap_pages() can swap pages correctly.  Note all other
+        * RELOC_KERNEL_* flags passed to relocate_kernel() are not
+        * restored.
+        */
+       movl    $RELOC_KERNEL_PRESERVE_CONTEXT, %r11d
        call    swap_pages
        movq    kexec_va_control_page(%rip), %rax
 0:     addq    $virtual_mapped - 0b, %rax
@@ -321,7 +325,7 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        UNWIND_HINT_END_OF_STACK
        /*
         * %rdi indirection page
-        * %r11 preserve_context
+        * %r11 flags: RELOC_KERNEL_*
         */
        movq    %rdi, %rcx      /* Put the indirection_page in %rcx */
        xorl    %edi, %edi
@@ -357,7 +361,8 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        movq    %rdi, %rdx    /* Save destination page to %rdx */
        movq    %rsi, %rax    /* Save source page to %rax */
 
-       testq   %r11, %r11    /* Only actually swap for ::preserve_context */
+       /* Only actually swap for ::preserve_context */
+       testb   $RELOC_KERNEL_PRESERVE_CONTEXT, %r11b
        jz      .Lnoswap
 
        /* copy source page to swap page */