[WARNING: UNSCANNABLE EXTRACTION FAILED][WARNING: UNSCANNABLE EXTRACTION FAILED][RFC v2-fix 1/1] x86/boot: Avoid #VE during boot for TDX platforms

From: Kuppuswamy Sathyanarayanan
Date: Mon May 17 2021 - 21:00:05 EST


From: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>

Avoid operations which will inject #VE during boot process,
which is obviously fatal for TDX platforms.

Details are,

1. TDX module injects #VE if a TDX guest attempts to write
   EFER.
   
   Boot code updates EFER in following cases:
   
   * When enabling Long Mode configuration, EFER.LME bit will
     be set. Since TDX forces EFER.LME=1, we can skip updating
     it again. Check for EFER.LME before updating it and skip
     it if it is already set.

   * EFER is also updated to enable support for features like
     System call and No Execute page setting. In TDX, these
     features are set up by the TDX module. So check whether
     it is already enabled, and skip enabling it again.
   
2. TDX module also injects a #VE if the guest attempts to clear
   CR0.NE. Ensure CR0.NE is set when loading CR0 during compressed
   boot. The Setting CR0.NE should be a nop on all CPUs that
   support 64-bit mode.
   
3. The TDX-Module (effectively part of the hypervisor) requires
   CR4.MCE to be set at all times and injects a #VE if the guest
   attempts to clear CR4.MCE. So, preserve CR4.MCE instead of
   clearing it during boot to avoid #VE.

Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
Reviewed-by: Andi Kleen <ak@xxxxxxxxxxxxxxx>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx>
---

Changes since RFC v2:
* Merged Avoid #VE related changes together.
* [RFC v2 22/32] x86/boot: Avoid #VE during compressed boot
for TDX platforms
* [RFC v2 23/32] x86/boot: Avoid unnecessary #VE during boot process.
* Fixed commit log as per review comments.

arch/x86/boot/compressed/head_64.S | 10 +++++++---
arch/x86/kernel/head_64.S | 13 +++++++++++--
arch/x86/realmode/rm/trampoline_64.S | 11 +++++++++--
3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index e94874f4bbc1..2d79e5f97360 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -616,12 +616,16 @@ SYM_CODE_START(trampoline_32bit_src)
movl $MSR_EFER, %ecx
rdmsr
btsl $_EFER_LME, %eax
+ jc 1f
wrmsr
- popl %edx
+1: popl %edx
popl %ecx

/* Enable PAE and LA57 (if required) paging modes */
- movl $X86_CR4_PAE, %eax
+ movl %cr4, %eax
+ /* Clearing CR4.MCE will #VE on TDX guests. Leave it alone. */
+ andl $X86_CR4_MCE, %eax
+ orl $X86_CR4_PAE, %eax
testl %edx, %edx
jz 1f
orl $X86_CR4_LA57, %eax
@@ -636,7 +640,7 @@ SYM_CODE_START(trampoline_32bit_src)
pushl %eax

/* Enable paging again */
- movl $(X86_CR0_PG | X86_CR0_PE), %eax
+ movl $(X86_CR0_PG | X86_CR0_NE | X86_CR0_PE), %eax
movl %eax, %cr0

lret
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 04bddaaba8e2..92c77cf75542 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -141,7 +141,10 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
1:

/* Enable PAE mode, PGE and LA57 */
- movl $(X86_CR4_PAE | X86_CR4_PGE), %ecx
+ movq %cr4, %rcx
+ /* Clearing CR4.MCE will #VE on TDX guests. Leave it alone. */
+ andl $X86_CR4_MCE, %ecx
+ orl $(X86_CR4_PAE | X86_CR4_PGE), %ecx
#ifdef CONFIG_X86_5LEVEL
testl $1, __pgtable_l5_enabled(%rip)
jz 1f
@@ -229,13 +232,19 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
/* Setup EFER (Extended Feature Enable Register) */
movl $MSR_EFER, %ecx
rdmsr
+ movl %eax, %edx
btsl $_EFER_SCE, %eax /* Enable System Call */
btl $20,%edi /* No Execute supported? */
jnc 1f
btsl $_EFER_NX, %eax
btsq $_PAGE_BIT_NX,early_pmd_flags(%rip)
-1: wrmsr /* Make changes effective */

+ /* Skip the WRMSR if the current value matches the desired value. */
+1: cmpl %edx, %eax
+ je 1f
+ xor %edx, %edx
+ wrmsr /* Make changes effective */
+1:
/* Setup cr0 */
movl $CR0_STATE, %eax
/* Make changes effective */
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 754f8d2ac9e8..12b734b1da8b 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -143,13 +143,20 @@ SYM_CODE_START(startup_32)
movl %eax, %cr3

# Set up EFER
+ movl $MSR_EFER, %ecx
+ rdmsr
+ cmp pa_tr_efer, %eax
+ jne .Lwrite_efer
+ cmp pa_tr_efer + 4, %edx
+ je .Ldone_efer
+.Lwrite_efer:
movl pa_tr_efer, %eax
movl pa_tr_efer + 4, %edx
- movl $MSR_EFER, %ecx
wrmsr

+.Ldone_efer:
# Enable paging and in turn activate Long Mode
- movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
+ movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_NE | X86_CR0_PE), %eax
movl %eax, %cr0

/*
--
2.25.1