Commit b677dfae authored by Wei Huang's avatar Wei Huang Committed by Thomas Gleixner
Browse files

x86/boot/compressed/64: Set EFER.LME=1 in 32-bit trampoline before returning to long mode



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: default avatarWei Huang <wei@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarKirill 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
parent 00ae831d
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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