From: David Woodhouse <d...@amazon.co.uk>

The restore_processor_state() function explicitly states that "the asm code
that gets us here will have restored a usable GDT". That wasn't true in the
case of returning from a preserve_context kexec. Make it so.

Without this, the kernel was depending on the called function to reload a
GDT which is appropriate for the kernel before returning.

Test program:

 #include <unistd.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <linux/kexec.h>
 #include <linux/reboot.h>
 #include <sys/reboot.h>
 #include <sys/syscall.h>

int main (void)
{
        struct kexec_segment segment = {};
        unsigned char purgatory[] = {
                0x66, 0xba, 0xf8, 0x03, // mov $0x3f8, %dx
                0xb0, 0x42,             // mov $0x42, %al
                0xee,                   // outb %al, (%dx)
                0xc3,                   // ret
        };
        int ret;

        segment.buf = &purgatory;
        segment.bufsz = sizeof(purgatory);
        segment.mem = (void *)0x400000;
        segment.memsz = 0x1000;
        ret = syscall(__NR_kexec_load, 0x400000, 1, &segment, 
KEXEC_PRESERVE_CONTEXT);
        if (ret) {
                perror("kexec_load");
                exit(1);
        }

        ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 
LINUX_REBOOT_CMD_KEXEC);
        if (ret) {
                perror("kexec reboot");
                exit(1);
        }
        printf("Success\n");
        return 0;
}

Signed-off-by: David Woodhouse <d...@amazon.co.uk>
Cc: sta...@vger.kernel.org
---
 arch/x86/kernel/relocate_kernel_64.S | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/x86/kernel/relocate_kernel_64.S 
b/arch/x86/kernel/relocate_kernel_64.S
index e9e88c342f75..1236f25fc8d1 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -242,6 +242,13 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
        movq    CR0(%r8), %r8
        movq    %rax, %cr3
        movq    %r8, %cr0
+
+#ifdef CONFIG_KEXEC_JUMP
+       /* Saved in save_processor_state. */
+       movq    $saved_context, %rax
+       lgdt    saved_context_gdt_desc(%rax)
+#endif
+
        movq    %rbp, %rax
 
        popf

base-commit: d0ceea662d459726487030237689835fcc0483e5
-- 
2.47.0


Reply via email to