x86/boot/compressed/64: Set EFER.LME=1 in 32-bit trampoline before returning to long...
authorWei Huang <wei@redhat.com>
Fri, 4 Jan 2019 05:44:11 +0000 (23:44 -0600)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 29 Jan 2019 20:58:59 +0000 (21:58 +0100)
In some old AMD KVM implementation, guest's EFER.LME bit is cleared by KVM
when the hypervsior detects that the guest sets CR0.PG to 0. This causes
the guest OS to reboot when it tries to return from 32-bit trampoline code
because the CPU is in incorrect state: CR4.PAE=1, CR0.PG=1, CS.L=1, but
EFER.LME=0.  As a precaution, set EFER.LME=1 as part of long mode
activation procedure. This extra step won't cause any harm when Linux is
booted on a bare-metal machine.

Signed-off-by: Wei Huang <wei@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: bp@alien8.de
Cc: hpa@zytor.com
Link: https://lkml.kernel.org/r/20190104054411.12489-1-wei@redhat.com
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/pgtable.h

index 64037895b0859fdb25b8b104a2e5ed5d028baf45..f105ae8651c9425429982fccabd47a8114edd5ff 100644 (file)
@@ -600,6 +600,14 @@ ENTRY(trampoline_32bit_src)
        leal    TRAMPOLINE_32BIT_PGTABLE_OFFSET(%ecx), %eax
        movl    %eax, %cr3
 3:
+       /* Set EFER.LME=1 as a precaution in case hypervsior pulls the rug */
+       pushl   %ecx
+       movl    $MSR_EFER, %ecx
+       rdmsr
+       btsl    $_EFER_LME, %eax
+       wrmsr
+       popl    %ecx
+
        /* Enable PAE and LA57 (if required) paging modes */
        movl    $X86_CR4_PAE, %eax
        cmpl    $0, %edx
index 91f75638f6e68ef5df8da5f428fe54341bef3813..6ff7e81b5628456b92779ede7a9c941fe7df6a85 100644 (file)
@@ -6,7 +6,7 @@
 #define TRAMPOLINE_32BIT_PGTABLE_OFFSET        0
 
 #define TRAMPOLINE_32BIT_CODE_OFFSET   PAGE_SIZE
-#define TRAMPOLINE_32BIT_CODE_SIZE     0x60
+#define TRAMPOLINE_32BIT_CODE_SIZE     0x70
 
 #define TRAMPOLINE_32BIT_STACK_END     TRAMPOLINE_32BIT_SIZE