diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h index a6d82dac7f..dc09c61e58 100644 --- a/OvmfPkg/Include/Library/MemEncryptSevLib.h +++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h @@ -21,10 +21,14 @@ // This structure is also used by assembler files: // OvmfPkg/ResetVector/ResetVector.nasmb // OvmfPkg/ResetVector/Ia32/PageTables64.asm +// OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm // any changes must stay in sync with its usage. // typedef struct _SEC_SEV_ES_WORK_AREA { UINT8 SevEsEnabled; + UINT8 Reserved1[7]; + + UINT64 RandomData; } SEC_SEV_ES_WORK_AREA; /** diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm new file mode 100644 index 0000000000..c6d0d898bc --- /dev/null +++ b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm @@ -0,0 +1,118 @@ +;------------------------------------------------------------------------------ +; @file +; Transition from 32 bit flat protected mode into 64 bit flat protected mode +; +; Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;------------------------------------------------------------------------------ + +BITS 32 + +; +; Modified: EAX, ECX, EDX +; +Transition32FlatTo64Flat: + + OneTimeCall SetCr3ForPageTables64 + + mov eax, cr4 + bts eax, 5 ; enable PAE + mov cr4, eax + + mov ecx, 0xc0000080 + rdmsr + bts eax, 8 ; set LME + wrmsr + + ; + ; SEV-ES mitigation check support + ; + xor ebx, ebx + + cmp byte[SEV_ES_WORK_AREA], 0 + jz EnablePaging + + ; + ; SEV-ES is active, perform a quick sanity check against the reported + ; encryption bit position. This is to help mitigate against attacks where + ; the hypervisor reports an incorrect encryption bit position. + ; + ; This is the first step in a two step process. Before paging is enabled + ; writes to memory are encrypted. Using the RDRAND instruction (available + ; on all SEV capable processors), write 64-bits of random data to the + ; SEV_ES_WORK_AREA and maintain the random data in registers (register + ; state is protected under SEV-ES). This will be used in the second step. + ; +RdRand1: + rdrand ecx + jnc RdRand1 + mov dword[SEV_ES_WORK_AREA_RDRAND], ecx +RdRand2: + rdrand edx + jnc RdRand2 + mov dword[SEV_ES_WORK_AREA_RDRAND + 4], edx + + ; + ; Use EBX instead of the SEV_ES_WORK_AREA memory to determine whether to + ; perform the second step. + ; + mov ebx, 1 + +EnablePaging: + mov eax, cr0 + bts eax, 31 ; set PG + mov cr0, eax ; enable paging + + jmp LINEAR_CODE64_SEL:ADDR_OF(jumpTo64BitAndLandHere) +BITS 64 +jumpTo64BitAndLandHere: + + ; + ; Check if the second step of the SEV-ES mitigation is to be performed. + ; + test ebx, ebx + jz InsnCompare + + ; + ; SEV-ES is active, perform the second step of the encryption bit postion + ; mitigation check. The ECX and EDX register contain data from RDRAND that + ; was stored to memory in encrypted form. If the encryption bit position is + ; valid, the contents of ECX and EDX will match the memory location. + ; + cmp dword[SEV_ES_WORK_AREA_RDRAND], ecx + jne SevEncBitHlt + cmp dword[SEV_ES_WORK_AREA_RDRAND + 4], edx + jne SevEncBitHlt + + ; + ; If SEV or SEV-ES is active, perform a quick sanity check against + ; the reported encryption bit position. This is to help mitigate + ; against attacks where the hypervisor reports an incorrect encryption + ; bit position. If SEV is not active, this check will always succeed. + ; + ; The cmp instruction compares the first four bytes of the cmp instruction + ; itself (which will be read decrypted if SEV or SEV-ES is active and the + ; encryption bit position is valid) against the immediate within the + ; instruction (an instruction fetch is always decrypted correctly by + ; hardware) based on RIP relative addressing. + ; +InsnCompare: + cmp dword[rel InsnCompare], 0xFFF63D81 + je GoodCompare + + ; + ; The hypervisor provided an incorrect encryption bit position, do not + ; proceed. + ; +SevEncBitHlt: + cli + hlt + jmp SevEncBitHlt + +GoodCompare: + debugShowPostCode POSTCODE_64BIT_MODE + + OneTimeCallRet Transition32FlatTo64Flat + diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm index 4032719c30..ccc95ad471 100644 --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm @@ -140,9 +140,18 @@ GetSevEncBit: ; Get pte bit position to enable memory encryption ; CPUID Fn8000_001F[EBX] - Bits 5:0 ; + and ebx, 0x3f mov eax, ebx - and eax, 0x3f - jmp SevExit + + ; The encryption bit position is always above 31 + sub ebx, 32 + jns SevExit + + ; Encryption bit was reported as 31 or below, enter a HLT loop +SevEncBitLowHlt: + cli + hlt + jmp SevEncBitLowHlt NoSev: xor eax, eax diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb index c5e0fe93ab..d3aa879829 100644 --- a/OvmfPkg/ResetVector/ResetVector.nasmb +++ b/OvmfPkg/ResetVector/ResetVector.nasmb @@ -3,6 +3,7 @@ ; This file includes all other code files to assemble the reset vector code ; ; Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.
+; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.
; SPDX-License-Identifier: BSD-2-Clause-Patent ; ;------------------------------------------------------------------------------ @@ -67,13 +68,14 @@ %endif %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset)) -%include "Ia32/Flat32ToFlat64.asm" %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase)) %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase)) %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize)) %define SEV_ES_WORK_AREA (FixedPcdGet32 (PcdSevEsWorkAreaBase)) + %define SEV_ES_WORK_AREA_RDRAND (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 8) %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize)) +%include "Ia32/Flat32ToFlat64.asm" %include "Ia32/PageTables64.asm" %endif