Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  *  sev_verify_cbit.S - Code for verification of the C-bit position reported
0004  *              by the Hypervisor when running with SEV enabled.
0005  *
0006  *  Copyright (c) 2020  Joerg Roedel (jroedel@suse.de)
0007  *
0008  * sev_verify_cbit() is called before switching to a new long-mode page-table
0009  * at boot.
0010  *
0011  * Verify that the C-bit position is correct by writing a random value to
0012  * an encrypted memory location while on the current page-table. Then it
0013  * switches to the new page-table to verify the memory content is still the
0014  * same. After that it switches back to the current page-table and when the
0015  * check succeeded it returns. If the check failed the code invalidates the
0016  * stack pointer and goes into a hlt loop. The stack-pointer is invalidated to
0017  * make sure no interrupt or exception can get the CPU out of the hlt loop.
0018  *
0019  * New page-table pointer is expected in %rdi (first parameter)
0020  *
0021  */
0022 SYM_FUNC_START(sev_verify_cbit)
0023 #ifdef CONFIG_AMD_MEM_ENCRYPT
0024     /* First check if a C-bit was detected */
0025     movq    sme_me_mask(%rip), %rsi
0026     testq   %rsi, %rsi
0027     jz  3f
0028 
0029     /* sme_me_mask != 0 could mean SME or SEV - Check also for SEV */
0030     movq    sev_status(%rip), %rsi
0031     testq   %rsi, %rsi
0032     jz  3f
0033 
0034     /* Save CR4 in %rsi */
0035     movq    %cr4, %rsi
0036 
0037     /* Disable Global Pages */
0038     movq    %rsi, %rdx
0039     andq    $(~X86_CR4_PGE), %rdx
0040     movq    %rdx, %cr4
0041 
0042     /*
0043      * Verified that running under SEV - now get a random value using
0044      * RDRAND. This instruction is mandatory when running as an SEV guest.
0045      *
0046      * Don't bail out of the loop if RDRAND returns errors. It is better to
0047      * prevent forward progress than to work with a non-random value here.
0048      */
0049 1:  rdrand  %rdx
0050     jnc 1b
0051 
0052     /* Store value to memory and keep it in %rdx */
0053     movq    %rdx, sev_check_data(%rip)
0054 
0055     /* Backup current %cr3 value to restore it later */
0056     movq    %cr3, %rcx
0057 
0058     /* Switch to new %cr3 - This might unmap the stack */
0059     movq    %rdi, %cr3
0060 
0061     /*
0062      * Compare value in %rdx with memory location. If C-bit is incorrect
0063      * this would read the encrypted data and make the check fail.
0064      */
0065     cmpq    %rdx, sev_check_data(%rip)
0066 
0067     /* Restore old %cr3 */
0068     movq    %rcx, %cr3
0069 
0070     /* Restore previous CR4 */
0071     movq    %rsi, %cr4
0072 
0073     /* Check CMPQ result */
0074     je  3f
0075 
0076     /*
0077      * The check failed, prevent any forward progress to prevent ROP
0078      * attacks, invalidate the stack and go into a hlt loop.
0079      */
0080     xorq    %rsp, %rsp
0081     subq    $0x1000, %rsp
0082 2:  hlt
0083     jmp 2b
0084 3:
0085 #endif
0086     /* Return page-table pointer */
0087     movq    %rdi, %rax
0088     RET
0089 SYM_FUNC_END(sev_verify_cbit)