lkml.org 
[lkml]   [2021]   [Dec]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 15/26] x86/boot: Avoid #VE during boot for TDX platforms
    Date
    From: Sean Christopherson <seanjc@google.com>

    There are a few MSRs and control register bits that the kernel
    normally needs to modify during boot. But, TDX disallows
    modification of these registers to help provide consistent security
    guarantees. Fortunately, TDX ensures that these are all in the correct
    state before the kernel loads, which means the kernel does not need to
    modify them.

    The conditions to avoid are:

    * Any writes to the EFER MSR
    * Clearing CR0.NE
    * Clearing CR3.MCE

    This theoretically makes the guest boot more fragile. If, for instance,
    EFER was set up incorrectly and a WRMSR was performed, it will trigger
    early exception panic or a triple fault, if it's before early
    exceptions are set up. However, this is likely to trip up the guest
    BIOS long before control reaches the kernel. In any case, these kinds
    of problems are unlikely to occur in production environments, and
    developers have good debug tools to fix them quickly.

    Change the common boot code to work on TDX and non-TDX systems.
    This should have no functional effect on non-TDX systems.

    Signed-off-by: Sean Christopherson <seanjc@google.com>
    Reviewed-by: Andi Kleen <ak@linux.intel.com>
    Reviewed-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
    Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
    ---
    arch/x86/Kconfig | 1 +
    arch/x86/boot/compressed/head_64.S | 25 +++++++++++++++++++++----
    arch/x86/boot/compressed/pgtable.h | 2 +-
    arch/x86/kernel/head_64.S | 24 ++++++++++++++++++++++--
    arch/x86/realmode/rm/trampoline_64.S | 27 +++++++++++++++++++++++----
    5 files changed, 68 insertions(+), 11 deletions(-)

    diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
    index 8e781f166030..fc4771a07fc0 100644
    --- a/arch/x86/Kconfig
    +++ b/arch/x86/Kconfig
    @@ -878,6 +878,7 @@ config INTEL_TDX_GUEST
    depends on X86_64 && CPU_SUP_INTEL
    depends on X86_X2APIC
    select ARCH_HAS_CC_PLATFORM
    + select X86_MCE
    help
    Support running as a guest under Intel TDX. Without this support,
    the guest kernel can not boot or run under TDX.
    diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
    index 572c535cf45b..dbbfafba553f 100644
    --- a/arch/x86/boot/compressed/head_64.S
    +++ b/arch/x86/boot/compressed/head_64.S
    @@ -643,12 +643,25 @@ SYM_CODE_START(trampoline_32bit_src)
    movl $MSR_EFER, %ecx
    rdmsr
    btsl $_EFER_LME, %eax
    + /* Avoid writing EFER if no change was made (for TDX guest) */
    + 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
    +
    +#ifdef CONFIG_X86_MCE
    + /*
    + * Preserve CR4.MCE if the kernel will enable #MC support. Clearing
    + * MCE may fault in some environments (that also force #MC support).
    + * Any machine check that occurs before #MC support is fully configured
    + * will crash the system regardless of the CR4.MCE value set here.
    + */
    + andl $X86_CR4_MCE, %eax
    +#endif
    + orl $X86_CR4_PAE, %eax
    testl %edx, %edx
    jz 1f
    orl $X86_CR4_LA57, %eax
    @@ -662,8 +675,12 @@ SYM_CODE_START(trampoline_32bit_src)
    pushl $__KERNEL_CS
    pushl %eax

    - /* Enable paging again */
    - movl $(X86_CR0_PG | X86_CR0_PE), %eax
    + /*
    + * Enable paging again. Keep CR0.NE set, FERR# is no longer used
    + * to handle x87 FPU errors and clearing NE may fault in some
    + * environments.
    + */
    + movl $(X86_CR0_PG | X86_CR0_NE | X86_CR0_PE), %eax
    movl %eax, %cr0

    lret
    diff --git a/arch/x86/boot/compressed/pgtable.h b/arch/x86/boot/compressed/pgtable.h
    index 6ff7e81b5628..cc9b2529a086 100644
    --- a/arch/x86/boot/compressed/pgtable.h
    +++ b/arch/x86/boot/compressed/pgtable.h
    @@ -6,7 +6,7 @@
    #define TRAMPOLINE_32BIT_PGTABLE_OFFSET 0

    #define TRAMPOLINE_32BIT_CODE_OFFSET PAGE_SIZE
    -#define TRAMPOLINE_32BIT_CODE_SIZE 0x70
    +#define TRAMPOLINE_32BIT_CODE_SIZE 0x80

    #define TRAMPOLINE_32BIT_STACK_END TRAMPOLINE_32BIT_SIZE

    diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
    index d8b3ebd2bb85..f503e97945d3 100644
    --- a/arch/x86/kernel/head_64.S
    +++ b/arch/x86/kernel/head_64.S
    @@ -141,7 +141,17 @@ 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
    +#ifdef CONFIG_X86_MCE
    + /*
    + * Preserve CR4.MCE if the kernel will enable #MC support. Clearing
    + * MCE may fault in some environments (that also force #MC support).
    + * Any machine check that occurs before #MC support is fully configured
    + * will crash the system regardless of the CR4.MCE value set here.
    + */
    + andl $X86_CR4_MCE, %ecx
    +#endif
    + orl $(X86_CR4_PAE | X86_CR4_PGE), %ecx
    #ifdef CONFIG_X86_5LEVEL
    testl $1, __pgtable_l5_enabled(%rip)
    jz 1f
    @@ -229,13 +239,23 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
    /* Setup EFER (Extended Feature Enable Register) */
    movl $MSR_EFER, %ecx
    rdmsr
    + /*
    + * Preserve current value of EFER for comparison and to skip
    + * EFER writes if no change was made (for TDX guest)
    + */
    + 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 */

    + /* Avoid writing EFER if no change was made (for TDX guest) */
    +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 ae112a91592f..170f248d5769 100644
    --- a/arch/x86/realmode/rm/trampoline_64.S
    +++ b/arch/x86/realmode/rm/trampoline_64.S
    @@ -143,13 +143,28 @@ SYM_CODE_START(startup_32)
    movl %eax, %cr3

    # Set up EFER
    + movl $MSR_EFER, %ecx
    + rdmsr
    + /*
    + * Skip writing to EFER if the register already has desired
    + * value (to avoid #VE for the TDX guest).
    + */
    + 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

    - # Enable paging and in turn activate Long Mode
    - movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
    +.Ldone_efer:
    + /*
    + * Enable paging and in turn activate Long Mode. Keep CR0.NE set, FERR#
    + * is no longer used to handle x87 FPU errors and clearing NE may fault
    + * in some environments.
    + */
    + movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_NE | X86_CR0_PE), %eax
    movl %eax, %cr0

    /*
    @@ -169,7 +184,11 @@ SYM_CODE_START(pa_trampoline_compat)
    movl $rm_stack_end, %esp
    movw $__KERNEL_DS, %dx

    - movl $X86_CR0_PE, %eax
    + /*
    + * Keep CR0.NE set, FERR# is no longer used to handle x87 FPU errors
    + * and clearing NE may fault in some environments.
    + */
    + movl $(X86_CR0_NE | X86_CR0_PE), %eax
    movl %eax, %cr0
    ljmpl $__KERNEL32_CS, $pa_startup_32
    SYM_CODE_END(pa_trampoline_compat)
    --
    2.32.0
    \
     
     \ /
      Last update: 2021-12-14 16:06    [W:4.103 / U:0.084 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site