* [RFC PATCH 00/28] SEV-ES guest support
@ 2019-08-19 21:35 thomas.lendacky
2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
` (28 more replies)
0 siblings, 29 replies; 46+ messages in thread
From: thomas.lendacky @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
This patch series provides support for running EDK2/OVMF under SEV-ES.
Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].
In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural support for notifying a guest's operating system
when certain types of VMEXITs are about to occur. This allows the guest to
selectively share information with the hypervisor to satisfy the requested
function. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].
The main areas of the EDK2 code that are updated to support SEV-ES are
around the exception handling support and the AP boot support.
Exception support is required starting in Sec, continuing through Pei
and into Dxe in order to handle #VC exceptions that are generated. Each
AP requires it's own GHCB page as well as a page to hold values specific
to that AP.
AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. The GHCB document [2] talks about how SMP
booting under SEV-ES is performed.
Since the GHCB page must be a shared (unencrypted) page, the processor
must be running in long mode in order for the guest and hypervisor to
communicate with each other. As a result, SEV-ES is only supported under
the X64 architecture.
[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] https://github.com/AMDESE/ovmf/tree/sev-es-v6
Tom Lendacky (28):
OvmfPkg/Sec: Enable cache early to speed up booting
OvmfPkg/ResetVector: Add support for a 32-bit SEV check
OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
OvmfPkg: Create a GHCB page for use during Sec phase
OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
OvmfPkg: A per-CPU variable area for #VC usage
OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
MdePkg/BaseLib: Implement the VMGEXIT support
UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling
support for Sec phase
UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
events
UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE
events
UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE
events
UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE
events
UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling
support for Pei/Dxe phases
UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if
SEV-ES is active
UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES
UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support
SEV-ES
OvmfPkg/OvmfPkg.dec | 5 +
UefiCpuPkg/UefiCpuPkg.dec | 7 +
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 6 +
OvmfPkg/OvmfPkgX64.fdf | 9 +-
MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +
MdePkg/Library/BaseLib/BaseLib.inf | 2 +
OvmfPkg/PlatformPei/PlatformPei.inf | 5 +
OvmfPkg/ResetVector/ResetVector.inf | 4 +
OvmfPkg/Sec/SecMain.inf | 1 +
.../DxeCpuExceptionHandlerLib.inf | 4 +
.../PeiCpuExceptionHandlerLib.inf | 4 +
.../SecPeiCpuExceptionHandlerLib.inf | 4 +
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 4 +-
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 2 +
.../Core/DxeIplPeim/X64/VirtualMemory.h | 12 +-
MdePkg/Include/Library/BaseLib.h | 30 +
MdePkg/Include/Protocol/Cpu.h | 6 +
OvmfPkg/Include/Library/MemEncryptSevLib.h | 12 +
UefiCpuPkg/CpuDxe/CpuDxe.h | 14 +
UefiCpuPkg/CpuDxe/CpuGdt.h | 2 +-
UefiCpuPkg/Include/Library/MpInitLib.h | 17 +
UefiCpuPkg/Include/Register/Amd/Fam17Msr.h | 28 +
UefiCpuPkg/Include/Register/Amd/Ghcb.h | 197 +++
.../CpuExceptionHandlerLib/AMDSevVcCommon.h | 19 +
.../CpuExceptionCommon.h | 2 +
UefiCpuPkg/Library/MpInitLib/MpLib.h | 73 +-
MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c | 5 +
.../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 6 +-
.../Core/DxeIplPeim/X64/DxeLoadFunc.c | 11 +-
.../Core/DxeIplPeim/X64/VirtualMemory.c | 49 +-
MdePkg/Library/BaseLib/Ia32/GccInline.c | 17 +
MdePkg/Library/BaseLib/X64/GccInline.c | 45 +
.../MemEncryptSevLibInternal.c | 78 +-
.../BaseMemEncryptSevLib/X64/VirtualMemory.c | 33 +-
OvmfPkg/PlatformPei/AmdSev.c | 83 ++
OvmfPkg/Sec/SecMain.c | 34 +-
UefiCpuPkg/CpuDxe/CpuDxe.c | 10 +
UefiCpuPkg/CpuDxe/CpuGdt.c | 10 +-
.../CpuExceptionCommon.c | 2 +-
.../Ia32/AMDSevVcCommon.c | 13 +
.../PeiDxeAMDSevVcHandler.c | 22 +
.../PeiDxeSmmCpuException.c | 16 +
.../SecAMDSevVcHandler.c | 45 +
.../SecPeiCpuException.c | 16 +
.../X64/AMDSevVcCommon.c | 1192 +++++++++++++++++
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 124 +-
UefiCpuPkg/Library/MpInitLib/MpLib.c | 255 +++-
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 16 +
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c | 2 +-
MdePkg/Library/BaseLib/X64/VmgExit.nasm | 38 +
MdePkg/Library/BaseLib/X64/XGetBv.nasm | 39 +
OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 85 ++
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 210 ++-
OvmfPkg/ResetVector/ResetVector.nasmb | 3 +-
.../X64/ExceptionHandlerAsm.nasm | 15 +
UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 4 +-
.../Library/MpInitLib/Ia32/MpFuncs.nasm | 15 +
UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 4 +-
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 367 ++++-
.../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm | 9 +
62 files changed, 3239 insertions(+), 108 deletions(-)
create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm
create mode 100644 MdePkg/Library/BaseLib/X64/XGetBv.nasm
create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
--
2.17.1
^ permalink raw reply [flat|nested] 46+ messages in thread
* [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-21 14:21 ` [edk2-devel] " Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
` (27 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Currently, the OVMF code relies on the hypervisor to enable the cache
support on the processor in order to improve the boot speed. However,
with SEV-ES, the hypervisor is not allowed to change the CR0 register
to enable caching.
Update the OVMF Sec support to enable caching in order to improve the
boot speed.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/Sec/SecMain.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 3914355cd17b..2448be0cd408 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -739,6 +739,11 @@ SecCoreStartupWithStack (
ProcessLibraryConstructorList (NULL, NULL);
+ //
+ // Enable caching
+ //
+ AsmEnableCache ();
+
DEBUG ((EFI_D_INFO,
"SecCoreStartupWithStack(0x%x, 0x%x)\n",
(UINT32)(UINTN)BootFv,
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
` (26 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
When running as an SEV-ES guest in 32-bit mode, it is not possible to
perform a CPUID instruction because it will require communicating with
the hypervisor using the GHCB. However, writes to the GHCB when in
32-bit mode will be will be encrypted and thus not able to be read
by the hypervisor.
To get around this, add an IDT entry for the #VC exception. The #VC
handler will use the GHCB CPUID request/response protocol to obtain
the requested CPUID function values and provide these to the guest.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/ResetVector/ResetVector.inf | 2 +
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 173 ++++++++++++++++++++++
OvmfPkg/ResetVector/ResetVector.nasmb | 1 +
3 files changed, 176 insertions(+)
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index b0ddfa5832a2..960b47cd0797 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -35,3 +35,5 @@ [BuildOptions]
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index abad009f20f5..c6071fe934de 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,6 +37,15 @@ BITS 32
; If SEV is disabled then EAX will be zero.
;
CheckSevFeature:
+ ;
+ ; Set up exception handlers to check for SEV-ES
+ ; Load temporary RAM stack based on PCDs
+ ; Establish exception handlers
+ ;
+ mov esp, SEV_TOP_OF_STACK
+ mov eax, ADDR_OF(idtr)
+ lidt [cs:eax]
+
; Check if we have a valid (0x8000_001F) CPUID leaf
mov eax, 0x80000000
cpuid
@@ -73,6 +82,15 @@ NoSev:
xor eax, eax
SevExit:
+ ;
+ ; Clear exception handlers and stack
+ ;
+ push eax
+ mov eax, ADDR_OF(idtr_clear)
+ lidt [cs:eax]
+ pop eax
+ mov esp, 0
+
OneTimeCallRet CheckSevFeature
;
@@ -146,3 +164,158 @@ pageTableEntriesLoop:
mov cr3, eax
OneTimeCallRet SetCr3ForPageTables64
+
+SevEsIdtCommon:
+ hlt
+ jmp SevEsIdtCommon
+ iret
+
+SevEsIdtVmmComm:
+ ;
+ ; If we're here, then we are an SEV-ES guest and this
+ ; was triggered by a CPUID instruction
+ ;
+ pop ecx ; Error code
+ cmp ecx, 0x72 ; Be sure it was CPUID
+ jne SevEsIdtCommon
+
+ ;
+ ; Set up local variable room on the stack
+ ; CPUID function : + 28
+ ; CPUID register : + 24
+ ; GHCB MSR (EAX) : + 20
+ ; GHCB MSR (EDX) : + 16
+ ; CPUID result (EDX) : + 12
+ ; CPUID result (ECX) : + 8
+ ; CPUID result (EBX) : + 4
+ ; CPUID result (EAX) : + 0
+ sub esp, 32
+
+ ; Save CPUID function and initial register request
+ mov [esp + 28], eax
+ xor eax, eax
+ mov [esp + 24], eax
+
+ ; Save current GHCB MSR value
+ mov ecx, 0xc0010130
+ rdmsr
+ mov [esp + 20], eax
+ mov [esp + 16], edx
+
+NextReg:
+ ;
+ ; Setup GHCB MSR
+ ; GHCB_MSR[63:32] = CPUID function
+ ; GHCB_MSR[31:30] = CPUID register
+ ; GHCB_MSR[11:0] = CPUID request protocol
+ ;
+ mov eax, [esp + 24]
+ cmp eax, 4
+ jge VmmDone
+
+ shl eax, 30
+ or eax, 0x004
+ mov edx, [esp + 28]
+ mov ecx, 0xc0010130
+ wrmsr
+
+ ; Issue VMGEXIT (rep; vmmcall)
+ db 0xf3
+ db 0x0f
+ db 0x01
+ db 0xd9
+
+ ;
+ ; Read GHCB MSR
+ ; GHCB_MSR[63:32] = CPUID register value
+ ; GHCB_MSR[31:30] = CPUID register
+ ; GHCB_MSR[11:0] = CPUID response protocol
+ ;
+ mov ecx, 0xc0010130
+ rdmsr
+ mov ecx, eax
+ and ecx, 0xfff
+ cmp ecx, 0x005
+ jne SevEsIdtCommon
+
+ ; Save returned value
+ shr eax, 30
+ and eax, 0x3
+ shl eax, 2
+ mov ecx, esp
+ add ecx, eax
+ mov [ecx], edx
+
+ ; Next register
+ inc word [esp + 24]
+
+ jmp NextReg
+
+VmmDone:
+ ;
+ ; At this point we have all CPUID register values. Restore the GHCB MSR,
+ ; set the return register values and return.
+ ;
+ mov eax, [esp + 20]
+ mov edx, [esp + 16]
+ mov ecx, 0xc0010130
+ wrmsr
+
+ mov eax, [esp + 0]
+ mov ebx, [esp + 4]
+ mov ecx, [esp + 8]
+ mov edx, [esp + 12]
+
+ add esp, 32
+ add word [esp], 2 ; Skip over the CPUID instruction
+ iret
+
+ALIGN 2
+
+idtr:
+ dw IDT_END - IDT_BASE - 1 ; Limit
+ dd ADDR_OF(IDT_BASE) ; Base
+
+idtr_clear:
+ dw 0 ; Limit
+ dd 0 ; Base
+
+ALIGN 16
+
+;
+; The Interrupt Descriptor Table (IDT)
+; This will be used to determine if SEV-ES is enabled. Upon execution
+; of the CPUID instruction, a VMM Communication Exception will occur.
+; This will tell us if SEV-ES is enabled. We can use the current value
+; of the GHCB MSR to determine the SEV attributes.
+;
+IDT_BASE:
+;
+; Vectors 0 - 28
+;
+%rep 29
+ dw (ADDR_OF(SevEsIdtCommon) & 0xffff) ; Offset low bits 15..0
+ dw 0x10 ; Selector
+ db 0 ; Reserved
+ db 0x8E ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+ dw (ADDR_OF(SevEsIdtCommon) >> 16) ; Offset high bits 31..16
+%endrep
+;
+; Vector 29 (VMM Communication Exception)
+;
+ dw (ADDR_OF(SevEsIdtVmmComm) & 0xffff) ; Offset low bits 15..0
+ dw 0x10 ; Selector
+ db 0 ; Reserved
+ db 0x8E ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+ dw (ADDR_OF(SevEsIdtVmmComm) >> 16) ; Offset high bits 31..16
+;
+; Vectors 30 - 31
+;
+%rep 2
+ dw (ADDR_OF(SevEsIdtCommon) & 0xffff) ; Offset low bits 15..0
+ dw 0x10 ; Selector
+ db 0 ; Reserved
+ db 0x8E ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+ dw (ADDR_OF(SevEsIdtCommon) >> 16) ; Offset high bits 31..16
+%endrep
+IDT_END:
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 75cfe16654b1..3b213cd05ab2 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -55,6 +55,7 @@
%define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
%include "Ia32/Flat32ToFlat64.asm"
+ %define SEV_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
%include "Ia32/PageTables64.asm"
%endif
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
` (25 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Create a function that can be used to determine if the VM is running
as an SEV-ES guest.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/Include/Library/MemEncryptSevLib.h | 12 +++
.../MemEncryptSevLibInternal.c | 77 ++++++++++++-------
2 files changed, 62 insertions(+), 27 deletions(-)
diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h
index 64dd6977b0f8..a50a0de9c870 100644
--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h
+++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h
@@ -13,6 +13,18 @@
#include <Base.h>
+/**
+ Returns a boolean to indicate whether SEV-ES is enabled
+
+ @retval TRUE SEV-ES is enabled
+ @retval FALSE SEV-ES is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevEsIsEnabled (
+ VOID
+ );
+
/**
Returns a boolean to indicate whether SEV is enabled
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
index 96a66e373f11..9c1d68e017fe 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
@@ -20,19 +20,17 @@
#include <Uefi/UefiBaseType.h>
STATIC BOOLEAN mSevStatus = FALSE;
+STATIC BOOLEAN mSevEsStatus = FALSE;
STATIC BOOLEAN mSevStatusChecked = FALSE;
/**
- Returns a boolean to indicate whether SEV is enabled
-
- @retval TRUE SEV is enabled
- @retval FALSE SEV is not enabled
+ Reads and sets the status of SEV features
**/
STATIC
-BOOLEAN
+VOID
EFIAPI
-InternalMemEncryptSevIsEnabled (
+InternalMemEncryptSevStatus (
VOID
)
{
@@ -56,32 +54,57 @@ InternalMemEncryptSevIsEnabled (
//
Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
if (Msr.Bits.SevBit) {
- return TRUE;
+ mSevStatus = TRUE;
+ }
+
+ if (Eax.Bits.SevEsBit) {
+ //
+ // Check MSR_0xC0010131 Bit 1 (Sev-Es Enabled)
+ //
+ if (Msr.Bits.SevEsBit) {
+ mSevEsStatus = TRUE;
+ }
}
}
}
- return FALSE;
-}
-
-/**
- Returns a boolean to indicate whether SEV is enabled
-
- @retval TRUE SEV is enabled
- @retval FALSE SEV is not enabled
-**/
-BOOLEAN
-EFIAPI
-MemEncryptSevIsEnabled (
- VOID
- )
-{
- if (mSevStatusChecked) {
- return mSevStatus;
- }
-
- mSevStatus = InternalMemEncryptSevIsEnabled();
mSevStatusChecked = TRUE;
+}
+
+/**
+ Returns a boolean to indicate whether SEV-ES is enabled
+
+ @retval TRUE SEV-ES is enabled
+ @retval FALSE SEV-ES is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevEsIsEnabled (
+ VOID
+ )
+{
+ if (!mSevStatusChecked) {
+ InternalMemEncryptSevStatus();
+ }
+
+ return mSevEsStatus;
+}
+
+/**
+ Returns a boolean to indicate whether SEV is enabled
+
+ @retval TRUE SEV is enabled
+ @retval FALSE SEV is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevIsEnabled (
+ VOID
+ )
+{
+ if (!mSevStatusChecked) {
+ InternalMemEncryptSevStatus();
+ }
return mSevStatus;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (2 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-21 14:25 ` [edk2-devel] " Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
` (24 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
A GHCB page is needed during the Sec phase, so this new page must be
created. Since the GHCB must be marked as an un-encrypted, or shared,
page, an additional pagetable page is required so break down the 2MB
region where the GHCB page lives into 4K pagetable entries.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/OvmfPkg.dec | 5 +++
OvmfPkg/OvmfPkgX64.fdf | 11 ++++---
OvmfPkg/PlatformPei/PlatformPei.inf | 2 ++
OvmfPkg/ResetVector/ResetVector.inf | 2 ++
UefiCpuPkg/Include/Register/Amd/Fam17Msr.h | 28 ++++++++++++++++
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 37 +++++++++++++++++++++-
OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
7 files changed, 81 insertions(+), 6 deletions(-)
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 9640360f6245..2ead9a944af4 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -218,6 +218,11 @@ [PcdsFixedAtBuild]
# The value should be a multiple of 4KB.
gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
+ ## Specify the GHCB base address and size.
+ # The value should be a multiple of 4KB for each.
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x32
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x33
+
[PcdsDynamic, PcdsDynamicEx]
gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 74407072563b..2a2427092382 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -67,13 +67,16 @@ [FD.MEMFD]
BlockSize = 0x10000
NumBlocks = 0xC0
-0x000000|0x006000
+0x000000|0x007000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
-0x006000|0x001000
-gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
-
0x007000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+
+0x008000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+
+0x009000|0x001000
gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
0x010000|0x010000
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index d9fd9c8f05b3..aed1f64b7c93 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -72,6 +72,8 @@ [Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 960b47cd0797..d66f4dc29737 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -37,3 +37,5 @@ [Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
diff --git a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
index 37b935dcdb30..55a5723e164e 100644
--- a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
+++ b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
@@ -17,6 +17,34 @@
#ifndef __FAM17_MSR_H__
#define __FAM17_MSR_H__
+/**
+ Secure Encrypted Virtualization - Encrypted State (SEV-ES) GHCB register
+
+**/
+#define MSR_SEV_ES_GHCB 0xc0010130
+
+/**
+ MSR information returned for #MSR_SEV_ES_GHCB
+**/
+typedef union {
+ struct {
+ UINT32 GhcbNegotiateBit:1;
+
+ UINT32 Reserved:31;
+ } Bits;
+
+ struct {
+ UINT8 Reserved[3];
+ UINT8 SevEncryptionBitPos;
+ UINT16 SevEsProtocolMin;
+ UINT16 SevEsProtocolMax;
+ } GhcbProtocol;
+
+ VOID *Ghcb;
+
+ UINT64 GhcbPhysicalAddress;
+} MSR_SEV_ES_GHCB_REGISTER;
+
/**
Secure Encrypted Virtualization (SEV) status register
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index c6071fe934de..fd4d5b1d8661 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -21,6 +21,11 @@ BITS 32
%define PAGE_2M_MBO 0x080
%define PAGE_2M_PAT 0x01000
+%define PAGE_4K_PDE_ATTR (PAGE_ACCESSED + \
+ PAGE_DIRTY + \
+ PAGE_READ_WRITE + \
+ PAGE_PRESENT)
+
%define PAGE_2M_PDE_ATTR (PAGE_2M_MBO + \
PAGE_ACCESSED + \
PAGE_DIRTY + \
@@ -120,7 +125,7 @@ SevNotActive:
; more permanent location by DxeIpl.
;
- mov ecx, 6 * 0x1000 / 4
+ mov ecx, 7 * 0x1000 / 4
xor eax, eax
clearPageTablesMemoryLoop:
mov dword[ecx * 4 + PT_ADDR (0) - 4], eax
@@ -157,6 +162,36 @@ pageTableEntriesLoop:
mov [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
loop pageTableEntriesLoop
+ ;
+ ; The GHCB will live at 0x807000 (just after the page tables)
+ ; and needs to be un-encrypted. This requires the 2MB page
+ ; (index 4 in the first 1GB page) for this range be broken down
+ ; into 512 4KB pages. All will be marked as encrypted, except
+ ; for the GHCB.
+ ;
+ mov ecx, 4
+ mov eax, PT_ADDR (0x6000) + PAGE_PDP_ATTR
+ mov [ecx * 8 + PT_ADDR (0x2000)], eax
+
+ mov ecx, 512
+pageTableEntries4kLoop:
+ mov eax, ecx
+ dec eax
+ shl eax, 12
+ add eax, 0x800000
+ add eax, PAGE_4K_PDE_ATTR
+ mov [ecx * 8 + PT_ADDR (0x6000 - 8)], eax
+ mov [(ecx * 8 + PT_ADDR (0x6000 - 8)) + 4], edx
+ loop pageTableEntries4kLoop
+
+ ;
+ ; Clear the encryption bit from the GHCB entry (index 7 in the
+ ; new PTE table - (0x807000 - 0x800000) >> 12).
+ ;
+ mov ecx, 7
+ xor edx, edx
+ mov [(ecx * 8 + PT_ADDR (0x6000)) + 4], edx
+
;
; Set CR3 now that the paging structures are available
;
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 3b213cd05ab2..56d9b86ed943 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -49,7 +49,7 @@
%ifdef ARCH_X64
#include <AutoGen.h>
- %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x6000)
+ %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x7000)
%error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
%endif
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (3 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-21 14:31 ` [edk2-devel] " Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
` (23 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Allocate memory for the GHCB pages during SEV initialization for use
during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
pages, modify CreateIdentityMappingPageTables() so that pagetable entries
are created without the encryption bit set.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
UefiCpuPkg/UefiCpuPkg.dec | 4 ++
OvmfPkg/OvmfPkgX64.dsc | 4 ++
MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +
OvmfPkg/PlatformPei/PlatformPei.inf | 2 +
.../Core/DxeIplPeim/X64/VirtualMemory.h | 12 +++-
.../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 4 +-
.../Core/DxeIplPeim/X64/DxeLoadFunc.c | 11 +++-
.../Core/DxeIplPeim/X64/VirtualMemory.c | 49 ++++++++++----
.../MemEncryptSevLibInternal.c | 1 -
.../BaseMemEncryptSevLib/X64/VirtualMemory.c | 33 ++++++++--
OvmfPkg/PlatformPei/AmdSev.c | 64 +++++++++++++++++++
11 files changed, 164 insertions(+), 23 deletions(-)
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 6ddf0cd22466..4d5a2593cf13 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -323,5 +323,9 @@ [PcdsDynamic, PcdsDynamicEx]
# @ValidRange 0x80000001 | 0 - 1
gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme|0x0|UINT8|0x60000015
+ ## Contains the GHCB page allocation information.<BR><BR>
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
+
[UserExtensions.TianoCore."ExtraFiles"]
UefiCpuPkgExtra.uni
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index dda8dac18441..d6fc7cdf7da8 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -569,6 +569,10 @@ [PcdsDynamicDefault]
# Set memory encryption mask
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
+ # Set GHCB base address for SEV-ES
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0
+
!if $(SMM_REQUIRE) == TRUE
gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index abc3217b0179..b994398633e3 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -52,6 +52,7 @@ [Sources.ARM, Sources.AARCH64]
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
[Packages.ARM, Packages.AARCH64]
ArmPkg/ArmPkg.dec
@@ -110,6 +111,8 @@ [Pcd.IA32,Pcd.X64]
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize ## CONSUMES
[Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index aed1f64b7c93..f53195e6dda5 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -102,6 +102,8 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
index 2d0493f109e8..6b7c38a441d6 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
@@ -201,6 +201,8 @@ EnableExecuteDisableBit (
@param[in, out] PageEntry2M Pointer to 2M page entry.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
**/
VOID
@@ -208,7 +210,9 @@ Split2MPageTo4K (
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
IN OUT UINT64 *PageEntry2M,
IN EFI_PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
);
/**
@@ -217,6 +221,8 @@ Split2MPageTo4K (
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
@return The address of 4 level page map.
@@ -224,7 +230,9 @@ Split2MPageTo4K (
UINTN
CreateIdentityMappingPageTables (
IN EFI_PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbkSize
);
diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
index 172d7cd1c60c..630a3503f6ba 100644
--- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -123,7 +123,7 @@ Create4GPageTablesIa32Pae (
//
// Need to split this 2M page that covers stack range.
//
- Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
+ Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
} else {
//
// Fill in the Page Directory entries
@@ -278,7 +278,7 @@ HandOffToDxeCore (
//
// Create page table and save PageMapLevel4 to CR3
//
- PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);
+ PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
//
// End of PEI phase signal
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
index 2867610bff4d..77da20e5c5c5 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
@@ -35,6 +35,8 @@ HandOffToDxeCore (
UINT32 Index;
EFI_VECTOR_HANDOFF_INFO *VectorInfo;
EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
+ VOID *GhcbBase;
+ UINTN GhcbSize;
if (IsNullDetectionEnabled ()) {
ClearFirst4KPage (HobList.Raw);
@@ -77,12 +79,19 @@ HandOffToDxeCore (
TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+ //
+ // Get the address and size of the GHCB pages
+ //
+ GhcbBase = (VOID *) PcdGet64 (PcdGhcbBase);
+ GhcbSize = PcdGet64 (PcdGhcbSize);
+
PageTables = 0;
if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
//
// Create page table and save PageMapLevel4 to CR3
//
- PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE);
+ PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) GhcbBase, GhcbSize);
} else {
//
// Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index edc38e4525c4..b3c3c3276e6a 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -180,6 +180,8 @@ EnableExecuteDisableBit (
@param Size Size of the given physical memory.
@param StackBase Base address of stack.
@param StackSize Size of stack.
+ @param GhcbBase Base address of GHCB pages.
+ @param GhcbSize Size of GHCB area.
@retval TRUE Page table should be split.
@retval FALSE Page table should not be split.
@@ -189,7 +191,9 @@ ToSplitPageTable (
IN EFI_PHYSICAL_ADDRESS Address,
IN UINTN Size,
IN EFI_PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
)
{
if (IsNullDetectionEnabled () && Address == 0) {
@@ -208,6 +212,12 @@ ToSplitPageTable (
}
}
+ if (GhcbBase) {
+ if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
+ return TRUE;
+ }
+ }
+
return FALSE;
}
/**
@@ -321,6 +331,8 @@ AllocatePageTableMemory (
@param[in, out] PageEntry2M Pointer to 2M page entry.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
**/
VOID
@@ -328,7 +340,9 @@ Split2MPageTo4K (
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
IN OUT UINT64 *PageEntry2M,
IN EFI_PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
)
{
EFI_PHYSICAL_ADDRESS PhysicalAddress4K;
@@ -354,7 +368,12 @@ Split2MPageTo4K (
//
// Fill in the Page Table entries
//
- PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
+ PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
+ if (!GhcbBase
+ || (PhysicalAddress4K < GhcbBase)
+ || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
+ PageTableEntry->Uint64 |= AddressEncMask;
+ }
PageTableEntry->Bits.ReadWrite = 1;
if ((IsNullDetectionEnabled () && PhysicalAddress4K == 0) ||
@@ -382,6 +401,8 @@ Split2MPageTo4K (
@param[in, out] PageEntry1G Pointer to 1G page entry.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
**/
VOID
@@ -389,7 +410,9 @@ Split1GPageTo2M (
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
IN OUT UINT64 *PageEntry1G,
IN EFI_PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
)
{
EFI_PHYSICAL_ADDRESS PhysicalAddress2M;
@@ -412,11 +435,11 @@ Split1GPageTo2M (
PhysicalAddress2M = PhysicalAddress;
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
- if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize)) {
+ if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
//
// Need to split this 2M page that covers NULL or stack range.
//
- Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
+ Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
} else {
//
// Fill in the Page Directory entries
@@ -615,6 +638,8 @@ EnablePageTableProtection (
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB base address.
+ @param[in] GhcbSize GHCB size.
@return The address of 4 level page map.
@@ -622,7 +647,9 @@ EnablePageTableProtection (
UINTN
CreateIdentityMappingPageTables (
IN EFI_PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
)
{
UINT32 RegEax;
@@ -734,8 +761,8 @@ CreateIdentityMappingPageTables (
PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
- if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
- Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
+ if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
+ Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
} else {
//
// Fill in the Page Directory entries
@@ -763,11 +790,11 @@ CreateIdentityMappingPageTables (
PageDirectoryPointerEntry->Bits.Present = 1;
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
- if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
+ if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
//
// Need to split this 2M page that covers NULL or stack range.
//
- Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
+ Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
} else {
//
// Fill in the Page Directory entries
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
index 9c1d68e017fe..1dce01dd7546 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
@@ -109,7 +109,6 @@ MemEncryptSevIsEnabled (
return mSevStatus;
}
-
/**
Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
Save State Map.
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
index 5e110c84ff81..3a4f223f8a86 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
@@ -183,6 +183,8 @@ AllocatePageTableMemory (
@param[in, out] PageEntry2M Pointer to 2M page entry.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
**/
STATIC
@@ -191,7 +193,9 @@ Split2MPageTo4K (
IN PHYSICAL_ADDRESS PhysicalAddress,
IN OUT UINT64 *PageEntry2M,
IN PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
)
{
PHYSICAL_ADDRESS PhysicalAddress4K;
@@ -217,7 +221,12 @@ Split2MPageTo4K (
//
// Fill in the Page Table entries
//
- PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
+ PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
+ if (!GhcbBase
+ || (PhysicalAddress4K < GhcbBase)
+ || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
+ PageTableEntry->Uint64 |= AddressEncMask;
+ }
PageTableEntry->Bits.ReadWrite = 1;
PageTableEntry->Bits.Present = 1;
if ((PhysicalAddress4K >= StackBase) &&
@@ -417,6 +426,8 @@ EnablePageTableProtection (
@param[in, out] PageEntry1G Pointer to 1G page entry.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
**/
STATIC
@@ -425,7 +436,9 @@ Split1GPageTo2M (
IN PHYSICAL_ADDRESS PhysicalAddress,
IN OUT UINT64 *PageEntry1G,
IN PHYSICAL_ADDRESS StackBase,
- IN UINTN StackSize
+ IN UINTN StackSize,
+ IN PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
)
{
PHYSICAL_ADDRESS PhysicalAddress2M;
@@ -450,8 +463,10 @@ Split1GPageTo2M (
(IndexOfPageDirectoryEntries++,
PageDirectoryEntry++,
PhysicalAddress2M += SIZE_2MB)) {
- if ((PhysicalAddress2M < StackBase + StackSize) &&
- ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
+ if (((PhysicalAddress2M < StackBase + StackSize) &&
+ ((PhysicalAddress2M + SIZE_2MB) > StackBase)) ||
+ ((PhysicalAddress2M < GhcbBase + GhcbSize) &&
+ ((PhysicalAddress2M + SIZE_2MB) > GhcbBase))) {
//
// Need to split this 2M page that covers stack range.
//
@@ -459,7 +474,9 @@ Split1GPageTo2M (
PhysicalAddress2M,
(UINT64 *)PageDirectoryEntry,
StackBase,
- StackSize
+ StackSize,
+ GhcbBase,
+ GhcbSize
);
} else {
//
@@ -714,6 +731,8 @@ SetMemoryEncDec (
(UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
(UINT64 *)PageDirectory1GEntry,
0,
+ 0,
+ 0,
0
);
continue;
@@ -768,6 +787,8 @@ SetMemoryEncDec (
(UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
(UINT64 *)PageDirectory2MEntry,
0,
+ 0,
+ 0,
0
);
continue;
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 2ae8126ccf8a..84896d4681f9 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -16,9 +16,68 @@
#include <PiPei.h>
#include <Register/Amd/Cpuid.h>
#include <Register/Cpuid.h>
+#include <Register/Amd/Msr.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
#include "Platform.h"
+/**
+
+ Initialize SEV-ES support if running an SEV-ES guest.
+
+ **/
+STATIC
+VOID
+AmdSevEsInitialize (
+ VOID
+ )
+{
+ VOID *GhcbBase;
+ PHYSICAL_ADDRESS GhcbBasePa;
+ UINTN GhcbPageCount;
+ RETURN_STATUS DecryptStatus, PcdStatus;
+
+ if (!MemEncryptSevEsIsEnabled ()) {
+ return;
+ }
+
+ GhcbPageCount = mMaxCpuCount;
+
+ //
+ // Allocate GHCB pages.
+ //
+ GhcbBase = AllocatePages (GhcbPageCount);
+ ASSERT (GhcbBase);
+
+ GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
+
+ DecryptStatus = MemEncryptSevClearPageEncMask (
+ 0,
+ GhcbBasePa,
+ GhcbPageCount,
+ TRUE
+ );
+ ASSERT_RETURN_ERROR (DecryptStatus);
+
+ BuildMemoryAllocationHob (
+ GhcbBasePa,
+ EFI_PAGES_TO_SIZE (GhcbPageCount),
+ EfiBootServicesData
+ );
+
+ SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
+
+ PcdStatus = PcdSet64S (PcdGhcbBase, (UINT64)GhcbBasePa);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
+
+ AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
+}
+
/**
Function checks if SEV support is available, if present then it sets
@@ -89,4 +148,9 @@ AmdSevInitialize (
EfiBootServicesData // MemoryType
);
}
+
+ //
+ // Check and perform SEV-ES initialization if required.
+ //
+ AmdSevEsInitialize ();
}
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (4 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
` (22 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
A per-CPU implementation for holding values specific to a CPU when
running as an SEV-ES guest, specifically to hold the Debug Register
value. Allocate an extra page immediately after the GHCB page for each
AP.
Using the page after the GHCB ensures that it is unique per AP. But,
it also ends up being marked shared/unencrypted when it doesn't need to
be. It is possible, during PEI, to mark only the GHCB pages as shared,
but DXE is not as easy. There needs to be a way to change the pagetables
created for DXE using CreateIdentityMappingPageTables() before switching
to them.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/OvmfPkgX64.fdf | 8 ++++----
OvmfPkg/PlatformPei/AmdSev.c | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 2a2427092382..3ba3d7384745 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -70,13 +70,13 @@ [FD.MEMFD]
0x000000|0x007000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
-0x007000|0x001000
+0x007000|0x002000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
-0x008000|0x001000
-gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
-
0x009000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+
+0x00A000|0x001000
gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
0x010000|0x010000
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 84896d4681f9..87ac842a1590 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -42,7 +42,7 @@ AmdSevEsInitialize (
return;
}
- GhcbPageCount = mMaxCpuCount;
+ GhcbPageCount = mMaxCpuCount * 2;
//
// Allocate GHCB pages.
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (5 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-21 15:44 ` [edk2-devel] " Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
` (21 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
The SEV support will clear the C-bit from non-RAM areas. The early GDT
lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
will be read as un-encrypted even though it is encrypted. This will result
in a failure to be able to handle the exception.
Move the GDT into RAM so it can be accessed without error when running as
an SEV-ES guest.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/PlatformPei/AmdSev.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 87ac842a1590..5f4983fd36d8 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -37,6 +37,8 @@ AmdSevEsInitialize (
PHYSICAL_ADDRESS GhcbBasePa;
UINTN GhcbPageCount;
RETURN_STATUS DecryptStatus, PcdStatus;
+ IA32_DESCRIPTOR Gdtr;
+ VOID *Gdt;
if (!MemEncryptSevEsIsEnabled ()) {
return;
@@ -76,6 +78,20 @@ AmdSevEsInitialize (
DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
+
+ //
+ // The SEV support will clear the C-bit from the non-RAM areas. Since
+ // the GDT initially lives in that area and it will be read when a #VC
+ // exception happens, it needs to be moved to RAM for an SEV-ES guest.
+ //
+ AsmReadGdtr (&Gdtr);
+
+ Gdt = AllocatePool (Gdtr.Limit + 1);
+ ASSERT (Gdt);
+
+ CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
+ Gdtr.Base = (UINTN) Gdt;
+ AsmWriteGdtr (&Gdtr);
}
/**
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (6 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-19 21:47 ` Ni, Ray
2019-08-19 21:35 ` [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
` (20 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
VMGEXIT is a new instruction used for Hypervisor/Guest communication when
running as an SEV-ES guest. A VMGEXIT will cause an automatic exit (AE)
to occur, resulting in a #VMEXIT with an exit code value of 0x403.
To support VMGEXIT, define the VMGEXIT assember routine to issue the
instruction (rep; vmmcall), the GHCB structure and some helper functions
for communicating register information to and from the hypervisor and the
guest.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
MdePkg/Library/BaseLib/BaseLib.inf | 1 +
MdePkg/Include/Library/BaseLib.h | 14 ++
UefiCpuPkg/Include/Register/Amd/Ghcb.h | 197 ++++++++++++++++++++++++
MdePkg/Library/BaseLib/X64/GccInline.c | 17 ++
MdePkg/Library/BaseLib/X64/VmgExit.nasm | 38 +++++
5 files changed, 267 insertions(+)
create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 3586beb0ab5c..a41401340f95 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -286,6 +286,7 @@ [Sources.X64]
X64/ReadCr2.nasm| MSFT
X64/ReadCr0.nasm| MSFT
X64/ReadEflags.nasm| MSFT
+ X64/VmgExit.nasm | MSFT
X64/Non-existing.c
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 2a75bc023f56..80bd5cf57a72 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7880,6 +7880,20 @@ AsmLfence (
VOID
);
+/**
+ Executes a VMGEXIT instruction (VMMCALL with a REP prefix)
+
+ Executes a VMGEXIT instruction. This function is only available on IA-32 and
+ x64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+ VOID
+ );
+
+
/**
Patch the immediate operand of an IA32 or X64 instruction such that the byte,
word, dword or qword operand is encoded at the end of the instruction's
diff --git a/UefiCpuPkg/Include/Register/Amd/Ghcb.h b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
new file mode 100644
index 000000000000..e9fd116fac25
--- /dev/null
+++ b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
@@ -0,0 +1,197 @@
+
+#ifndef __GHCB_H__
+#define __GHCB_H__
+
+#include <Protocol/DebugSupport.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#define UD_EXCEPTION 6
+#define GP_EXCEPTION 13
+
+#define GHCB_VERSION_MIN 1
+#define GHCB_VERSION_MAX 1
+
+#define GHCB_STANDARD_USAGE 0
+
+typedef enum {
+ SvmExitDr7Read = 0x27,
+ SvmExitDr7Write = 0x37,
+ SvmExitRdtsc = 0x6E,
+ SvmExitRdpmc,
+ SvmExitCpuid = 0x72,
+ SvmExitInvd = 0x76,
+ SvmExitIoioProt = 0x7B,
+ SvmExitMsr,
+ SvmExitVmmCall = 0x81,
+ SvmExitRdtscp = 0x87,
+ SvmExitWbinvd = 0x89,
+ SvmExitMonitor,
+ SvmExitMwait,
+ SvmExitNpf = 0x400,
+
+ // VMG special exits
+ SvmExitMmioRead = 0x80000001,
+ SvmExitMmioWrite,
+ SvmExitNmiComplete,
+ SvmExitApResetHold,
+
+ SvmExitUnsupported = 0x8000FFFF,
+} SVM_EXITCODE;
+
+typedef enum {
+ GhcbCpl = 25,
+ GhcbRflags = 46,
+ GhcbRip,
+ GhcbRsp = 59,
+ GhcbRax = 63,
+ GhcbRcx = 97,
+ GhcbRdx,
+ GhcbRbx,
+ GhcbRbp = 101,
+ GhcbRsi,
+ GhcbRdi,
+ GhcbR8,
+ GhcbR9,
+ GhcbR10,
+ GhcbR11,
+ GhcbR12,
+ GhcbR13,
+ GhcbR14,
+ GhcbR15,
+ GhcbXCr0 = 125,
+} GHCB_REGISTER;
+
+typedef struct {
+ UINT8 Reserved1[203];
+ UINT8 Cpl;
+ UINT8 Reserved2[148];
+ UINT64 Dr7;
+ UINT8 Reserved3[144];
+ UINT64 Rax;
+ UINT8 Reserved4[264];
+ UINT64 Rcx;
+ UINT64 Rdx;
+ UINT64 Rbx;
+ UINT8 Reserved5[112];
+ UINT64 SwExitCode;
+ UINT64 SwExitInfo1;
+ UINT64 SwExitInfo2;
+ UINT64 SwScratch;
+ UINT8 Reserved6[56];
+ UINT64 XCr0;
+ UINT8 ValidBitmap[16];
+ UINT64 X87StateGpa;
+ UINT8 Reserved7[1016];
+} __attribute__ ((__packed__)) GHCB_SAVE_AREA;
+
+typedef struct {
+ GHCB_SAVE_AREA SaveArea;
+ UINT8 SharedBuffer[2032];
+ UINT8 Reserved1[10];
+ UINT16 ProtocolVersion;
+ UINT32 GhcbUsage;
+} __attribute__ ((__packed__)) __attribute__ ((aligned(SIZE_4KB))) GHCB;
+
+typedef union {
+ struct {
+ UINT32 Lower32Bits;
+ UINT32 Upper32Bits;
+ } Elements;
+
+ UINT64 Uint64;
+} GHCB_EXIT_INFO;
+
+static inline
+BOOLEAN
+GhcbIsRegValid(
+ GHCB *Ghcb,
+ GHCB_REGISTER Reg
+ )
+{
+ UINT32 RegIndex = Reg / 8;
+ UINT32 RegBit = Reg & 0x07;
+
+ return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
+}
+
+static inline
+VOID
+GhcbSetRegValid(
+ GHCB *Ghcb,
+ GHCB_REGISTER Reg
+ )
+{
+ UINT32 RegIndex = Reg / 8;
+ UINT32 RegBit = Reg & 0x07;
+
+ Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
+}
+
+static inline
+VOID
+VmgException(
+ UINTN Exception
+ )
+{
+ switch (Exception) {
+ case UD_EXCEPTION:
+ case GP_EXCEPTION:
+ break;
+ default:
+ ASSERT (0);
+ }
+}
+
+static inline
+UINTN
+VmgExit(
+ GHCB *Ghcb,
+ UINT64 ExitCode,
+ UINT64 ExitInfo1,
+ UINT64 ExitInfo2
+ )
+{
+ GHCB_EXIT_INFO ExitInfo;
+ UINTN Reason, Action;
+
+ Ghcb->SaveArea.SwExitCode = ExitCode;
+ Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
+ Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
+ AsmVmgExit ();
+
+ if (!Ghcb->SaveArea.SwExitInfo1) {
+ return 0;
+ }
+
+ ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
+ Reason = ExitInfo.Elements.Upper32Bits;
+ Action = ExitInfo.Elements.Lower32Bits;
+ switch (Action) {
+ case 1:
+ VmgException (Reason);
+ break;
+ default:
+ ASSERT (0);
+ }
+
+ return Reason;
+}
+
+static inline
+VOID
+VmgInit(
+ GHCB *Ghcb
+ )
+{
+ SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
+}
+
+static inline
+VOID
+VmgDone(
+ GHCB *Ghcb
+ )
+{
+}
+#endif
diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
index 154ce1f57e92..17539caa0798 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1798,3 +1798,20 @@ AsmFlushCacheLine (
}
+/**
+ Executes a VMGEXIT instruction.
+
+ Executes a VMGEXIT instruction. This function is only available on IA-32 and
+ X64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+ VOID
+ )
+{
+ __asm__ __volatile__ ("rep; vmmcall":::"memory");
+}
+
+
diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
new file mode 100644
index 000000000000..b673bb94b60d
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
@@ -0,0 +1,38 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; VmgExit.Asm
+;
+; Abstract:
+;
+; AsmVmgExit function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+ DEFAULT REL
+ SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; AsmVmgExit (
+; VOID
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmVmgExit)
+ASM_PFX(AsmVmgExit):
+ rep; vmmcall
+ ret
+
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (7 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase Lendacky, Thomas
` (19 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Add base support to handle #VC exceptions. This includes a stub routine
to invoke when a #VC exception occurs and special checks in the common
exception handlers to invoke the #VC exception handler routine.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../DxeCpuExceptionHandlerLib.inf | 2 ++
.../PeiCpuExceptionHandlerLib.inf | 2 ++
.../SecPeiCpuExceptionHandlerLib.inf | 2 ++
.../CpuExceptionHandlerLib/AMDSevVcCommon.h | 12 ++++++++++++
.../CpuExceptionHandlerLib/CpuExceptionCommon.h | 2 ++
.../CpuExceptionHandlerLib/CpuExceptionCommon.c | 2 +-
.../PeiDxeAMDSevVcHandler.c | 11 +++++++++++
.../PeiDxeSmmCpuException.c | 16 ++++++++++++++++
.../CpuExceptionHandlerLib/SecAMDSevVcHandler.c | 11 +++++++++++
.../CpuExceptionHandlerLib/SecPeiCpuException.c | 16 ++++++++++++++++
10 files changed, 75 insertions(+), 1 deletion(-)
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index e41383573043..331ae7334c45 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -37,6 +37,8 @@ [Sources.common]
CpuExceptionCommon.c
PeiDxeSmmCpuException.c
DxeException.c
+ PeiDxeAMDSevVcHandler.c
+ AMDSevVcCommon.h
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index f31423ac0f91..89b5d496e56f 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -37,6 +37,8 @@ [Sources.common]
CpuExceptionCommon.c
PeiCpuException.c
PeiDxeSmmCpuException.c
+ PeiDxeAMDSevVcHandler.c
+ AMDSevVcCommon.h
[Packages]
MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index 6d25cafe2ca3..5e5ab6244b11 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -36,6 +36,8 @@ [Sources.common]
CpuExceptionCommon.h
CpuExceptionCommon.c
SecPeiCpuException.c
+ SecAMDSevVcHandler.c
+ AMDSevVcCommon.h
[Packages]
MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
new file mode 100644
index 000000000000..ee52f3b5220d
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
@@ -0,0 +1,12 @@
+
+#ifndef _AMD_SEV_VC_COMMON_H_
+#define _AMD_SEV_VC_COMMON_H_
+
+#include <Protocol/DebugSupport.h>
+
+UINTN
+DoVcException(
+ EFI_SYSTEM_CONTEXT Context
+ );
+
+#endif
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
index 805dd9cbb4ff..0f274e7ea328 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
@@ -24,6 +24,8 @@
#define CPU_INTERRUPT_NUM 256
#define HOOKAFTER_STUB_SIZE 16
+#define VC_EXCEPTION 29
+
//
// Exception Error Code of Page-Fault Exception
//
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
index 8adbd43fefb4..39e4dd9e9417 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
@@ -14,7 +14,7 @@
//
// 1 means an error code will be pushed, otherwise 0
//
-CONST UINT32 mErrorCodeFlag = 0x00227d00;
+CONST UINT32 mErrorCodeFlag = 0x20227d00;
//
// Define the maximum message length
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
new file mode 100644
index 000000000000..1e027b3f2964
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
@@ -0,0 +1,11 @@
+
+#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcException(
+ EFI_SYSTEM_CONTEXT Context
+ )
+{
+ return 0;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
index 72c2aeca4c13..0c248e7eb904 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -7,6 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
#include <Library/DebugLib.h>
/**
@@ -86,6 +87,21 @@ CommonExceptionHandlerWorker (
break;
}
+ if (ExceptionType == VC_EXCEPTION) {
+ UINTN Status;
+ //
+ // #VC must be handled for an SEV-ES guest
+ //
+ Status = DoVcException(SystemContext);
+ if (Status) {
+ // Exception not handled - Status contains the desired exception now
+ ExceptionType = Status;
+ } else {
+ // Exception handled
+ return;
+ }
+ }
+
if (ExternalInterruptHandler != NULL &&
ExternalInterruptHandler[ExceptionType] != NULL) {
(ExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
new file mode 100644
index 000000000000..1e027b3f2964
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
@@ -0,0 +1,11 @@
+
+#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcException(
+ EFI_SYSTEM_CONTEXT Context
+ )
+{
+ return 0;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
index 20148db74cf8..998a90ba61a6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <PiPei.h>
#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
CONST UINTN mDoFarReturnFlag = 0;
@@ -24,6 +25,21 @@ CommonExceptionHandler (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
+ if (ExceptionType == VC_EXCEPTION) {
+ UINTN Status;
+ //
+ // #VC must be handled for an SEV-ES guest
+ //
+ Status = DoVcException(SystemContext);
+ if (Status) {
+ // Exception not handled - Status contains the desired exception now
+ ExceptionType = Status;
+ } else {
+ // Exception handled
+ return;
+ }
+ }
+
//
// Initialize the serial port before dumping.
//
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (8 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
` (18 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
An SEV-ES guest will generate a #VC exception when it encounters a
non-automatic exit (NAE) event. It is expected that the #VC exception
handler will communicate with the hypervisor using the GHCB to handle
the NAE event.
NAE events can occur during the Sec phase, so initialize exception
handling early in the OVMF Sec support. Add to the basic #VC exception
handler to set the GHCB MSR to a pre-allocated GHCB and call a common
#VC handler.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/Sec/SecMain.inf | 1 +
.../SecPeiCpuExceptionHandlerLib.inf | 2 ++
.../CpuExceptionHandlerLib/AMDSevVcCommon.h | 7 ++++
MdePkg/Library/BaseLib/Ia32/GccInline.c | 17 +++++++++
OvmfPkg/Sec/SecMain.c | 29 ++++++++-------
.../Ia32/AMDSevVcCommon.c | 13 +++++++
.../SecAMDSevVcHandler.c | 36 ++++++++++++++++++-
.../X64/AMDSevVcCommon.c | 27 ++++++++++++++
8 files changed, 118 insertions(+), 14 deletions(-)
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 63ba4cb555fb..7f53845f5436 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -50,6 +50,7 @@ [LibraryClasses]
PeCoffExtraActionLib
ExtractGuidedSectionLib
LocalApicLib
+ CpuExceptionHandlerLib
[Ppis]
gEfiTemporaryRamSupportPpiGuid # PPI ALWAYS_PRODUCED
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index 5e5ab6244b11..1b3605af5ca4 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -26,11 +26,13 @@ [Sources.Ia32]
Ia32/ExceptionTssEntryAsm.nasm
Ia32/ArchExceptionHandler.c
Ia32/ArchInterruptDefs.h
+ Ia32/AMDSevVcCommon.c
[Sources.X64]
X64/ExceptionHandlerAsm.nasm
X64/ArchExceptionHandler.c
X64/ArchInterruptDefs.h
+ X64/AMDSevVcCommon.c
[Sources.common]
CpuExceptionCommon.h
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
index ee52f3b5220d..94f9e6e5122d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
@@ -3,10 +3,17 @@
#define _AMD_SEV_VC_COMMON_H_
#include <Protocol/DebugSupport.h>
+#include <Register/Amd/Ghcb.h>
UINTN
DoVcException(
EFI_SYSTEM_CONTEXT Context
);
+UINTN
+DoVcCommon(
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT Context
+ );
+
#endif
diff --git a/MdePkg/Library/BaseLib/Ia32/GccInline.c b/MdePkg/Library/BaseLib/Ia32/GccInline.c
index 5287200f8754..55d2e12bcdc9 100644
--- a/MdePkg/Library/BaseLib/Ia32/GccInline.c
+++ b/MdePkg/Library/BaseLib/Ia32/GccInline.c
@@ -1763,3 +1763,20 @@ AsmFlushCacheLine (
}
+/**
+ Executes a VMGEXIT instruction.
+
+ Executes a VMGEXIT instruction. This function is only available on IA-32 and
+ X64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+ VOID
+ )
+{
+ __asm__ __volatile__ ("rep; vmmcall":::"memory");
+}
+
+
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 2448be0cd408..021c1bd30711 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -24,6 +24,7 @@
#include <Library/PeCoffExtraActionLib.h>
#include <Library/ExtractGuidedSectionLib.h>
#include <Library/LocalApicLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
#include <Ppi/TemporaryRamSupport.h>
@@ -737,6 +738,21 @@ SecCoreStartupWithStack (
Table[Index] = 0;
}
+ //
+ // Initialize IDT
+ //
+ IdtTableInStack.PeiService = NULL;
+ for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
+ CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
+ }
+
+ IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;
+ IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
+
+ AsmWriteIdtr (&IdtDescriptor);
+
+ InitializeCpuExceptionHandlers (NULL);
+
ProcessLibraryConstructorList (NULL, NULL);
//
@@ -756,19 +772,6 @@ SecCoreStartupWithStack (
//
InitializeFloatingPointUnits ();
- //
- // Initialize IDT
- //
- IdtTableInStack.PeiService = NULL;
- for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
- CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
- }
-
- IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;
- IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
-
- AsmWriteIdtr (&IdtDescriptor);
-
#if defined (MDE_CPU_X64)
//
// ASSERT that the Page Tables were set by the reset vector code to
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
new file mode 100644
index 000000000000..1b0c44bd6a61
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
@@ -0,0 +1,13 @@
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcCommon (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT Context
+ )
+{
+ return GP_EXCEPTION;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
index 1e027b3f2964..a32025d3481b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
@@ -1,11 +1,45 @@
+#include <Library/BaseLib.h>
+#include <Register/Amd/Msr.h>
#include "CpuExceptionCommon.h"
#include "AMDSevVcCommon.h"
+
+#define GHCB_INIT 0x807000
+
UINTN
DoVcException(
EFI_SYSTEM_CONTEXT Context
)
{
- return 0;
+ MSR_SEV_ES_GHCB_REGISTER Msr;
+ GHCB *Ghcb;
+
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+ Ghcb = Msr.Ghcb;
+
+ if (Msr.Bits.GhcbNegotiateBit) {
+ if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {
+ ASSERT (0);
+ return GP_EXCEPTION;
+ }
+
+ if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||
+ (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN)) {
+ ASSERT (0);
+ return GP_EXCEPTION;
+ }
+
+ Msr.GhcbPhysicalAddress = GHCB_INIT;
+ AsmWriteMsr64(MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+ Ghcb = Msr.Ghcb;
+ SetMem (Ghcb, sizeof (*Ghcb), 0);
+
+ /* Set the version to the maximum that can be supported */
+ Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);
+ Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;
+ }
+
+ return DoVcCommon(Ghcb, Context);
}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
new file mode 100644
index 000000000000..18e462ce80a2
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -0,0 +1,27 @@
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcCommon (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT Context
+ )
+{
+ EFI_SYSTEM_CONTEXT_X64 *Regs = Context.SystemContextX64;
+ UINTN ExitCode;
+ UINTN Status;
+
+ VmgInit (Ghcb);
+
+ ExitCode = Regs->ExceptionData;
+ switch (ExitCode) {
+ default:
+ Status = VmgExit (Ghcb, SvmExitUnsupported, ExitCode, 0);
+ }
+
+ VmgDone (Ghcb);
+
+ return Status;
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (9 preceding siblings ...)
2019-08-19 21:35 ` [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
` (17 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a IOIO_PROT intercept generates a #VC exception. VMGEXIT
must be used to allow the hypervisor to handle this intercept.
Add support to construct the required GHCB values to support a IOIO_PROT
NAE event. Parse the instruction that generated the #VC exception,
setting the required register values in the GHCB and creating the proper
SW_EXITINFO1 value in the GHCB.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 425 +++++++++++++++++-
1 file changed, 420 insertions(+), 5 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 18e462ce80a2..3b69aca48055 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -3,25 +3,440 @@
#include <Library/DebugLib.h>
#include "AMDSevVcCommon.h"
+typedef enum {
+ LongMode64Bit = 0,
+ LongModeCompat32Bit,
+ LongModeCompat16Bit,
+} SEV_ES_INSTRUCTION_MODE;
+
+typedef enum {
+ Size8Bits = 0,
+ Size16Bits,
+ Size32Bits,
+ Size64Bits,
+} SEV_ES_INSTRUCTION_SIZE;
+
+typedef enum {
+ SegmentEs = 0,
+ SegmentCs,
+ SegmentSs,
+ SegmentDs,
+ SegmentFs,
+ SegmentGs,
+} SEV_ES_INSTRUCTION_SEGMENT;
+
+typedef enum {
+ RepNone = 0,
+ RepZ,
+ RepNZ,
+} SEV_ES_INSTRUCTION_REP;
+
+typedef union {
+ struct {
+ UINT8 B:1;
+ UINT8 X:1;
+ UINT8 R:1;
+ UINT8 W:1;
+ UINT8 REX:4;
+ } Bits;
+
+ UINT8 Uint8;
+} SEV_ES_INSTRUCTION_REX_PREFIX;
+
+typedef union {
+ struct {
+ UINT8 Rm:3;
+ UINT8 Reg:3;
+ UINT8 Mod:2;
+ } Bits;
+
+ UINT8 Uint8;
+} SEV_ES_INSTRUCTION_MODRM;
+
+typedef union {
+ struct {
+ UINT8 Base:3;
+ UINT8 Index:3;
+ UINT8 Scale:2;
+ } Bits;
+
+ UINT8 Uint8;
+} SEV_ES_INSTRUCTION_SIB;
+
+typedef struct {
+ struct {
+ UINT8 Rm;
+ UINT8 Reg;
+ UINT8 Mod;
+ } ModRm;
+
+ struct {
+ UINT8 Base;
+ UINT8 Index;
+ UINT8 Scale;
+ } Sib;
+
+ UINTN RegData;
+ UINTN RmData;
+} SEV_ES_INSTRUCTION_OPCODE_EXT;
+
+typedef struct {
+ GHCB *Ghcb;
+
+ SEV_ES_INSTRUCTION_MODE Mode;
+ SEV_ES_INSTRUCTION_SIZE DataSize;
+ SEV_ES_INSTRUCTION_SIZE AddrSize;
+ BOOLEAN SegmentSpecified;
+ SEV_ES_INSTRUCTION_SEGMENT Segment;
+ SEV_ES_INSTRUCTION_REP RepMode;
+
+ UINT8 *Begin;
+ UINT8 *End;
+
+ UINT8 *Prefixes;
+ UINT8 *OpCodes;
+ UINT8 *Displacement;
+ UINT8 *Immediate;
+
+ SEV_ES_INSTRUCTION_REX_PREFIX RexPrefix;
+
+ BOOLEAN ModRmPresent;
+ SEV_ES_INSTRUCTION_MODRM ModRm;
+
+ BOOLEAN SibPresent;
+ SEV_ES_INSTRUCTION_SIB Sib;
+
+ UINT8 PrefixSize;
+ UINT8 OpCodeSize;
+ UINT8 DisplacementSize;
+ UINT8 ImmediateSize;
+
+ SEV_ES_INSTRUCTION_OPCODE_EXT Ext;
+} SEV_ES_INSTRUCTION_DATA;
+
+typedef
+UINTN
+(*NAE_EXIT) (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ );
+
+STATIC
+VOID
+DecodePrefixes (
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ SEV_ES_INSTRUCTION_MODE Mode;
+ SEV_ES_INSTRUCTION_SIZE ModeDataSize;
+ SEV_ES_INSTRUCTION_SIZE ModeAddrSize;
+ UINT8 *Byte;
+
+ /*TODO: Determine current mode - 64-bit for now */
+ Mode = LongMode64Bit;
+ ModeDataSize = Size32Bits;
+ ModeAddrSize = Size64Bits;
+
+ InstructionData->Mode = Mode;
+ InstructionData->DataSize = ModeDataSize;
+ InstructionData->AddrSize = ModeAddrSize;
+
+ InstructionData->Prefixes = InstructionData->Begin;
+
+ Byte = InstructionData->Prefixes;
+ for ( ; ; Byte++, InstructionData->PrefixSize++) {
+ switch (*Byte) {
+ case 0x26:
+ case 0x2E:
+ case 0x36:
+ case 0x3E:
+ if (Mode != LongMode64Bit) {
+ InstructionData->SegmentSpecified = TRUE;
+ InstructionData->Segment = (*Byte >> 3) & 3;
+ }
+ break;
+
+ case 0x40 ... 0x4F:
+ InstructionData->RexPrefix.Uint8 = *Byte;
+ if (*Byte & 0x08)
+ InstructionData->DataSize = Size64Bits;
+ break;
+
+ case 0x64:
+ InstructionData->SegmentSpecified = TRUE;
+ InstructionData->Segment = *Byte & 7;
+ break;
+
+ case 0x66:
+ if (!InstructionData->RexPrefix.Uint8) {
+ InstructionData->DataSize =
+ (Mode == LongMode64Bit) ? Size16Bits :
+ (Mode == LongModeCompat32Bit) ? Size16Bits :
+ (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
+ }
+ break;
+
+ case 0x67:
+ InstructionData->AddrSize =
+ (Mode == LongMode64Bit) ? Size32Bits :
+ (Mode == LongModeCompat32Bit) ? Size16Bits :
+ (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
+ break;
+
+ case 0xF0:
+ break;
+
+ case 0xF2:
+ InstructionData->RepMode = RepZ;
+ break;
+
+ case 0xF3:
+ InstructionData->RepMode = RepNZ;
+ break;
+
+ default:
+ InstructionData->OpCodes = Byte;
+ InstructionData->OpCodeSize = (*Byte == 0x0F) ? 2 : 1;
+
+ InstructionData->End = Byte + InstructionData->OpCodeSize;
+ InstructionData->Displacement = InstructionData->End;
+ InstructionData->Immediate = InstructionData->End;
+ return;
+ }
+ }
+}
+
+STATIC
+UINT64
+InstructionLength (
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ return (UINT64) (InstructionData->End - InstructionData->Begin);
+}
+
+STATIC
+VOID
+InitInstructionData (
+ SEV_ES_INSTRUCTION_DATA *InstructionData,
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs
+ )
+{
+ SetMem (InstructionData, sizeof (*InstructionData), 0);
+ InstructionData->Ghcb = Ghcb;
+ InstructionData->Begin = (UINT8 *) Regs->Rip;
+ InstructionData->End = (UINT8 *) Regs->Rip;
+
+ DecodePrefixes (Regs, InstructionData);
+}
+
+STATIC
+UINTN
+UnsupportedExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ Status = VmgExit (Ghcb, SvmExitUnsupported, Regs->ExceptionData, 0);
+ ASSERT (0);
+
+ return Status;
+}
+
+#define IOIO_TYPE_STR (1 << 2)
+#define IOIO_TYPE_IN 1
+#define IOIO_TYPE_INS (IOIO_TYPE_IN | IOIO_TYPE_STR)
+#define IOIO_TYPE_OUT 0
+#define IOIO_TYPE_OUTS (IOIO_TYPE_OUT | IOIO_TYPE_STR)
+
+#define IOIO_REP (1 << 3)
+
+#define IOIO_ADDR_64 (1 << 9)
+#define IOIO_ADDR_32 (1 << 8)
+#define IOIO_ADDR_16 (1 << 7)
+
+#define IOIO_DATA_32 (1 << 6)
+#define IOIO_DATA_16 (1 << 5)
+#define IOIO_DATA_8 (1 << 4)
+
+#define IOIO_SEG_ES (0 << 10)
+#define IOIO_SEG_DS (3 << 10)
+
+STATIC
+UINT64
+IoioExitInfo (
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINT64 ExitInfo = 0;
+
+ switch (*(InstructionData->OpCodes)) {
+ case 0xE4: /* IN AL, imm8 */
+ InstructionData->ImmediateSize = 1;
+ InstructionData->End++;
+ ExitInfo |= IOIO_TYPE_IN;
+ ExitInfo |= IOIO_DATA_8;
+ ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
+ break;
+ case 0xE5: /* IN AX, imm8 / IN EAX, imm8 */
+ InstructionData->ImmediateSize = 1;
+ InstructionData->End++;
+ ExitInfo |= IOIO_TYPE_IN;
+ ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+ : IOIO_DATA_32;
+ ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
+ break;
+
+ case 0xEC: /* IN AL, DX */
+ ExitInfo |= IOIO_TYPE_IN;
+ ExitInfo |= IOIO_DATA_8;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+ case 0xED: /* IN AX, DX / IN EAX, DX */
+ ExitInfo |= IOIO_TYPE_IN;
+ ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+ : IOIO_DATA_32;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+
+ case 0xE6: /* OUT imm8, AL */
+ InstructionData->ImmediateSize = 1;
+ InstructionData->End++;
+ ExitInfo |= IOIO_TYPE_OUT;
+ ExitInfo |= IOIO_DATA_8;
+ ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
+ break;
+ case 0xE7: /* OUT imm8, AX / OUT imm8, EAX */
+ InstructionData->ImmediateSize = 1;
+ InstructionData->End++;
+ ExitInfo |= IOIO_TYPE_OUT;
+ ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+ : IOIO_DATA_32;
+ ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
+ break;
+
+ case 0xEE: /* OUT DX, AL */
+ ExitInfo |= IOIO_TYPE_OUT;
+ ExitInfo |= IOIO_DATA_8;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+ case 0xEF: /* OUT DX, AX / OUT DX, EAX */
+ ExitInfo |= IOIO_TYPE_OUT;
+ ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+ : IOIO_DATA_32;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+
+ default:
+ return 0;
+ }
+
+ switch (InstructionData->AddrSize) {
+ case Size16Bits:
+ ExitInfo |= IOIO_ADDR_16;
+ break;
+
+ case Size32Bits:
+ ExitInfo |= IOIO_ADDR_32;
+ break;
+
+ case Size64Bits:
+ ExitInfo |= IOIO_ADDR_64;
+ break;
+
+ default:
+ break;
+ }
+
+ if (InstructionData->RepMode) {
+ ExitInfo |= IOIO_REP;
+ }
+
+ return ExitInfo;
+}
+
+STATIC
+UINTN
+IoioExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINT64 ExitInfo1;
+ UINTN Status;
+
+ ExitInfo1 = IoioExitInfo (Regs, InstructionData);
+ if (!ExitInfo1) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
+ ASSERT (0);
+ }
+
+ if (!(ExitInfo1 & IOIO_TYPE_IN)) {
+ Ghcb->SaveArea.Rax = Regs->Rax;
+ GhcbSetRegValid (Ghcb, GhcbRax);
+ }
+
+ //FIXME: This is likely needed for the merging cases (size<32 bits)
+ // Pass in zero and perform merge here (only for non-string)
+ Ghcb->SaveArea.Rax = Regs->Rax;
+ GhcbSetRegValid (Ghcb, GhcbRax);
+
+ Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (ExitInfo1 & IOIO_TYPE_IN) {
+ if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
+ }
+
+ return 0;
+}
+
UINTN
DoVcCommon (
GHCB *Ghcb,
EFI_SYSTEM_CONTEXT Context
)
{
- EFI_SYSTEM_CONTEXT_X64 *Regs = Context.SystemContextX64;
- UINTN ExitCode;
- UINTN Status;
+ EFI_SYSTEM_CONTEXT_X64 *Regs = Context.SystemContextX64;
+ SEV_ES_INSTRUCTION_DATA InstructionData;
+ NAE_EXIT NaeExit;
+ UINTN ExitCode;
+ UINTN Status;
VmgInit (Ghcb);
ExitCode = Regs->ExceptionData;
switch (ExitCode) {
+ case SvmExitIoioProt:
+ NaeExit = IoioExit;
+ break;
+
default:
- Status = VmgExit (Ghcb, SvmExitUnsupported, ExitCode, 0);
+ NaeExit = UnsupportedExit;
+ }
+
+ InitInstructionData (&InstructionData, Ghcb, Regs);
+
+ Status = NaeExit (Ghcb, Regs, &InstructionData);
+ if (!Status) {
+ Regs->Rip += InstructionLength(&InstructionData);
}
VmgDone (Ghcb);
- return Status;
+ return 0;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (10 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
` (16 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Add support to the #VC exception handler to handle string IO. This
requires expanding the IO instruction parsing to recognize string based
IO instructions as well as preparing an un-encrypted buffer to be used
to transfer (either to or from the guest) the string contents for the IO
operation. The SW_EXITINFO2 and SW_SCRATCH fields of the GHCB are set
appropriately for the operation. Multiple VMGEXIT invocations may be
needed to complete the string IO operation.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 92 ++++++++++++++++---
1 file changed, 80 insertions(+), 12 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 3b69aca48055..2bc156840e74 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -278,6 +278,34 @@ IoioExitInfo (
UINT64 ExitInfo = 0;
switch (*(InstructionData->OpCodes)) {
+ case 0x6C: /* INSB / INS mem8, DX */
+ ExitInfo |= IOIO_TYPE_INS;
+ ExitInfo |= IOIO_DATA_8;
+ ExitInfo |= IOIO_SEG_ES;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+ case 0x6D: /* INSW / INS mem16, DX / INSD / INS mem32, DX */
+ ExitInfo |= IOIO_TYPE_INS;
+ ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+ : IOIO_DATA_32;
+ ExitInfo |= IOIO_SEG_ES;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+
+ case 0x6E: /* OUTSB / OUTS DX, mem8 */
+ ExitInfo |= IOIO_TYPE_OUTS;
+ ExitInfo |= IOIO_DATA_8;
+ ExitInfo |= IOIO_SEG_DS;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+ case 0x6F: /* OUTSW / OUTS DX, mem16 / OUTSD / OUTS DX, mem32 */
+ ExitInfo |= IOIO_TYPE_OUTS;
+ ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+ : IOIO_DATA_32;
+ ExitInfo |= IOIO_SEG_DS;
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+ break;
+
case 0xE4: /* IN AL, imm8 */
InstructionData->ImmediateSize = 1;
InstructionData->End++;
@@ -370,8 +398,9 @@ IoioExit (
SEV_ES_INSTRUCTION_DATA *InstructionData
)
{
- UINT64 ExitInfo1;
- UINTN Status;
+ UINT64 ExitInfo1, ExitInfo2;
+ UINTN Status;
+ BOOLEAN String;
ExitInfo1 = IoioExitInfo (Regs, InstructionData);
if (!ExitInfo1) {
@@ -389,17 +418,56 @@ IoioExit (
Ghcb->SaveArea.Rax = Regs->Rax;
GhcbSetRegValid (Ghcb, GhcbRax);
- Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, 0);
- if (Status) {
- return Status;
- }
-
- if (ExitInfo1 & IOIO_TYPE_IN) {
- if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
- VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
- ASSERT (0);
+ String = (ExitInfo1 & IOIO_TYPE_STR) ? TRUE : FALSE;
+ if (String) {
+ UINTN IoBytes, VmgExitBytes;
+ UINTN GhcbCount, OpCount;
+
+ Status = 0;
+
+ IoBytes = (ExitInfo1 >> 4) & 0x7;
+ GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
+
+ OpCount = (ExitInfo1 & IOIO_REP) ? Regs->Rcx : 1;
+ while (OpCount) {
+ ExitInfo2 = MIN (OpCount, GhcbCount);
+ VmgExitBytes = ExitInfo2 * IoBytes;
+
+ if (!(ExitInfo1 & IOIO_TYPE_IN)) {
+ CopyMem (Ghcb->SharedBuffer, (VOID *) Regs->Rsi, VmgExitBytes);
+ Regs->Rsi += VmgExitBytes;
+ }
+
+ Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+ Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, ExitInfo2);
+ if (Status) {
+ return Status;
+ }
+
+ if (ExitInfo1 & IOIO_TYPE_IN) {
+ CopyMem ((VOID *) Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
+ Regs->Rdi += VmgExitBytes;
+ }
+
+ if (ExitInfo1 & IOIO_REP) {
+ Regs->Rcx -= ExitInfo2;
+ }
+
+ OpCount -= ExitInfo2;
+ }
+ } else {
+ Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (ExitInfo1 & IOIO_TYPE_IN) {
+ if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
}
- Regs->Rax = Ghcb->SaveArea.Rax;
}
return 0;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (11 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
` (15 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a CPUID intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.
Add support to construct the required GHCB values to support a CPUID NAE
event. Additionally, CPUID 0x0000_000d requires XCR0 to be supplied in
the GHCB, so add support to issue the XGETBV instruction.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
MdePkg/Library/BaseLib/BaseLib.inf | 1 +
MdePkg/Include/Library/BaseLib.h | 16 +++++++
MdePkg/Library/BaseLib/X64/GccInline.c | 28 ++++++++++++
.../X64/AMDSevVcCommon.c | 45 +++++++++++++++++++
MdePkg/Library/BaseLib/X64/XGetBv.nasm | 39 ++++++++++++++++
5 files changed, 129 insertions(+)
create mode 100644 MdePkg/Library/BaseLib/X64/XGetBv.nasm
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index a41401340f95..7c1c077c63a9 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -287,6 +287,7 @@ [Sources.X64]
X64/ReadCr0.nasm| MSFT
X64/ReadEflags.nasm| MSFT
X64/VmgExit.nasm | MSFT
+ X64/XGetBv.nasm | MSFT
X64/Non-existing.c
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 80bd5cf57a72..ae16fa6f1c52 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7893,6 +7893,22 @@ AsmVmgExit (
VOID
);
+/**
+ Executes a XGETBV instruction
+
+ Executes a XGETBV instruction. This function is only available on IA-32 and
+ x64.
+
+ @param[in] Index Extended control register index
+
+ @retval The current value of the extended control register
+**/
+UINT64
+EFIAPI
+AsmXGetBv (
+ IN UINT32 Index
+ );
+
/**
Patch the immediate operand of an IA32 or X64 instruction such that the byte,
diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
index 17539caa0798..46aa96d67ab9 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1814,4 +1814,32 @@ AsmVmgExit (
__asm__ __volatile__ ("rep; vmmcall":::"memory");
}
+/**
+ Executes a XGETBV instruction
+
+ Executes a XGETBV instruction. This function is only available on IA-32 and
+ x64.
+
+ @param[in] Index Extended control register index
+
+ @retval The current value of the extended control register
+**/
+UINT64
+EFIAPI
+AsmXGetBv (
+ IN UINT32 Index
+ )
+{
+ UINT32 LowData;
+ UINT32 HighData;
+
+ __asm__ __volatile__ (
+ "xgetbv"
+ : "=a" (LowData), // %0
+ "=d" (HighData) // %1
+ : "c" (Index) // %2
+ );
+
+ return (((UINT64)HighData) << 32) | LowData;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 2bc156840e74..66cd0f9eb196 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -3,6 +3,8 @@
#include <Library/DebugLib.h>
#include "AMDSevVcCommon.h"
+#define CR4_OSXSAVE (1 << 18)
+
typedef enum {
LongMode64Bit = 0,
LongModeCompat32Bit,
@@ -473,6 +475,45 @@ IoioExit (
return 0;
}
+STATIC
+UINTN
+CpuidExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ Ghcb->SaveArea.Rax = Regs->Rax;
+ GhcbSetRegValid (Ghcb, GhcbRax);
+ Ghcb->SaveArea.Rcx = Regs->Rcx;
+ GhcbSetRegValid (Ghcb, GhcbRcx);
+ if (Regs->Rax == 0x0000000d) {
+ Ghcb->SaveArea.XCr0 = (AsmReadCr4 () & CR4_OSXSAVE) ? AsmXGetBv (0) : 1;
+ GhcbSetRegValid (Ghcb, GhcbXCr0);
+ }
+
+ Status = VmgExit (Ghcb, SvmExitCpuid, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+ !GhcbIsRegValid (Ghcb, GhcbRbx) ||
+ !GhcbIsRegValid (Ghcb, GhcbRcx) ||
+ !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitCpuid, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
+ Regs->Rbx = Ghcb->SaveArea.Rbx;
+ Regs->Rcx = Ghcb->SaveArea.Rcx;
+ Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+ return 0;
+}
+
UINTN
DoVcCommon (
GHCB *Ghcb,
@@ -489,6 +530,10 @@ DoVcCommon (
ExitCode = Regs->ExceptionData;
switch (ExitCode) {
+ case SvmExitCpuid:
+ NaeExit = CpuidExit;
+ break;
+
case SvmExitIoioProt:
NaeExit = IoioExit;
break;
diff --git a/MdePkg/Library/BaseLib/X64/XGetBv.nasm b/MdePkg/Library/BaseLib/X64/XGetBv.nasm
new file mode 100644
index 000000000000..83c10b40e369
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/XGetBv.nasm
@@ -0,0 +1,39 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; XGetBv.Asm
+;
+; Abstract:
+;
+; AsmXgetBv function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+ DEFAULT REL
+ SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; AsmXGetBv (
+; IN UINT32 Index
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmXGetBv)
+ASM_PFX(AsmXGetBv):
+ xgetbv
+ shl rdx, 0x20
+ or rax, rdx
+ ret
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (12 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
` (14 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a MSR_PROT intercept generates a #VC exception. VMGEXIT must
be used to allow the hypervisor to handle this intercept.
Add support to construct the required GHCB values to support an MSR_PROT
NAE event. Parse the instruction that generated the #VC exception to
determine whether it is RDMSR or WRMSR, setting the required register
register values in the GHCB and creating the proper SW_EXIT_INFO1 value in
the GHCB.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 66cd0f9eb196..2b25919ea496 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -251,6 +251,54 @@ UnsupportedExit (
return Status;
}
+STATIC
+UINTN
+MsrExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINT64 ExitInfo1;
+ UINTN Status;
+
+ ExitInfo1 = 0;
+
+ switch (*(InstructionData->OpCodes + 1)) {
+ case 0x30: // WRMSR
+ ExitInfo1 = 1;
+ Ghcb->SaveArea.Rax = Regs->Rax;
+ GhcbSetRegValid (Ghcb, GhcbRax);
+ Ghcb->SaveArea.Rdx = Regs->Rdx;
+ GhcbSetRegValid (Ghcb, GhcbRdx);
+ /* Fallthrough */
+ case 0x32: // RDMSR
+ Ghcb->SaveArea.Rcx = Regs->Rcx;
+ GhcbSetRegValid (Ghcb, GhcbRcx);
+ break;
+ default:
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitMsr, 0);
+ ASSERT (0);
+ }
+
+ Status = VmgExit (Ghcb, SvmExitMsr, ExitInfo1, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (!ExitInfo1) {
+ if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+ !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitMsr, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
+ Regs->Rdx = Ghcb->SaveArea.Rdx;
+ }
+
+ return 0;
+}
+
#define IOIO_TYPE_STR (1 << 2)
#define IOIO_TYPE_IN 1
#define IOIO_TYPE_INS (IOIO_TYPE_IN | IOIO_TYPE_STR)
@@ -538,6 +586,10 @@ DoVcCommon (
NaeExit = IoioExit;
break;
+ case SvmExitMsr:
+ NaeExit = MsrExit;
+ break;
+
default:
NaeExit = UnsupportedExit;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (13 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
` (13 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a NPF intercept for an NPT entry with a reserved bit set
generates a #VC exception. This condition is assumed to be an MMIO access.
VMGEXIT must be used to allow the hypervisor to handle this intercept.
Add support to construct the required GHCB values to support a NPF NAE
event for MMIO. Parse the instruction that generated the #VC exception,
setting the required register values in the GHCB and creating the proper
SW_EXIT_INFO1, SW_EXITINFO2 and SW_SCRATCH values in the GHCB.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 285 +++++++++++++++++-
1 file changed, 283 insertions(+), 2 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 2b25919ea496..5b2df92acf72 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -78,8 +78,8 @@ typedef struct {
UINT8 Scale;
} Sib;
- UINTN RegData;
- UINTN RmData;
+ INTN RegData;
+ INTN RmData;
} SEV_ES_INSTRUCTION_OPCODE_EXT;
typedef struct {
@@ -124,6 +124,198 @@ UINTN
SEV_ES_INSTRUCTION_DATA *InstructionData
);
+STATIC
+INT64 *
+GetRegisterPointer (
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ UINT8 Register
+ )
+{
+ UINT64 *Reg;
+
+ switch (Register) {
+ case 0:
+ Reg = &Regs->Rax;
+ break;
+ case 1:
+ Reg = &Regs->Rcx;
+ break;
+ case 2:
+ Reg = &Regs->Rdx;
+ break;
+ case 3:
+ Reg = &Regs->Rbx;
+ break;
+ case 4:
+ Reg = &Regs->Rsp;
+ break;
+ case 5:
+ Reg = &Regs->Rbp;
+ break;
+ case 6:
+ Reg = &Regs->Rsi;
+ break;
+ case 7:
+ Reg = &Regs->Rdi;
+ break;
+ case 8:
+ Reg = &Regs->R8;
+ break;
+ case 9:
+ Reg = &Regs->R9;
+ break;
+ case 10:
+ Reg = &Regs->R10;
+ break;
+ case 11:
+ Reg = &Regs->R11;
+ break;
+ case 12:
+ Reg = &Regs->R12;
+ break;
+ case 13:
+ Reg = &Regs->R13;
+ break;
+ case 14:
+ Reg = &Regs->R14;
+ break;
+ case 15:
+ Reg = &Regs->R15;
+ break;
+ default:
+ Reg = NULL;
+ }
+ ASSERT (Reg);
+
+ return (INT64 *) Reg;
+}
+
+STATIC
+VOID
+UpdateForDisplacement (
+ SEV_ES_INSTRUCTION_DATA *InstructionData,
+ UINTN Size
+ )
+{
+ InstructionData->DisplacementSize = Size;
+ InstructionData->Immediate += Size;
+ InstructionData->End += Size;
+}
+
+STATIC
+BOOLEAN
+IsRipRelative (
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext = &InstructionData->Ext;
+
+ return ((InstructionData == LongMode64Bit) &&
+ (Ext->ModRm.Mod == 0) &&
+ (Ext->ModRm.Rm == 5) &&
+ (InstructionData->SibPresent == FALSE));
+}
+
+STATIC
+UINTN
+GetEffectiveMemoryAddress (
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext = &InstructionData->Ext;
+ INTN EffectiveAddress = 0;
+
+ if (IsRipRelative (InstructionData)) {
+ /* RIP-relative displacement is a 32-bit signed value */
+ INT32 RipRelative = *(INT32 *) InstructionData->Displacement;
+
+ UpdateForDisplacement (InstructionData, 4);
+ return (UINTN) ((INTN) Regs->Rip + RipRelative);
+ }
+
+ switch (Ext->ModRm.Mod) {
+ case 1:
+ UpdateForDisplacement (InstructionData, 1);
+ EffectiveAddress += (INT8) (*(INT8 *) (InstructionData->Displacement));
+ break;
+ case 2:
+ switch (InstructionData->AddrSize) {
+ case Size16Bits:
+ UpdateForDisplacement (InstructionData, 2);
+ EffectiveAddress += (INT16) (*(INT16 *) (InstructionData->Displacement));
+ break;
+ default:
+ UpdateForDisplacement (InstructionData, 4);
+ EffectiveAddress += (INT32) (*(INT32 *) (InstructionData->Displacement));
+ break;
+ }
+ break;
+ }
+
+ if (InstructionData->SibPresent) {
+ if (Ext->Sib.Index != 4) {
+ EffectiveAddress += (*GetRegisterPointer (Regs, Ext->Sib.Index) << Ext->Sib.Scale);
+ }
+
+ if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {
+ EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);
+ } else {
+ UpdateForDisplacement (InstructionData, 4);
+ EffectiveAddress += (INT32) (*(INT32 *) (InstructionData->Displacement));
+ }
+ } else {
+ EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);
+ }
+
+ return (UINTN) EffectiveAddress;
+}
+
+STATIC
+VOID
+DecodeModRm (
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ SEV_ES_INSTRUCTION_REX_PREFIX *RexPrefix = &InstructionData->RexPrefix;
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext = &InstructionData->Ext;
+ SEV_ES_INSTRUCTION_MODRM *ModRm = &InstructionData->ModRm;
+ SEV_ES_INSTRUCTION_SIB *Sib = &InstructionData->Sib;
+
+ InstructionData->ModRmPresent = TRUE;
+ ModRm->Uint8 = *(InstructionData->End);
+
+ InstructionData->Displacement++;
+ InstructionData->Immediate++;
+ InstructionData->End++;
+
+ Ext->ModRm.Mod = ModRm->Bits.Mod;
+ Ext->ModRm.Reg = (RexPrefix->Bits.R << 3) | ModRm->Bits.Reg;
+ Ext->ModRm.Rm = (RexPrefix->Bits.B << 3) | ModRm->Bits.Rm;
+
+ Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);
+
+ if (Ext->ModRm.Mod == 3) {
+ Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);
+ } else {
+ if (ModRm->Bits.Rm == 4) {
+ InstructionData->SibPresent = TRUE;
+ Sib->Uint8 = *(InstructionData->End);
+
+ InstructionData->Displacement++;
+ InstructionData->Immediate++;
+ InstructionData->End++;
+
+ Ext->Sib.Scale = Sib->Bits.Scale;
+ Ext->Sib.Index = (RexPrefix->Bits.X << 3) | Sib->Bits.Index;
+ Ext->Sib.Base = (RexPrefix->Bits.B << 3) | Sib->Bits.Base;
+ }
+
+ Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);
+ }
+}
+
STATIC
VOID
DecodePrefixes (
@@ -235,6 +427,91 @@ InitInstructionData (
DecodePrefixes (Regs, InstructionData);
}
+STATIC
+UINT64
+MmioExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINT64 ExitInfo1, ExitInfo2;
+ UINTN Status;
+ UINTN Bytes;
+ INTN *Register;
+
+ Bytes = 0;
+
+ switch (*(InstructionData->OpCodes)) {
+ /* MMIO write */
+ case 0x88:
+ Bytes = 1;
+ case 0x89:
+ DecodeModRm (Regs, InstructionData);
+ Bytes = (Bytes) ? Bytes
+ : (InstructionData->DataSize == Size16Bits) ? 2
+ : (InstructionData->DataSize == Size32Bits) ? 4
+ : (InstructionData->DataSize == Size64Bits) ? 8
+ : 0;
+
+ if (InstructionData->Ext.ModRm.Mod == 3) {
+ /* NPF on two register operands??? */
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitNpf, 0);
+ ASSERT (0);
+ }
+
+ ExitInfo1 = InstructionData->Ext.RmData;
+ ExitInfo2 = Bytes;
+ CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
+
+ Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+ Status = VmgExit (Ghcb, SvmExitMmioWrite, ExitInfo1, ExitInfo2);
+ if (Status) {
+ return Status;
+ }
+ break;
+
+ /* MMIO read */
+ case 0x8A:
+ Bytes = 1;
+ case 0x8B:
+ DecodeModRm (Regs, InstructionData);
+ Bytes = (Bytes) ? Bytes
+ : (InstructionData->DataSize == Size16Bits) ? 2
+ : (InstructionData->DataSize == Size32Bits) ? 4
+ : (InstructionData->DataSize == Size64Bits) ? 8
+ : 0;
+ if (InstructionData->Ext.ModRm.Mod == 3) {
+ /* NPF on two register operands??? */
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitNpf, 0);
+ ASSERT (0);
+ }
+
+ ExitInfo1 = InstructionData->Ext.RmData;
+ ExitInfo2 = Bytes;
+
+ Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+ Status = VmgExit (Ghcb, SvmExitMmioRead, ExitInfo1, ExitInfo2);
+ if (Status) {
+ return Status;
+ }
+
+ Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
+ if (Bytes == 4) {
+ /* Zero-extend for 32-bit operation */
+ *Register = 0;
+ }
+ CopyMem (Register, Ghcb->SharedBuffer, Bytes);
+ break;
+
+ default:
+ Status = GP_EXCEPTION;
+ ASSERT (0);
+ }
+
+ return Status;
+}
+
STATIC
UINTN
UnsupportedExit (
@@ -590,6 +867,10 @@ DoVcCommon (
NaeExit = MsrExit;
break;
+ case SvmExitNpf:
+ NaeExit = MmioExit;
+ break;
+
default:
NaeExit = UnsupportedExit;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (14 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
` (12 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a WBINVD intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 5b2df92acf72..78d9b315c446 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -528,6 +528,24 @@ UnsupportedExit (
return Status;
}
+STATIC
+UINTN
+WbinvdExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ Status = VmgExit (Ghcb, SvmExitWbinvd, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ return 0;
+}
+
STATIC
UINTN
MsrExit (
@@ -867,6 +885,10 @@ DoVcCommon (
NaeExit = MsrExit;
break;
+ case SvmExitWbinvd:
+ NaeExit = WbinvdExit;
+ break;
+
case SvmExitNpf:
NaeExit = MmioExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (15 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
` (11 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a RDTSC intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 30 +++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 78d9b315c446..198b979bbb01 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -857,6 +857,32 @@ CpuidExit (
return 0;
}
+STATIC
+UINTN
+RdtscExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ Status = VmgExit (Ghcb, SvmExitRdtsc, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+ !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitRdtsc, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
+ Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+ return 0;
+}
+
UINTN
DoVcCommon (
GHCB *Ghcb,
@@ -873,6 +899,10 @@ DoVcCommon (
ExitCode = Regs->ExceptionData;
switch (ExitCode) {
+ case SvmExitRdtsc:
+ NaeExit = RdtscExit;
+ break;
+
case SvmExitCpuid:
NaeExit = CpuidExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (16 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
` (10 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a RDPMC intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 33 +++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 198b979bbb01..6c3e7f67f6cb 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -857,6 +857,35 @@ CpuidExit (
return 0;
}
+STATIC
+UINTN
+RdpmcExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ Ghcb->SaveArea.Rcx = Regs->Rcx;
+ GhcbSetRegValid (Ghcb, GhcbRcx);
+
+ Status = VmgExit (Ghcb, SvmExitRdpmc, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+ !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitRdpmc, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
+ Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+ return 0;
+}
+
STATIC
UINTN
RdtscExit (
@@ -903,6 +932,10 @@ DoVcCommon (
NaeExit = RdtscExit;
break;
+ case SvmExitRdpmc:
+ NaeExit = RdpmcExit;
+ break;
+
case SvmExitCpuid:
NaeExit = CpuidExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (17 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
` (9 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a INVD intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 6c3e7f67f6cb..3f10af401aa0 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -818,6 +818,24 @@ IoioExit (
return 0;
}
+STATIC
+UINTN
+InvdExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ Status = VmgExit (Ghcb, SvmExitInvd, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ return 0;
+}
+
STATIC
UINTN
CpuidExit (
@@ -940,6 +958,10 @@ DoVcCommon (
NaeExit = CpuidExit;
break;
+ case SvmExitInvd:
+ NaeExit = InvdExit;
+ break;
+
case SvmExitIoioProt:
NaeExit = IoioExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (18 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
` (8 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a VMMCALL intercept generates a #VC exception. VMGEXIT must
be used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 3f10af401aa0..1a0a8f5cd718 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -546,6 +546,37 @@ WbinvdExit (
return 0;
}
+STATIC
+UINTN
+VmmCallExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ DecodeModRm (Regs, InstructionData);
+
+ Ghcb->SaveArea.Rax = Regs->Rax;
+ GhcbSetRegValid (Ghcb, GhcbRax);
+ Ghcb->SaveArea.Cpl = (UINT8) (Regs->Cs & 0x3);
+ GhcbSetRegValid (Ghcb, GhcbCpl);
+
+ Status = VmgExit (Ghcb, SvmExitVmmCall, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitVmmCall, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
+
+ return 0;
+}
+
STATIC
UINTN
MsrExit (
@@ -970,6 +1001,10 @@ DoVcCommon (
NaeExit = MsrExit;
break;
+ case SvmExitVmmCall:
+ NaeExit = VmmCallExit;
+ break;
+
case SvmExitWbinvd:
NaeExit = WbinvdExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (19 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
` (7 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a RDTSCP intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 34 +++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 1a0a8f5cd718..8f9b742f942c 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -546,6 +546,36 @@ WbinvdExit (
return 0;
}
+STATIC
+UINTN
+RdtscpExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ DecodeModRm (Regs, InstructionData);
+
+ Status = VmgExit (Ghcb, SvmExitRdtscp, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+ !GhcbIsRegValid (Ghcb, GhcbRcx) ||
+ !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+ VmgExit (Ghcb, SvmExitUnsupported, SvmExitRdtscp, 0);
+ ASSERT (0);
+ }
+ Regs->Rax = Ghcb->SaveArea.Rax;
+ Regs->Rcx = Ghcb->SaveArea.Rcx;
+ Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+ return 0;
+}
+
STATIC
UINTN
VmmCallExit (
@@ -1005,6 +1035,10 @@ DoVcCommon (
NaeExit = VmmCallExit;
break;
+ case SvmExitRdtscp:
+ NaeExit = RdtscpExit;
+ break;
+
case SvmExitWbinvd:
NaeExit = WbinvdExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (20 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
` (6 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a MONITOR/MONITORX intercept generates a #VC exception.
VMGEXIT must be used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 8f9b742f942c..154ca091936d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -528,6 +528,33 @@ UnsupportedExit (
return Status;
}
+STATIC
+UINTN
+MonitorExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ DecodeModRm (Regs, InstructionData);
+
+ Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA
+ GhcbSetRegValid (Ghcb, GhcbRax);
+ Ghcb->SaveArea.Rcx = Regs->Rcx;
+ GhcbSetRegValid (Ghcb, GhcbRcx);
+ Ghcb->SaveArea.Rdx = Regs->Rdx;
+ GhcbSetRegValid (Ghcb, GhcbRdx);
+
+ Status = VmgExit (Ghcb, SvmExitMonitor, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ return 0;
+}
+
STATIC
UINTN
WbinvdExit (
@@ -1043,6 +1070,10 @@ DoVcCommon (
NaeExit = WbinvdExit;
break;
+ case SvmExitMonitor:
+ NaeExit = MonitorExit;
+ break;
+
case SvmExitNpf:
NaeExit = MmioExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (21 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
` (5 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a MWAIT/MWAITX intercept generates a #VC exception.
VMGEXIT must be used to allow the hypervisor to handle this intercept.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 154ca091936d..43a3a116af5d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -528,6 +528,31 @@ UnsupportedExit (
return Status;
}
+STATIC
+UINTN
+MwaitExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ UINTN Status;
+
+ DecodeModRm (Regs, InstructionData);
+
+ Ghcb->SaveArea.Rax = Regs->Rax;
+ GhcbSetRegValid (Ghcb, GhcbRax);
+ Ghcb->SaveArea.Rcx = Regs->Rcx;
+ GhcbSetRegValid (Ghcb, GhcbRcx);
+
+ Status = VmgExit (Ghcb, SvmExitMwait, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ return 0;
+}
+
STATIC
UINTN
MonitorExit (
@@ -1074,6 +1099,10 @@ DoVcCommon (
NaeExit = MonitorExit;
break;
+ case SvmExitMwait:
+ NaeExit = MwaitExit;
+ break;
+
case SvmExitNpf:
NaeExit = MmioExit;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (22 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases Lendacky, Thomas
` (4 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Under SEV-ES, a DR7 read or write intercept generates a #VC exception.
The #VC handler must provide special support to the guest for this. On
a DR7 write, the #VC handler must cache the value and issue a VMGEXIT
to notify the hypervisor of the write. However, the #VC handler must
not actually set the value of the DR7 register. On a DR7 read, the #VC
handler must return the cached value of the DR7 register to the guest.
VMGEXIT is not invoked for a DR7 register read.
To avoid exception recursion, a #VC exception will not try to read and
push the actual debug registers into the EFI_SYSTEM_CONTEXT_X64 struct
and instead push zeroes. The #VC exception handler does not make use of
the debug registers from saved context.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../X64/AMDSevVcCommon.c | 68 +++++++++++++++++++
.../X64/ExceptionHandlerAsm.nasm | 15 ++++
2 files changed, 83 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 43a3a116af5d..8d7633b15e25 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -5,6 +5,12 @@
#define CR4_OSXSAVE (1 << 18)
+#define DR7_RESET_VALUE 0x400
+typedef struct {
+ BOOLEAN Dr7Cached;
+ UINT64 Dr7;
+} SEV_ES_PER_CPU_DATA;
+
typedef enum {
LongMode64Bit = 0,
LongModeCompat32Bit,
@@ -1043,6 +1049,60 @@ RdtscExit (
return 0;
}
+STATIC
+UINTN
+Dr7WriteExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext = &InstructionData->Ext;
+ SEV_ES_PER_CPU_DATA *SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);
+ INTN *Register;
+ UINTN Status;
+
+ DecodeModRm (Regs, InstructionData);
+
+ /* MOV DRn always treats MOD == 3 no matter how encoded */
+ Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
+
+ /* Using a value of 0 for ExitInfo1 means RAX holds the value */
+ Ghcb->SaveArea.Rax = *Register;
+ GhcbSetRegValid (Ghcb, GhcbRax);
+
+ Status = VmgExit (Ghcb, SvmExitDr7Write, 0, 0);
+ if (Status) {
+ return Status;
+ }
+
+ SevEsData->Dr7 = *Register;
+ SevEsData->Dr7Cached = TRUE;
+
+ return 0;
+}
+
+STATIC
+UINTN
+Dr7ReadExit (
+ GHCB *Ghcb,
+ EFI_SYSTEM_CONTEXT_X64 *Regs,
+ SEV_ES_INSTRUCTION_DATA *InstructionData
+ )
+{
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext = &InstructionData->Ext;
+ SEV_ES_PER_CPU_DATA *SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);
+ INTN *Register;
+
+ DecodeModRm (Regs, InstructionData);
+
+ /* MOV DRn always treats MOD == 3 no matter how encoded */
+ Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
+ *Register = (SevEsData->Dr7Cached) ? SevEsData->Dr7 : DR7_RESET_VALUE;
+
+ return 0;
+}
+
UINTN
DoVcCommon (
GHCB *Ghcb,
@@ -1059,6 +1119,14 @@ DoVcCommon (
ExitCode = Regs->ExceptionData;
switch (ExitCode) {
+ case SvmExitDr7Read:
+ NaeExit = Dr7ReadExit;
+ break;
+
+ case SvmExitDr7Write:
+ NaeExit = Dr7WriteExit;
+ break;
+
case SvmExitRdtsc:
NaeExit = RdtscExit;
break;
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
index 4db1a09f2881..d23af671df66 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
@@ -223,6 +223,9 @@ HasErrorCode:
push rax
;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ cmp qword [rbp + 8], 29
+ je VcDebugRegs ; For SEV-ES (#VC) Debug registers ignored
+
mov rax, dr7
push rax
mov rax, dr6
@@ -235,7 +238,19 @@ HasErrorCode:
push rax
mov rax, dr0
push rax
+ jmp DrFinish
+VcDebugRegs:
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion
+ xor rax, rax
+ push rax
+ push rax
+ push rax
+ push rax
+ push rax
+ push rax
+
+DrFinish:
;; FX_SAVE_STATE_X64 FxSaveState;
sub rsp, 512
mov rdi, rsp
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (23 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
` (3 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
An SEV-ES guest will generate a #VC exception when it encounters a
non-automatic exit (NAE) event. It is expected that the #VC exception
handler will communicate with the hypervisor using the GHCB to handle
the NAE event.
Update the Pei and Dxe exception handling support to recognize the #VC
exception and call a common #VC handler.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
.../DxeCpuExceptionHandlerLib.inf | 2 ++
.../PeiCpuExceptionHandlerLib.inf | 2 ++
.../PeiDxeAMDSevVcHandler.c | 15 +++++++++++++--
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index 331ae7334c45..75fafd346add 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -26,11 +26,13 @@ [Sources.Ia32]
Ia32/ExceptionTssEntryAsm.nasm
Ia32/ArchExceptionHandler.c
Ia32/ArchInterruptDefs.h
+ Ia32/AMDSevVcCommon.c
[Sources.X64]
X64/ExceptionHandlerAsm.nasm
X64/ArchExceptionHandler.c
X64/ArchInterruptDefs.h
+ X64/AMDSevVcCommon.c
[Sources.common]
CpuExceptionCommon.h
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index 89b5d496e56f..50124b598509 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -26,11 +26,13 @@ [Sources.Ia32]
Ia32/ExceptionTssEntryAsm.nasm
Ia32/ArchExceptionHandler.c
Ia32/ArchInterruptDefs.h
+ Ia32/AMDSevVcCommon.c
[Sources.X64]
X64/ExceptionHandlerAsm.nasm
X64/ArchExceptionHandler.c
X64/ArchInterruptDefs.h
+ X64/AMDSevVcCommon.c
[Sources.common]
CpuExceptionCommon.h
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
index 1e027b3f2964..d32de9efb09e 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
@@ -1,11 +1,22 @@
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Amd/Msr.h>
#include "CpuExceptionCommon.h"
#include "AMDSevVcCommon.h"
UINTN
-DoVcException(
+DoVcException (
EFI_SYSTEM_CONTEXT Context
)
{
- return 0;
+ MSR_SEV_ES_GHCB_REGISTER Msr;
+ GHCB *Ghcb;
+
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+ ASSERT(!Msr.Bits.GhcbNegotiateBit);
+
+ Ghcb = Msr.Ghcb;
+
+ return DoVcCommon (Ghcb, Context);
}
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (24 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES Lendacky, Thomas
` (2 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
When starting APs in an SMP configuration, the AP needs to know if it is
running as an SEV-ES guest in order to assign a GHCB page.
Add a field to the CPU_MP_DATA structure that will indicate if SEV-ES is
active. This new field is set during MP library initialization with the
PCD value PcdCpuSevEsActive. This flag can then be used to determine if
SEV-ES is active.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
UefiCpuPkg/UefiCpuPkg.dec | 3 +++
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 1 +
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 1 +
UefiCpuPkg/Library/MpInitLib/MpLib.h | 2 ++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 1 +
5 files changed, 8 insertions(+)
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 4d5a2593cf13..163146afb752 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -327,5 +327,8 @@ [PcdsDynamic, PcdsDynamicEx]
gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
+ ## Contains the SEV-ES active setting
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0x0|UINT32|0x60000019
+
[UserExtensions.TianoCore."ExtraFiles"]
UefiCpuPkgExtra.uni
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 37b3f64e578a..1b7ac00ab361 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -67,5 +67,6 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 82b77b63ea87..bcdd2ca82612 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -59,6 +59,7 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive ## CONSUMES
[Guids]
gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index f89037c59e13..2f75b82e8401 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -256,6 +256,8 @@ struct _CPU_MP_DATA {
// driver.
//
BOOLEAN WakeUpByInitSipiSipi;
+
+ UINT32 SevEsActive;
};
extern EFI_GUID mCpuInitMpLibHobGuid;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 6f51bc4ebfb9..74cfc513ec93 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1639,6 +1639,7 @@ MpInitLibInitialize (
CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;
}
+ CpuMpData->SevEsActive = PcdGet32 (PcdCpuSevEsActive);
InitializeSpinLock(&CpuMpData->MpLock);
//
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (25 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES Lendacky, Thomas
2019-08-21 14:17 ` [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support Laszlo Ersek
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Typically, an AP is booted using the INIT-SIPI-SIPI sequence. This
sequence is intercepted by the hypervisor, which sets the AP's registers
to the values requested by the sequence. At that point, the hypervisor can
start the AP, which will then begin execution at the appropriate location.
Under SEV-ES, AP booting presents some challenges since the hypervisor is
not allowed to alter the AP's register state. In this situation, we have
to distinguish between the AP's first boot and AP's subsequent boots.
First boot:
Once the AP's register state has been defined (which is before the guest
is first booted) it cannot be altered. Should the hypervisor attempt to
alter the register state, the change would be detected by the hardware
and the VMRUN instruction would fail. Given this, the first boot for the
AP is required to begin execution with this initial register state, which
is typically the reset vector. This prevents the BSP from directing the
AP startup location through the INIT-SIPI-SIPI sequence.
To work around this, provide a four-byte field at offset 0xffffffd0 that
can contain an IP / CS register combination, that if non-zero, causes
the AP to perform a far jump to that location instead of a near jump to
EarlyBspInitReal16. Before booting the AP for the first time, the BSP
should set the IP / CS value for the AP based on the value that would be
derived from the INIT-SIPI-SIPI sequence.
Subsequent boots:
Again, the hypervisor cannot alter the AP register state, so a method is
required to take the AP out of halt state and redirect it to the desired
IP location. If it is determined that the AP is running in an SEV-ES
guest, then instead of calling CpuSleep(), a VMGEXIT is issued with the
AP Reset Hold exit code (0x80000004). The hypervisor will put the AP in
a halt state, waiting for an INIT-SIPI-SIPI sequence. Once the sequence
is recognized, the hypervisor will resume the AP. At this point the AP
must transition from the current 64-bit long mode down to 16-bit real
mode and begin executing at the derived location from the INIT-SIPI-SIPI
sequence.
Another change is around the area of obtaining the (x2)APIC ID during AP
startup. During AP startup, the AP can't take a #VC exception before the
AP has established a stack. However, the AP stack is set by using the
(x2)APIC ID, which is obtained through CPUID instructions. A CPUID
instruction will cause a #VC, so a different method must be used. The
GHCB protocol supports a method to obtain CPUID information from the
hypervisor through the GHCB MSR. This method does not require a stack,
so it is used to obtain the necessary CPUID information to determine the
(x2)APIC ID.
The OVMF SEV support is updated to set the SEV-ES active PCD entry
(PcdCpuSevEsActive) when the guest is an SEV-ES guest. Also, the OVMF
support is updated to create its own reset vector routine in order to
supply the far jump field required for an AP first boot.
A new 16-bit protected mode GDT entry is created in order to transition
from 64-bit long mode down to 16-bit real mode.
A new assembler routine is created that takes the AP from 64-bit long mode
to 16-bit real mode. This is located under 1MB in memory and transitions
from 64-bit long mode to 32-bit compatibility mode to 16-bit protected
mode and finally 16-bit real mode.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 2 +
OvmfPkg/PlatformPei/PlatformPei.inf | 1 +
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +-
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 1 +
UefiCpuPkg/CpuDxe/CpuGdt.h | 2 +-
UefiCpuPkg/Library/MpInitLib/MpLib.h | 55 ++++
.../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 2 +-
OvmfPkg/PlatformPei/AmdSev.c | 3 +
UefiCpuPkg/CpuDxe/CpuGdt.c | 10 +-
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 67 ++++-
UefiCpuPkg/Library/MpInitLib/MpLib.c | 229 ++++++++++++++++-
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 16 ++
UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c | 2 +-
OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 85 +++++++
UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 4 +-
.../Library/MpInitLib/Ia32/MpFuncs.nasm | 15 ++
UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 4 +-
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 239 ++++++++++++++++++
.../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm | 9 +
21 files changed, 728 insertions(+), 23 deletions(-)
create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 5bbf87540ab9..566a631efbff 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -554,6 +554,7 @@ [PcdsDynamicDefault]
# UefiCpuPkg PCDs related to initial AP bringup and general AP management.
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64
gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0
# Set memory encryption mask
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 5015e92b6eea..776a0186498d 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -566,6 +566,7 @@ [PcdsDynamicDefault]
# UefiCpuPkg PCDs related to initial AP bringup and general AP management.
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64
gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0
# Set memory encryption mask
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index d6fc7cdf7da8..5e8e6e76d63d 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -300,6 +300,7 @@ [LibraryClasses.common.DXE_CORE]
DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
!endif
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+ MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
[LibraryClasses.common.DXE_RUNTIME_DRIVER]
@@ -565,6 +566,7 @@ [PcdsDynamicDefault]
# UefiCpuPkg PCDs related to initial AP bringup and general AP management.
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64
gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0
# Set memory encryption mask
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index f53195e6dda5..76599d9e5649 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -104,6 +104,7 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 1b7ac00ab361..e6c0b1c5f3b9 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -13,7 +13,7 @@ [Defines]
FILE_GUID = B88F7146-9834-4c55-BFAC-481CC0C33736
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.1
- LIBRARY_CLASS = MpInitLib|DXE_DRIVER
+ LIBRARY_CLASS = MpInitLib|DXE_CORE DXE_DRIVER
#
# The following information is for reference only and not required by the build tools.
@@ -68,5 +68,6 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index bcdd2ca82612..d57110c93fdf 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -60,6 +60,7 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
[Guids]
gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.h b/UefiCpuPkg/CpuDxe/CpuGdt.h
index e5c36f37b96a..b8798cdb1fd4 100644
--- a/UefiCpuPkg/CpuDxe/CpuGdt.h
+++ b/UefiCpuPkg/CpuDxe/CpuGdt.h
@@ -36,7 +36,7 @@ struct _GDT_ENTRIES {
GDT_ENTRY LinearCode;
GDT_ENTRY SysData;
GDT_ENTRY SysCode;
- GDT_ENTRY Spare4;
+ GDT_ENTRY SysCode16;
GDT_ENTRY LinearData64;
GDT_ENTRY LinearCode64;
GDT_ENTRY Spare5;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 2f75b82e8401..f2ba1a508715 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -151,6 +151,11 @@ typedef struct {
UINT8 *RelocateApLoopFuncAddress;
UINTN RelocateApLoopFuncSize;
UINTN ModeTransitionOffset;
+ UINTN SwitchToRealSize;
+ UINTN SwitchToRealOffset;
+ UINTN SwitchToRealNoNxOffset;
+ UINTN SwitchToRealPM16ModeOffset;
+ UINTN SwitchToRealPM16ModeSize;
} MP_ASSEMBLY_ADDRESS_MAP;
typedef struct _CPU_MP_DATA CPU_MP_DATA;
@@ -185,6 +190,8 @@ typedef struct {
UINT16 ModeTransitionSegment;
UINT32 ModeHighMemory;
UINT16 ModeHighSegment;
+ UINT32 SevEsActive;
+ UINTN GhcbBase;
} MP_CPU_EXCHANGE_INFO;
#pragma pack()
@@ -232,6 +239,7 @@ struct _CPU_MP_DATA {
UINT8 ApLoopMode;
UINT8 ApTargetCState;
UINT16 PmCodeSegment;
+ UINT16 Pm16CodeSegment;
CPU_AP_DATA *CpuData;
volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
@@ -258,8 +266,45 @@ struct _CPU_MP_DATA {
BOOLEAN WakeUpByInitSipiSipi;
UINT32 SevEsActive;
+ UINTN SevEsAPBuffer;
+ UINTN SevEsAPResetStackStart;
+ CPU_MP_DATA *NewCpuMpData;
+
+ UINT64 GhcbBase;
};
+#define AP_RESET_STACK_SIZE 64
+
+typedef union {
+ struct {
+ UINT16 Rip;
+ UINT16 Segment;
+ } ApStart;
+ UINT32 Uint32;
+} SEV_ES_AP_JMP_FAR;
+
+/**
+ Assembly code to move an AP from long mode to real mode.
+
+ Move an AP from long mode to real mode in preparation to invoking
+ the reset vector. This is used for SEV-ES guests where a hypervisor
+ is not allowed to set the CS and RIP to point to the reset vector.
+
+ @param[in] BufferStart The reset vector target.
+ @param[in] Code16 16-bit protected mode code segment value.
+ @param[in] Code32 32-bit protected mode code segment value.
+ @param[in] StackStart The start of a stack to be used for transitioning
+ from long mode to real mode.
+**/
+typedef
+VOID
+(EFIAPI AP_RESET) (
+ IN UINTN BufferStart,
+ IN UINT16 Code16,
+ IN UINT16 Code32,
+ IN UINTN StackStart
+ );
+
extern EFI_GUID mCpuInitMpLibHobGuid;
/**
@@ -365,6 +410,16 @@ GetModeTransitionBuffer (
IN UINTN BufferSize
);
+/**
+ Get ...
+
+ @retval other Return SEV-ES AP wakeup buffer
+**/
+UINTN
+GetSevEsAPMemory (
+ VOID
+ );
+
/**
This function will be called by BSP to wakeup AP.
diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
index 630a3503f6ba..b9af22bede61 100644
--- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -33,7 +33,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT gGdtEntries[] = {
/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
-/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+/* 0x28 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 0, 1, 0}}, //system code16 segment descriptor
/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 5f4983fd36d8..fc396a6f229d 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -74,6 +74,8 @@ AmdSevEsInitialize (
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet32S (PcdCpuSevEsActive, 1);
+ ASSERT_RETURN_ERROR (PcdStatus);
DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
@@ -92,6 +94,7 @@ AmdSevEsInitialize (
CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
Gdtr.Base = (UINTN) Gdt;
AsmWriteGdtr (&Gdtr);
+
}
/**
diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.c b/UefiCpuPkg/CpuDxe/CpuGdt.c
index 87fd6955f24b..b2fdb87a285e 100644
--- a/UefiCpuPkg/CpuDxe/CpuGdt.c
+++ b/UefiCpuPkg/CpuDxe/CpuGdt.c
@@ -70,15 +70,15 @@ STATIC GDT_ENTRIES GdtTemplate = {
0x0,
},
//
- // SPARE4_SEL
+ // SYS_CODE16_SEL
//
{
- 0x0, // limit 15:0
+ 0x0FFFF, // limit 15:0
0x0, // base 15:0
0x0, // base 23:16
- 0x0, // type
- 0x0, // limit 19:16, flags
- 0x0, // base 31:24
+ 0x09A, // present, ring 0, code, execute/read
+ 0x08F, // page-granular, 16-bit
+ 0x0,
},
//
// LINEAR_DATA64_SEL
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 6be1bae464fb..127f64eb87e1 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -12,6 +12,8 @@
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugAgentLib.h>
#include <Library/DxeServicesTableLib.h>
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
#include <Protocol/Timer.h>
@@ -145,6 +147,36 @@ GetModeTransitionBuffer (
return (UINTN)StartAddress;
}
+/**
+ Get ...
+
+ @retval other Return SEV-ES AP wakeup buffer
+**/
+UINTN
+GetSevEsAPMemory (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+
+ //
+ // Allocate 1 page for AP jump table page
+ //
+ StartAddress = BASE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ 1,
+ &StartAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN) StartAddress));
+
+ return (UINTN) StartAddress;
+}
+
/**
Checks APs status and updates APs status if needed.
@@ -219,6 +251,38 @@ CheckApsStatus (
}
}
+/**
+ Get Protected mode code segment with 16-bit default addressing
+ from current GDT table.
+
+ @return Protected mode 16-bit code segment value.
+**/
+UINT16
+GetProtectedMode16CS (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtrDesc;
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;
+ UINTN GdtEntryCount;
+ UINT16 Index;
+
+ Index = (UINT16) -1;
+ AsmReadGdtr (&GdtrDesc);
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+ for (Index = 0; Index < GdtEntryCount; Index++) {
+ if (GdtEntry->Bits.L == 0) {
+ if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 0) {
+ break;
+ }
+ }
+ GdtEntry++;
+ }
+ ASSERT (Index != GdtEntryCount);
+ return Index * 8;
+}
+
/**
Get Protected mode code segment from current GDT table.
@@ -239,7 +303,7 @@ GetProtectedModeCS (
GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
for (Index = 0; Index < GdtEntryCount; Index++) {
if (GdtEntry->Bits.L == 0) {
- if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {
+ if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 1) {
break;
}
}
@@ -301,6 +365,7 @@ MpInitChangeApLoopCallback (
CpuMpData = GetCpuMpData ();
CpuMpData->PmCodeSegment = GetProtectedModeCS ();
+ CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();
CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
mNumberToFinish = CpuMpData->CpuCount - 1;
WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 74cfc513ec93..0939019d7b8c 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -7,6 +7,8 @@
**/
#include "MpLib.h"
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
@@ -555,6 +557,108 @@ InitializeApData (
SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
}
+/**
+ Get Protected mode code segment with 16-bit default addressing
+ from current GDT table.
+
+ @return Protected mode 16-bit code segment value.
+**/
+STATIC
+UINT16
+GetProtectedMode16CS (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtrDesc;
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;
+ UINTN GdtEntryCount;
+ UINT16 Index;
+
+ Index = (UINT16) -1;
+ AsmReadGdtr (&GdtrDesc);
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+ for (Index = 0; Index < GdtEntryCount; Index++) {
+ if (GdtEntry->Bits.L == 0 &&
+ GdtEntry->Bits.DB == 0 &&
+ GdtEntry->Bits.Type > 8) {
+ break;
+ }
+ GdtEntry++;
+ }
+ ASSERT (Index != GdtEntryCount);
+ return Index * 8;
+}
+
+/**
+ Get Protected mode code segment with 32-bit default addressing
+ from current GDT table.
+
+ @return Protected mode 32-bit code segment value.
+**/
+STATIC
+UINT16
+GetProtectedMode32CS (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtrDesc;
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;
+ UINTN GdtEntryCount;
+ UINT16 Index;
+
+ Index = (UINT16) -1;
+ AsmReadGdtr (&GdtrDesc);
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+ for (Index = 0; Index < GdtEntryCount; Index++) {
+ if (GdtEntry->Bits.L == 0 &&
+ GdtEntry->Bits.DB == 1 &&
+ GdtEntry->Bits.Type > 8) {
+ break;
+ }
+ GdtEntry++;
+ }
+ ASSERT (Index != GdtEntryCount);
+ return Index * 8;
+}
+
+/**
+ Reset an AP when in SEV-ES mode.
+
+ @retval EFI_DEVICE_ERROR Reset of AP failed.
+**/
+STATIC
+VOID
+MpInitLibSevEsAPReset (
+ GHCB *Ghcb,
+ CPU_MP_DATA *CpuMpData
+ )
+{
+ UINT16 Code16, Code32;
+ AP_RESET *APResetFn;
+ UINTN BufferStart;
+ UINTN StackStart;
+
+ Code16 = GetProtectedMode16CS ();
+ Code32 = GetProtectedMode32CS ();
+
+ if (CpuMpData->WakeupBufferHigh != 0) {
+ APResetFn = (AP_RESET *) (CpuMpData->WakeupBufferHigh + CpuMpData->AddressMap.SwitchToRealNoNxOffset);
+ } else {
+ APResetFn = (AP_RESET *) (CpuMpData->MpCpuExchangeInfo->BufferStart + CpuMpData->AddressMap.SwitchToRealOffset);
+ }
+
+ BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart;
+ StackStart = CpuMpData->SevEsAPResetStackStart -
+ (AP_RESET_STACK_SIZE * GetApicId ());
+
+ //
+ // This call never returns.
+ //
+ APResetFn (BufferStart, Code16, Code32, StackStart);
+}
+
/**
This function will be called from AP reset code if BSP uses WakeUpAP.
@@ -714,7 +818,28 @@ ApWakeupFunction (
//
while (TRUE) {
DisableInterrupts ();
- CpuSleep ();
+ if (CpuMpData->SevEsActive) {
+ MSR_SEV_ES_GHCB_REGISTER Msr;
+ GHCB *Ghcb;
+
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+ Ghcb = Msr.Ghcb;
+
+ VmgInit (Ghcb);
+ VmgExit (Ghcb, SvmExitApResetHold, 0, 0);
+ /*TODO: Check return value to verify SIPI issued */
+
+ //
+ // Awakened in a new phase? Use the new CpuMpData
+ //
+ if (CpuMpData->NewCpuMpData) {
+ CpuMpData = CpuMpData->NewCpuMpData;
+ }
+
+ MpInitLibSevEsAPReset (Ghcb, CpuMpData);
+ } else {
+ CpuSleep ();
+ }
CpuPause ();
}
}
@@ -814,6 +939,9 @@ FillExchangeInfoData (
ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;
+ ExchangeInfo->SevEsActive = CpuMpData->SevEsActive;
+ ExchangeInfo->GhcbBase = CpuMpData->GhcbBase;
+
//
// Get the BSP's data of GDT and IDT
//
@@ -840,8 +968,9 @@ FillExchangeInfoData (
// EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
//
if (CpuMpData->WakeupBufferHigh != 0) {
- Size = CpuMpData->AddressMap.RendezvousFunnelSize -
- CpuMpData->AddressMap.ModeTransitionOffset;
+ Size = CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize -
+ CpuMpData->AddressMap.ModeTransitionOffset;
CopyMem (
(VOID *)CpuMpData->WakeupBufferHigh,
CpuMpData->AddressMap.RendezvousFunnelAddress +
@@ -894,7 +1023,8 @@ BackupAndPrepareWakeupBuffer(
CopyMem (
(VOID *) CpuMpData->WakeupBuffer,
(VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
- CpuMpData->AddressMap.RendezvousFunnelSize
+ CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize
);
}
@@ -915,6 +1045,40 @@ RestoreWakeupBuffer(
);
}
+/**
+ Calculate the size of the reset stack.
+**/
+STATIC
+UINTN
+GetApResetStackSize(
+ VOID
+ )
+{
+ return AP_RESET_STACK_SIZE * PcdGet32(PcdCpuMaxLogicalProcessorNumber);
+}
+
+/**
+ Calculate the size of the reset vector.
+
+ @param[in] AddressMap The pointer to Address Map structure.
+**/
+STATIC
+UINTN
+GetApResetVectorSize(
+ IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ )
+{
+ UINTN Size;
+
+ Size = ALIGN_VALUE (AddressMap->RendezvousFunnelSize +
+ AddressMap->SwitchToRealSize +
+ sizeof (MP_CPU_EXCHANGE_INFO),
+ CPU_STACK_ALIGNMENT);
+ Size += GetApResetStackSize ();
+
+ return Size;
+}
+
/**
Allocate reset vector buffer.
@@ -928,16 +1092,22 @@ AllocateResetVector (
UINTN ApResetVectorSize;
if (CpuMpData->WakeupBuffer == (UINTN) -1) {
- ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +
- sizeof (MP_CPU_EXCHANGE_INFO);
+ ApResetVectorSize = GetApResetVectorSize (&CpuMpData->AddressMap);
CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);
CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
- (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);
+ (CpuMpData->WakeupBuffer +
+ CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize);
CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (
- CpuMpData->AddressMap.RendezvousFunnelSize -
+ CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize -
CpuMpData->AddressMap.ModeTransitionOffset
);
+ //
+ // The reset stack starts at the end of the buffer.
+ //
+ CpuMpData->SevEsAPResetStackStart = CpuMpData->WakeupBuffer + ApResetVectorSize;
}
BackupAndPrepareWakeupBuffer (CpuMpData);
}
@@ -952,7 +1122,30 @@ FreeResetVector (
IN CPU_MP_DATA *CpuMpData
)
{
- RestoreWakeupBuffer (CpuMpData);
+ //
+ // If SEV-ES is active, the reset area is needed for AP parking and
+ // and AP startup in the OS, so the reset area is reserved. Do not
+ // perform the restore as this will overwrite memory which has data
+ // needed by SEV-ES.
+ //
+ if (!CpuMpData->SevEsActive) {
+ RestoreWakeupBuffer (CpuMpData);
+ }
+}
+
+/**
+ Allocate ...
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+AllocateSevEsAPMemory (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ if (CpuMpData->SevEsAPBuffer == (UINTN) -1) {
+ CpuMpData->SevEsAPBuffer = CpuMpData->SevEsActive ? GetSevEsAPMemory () : 0;
+ }
}
/**
@@ -985,10 +1178,12 @@ WakeUpAP (
CpuMpData->FinishedCount = 0;
ResetVectorRequired = FALSE;
+ AllocateResetVector (CpuMpData);
+ AllocateSevEsAPMemory (CpuMpData);
+
if (CpuMpData->WakeUpByInitSipiSipi ||
CpuMpData->InitFlag != ApInitDone) {
ResetVectorRequired = TRUE;
- AllocateResetVector (CpuMpData);
FillExchangeInfoData (CpuMpData);
SaveLocalApicTimerSetting (CpuMpData);
}
@@ -1025,6 +1220,15 @@ WakeUpAP (
}
}
if (ResetVectorRequired) {
+ //
+ // For SEV-ES, set the jump address for initial AP boot
+ //
+ if (CpuMpData->SevEsActive) {
+ SEV_ES_AP_JMP_FAR *JmpFar = (SEV_ES_AP_JMP_FAR *)0xFFFFFFD0;
+
+ JmpFar->ApStart.Rip = 0;
+ JmpFar->ApStart.Segment = (UINT16) (ExchangeInfo->BufferStart >> 4);
+ }
//
// Wakeup all APs
//
@@ -1550,7 +1754,7 @@ MpInitLibInitialize (
ASSERT (MaxLogicalProcessorNumber != 0);
AsmGetAddressMap (&AddressMap);
- ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
+ ApResetVectorSize = GetApResetVectorSize (&AddressMap);
ApStackSize = PcdGet32(PcdCpuApStackSize);
ApLoopMode = GetApLoopMode (&MonitorFilterSize);
@@ -1640,6 +1844,8 @@ MpInitLibInitialize (
}
CpuMpData->SevEsActive = PcdGet32 (PcdCpuSevEsActive);
+ CpuMpData->SevEsAPBuffer = (UINTN) -1;
+ CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
InitializeSpinLock(&CpuMpData->MpLock);
//
@@ -1707,6 +1913,7 @@ MpInitLibInitialize (
// APs have been wakeup before, just get the CPU Information
// from HOB
//
+ OldCpuMpData->NewCpuMpData = CpuMpData;
CpuMpData->CpuCount = OldCpuMpData->CpuCount;
CpuMpData->BspNumber = OldCpuMpData->BspNumber;
CpuMpData->InitFlag = ApInitReconfig;
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index 35dff91fd2a5..75b8e38ae8e3 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -279,6 +279,22 @@ GetModeTransitionBuffer (
return 0;
}
+/**
+ Get ...
+
+ @retval other Return SEV-ES AP wakeup buffer
+**/
+UINTN
+GetSevEsAPMemory (
+ VOID
+ )
+{
+ //
+ // PEI phase doesn't need to do this pre-allocation. So simply return 0.
+ //
+ return 0;
+}
+
/**
Checks APs status and updates APs status if needed.
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
index 6298571e29b2..28f8e8e133e5 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
@@ -121,7 +121,7 @@ GetProtectedModeCS (
GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
for (Index = 0; Index < GdtEntryCount; Index++) {
if (GdtEntry->Bits.L == 0) {
- if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {
+ if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 1) {
break;
}
}
diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
new file mode 100644
index 000000000000..bed832d7efe6
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -0,0 +1,85 @@
+;------------------------------------------------------------------------------
+; @file
+; First code executed by processor after resetting.
+;
+; Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+;------------------------------------------------------------------------------
+
+BITS 16
+
+ALIGN 16
+
+;
+; Pad the image size to 4k when page tables are in VTF0
+;
+; If the VTF0 image has page tables built in, then we need to make
+; sure the end of VTF0 is 4k above where the page tables end.
+;
+; This is required so the page tables will be 4k aligned when VTF0 is
+; located just below 0x100000000 (4GB) in the firmware device.
+;
+%ifdef ALIGN_TOP_TO_4K_FOR_PAGING
+ TIMES (0x1000 - ($ - EndOfPageTables) - 0x20) DB 0
+%endif
+
+;
+; SEV-ES Processor Reset support
+;
+; standardProcessorReset: (0xffffffd0)
+; When using the Application Processors entry point, always perform a
+; far jump to the RIP/CS value contained at this location. This will
+; default to EarlyBspInitReal16 unless specifically overridden.
+
+standardProcessorSevEsReset:
+ DW 0x0000
+ DW 0x0000
+
+ALIGN 16
+
+applicationProcessorEntryPoint:
+;
+; Application Processors entry point
+;
+; GenFv generates code aligned on a 4k boundary which will jump to this
+; location. (0xffffffe0) This allows the Local APIC Startup IPI to be
+; used to wake up the application processors.
+;
+ jmp EarlyApInitReal16
+
+ALIGN 8
+
+ DD 0
+
+;
+; The VTF signature
+;
+; VTF-0 means that the VTF (Volume Top File) code does not require
+; any fixups.
+;
+vtfSignature:
+ DB 'V', 'T', 'F', 0
+
+ALIGN 16
+
+resetVector:
+;
+; Reset Vector
+;
+; This is where the processor will begin execution
+;
+ cmp dword [CS:0xFFD0], 0
+ je EarlyBspInitReal16
+ jmp far [CS:0xFFD0]
+
+ALIGN 16
+
+fourGigabytes:
+
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
index efb1bc2bf7cb..180fa87b8dca 100644
--- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
@@ -19,7 +19,7 @@ CPU_SWITCH_STATE_IDLE equ 0
CPU_SWITCH_STATE_STORED equ 1
CPU_SWITCH_STATE_LOADED equ 2
-LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+LockLocation equ (SwitchToRealProcEnd - RendezvousFunnelProcStart)
StackStartAddressLocation equ LockLocation + 04h
StackSizeLocation equ LockLocation + 08h
ApProcedureLocation equ LockLocation + 0Ch
@@ -40,4 +40,6 @@ ModeTransitionMemoryLocation equ LockLocation + 4Ch
ModeTransitionSegmentLocation equ LockLocation + 50h
ModeHighMemoryLocation equ LockLocation + 52h
ModeHighSegmentLocation equ LockLocation + 56h
+SevEsActiveLocation equ LockLocation + 58h
+GhcbBaseLocation equ LockLocation + 5Ch
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
index b74046b76af3..309d53bf3b37 100644
--- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
@@ -215,6 +215,16 @@ CProcedureInvoke:
jmp $ ; Never reach here
RendezvousFunnelProcEnd:
+;-------------------------------------------------------------------------------------
+;SwitchToRealProc procedure follows.
+;NOT USED IN 32 BIT MODE.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(SwitchToRealProc)
+ASM_PFX(SwitchToRealProc):
+SwitchToRealProcStart:
+ jmp $ ; Never reach here
+SwitchToRealProcEnd:
+
;-------------------------------------------------------------------------------------
; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);
;-------------------------------------------------------------------------------------
@@ -263,6 +273,11 @@ ASM_PFX(AsmGetAddressMap):
mov dword [ebx + 0Ch], AsmRelocateApLoopStart
mov dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
mov dword [ebx + 14h], Flat32Start - RendezvousFunnelProcStart
+ mov dword [ebx + 18h], SwitchToRealProcEnd - SwitchToRealProcStart ; SwitchToRealSize
+ mov dword [ebx + 1Ch], SwitchToRealProcStart - RendezvousFunnelProcStart ; SwitchToRealOffset
+ mov dword [ebx + 20h], SwitchToRealProcStart - Flat32Start ; SwitchToRealNoNxOffset
+ mov dword [ebx + 24h], 0 ; SwitchToRealPM16ModeOffset
+ mov dword [ebx + 28h], 0 ; SwitchToRealPM16ModeSize
popad
ret
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
index 467f54a8602e..e05ef9a664ba 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
@@ -19,7 +19,7 @@ CPU_SWITCH_STATE_IDLE equ 0
CPU_SWITCH_STATE_STORED equ 1
CPU_SWITCH_STATE_LOADED equ 2
-LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+LockLocation equ (SwitchToRealProcEnd - RendezvousFunnelProcStart)
StackStartAddressLocation equ LockLocation + 08h
StackSizeLocation equ LockLocation + 10h
ApProcedureLocation equ LockLocation + 18h
@@ -40,3 +40,5 @@ ModeTransitionMemoryLocation equ LockLocation + 94h
ModeTransitionSegmentLocation equ LockLocation + 98h
ModeHighMemoryLocation equ LockLocation + 9Ah
ModeHighSegmentLocation equ LockLocation + 9Eh
+SevEsActiveLocation equ LockLocation + 0A0h
+GhcbBaseLocation equ LockLocation + 0A4h
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index cea90f3d4deb..286fa297791c 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -172,9 +172,97 @@ Releaselock:
add edi, StackStartAddressLocation
add rax, qword [edi]
mov rsp, rax
+
+ lea edi, [esi + SevEsActiveLocation]
+ cmp dword [edi], 1 ; SevEsActive
+ jne CProcedureInvoke
+
+ ;
+ ; program GHCB
+ ; Each page after the GHCB is a per-CPU page, so the calculation programs
+ ; a GHCB to be every 8KB.
+ ;
+ mov eax, SIZE_4KB
+ shl eax, 1 ; EAX = SIZE_4K * 2
+ mov ecx, ebx
+ mul ecx ; EAX = SIZE_4K * 2 * CpuNumber
+ mov edi, esi
+ add edi, GhcbBaseLocation
+ add rax, qword [edi]
+ mov rdx, rax
+ shr rdx, 32
+ mov rcx, 0xc0010130
+ wrmsr
jmp CProcedureInvoke
GetApicId:
+ lea edi, [esi + SevEsActiveLocation]
+ cmp dword [edi], 1 ; SevEsActive
+ jne DoCpuid
+
+ ;
+ ; Since we don't have a stack yet, we can't take a #VC
+ ; exception. Use the GHCB protocol to perform the CPUID
+ ; calls.
+ ;
+ mov rcx, 0xc0010130
+ rdmsr
+ shl rdx, 32
+ or rax, rdx
+ mov rdi, rax ; RDI now holds the original GHCB GPA
+
+ mov rdx, 0 ; CPUID function 0
+ mov rax, 0 ; RAX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+ cmp edx, 0bh
+ jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY
+
+ mov rdx, 0bh ; CPUID function 0x0b
+ mov rax, 040000000h ; RBX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+ test edx, 0ffffh
+ jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero
+
+ mov rdx, 0bh ; CPUID function 0x0b
+ mov rax, 0c0000000h ; RDX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+
+ ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX
+ jmp RestoreGhcb
+
+NoX2ApicSevEs:
+ ; Processor is not x2APIC capable, so get 8-bit APIC ID
+ mov rdx, 1 ; CPUID function 1
+ mov rax, 040000000h ; RBX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+ shr edx, 24
+
+RestoreGhcb:
+ mov rbx, rdx ; Save x2APIC/APIC ID
+
+ mov rdx, rdi ; RDI holds the saved GHCB GPA
+ shr rdx, 32
+ mov eax, edi
+ wrmsr
+
+ mov rdx, rbx
+
+ ; x2APIC ID or APIC ID is in EDX
+ jmp GetProcessorNumber
+
+DoCpuid:
mov eax, 0
cpuid
cmp eax, 0bh
@@ -241,12 +329,158 @@ CProcedureInvoke:
RendezvousFunnelProcEnd:
+;-------------------------------------------------------------------------------------
+;SwitchToRealProc procedure follows.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)
+; rcx - Buffer Start
+; rdx - Code16 Selector Offset
+; r8 - Code32 Selector Offset
+; r9 - Stack Start
+;-------------------------------------------------------------------------------------
+global ASM_PFX(SwitchToRealProc)
+ASM_PFX(SwitchToRealProc):
+SwitchToRealProcStart:
+BITS 64
+ cli
+
+ ;
+ ; Get RDX reset value before changing stacks since the
+ ; new stack won't be able to accomodate a #VC exception.
+ ;
+ push rax
+ push rbx
+ push rcx
+ push rdx
+
+ mov rax, 1
+ cpuid
+ mov rsi, rax ; Save off the reset value for RDX
+
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ;
+ ; Establish stack below 1MB
+ ;
+ mov rsp, r9
+
+ ;
+ ; Push ultimate Reset Vector onto the stack
+ ;
+ mov rax, rcx
+ shr rax, 4
+ push word 0x0002 ; RFLAGS
+ push ax ; CS
+ push word 0x0000 ; RIP
+ push word 0x0000 ; For alignment, will be discarded
+
+ ;
+ ; Get address of "16-bit operand size" label
+ ;
+ lea rbx, [PM16Mode]
+
+ ;
+ ; Push addresses used to change to compatibility mode
+ ;
+ lea rax, [CompatMode]
+ push r8
+ push rax
+
+ ;
+ ; Clear R8 - R15, for reset, before going into 32-bit mode
+ ;
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r11, r11
+ xor r12, r12
+ xor r13, r13
+ xor r14, r14
+ xor r15, r15
+
+ ;
+ ; Far return into 32-bit mode
+ ;
+o64 retf
+
+BITS 32
+CompatMode:
+ ;
+ ; Set up stack to prepare for exiting protected mode
+ ;
+ push edx ; Code16 CS
+ push ebx ; PM16Mode label address
+
+ ;
+ ; Disable paging
+ ;
+ mov eax, cr0 ; Read CR0
+ btr eax, 31 ; Set PG=0
+ mov cr0, eax ; Write CR0
+
+ ;
+ ; Disable long mode
+ ;
+ mov ecx, 0c0000080h ; EFER MSR number
+ rdmsr ; Read EFER
+ btr eax, 8 ; Set LME=0
+ wrmsr ; Write EFER
+
+ ;
+ ; Disable PAE
+ ;
+ mov eax, cr4 ; Read CR4
+ btr eax, 5 ; Set PAE=0
+ mov cr4, eax ; Write CR4
+
+ mov edx, esi ; Restore RDX reset value
+
+ ;
+ ; Switch to 16-bit operand size
+ ;
+ retf
+
+BITS 16
+ ;
+ ; At entry to this label
+ ; - RDX will have its reset value
+ ; - On the top of the stack
+ ; - Alignment data (two bytes) to be discarded
+ ; - IP for Real Mode (two bytes)
+ ; - CS for Real Mode (two bytes)
+ ;
+PM16Mode:
+ mov eax, cr0 ; Read CR0
+ btr eax, 0 ; Set PE=0
+ mov cr0, eax ; Write CR0
+
+ pop ax ; Discard alignment data
+
+ ;
+ ; Clear registers (except RDX and RSP) before going into 16-bit mode
+ ;
+ xor eax, eax
+ xor ebx, ebx
+ xor ecx, ecx
+ xor esi, esi
+ xor edi, edi
+ xor ebp, ebp
+
+ iret
+
+SwitchToRealProcEnd:
+
;-------------------------------------------------------------------------------------
; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmRelocateApLoop)
ASM_PFX(AsmRelocateApLoop):
AsmRelocateApLoopStart:
+BITS 64
cli ; Disable interrupt before switching to 32-bit mode
mov rax, [rsp + 40] ; CountTofinish
lock dec dword [rax] ; (*CountTofinish)--
@@ -312,6 +546,11 @@ ASM_PFX(AsmGetAddressMap):
mov qword [rcx + 18h], rax
mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart
+ mov qword [rcx + 30h], SwitchToRealProcEnd - SwitchToRealProcStart ; SwitchToRealSize
+ mov qword [rcx + 38h], SwitchToRealProcStart - RendezvousFunnelProcStart ; SwitchToRealOffset
+ mov qword [rcx + 40h], SwitchToRealProcStart - Flat32Start ; SwitchToRealNoNxOffset
+ mov qword [rcx + 48h], PM16Mode - RendezvousFunnelProcStart ; SwitchToRealPM16ModeOffset
+ mov qword [rcx + 50h], SwitchToRealProcEnd - PM16Mode ; SwitchToRealPM16ModeSize
ret
;-------------------------------------------------------------------------------------
diff --git a/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm b/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm
index ce4ebfffb688..0e79a3984b16 100644
--- a/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm
+++ b/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm
@@ -129,5 +129,14 @@ LINEAR_CODE64_SEL equ $-GDT_BASE
DB 0 ; base 31:24
%endif
+; linear code segment descriptor
+LINEAR_CODE16_SEL equ $-GDT_BASE
+ DW 0xffff ; limit 15:0
+ DW 0 ; base 15:0
+ DB 0 ; base 23:16
+ DB PRESENT_FLAG(1)|DPL(0)|SYSTEM_FLAG(1)|DESC_TYPE(CODE32_TYPE)
+ DB GRANULARITY_FLAG(1)|DEFAULT_SIZE32(0)|CODE64_FLAG(0)|UPPER_LIMIT(0xf)
+ DB 0 ; base 31:24
+
GDT_END:
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (26 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
2019-08-21 14:17 ` [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support Laszlo Ersek
28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh
From: Tom Lendacky <thomas.lendacky@amd.com>
Introduce a finalization routine to the MP library. This routine is
used at the end of UEFI before transferring control to the OS and allows
for SEV-ES related AP state and information to be communicated to the OS.
The APs will be parked using VMGEXIT AP Reset Hold and the GHCB will be
modified to communicate a reserved page of memory that will be used by the
OS to direct the "initial" AP boot in the OS.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
MdePkg/Include/Protocol/Cpu.h | 6 +
UefiCpuPkg/CpuDxe/CpuDxe.h | 14 ++
UefiCpuPkg/Include/Library/MpInitLib.h | 17 +++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 18 ++-
MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c | 5 +
OvmfPkg/PlatformPei/AmdSev.c | 2 +-
UefiCpuPkg/CpuDxe/CpuDxe.c | 10 ++
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 57 +++++++-
UefiCpuPkg/Library/MpInitLib/MpLib.c | 25 ++++
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 130 ++++++++++++++++--
10 files changed, 265 insertions(+), 19 deletions(-)
diff --git a/MdePkg/Include/Protocol/Cpu.h b/MdePkg/Include/Protocol/Cpu.h
index e392f4cd9a13..79a701bc0d93 100644
--- a/MdePkg/Include/Protocol/Cpu.h
+++ b/MdePkg/Include/Protocol/Cpu.h
@@ -257,6 +257,11 @@ EFI_STATUS
IN UINT64 Attributes
);
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_FINALIZE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
///
/// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
@@ -273,6 +278,7 @@ struct _EFI_CPU_ARCH_PROTOCOL {
EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler;
EFI_CPU_GET_TIMER_VALUE GetTimerValue;
EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes;
+ EFI_CPU_FINALIZE Finalize;
///
/// The number of timers that are available in a processor. The value in this
/// field is a constant that must not be modified after the CPU Architectural
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h
index b029be430b4c..c5b9ada72ac9 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.h
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.h
@@ -232,6 +232,20 @@ CpuSetMemoryAttributes (
IN UINT64 Attributes
);
+/**
+ Set ...
+
+ @param This Protocol instance structure
+
+ @retval EFI_SUCCESS If ...
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFinalize (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
/**
Initialize Global Descriptor Table.
diff --git a/UefiCpuPkg/Include/Library/MpInitLib.h b/UefiCpuPkg/Include/Library/MpInitLib.h
index fa8252937313..2095fb758664 100644
--- a/UefiCpuPkg/Include/Library/MpInitLib.h
+++ b/UefiCpuPkg/Include/Library/MpInitLib.h
@@ -344,4 +344,21 @@ MpInitLibWhoAmI (
OUT UINTN *ProcessorNumber
);
+/**
+ MP Exit ...
+
+ This service ...
+
+ This service must be invoked before ...
+
+ @retval EFI_SUCCESS MP initialization succeeds.
+ @retval Others MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpLibFinalize (
+ VOID
+ );
+
#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index f2ba1a508715..a2ba6de0278f 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -273,7 +273,8 @@ struct _CPU_MP_DATA {
UINT64 GhcbBase;
};
-#define AP_RESET_STACK_SIZE 64
+#define AP_SAFE_STACK_SIZE 128
+#define AP_RESET_STACK_SIZE AP_SAFE_STACK_SIZE
typedef union {
struct {
@@ -327,8 +328,11 @@ VOID
IN BOOLEAN MwaitSupport,
IN UINTN ApTargetCState,
IN UINTN PmCodeSegment,
+ IN UINTN Pm16CodeSegment,
IN UINTN TopOfApStack,
- IN UINTN NumberToFinish
+ IN UINTN NumberToFinish,
+ IN UINTN SevEsAPJumpTable,
+ IN UINTN WakeupBuffer
);
/**
@@ -645,5 +649,15 @@ EnableDebugAgent (
VOID
);
+/**
+ MP finalize ...
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+EFI_STATUS
+MpFinalize (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
#endif
diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
index 514d1aa75ada..13c962247243 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
+++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
@@ -785,6 +785,11 @@ CoreExitBootServices (
//
gCpu->DisableInterrupt (gCpu);
+ //
+ // Finalize CPU
+ //
+ gCpu->Finalize (gCpu);
+
//
// Clear the non-runtime values of the EFI System Table
//
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index fc396a6f229d..f0a18f026460 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -65,7 +65,7 @@ AmdSevEsInitialize (
BuildMemoryAllocationHob (
GhcbBasePa,
EFI_PAGES_TO_SIZE (GhcbPageCount),
- EfiBootServicesData
+ EfiReservedMemoryType
);
SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c
index 7d7270e10b4a..7003f74e7d87 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.c
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.c
@@ -92,6 +92,7 @@ EFI_CPU_ARCH_PROTOCOL gCpu = {
CpuRegisterInterruptHandler,
CpuGetTimerValue,
CpuSetMemoryAttributes,
+ CpuFinalize,
1, // NumberOfTimers
4 // DmaBufferAlignment
};
@@ -499,6 +500,15 @@ CpuSetMemoryAttributes (
return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);
}
+EFI_STATUS
+EFIAPI
+CpuFinalize (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ return MpLibFinalize ();
+}
+
/**
Initializes the valid bits mask and valid address mask for MTRRs.
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 127f64eb87e1..6e1bdbeed259 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -18,7 +18,6 @@
#include <Protocol/Timer.h>
#define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100))
-#define AP_SAFE_STACK_SIZE 128
CPU_MP_DATA *mCpuMpData = NULL;
EFI_EVENT mCheckAllApsEvent = NULL;
@@ -98,7 +97,7 @@ GetWakeupBuffer (
StartAddress = 0x88000;
Status = gBS->AllocatePages (
AllocateMaxAddress,
- EfiBootServicesData,
+ EfiReservedMemoryType,
EFI_SIZE_TO_PAGES (WakeupBufferSize),
&StartAddress
);
@@ -328,17 +327,26 @@ RelocateApLoop (
BOOLEAN MwaitSupport;
ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;
UINTN ProcessorNumber;
+ UINTN StackStart;
MpInitLibWhoAmI (&ProcessorNumber);
CpuMpData = GetCpuMpData ();
MwaitSupport = IsMwaitSupport ();
+ if (CpuMpData->SevEsActive) {
+ StackStart = CpuMpData->SevEsAPResetStackStart;
+ } else {
+ StackStart = mReservedTopOfApStack;
+ }
AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;
AsmRelocateApLoopFunc (
MwaitSupport,
CpuMpData->ApTargetCState,
CpuMpData->PmCodeSegment,
- mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,
- (UINTN) &mNumberToFinish
+ CpuMpData->Pm16CodeSegment,
+ StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
+ (UINTN) &mNumberToFinish,
+ CpuMpData->SevEsAPBuffer,
+ CpuMpData->WakeupBuffer
);
//
// It should never reach here
@@ -880,3 +888,44 @@ MpInitLibEnableDisableAP (
return Status;
}
+
+/**
+ MP finalize ...
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+EFI_STATUS
+MpFinalize (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ if (CpuMpData->SevEsActive) {
+ //
+ // Perform SEV-ES specific finalization
+ //
+ if (CpuMpData->WakeupBuffer == (UINTN) -1) {
+ //
+ // No APs parked in UEFI, clear the GHCB
+ //
+ AsmWriteMsr64 (MSR_SEV_ES_GHCB, 0);
+ } else {
+ //
+ // Re-use reserved memory area below 1MB from WakeupBuffer
+ //
+ CopyMem (
+ (VOID *) CpuMpData->WakeupBuffer,
+ (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress +
+ CpuMpData->AddressMap.SwitchToRealPM16ModeOffset,
+ CpuMpData->AddressMap.SwitchToRealPM16ModeSize
+ );
+
+ //
+ // Point the GHCB at the AP jump table to communicate the address to
+ // the booting system.
+ //
+ AsmWriteMsr64 (MSR_SEV_ES_GHCB, (CpuMpData->SevEsAPBuffer) | 0x03);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 0939019d7b8c..bc800a69527e 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1707,6 +1707,31 @@ CheckAllAPs (
return EFI_NOT_READY;
}
+/**
+ MP Exit ...
+
+ This service ...
+
+ This service must be invoked before ...
+
+ @retval EFI_SUCCESS MP initialization succeeds.
+ @retval Others MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpLibFinalize (
+ VOID
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+ MpFinalize (CpuMpData);
+
+ return EFI_SUCCESS;
+}
+
/**
MP Initialize Library initialization.
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 286fa297791c..8936963913c4 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -446,7 +446,7 @@ CompatMode:
BITS 16
;
- ; At entry to this label
+ ; At entry to this label (used also by AsmRelocateApLoop):
; - RDX will have its reset value
; - On the top of the stack
; - Alignment data (two bytes) to be discarded
@@ -475,32 +475,93 @@ PM16Mode:
SwitchToRealProcEnd:
;-------------------------------------------------------------------------------------
-; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, Pm16CodeSegment, TopOfApStack, CountTofinish, SevEsAPJumpTable, WakeupBuffer);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmRelocateApLoop)
ASM_PFX(AsmRelocateApLoop):
AsmRelocateApLoopStart:
BITS 64
+ cmp qword [rsp + 56], 0
+ je NoSevEs
+
+ ;
+ ; Perform some SEV-ES related setup before leaving 64-bit mode
+ ;
+ push rcx
+ push rdx
+
+ ;
+ ; Get the RDX reset value using CPUID
+ ;
+ mov rax, 1
+ cpuid
+ mov rsi, rax ; Save off the reset value for RDX
+
+ ;
+ ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call
+ ; - No NAE events can be generated once this is set otherwise
+ ; the AP_HLT_LOOP SW_EXITCODE will be overwritten.
+ ;
+ mov rcx, 0xc0010130
+ rdmsr ; Retrieve current GHCB address
+ shl rdx, 32
+ or rdx, rax
+
+ mov rdi, rdx
+ xor rax, rax
+ mov rcx, 0x800
+ shr rcx, 3
+ rep stosq ; Clear the GHCB
+
+ mov rax, 0x80000004 ; VMGEXIT AP_HLT_LOOP
+ mov [rdx + 0x390], rax
+
+ pop rdx
+ pop rcx
+
+NoSevEs:
cli ; Disable interrupt before switching to 32-bit mode
- mov rax, [rsp + 40] ; CountTofinish
+ mov rax, [rsp + 48] ; CountTofinish
lock dec dword [rax] ; (*CountTofinish)--
- mov rsp, r9
- push rcx
- push rdx
- lea rsi, [PmEntry] ; rsi <- The start address of transition code
+ mov rax, [rsp + 56] ; SevEsAPJumpTable
+ mov rbx, [rsp + 64] ; WakeupBuffer
+ mov rsp, [rsp + 40] ; TopOfApStack
+
+ push rax ; Save SevEsAPJumpTable
+ push rbx ; Save WakeupBuffer
+ push r9 ; Save Pm16CodeSegment
+ push rcx ; Save MwaitSupport
+ push rdx ; Save ApTargetCState
+
+ lea rax, [PmEntry] ; rax <- The start address of transition code
push r8
- push rsi
- DB 0x48
- retf
+ push rax
+
+ ;
+ ; Clear R8 - R15, for reset, before going into 32-bit mode
+ ;
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r11, r11
+ xor r12, r12
+ xor r13, r13
+ xor r14, r14
+ xor r15, r15
+
+ ;
+ ; Far return into 32-bit mode
+ ;
+o64 retf
+
BITS 32
PmEntry:
mov eax, cr0
btr eax, 31 ; Clear CR0.PG
mov cr0, eax ; Disable paging and caches
- mov ebx, edx ; Save EntryPoint to rbx, for rdmsr will overwrite rdx
mov ecx, 0xc0000080
rdmsr
and ah, ~ 1 ; Clear LME
@@ -513,6 +574,8 @@ PmEntry:
add esp, 4
pop ecx,
add esp, 4
+
+MwaitCheck:
cmp cl, 1 ; Check mwait-monitor support
jnz HltLoop
mov ebx, edx ; Save C-State to ebx
@@ -526,10 +589,53 @@ MwaitLoop:
shl eax, 4
mwait
jmp MwaitLoop
+
HltLoop:
+ pop edx ; PM16CodeSegment
+ add esp, 4
+ pop ebx ; WakeupBuffer
+ add esp, 4
+ pop eax ; SevEsAPJumpTable
+ add esp, 4
+ cmp eax, 0 ; Check for SEV-ES
+ je DoHlt
+
+ cli
+ ;
+ ; SEV-ES is active, use VMGEXIT (GHCB information already
+ ; set by caller)
+ ;
+ ; VMGEXIT is rep vmmcall
+ ;
+ db 0xf3
+ db 0x0f
+ db 0x01
+ db 0xd9
+
+ ;
+ ; Back from VMGEXIT AP_HLT_LOOP
+ ; Push the FLAGS/CS/IP values to use
+ ;
+ push word 0x0002 ; EFLAGS
+ xor ecx, ecx
+ mov cx, [eax + 2] ; CS
+ push cx
+ mov cx, [eax] ; IP
+ push cx
+ push word 0x0000 ; For alignment, will be discarded
+
+ push edx
+ push ebx
+
+ mov edx, esi ; Restore RDX reset value
+
+ retf
+
+DoHlt:
cli
hlt
- jmp HltLoop
+ jmp DoHlt
+
BITS 64
AsmRelocateApLoopEnd:
--
2.17.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* Re: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
@ 2019-08-19 21:47 ` Ni, Ray
2019-08-19 22:25 ` Lendacky, Thomas
0 siblings, 1 reply; 46+ messages in thread
From: Ni, Ray @ 2019-08-19 21:47 UTC (permalink / raw)
To: Lendacky, Thomas, devel@edk2.groups.io
Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
Gao, Liming, Dong, Eric, Singh, Brijesh
Tom,
1. It's not a common practice to have static inline functions defined in header file. Who is going to call them?
2. Recently I made a change to move the AMD registers definitions to MdePkg/Include/Register/Amd from UefiCpuPkg. Do you think that's a good idea and can you please put your new register definitions to MdePkg as well?
3. What happens if the "rep; vmmcall" is executed in Intel processor?
Thanks,
Ray
> -----Original Message-----
> From: Lendacky, Thomas <Thomas.Lendacky@amd.com>
> Sent: Monday, August 19, 2019 2:36 PM
> To: devel@edk2.groups.io
> Cc: Justen, Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ard Biesheuvel
> <ard.biesheuvel@linaro.org>; Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>; Dong,
> Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Singh, Brijesh <brijesh.singh@amd.com>
> Subject: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
>
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> VMGEXIT is a new instruction used for Hypervisor/Guest communication when
> running as an SEV-ES guest. A VMGEXIT will cause an automatic exit (AE)
> to occur, resulting in a #VMEXIT with an exit code value of 0x403.
>
> To support VMGEXIT, define the VMGEXIT assember routine to issue the
> instruction (rep; vmmcall), the GHCB structure and some helper functions
> for communicating register information to and from the hypervisor and the
> guest.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
> MdePkg/Library/BaseLib/BaseLib.inf | 1 +
> MdePkg/Include/Library/BaseLib.h | 14 ++
> UefiCpuPkg/Include/Register/Amd/Ghcb.h | 197 ++++++++++++++++++++++++
> MdePkg/Library/BaseLib/X64/GccInline.c | 17 ++
> MdePkg/Library/BaseLib/X64/VmgExit.nasm | 38 +++++
> 5 files changed, 267 insertions(+)
> create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
> create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm
>
> diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
> index 3586beb0ab5c..a41401340f95 100644
> --- a/MdePkg/Library/BaseLib/BaseLib.inf
> +++ b/MdePkg/Library/BaseLib/BaseLib.inf
> @@ -286,6 +286,7 @@ [Sources.X64]
> X64/ReadCr2.nasm| MSFT
> X64/ReadCr0.nasm| MSFT
> X64/ReadEflags.nasm| MSFT
> + X64/VmgExit.nasm | MSFT
>
>
> X64/Non-existing.c
> diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
> index 2a75bc023f56..80bd5cf57a72 100644
> --- a/MdePkg/Include/Library/BaseLib.h
> +++ b/MdePkg/Include/Library/BaseLib.h
> @@ -7880,6 +7880,20 @@ AsmLfence (
> VOID
> );
>
> +/**
> + Executes a VMGEXIT instruction (VMMCALL with a REP prefix)
> +
> + Executes a VMGEXIT instruction. This function is only available on IA-32 and
> + x64.
> +
> +**/
> +VOID
> +EFIAPI
> +AsmVmgExit (
> + VOID
> + );
> +
> +
> /**
> Patch the immediate operand of an IA32 or X64 instruction such that the byte,
> word, dword or qword operand is encoded at the end of the instruction's
> diff --git a/UefiCpuPkg/Include/Register/Amd/Ghcb.h b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
> new file mode 100644
> index 000000000000..e9fd116fac25
> --- /dev/null
> +++ b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
> @@ -0,0 +1,197 @@
> +
> +#ifndef __GHCB_H__
> +#define __GHCB_H__
> +
> +#include <Protocol/DebugSupport.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +
> +#define UD_EXCEPTION 6
> +#define GP_EXCEPTION 13
> +
> +#define GHCB_VERSION_MIN 1
> +#define GHCB_VERSION_MAX 1
> +
> +#define GHCB_STANDARD_USAGE 0
> +
> +typedef enum {
> + SvmExitDr7Read = 0x27,
> + SvmExitDr7Write = 0x37,
> + SvmExitRdtsc = 0x6E,
> + SvmExitRdpmc,
> + SvmExitCpuid = 0x72,
> + SvmExitInvd = 0x76,
> + SvmExitIoioProt = 0x7B,
> + SvmExitMsr,
> + SvmExitVmmCall = 0x81,
> + SvmExitRdtscp = 0x87,
> + SvmExitWbinvd = 0x89,
> + SvmExitMonitor,
> + SvmExitMwait,
> + SvmExitNpf = 0x400,
> +
> + // VMG special exits
> + SvmExitMmioRead = 0x80000001,
> + SvmExitMmioWrite,
> + SvmExitNmiComplete,
> + SvmExitApResetHold,
> +
> + SvmExitUnsupported = 0x8000FFFF,
> +} SVM_EXITCODE;
> +
> +typedef enum {
> + GhcbCpl = 25,
> + GhcbRflags = 46,
> + GhcbRip,
> + GhcbRsp = 59,
> + GhcbRax = 63,
> + GhcbRcx = 97,
> + GhcbRdx,
> + GhcbRbx,
> + GhcbRbp = 101,
> + GhcbRsi,
> + GhcbRdi,
> + GhcbR8,
> + GhcbR9,
> + GhcbR10,
> + GhcbR11,
> + GhcbR12,
> + GhcbR13,
> + GhcbR14,
> + GhcbR15,
> + GhcbXCr0 = 125,
> +} GHCB_REGISTER;
> +
> +typedef struct {
> + UINT8 Reserved1[203];
> + UINT8 Cpl;
> + UINT8 Reserved2[148];
> + UINT64 Dr7;
> + UINT8 Reserved3[144];
> + UINT64 Rax;
> + UINT8 Reserved4[264];
> + UINT64 Rcx;
> + UINT64 Rdx;
> + UINT64 Rbx;
> + UINT8 Reserved5[112];
> + UINT64 SwExitCode;
> + UINT64 SwExitInfo1;
> + UINT64 SwExitInfo2;
> + UINT64 SwScratch;
> + UINT8 Reserved6[56];
> + UINT64 XCr0;
> + UINT8 ValidBitmap[16];
> + UINT64 X87StateGpa;
> + UINT8 Reserved7[1016];
> +} __attribute__ ((__packed__)) GHCB_SAVE_AREA;
> +
> +typedef struct {
> + GHCB_SAVE_AREA SaveArea;
> + UINT8 SharedBuffer[2032];
> + UINT8 Reserved1[10];
> + UINT16 ProtocolVersion;
> + UINT32 GhcbUsage;
> +} __attribute__ ((__packed__)) __attribute__ ((aligned(SIZE_4KB))) GHCB;
> +
> +typedef union {
> + struct {
> + UINT32 Lower32Bits;
> + UINT32 Upper32Bits;
> + } Elements;
> +
> + UINT64 Uint64;
> +} GHCB_EXIT_INFO;
> +
> +static inline
> +BOOLEAN
> +GhcbIsRegValid(
> + GHCB *Ghcb,
> + GHCB_REGISTER Reg
> + )
> +{
> + UINT32 RegIndex = Reg / 8;
> + UINT32 RegBit = Reg & 0x07;
> +
> + return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
> +}
> +
> +static inline
> +VOID
> +GhcbSetRegValid(
> + GHCB *Ghcb,
> + GHCB_REGISTER Reg
> + )
> +{
> + UINT32 RegIndex = Reg / 8;
> + UINT32 RegBit = Reg & 0x07;
> +
> + Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
> +}
> +
> +static inline
> +VOID
> +VmgException(
> + UINTN Exception
> + )
> +{
> + switch (Exception) {
> + case UD_EXCEPTION:
> + case GP_EXCEPTION:
> + break;
> + default:
> + ASSERT (0);
> + }
> +}
> +
> +static inline
> +UINTN
> +VmgExit(
> + GHCB *Ghcb,
> + UINT64 ExitCode,
> + UINT64 ExitInfo1,
> + UINT64 ExitInfo2
> + )
> +{
> + GHCB_EXIT_INFO ExitInfo;
> + UINTN Reason, Action;
> +
> + Ghcb->SaveArea.SwExitCode = ExitCode;
> + Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
> + Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
> + AsmVmgExit ();
> +
> + if (!Ghcb->SaveArea.SwExitInfo1) {
> + return 0;
> + }
> +
> + ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
> + Reason = ExitInfo.Elements.Upper32Bits;
> + Action = ExitInfo.Elements.Lower32Bits;
> + switch (Action) {
> + case 1:
> + VmgException (Reason);
> + break;
> + default:
> + ASSERT (0);
> + }
> +
> + return Reason;
> +}
> +
> +static inline
> +VOID
> +VmgInit(
> + GHCB *Ghcb
> + )
> +{
> + SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
> +}
> +
> +static inline
> +VOID
> +VmgDone(
> + GHCB *Ghcb
> + )
> +{
> +}
> +#endif
> diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
> index 154ce1f57e92..17539caa0798 100644
> --- a/MdePkg/Library/BaseLib/X64/GccInline.c
> +++ b/MdePkg/Library/BaseLib/X64/GccInline.c
> @@ -1798,3 +1798,20 @@ AsmFlushCacheLine (
> }
>
>
> +/**
> + Executes a VMGEXIT instruction.
> +
> + Executes a VMGEXIT instruction. This function is only available on IA-32 and
> + X64.
> +
> +**/
> +VOID
> +EFIAPI
> +AsmVmgExit (
> + VOID
> + )
> +{
> + __asm__ __volatile__ ("rep; vmmcall":::"memory");
> +}
> +
> +
> diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
> new file mode 100644
> index 000000000000..b673bb94b60d
> --- /dev/null
> +++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
> @@ -0,0 +1,38 @@
> +;------------------------------------------------------------------------------
> +;
> +; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
> +; This program and the accompanying materials
> +; are licensed and made available under the terms and conditions of the BSD License
> +; which accompanies this distribution. The full text of the license may be found at
> +; http://opensource.org/licenses/bsd-license.php.
> +;
> +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +;
> +; Module Name:
> +;
> +; VmgExit.Asm
> +;
> +; Abstract:
> +;
> +; AsmVmgExit function
> +;
> +; Notes:
> +;
> +;------------------------------------------------------------------------------
> +
> + DEFAULT REL
> + SECTION .text
> +
> +;------------------------------------------------------------------------------
> +; VOID
> +; EFIAPI
> +; AsmVmgExit (
> +; VOID
> +; );
> +;------------------------------------------------------------------------------
> +global ASM_PFX(AsmVmgExit)
> +ASM_PFX(AsmVmgExit):
> + rep; vmmcall
> + ret
> +
> --
> 2.17.1
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
2019-08-19 21:47 ` Ni, Ray
@ 2019-08-19 22:25 ` Lendacky, Thomas
0 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 22:25 UTC (permalink / raw)
To: Ni, Ray, devel@edk2.groups.io
Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
Gao, Liming, Dong, Eric, Singh, Brijesh
Hi Ray,
On 8/19/19 4:47 PM, Ni, Ray wrote:
> Tom,
> 1. It's not a common practice to have static inline functions defined in header file. Who is going to call them?
The functions are called from two locations, so that's why I made them
static inline. I'm new to EDK2 programming, so I'm sure there will be a
number of things I do that will need to be changed.
Should I make them non-inline and move them to the BaseLib in MdePkg or
somewhere else?
> 2. Recently I made a change to move the AMD registers definitions to MdePkg/Include/Register/Amd from UefiCpuPkg. Do you think that's a good idea and can you please put your new register definitions to MdePkg as well?
Ok, let me pull the latest tree and rebase. This patchset is currently
based on a July 17th patch:
cce01f538fb4 ("MdePkg/BaseLib: Base64Decode(): don't declare variables in nested blocks")
so I'm probably behind the change that you made if it was recent.
> 3. What happens if the "rep; vmmcall" is executed in Intel processor?
Good question, I'm not sure. Is there a way that EDK2 has to prevent
execution of unsupported instructions? Currently, this instruction will
only be invoked when it is known that SEV-ES is active.
Thanks,
Tom
>
> Thanks,
> Ray
>
>> -----Original Message-----
>> From: Lendacky, Thomas <Thomas.Lendacky@amd.com>
>> Sent: Monday, August 19, 2019 2:36 PM
>> To: devel@edk2.groups.io
>> Cc: Justen, Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ard Biesheuvel
>> <ard.biesheuvel@linaro.org>; Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>; Dong,
>> Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Singh, Brijesh <brijesh.singh@amd.com>
>> Subject: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
>>
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> VMGEXIT is a new instruction used for Hypervisor/Guest communication when
>> running as an SEV-ES guest. A VMGEXIT will cause an automatic exit (AE)
>> to occur, resulting in a #VMEXIT with an exit code value of 0x403.
>>
>> To support VMGEXIT, define the VMGEXIT assember routine to issue the
>> instruction (rep; vmmcall), the GHCB structure and some helper functions
>> for communicating register information to and from the hypervisor and the
>> guest.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>> MdePkg/Library/BaseLib/BaseLib.inf | 1 +
>> MdePkg/Include/Library/BaseLib.h | 14 ++
>> UefiCpuPkg/Include/Register/Amd/Ghcb.h | 197 ++++++++++++++++++++++++
>> MdePkg/Library/BaseLib/X64/GccInline.c | 17 ++
>> MdePkg/Library/BaseLib/X64/VmgExit.nasm | 38 +++++
>> 5 files changed, 267 insertions(+)
>> create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
>> create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm
>>
>> diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
>> index 3586beb0ab5c..a41401340f95 100644
>> --- a/MdePkg/Library/BaseLib/BaseLib.inf
>> +++ b/MdePkg/Library/BaseLib/BaseLib.inf
>> @@ -286,6 +286,7 @@ [Sources.X64]
>> X64/ReadCr2.nasm| MSFT
>> X64/ReadCr0.nasm| MSFT
>> X64/ReadEflags.nasm| MSFT
>> + X64/VmgExit.nasm | MSFT
>>
>>
>> X64/Non-existing.c
>> diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
>> index 2a75bc023f56..80bd5cf57a72 100644
>> --- a/MdePkg/Include/Library/BaseLib.h
>> +++ b/MdePkg/Include/Library/BaseLib.h
>> @@ -7880,6 +7880,20 @@ AsmLfence (
>> VOID
>> );
>>
>> +/**
>> + Executes a VMGEXIT instruction (VMMCALL with a REP prefix)
>> +
>> + Executes a VMGEXIT instruction. This function is only available on IA-32 and
>> + x64.
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +AsmVmgExit (
>> + VOID
>> + );
>> +
>> +
>> /**
>> Patch the immediate operand of an IA32 or X64 instruction such that the byte,
>> word, dword or qword operand is encoded at the end of the instruction's
>> diff --git a/UefiCpuPkg/Include/Register/Amd/Ghcb.h b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
>> new file mode 100644
>> index 000000000000..e9fd116fac25
>> --- /dev/null
>> +++ b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
>> @@ -0,0 +1,197 @@
>> +
>> +#ifndef __GHCB_H__
>> +#define __GHCB_H__
>> +
>> +#include <Protocol/DebugSupport.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +
>> +#define UD_EXCEPTION 6
>> +#define GP_EXCEPTION 13
>> +
>> +#define GHCB_VERSION_MIN 1
>> +#define GHCB_VERSION_MAX 1
>> +
>> +#define GHCB_STANDARD_USAGE 0
>> +
>> +typedef enum {
>> + SvmExitDr7Read = 0x27,
>> + SvmExitDr7Write = 0x37,
>> + SvmExitRdtsc = 0x6E,
>> + SvmExitRdpmc,
>> + SvmExitCpuid = 0x72,
>> + SvmExitInvd = 0x76,
>> + SvmExitIoioProt = 0x7B,
>> + SvmExitMsr,
>> + SvmExitVmmCall = 0x81,
>> + SvmExitRdtscp = 0x87,
>> + SvmExitWbinvd = 0x89,
>> + SvmExitMonitor,
>> + SvmExitMwait,
>> + SvmExitNpf = 0x400,
>> +
>> + // VMG special exits
>> + SvmExitMmioRead = 0x80000001,
>> + SvmExitMmioWrite,
>> + SvmExitNmiComplete,
>> + SvmExitApResetHold,
>> +
>> + SvmExitUnsupported = 0x8000FFFF,
>> +} SVM_EXITCODE;
>> +
>> +typedef enum {
>> + GhcbCpl = 25,
>> + GhcbRflags = 46,
>> + GhcbRip,
>> + GhcbRsp = 59,
>> + GhcbRax = 63,
>> + GhcbRcx = 97,
>> + GhcbRdx,
>> + GhcbRbx,
>> + GhcbRbp = 101,
>> + GhcbRsi,
>> + GhcbRdi,
>> + GhcbR8,
>> + GhcbR9,
>> + GhcbR10,
>> + GhcbR11,
>> + GhcbR12,
>> + GhcbR13,
>> + GhcbR14,
>> + GhcbR15,
>> + GhcbXCr0 = 125,
>> +} GHCB_REGISTER;
>> +
>> +typedef struct {
>> + UINT8 Reserved1[203];
>> + UINT8 Cpl;
>> + UINT8 Reserved2[148];
>> + UINT64 Dr7;
>> + UINT8 Reserved3[144];
>> + UINT64 Rax;
>> + UINT8 Reserved4[264];
>> + UINT64 Rcx;
>> + UINT64 Rdx;
>> + UINT64 Rbx;
>> + UINT8 Reserved5[112];
>> + UINT64 SwExitCode;
>> + UINT64 SwExitInfo1;
>> + UINT64 SwExitInfo2;
>> + UINT64 SwScratch;
>> + UINT8 Reserved6[56];
>> + UINT64 XCr0;
>> + UINT8 ValidBitmap[16];
>> + UINT64 X87StateGpa;
>> + UINT8 Reserved7[1016];
>> +} __attribute__ ((__packed__)) GHCB_SAVE_AREA;
>> +
>> +typedef struct {
>> + GHCB_SAVE_AREA SaveArea;
>> + UINT8 SharedBuffer[2032];
>> + UINT8 Reserved1[10];
>> + UINT16 ProtocolVersion;
>> + UINT32 GhcbUsage;
>> +} __attribute__ ((__packed__)) __attribute__ ((aligned(SIZE_4KB))) GHCB;
>> +
>> +typedef union {
>> + struct {
>> + UINT32 Lower32Bits;
>> + UINT32 Upper32Bits;
>> + } Elements;
>> +
>> + UINT64 Uint64;
>> +} GHCB_EXIT_INFO;
>> +
>> +static inline
>> +BOOLEAN
>> +GhcbIsRegValid(
>> + GHCB *Ghcb,
>> + GHCB_REGISTER Reg
>> + )
>> +{
>> + UINT32 RegIndex = Reg / 8;
>> + UINT32 RegBit = Reg & 0x07;
>> +
>> + return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
>> +}
>> +
>> +static inline
>> +VOID
>> +GhcbSetRegValid(
>> + GHCB *Ghcb,
>> + GHCB_REGISTER Reg
>> + )
>> +{
>> + UINT32 RegIndex = Reg / 8;
>> + UINT32 RegBit = Reg & 0x07;
>> +
>> + Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
>> +}
>> +
>> +static inline
>> +VOID
>> +VmgException(
>> + UINTN Exception
>> + )
>> +{
>> + switch (Exception) {
>> + case UD_EXCEPTION:
>> + case GP_EXCEPTION:
>> + break;
>> + default:
>> + ASSERT (0);
>> + }
>> +}
>> +
>> +static inline
>> +UINTN
>> +VmgExit(
>> + GHCB *Ghcb,
>> + UINT64 ExitCode,
>> + UINT64 ExitInfo1,
>> + UINT64 ExitInfo2
>> + )
>> +{
>> + GHCB_EXIT_INFO ExitInfo;
>> + UINTN Reason, Action;
>> +
>> + Ghcb->SaveArea.SwExitCode = ExitCode;
>> + Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
>> + Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
>> + AsmVmgExit ();
>> +
>> + if (!Ghcb->SaveArea.SwExitInfo1) {
>> + return 0;
>> + }
>> +
>> + ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
>> + Reason = ExitInfo.Elements.Upper32Bits;
>> + Action = ExitInfo.Elements.Lower32Bits;
>> + switch (Action) {
>> + case 1:
>> + VmgException (Reason);
>> + break;
>> + default:
>> + ASSERT (0);
>> + }
>> +
>> + return Reason;
>> +}
>> +
>> +static inline
>> +VOID
>> +VmgInit(
>> + GHCB *Ghcb
>> + )
>> +{
>> + SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
>> +}
>> +
>> +static inline
>> +VOID
>> +VmgDone(
>> + GHCB *Ghcb
>> + )
>> +{
>> +}
>> +#endif
>> diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
>> index 154ce1f57e92..17539caa0798 100644
>> --- a/MdePkg/Library/BaseLib/X64/GccInline.c
>> +++ b/MdePkg/Library/BaseLib/X64/GccInline.c
>> @@ -1798,3 +1798,20 @@ AsmFlushCacheLine (
>> }
>>
>>
>> +/**
>> + Executes a VMGEXIT instruction.
>> +
>> + Executes a VMGEXIT instruction. This function is only available on IA-32 and
>> + X64.
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +AsmVmgExit (
>> + VOID
>> + )
>> +{
>> + __asm__ __volatile__ ("rep; vmmcall":::"memory");
>> +}
>> +
>> +
>> diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
>> new file mode 100644
>> index 000000000000..b673bb94b60d
>> --- /dev/null
>> +++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
>> @@ -0,0 +1,38 @@
>> +;------------------------------------------------------------------------------
>> +;
>> +; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
>> +; This program and the accompanying materials
>> +; are licensed and made available under the terms and conditions of the BSD License
>> +; which accompanies this distribution. The full text of the license may be found at
>> +; http://opensource.org/licenses/bsd-license.php.
>> +;
>> +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
>> +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
>> +;
>> +; Module Name:
>> +;
>> +; VmgExit.Asm
>> +;
>> +; Abstract:
>> +;
>> +; AsmVmgExit function
>> +;
>> +; Notes:
>> +;
>> +;------------------------------------------------------------------------------
>> +
>> + DEFAULT REL
>> + SECTION .text
>> +
>> +;------------------------------------------------------------------------------
>> +; VOID
>> +; EFIAPI
>> +; AsmVmgExit (
>> +; VOID
>> +; );
>> +;------------------------------------------------------------------------------
>> +global ASM_PFX(AsmVmgExit)
>> +ASM_PFX(AsmVmgExit):
>> + rep; vmmcall
>> + ret
>> +
>> --
>> 2.17.1
>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
` (27 preceding siblings ...)
2019-08-19 21:36 ` [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES Lendacky, Thomas
@ 2019-08-21 14:17 ` Laszlo Ersek
28 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:17 UTC (permalink / raw)
To: devel, thomas.lendacky
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
Hi Tom,
On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> This patch series provides support for running EDK2/OVMF under SEV-ES.
>
> Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
> SEV support to protect the guest register state from the hypervisor. See
> "AMD64 Architecture Programmer's Manual Volume 2: System Programming",
> section "15.35 Encrypted State (SEV-ES)" [1].
>
> In order to allow a hypervisor to perform functions on behalf of a guest,
> there is architectural support for notifying a guest's operating system
> when certain types of VMEXITs are about to occur. This allows the guest to
> selectively share information with the hypervisor to satisfy the requested
> function. The notification is performed using a new exception, the VMM
> Communication exception (#VC). The information is shared through the
> Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
> The GHCB format and the protocol for using it is documented in "SEV-ES
> Guest-Hypervisor Communication Block Standardization" [2].
>
> The main areas of the EDK2 code that are updated to support SEV-ES are
> around the exception handling support and the AP boot support.
>
> Exception support is required starting in Sec, continuing through Pei
> and into Dxe in order to handle #VC exceptions that are generated. Each
> AP requires it's own GHCB page as well as a page to hold values specific
> to that AP.
>
> AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
> is typically used to boot the APs. However, the hypervisor is not allowed
> to update the guest registers. The GHCB document [2] talks about how SMP
> booting under SEV-ES is performed.
>
> Since the GHCB page must be a shared (unencrypted) page, the processor
> must be running in long mode in order for the guest and hypervisor to
> communicate with each other. As a result, SEV-ES is only supported under
> the X64 architecture.
>
> [1] https://www.amd.com/system/files/TechDocs/24593.pdf
> [2] https://developer.amd.com/wp-content/resources/56421.pdf
> [3] https://github.com/AMDESE/ovmf/tree/sev-es-v6
some very high level comments first.
(1) If there is any way, please avoid modifying multiple top-level
directories in a single patch. For example, a patch that currently
modifies both OvmfPkg and UefiCpuPkg, should be split in at least two,
but possibly three, parts. Otherwise, it becomes very difficult to
isolate reviewer responsibilities.
Furthermore, if you can split changes even inside a top-level package
directory, along module boundaries (such that a patch only modify a
single library instance or a driver module, if possible), that's
appreciated.
Clearly this would result in an even larger number of patches in the
series -- for which reason it's usually good to split the series into
"waves" (smaller series). Of course whenever you post a wave, you should
have a functional "whole" (a full stack of waves) in your local tree.
But posting smaller waves is helpful for reviewers (speaking generally),
and the tail of the full work might undergo quite significant updates
due to changes requested for the front.
(2) Please pass "--stat=1000" to git-format-patch. (The additional
"--stat-graph-width=20" option should already be present in your config,
persistently, from running SetupGit.py.) Otherwise, pathnames will be
truncated on the left in the diffstat sections, and that's quite
distracting.
(3) Please consider using "BaseTools/Scripts/GetMaintainer.py", for
determining the set of reviewers for each patch in isolation. Please use
explicit "Cc:" tags in the commit messages. The cover letter should
contain a unified "Cc:" list, also explicitly.
(4) As a general rule, any new memory areas that you access during SEC
and PEI by constant addresses (PCDs) must be considered for S3 resume.
These areas should be reserved from the OS, so that the OS not store
data there, which we'd overwrite during S3. It is also necessary to
guarantee that we never read data from such an area before writing to it
-- in S3, we must not consume any data planted by the OS. So, we should
protect a well-meaning OS during S3, and thwart a malicious OS.
This applies to the new ranges you introduce in [FD.MEMFD]. The current
areas are all covered by PlatformPei explicitly. For details, please
refer to the following document (it could be somewhat out of date, but
the general point stands):
http://www.linux-kvm.org/downloads/lersek/ovmf-whitepaper-c770f8c.txt
section "A comprehensive memory map of OVMF" -- look for the part saying
"With regard to RAM that is statically used by OVMF, ...".
It's OK if S3 support is out of scope for this work. Even in that case,
the life cycles of the new memory ranges should be investigated and
documented explicitly. If S3 is not to be supported with SEV-ES, then
the S3Verification() function should catch that.
(5) Specifically for the SEC GHCB range: can it be carved out of the
32KB gap at 0x80_8000, i.e. without shuffling around preexistent areas?
(6) Please file a BZ (Product = TianoCore Feature Request) in the
TianoCore bugzilla instance, and assign it to yourself. The patches
should all reference the BZ (in the commit message). The bugzilla should
please contain a high level description of the feature (more or less the
current cover letter). In addition, whenever a new version or wave of
the work is posted to edk2-devel, a mailing list URL should be captured
in the BZ, so that in a few months or years distance, we can see the
posted versions under a single ticket.
Thanks
Laszlo
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-08-21 14:21 ` Laszlo Ersek
2019-08-21 21:25 ` Lendacky, Thomas
2019-08-21 21:51 ` Jordan Justen
0 siblings, 2 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:21 UTC (permalink / raw)
To: devel, thomas.lendacky
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> Currently, the OVMF code relies on the hypervisor to enable the cache
> support on the processor in order to improve the boot speed. However,
> with SEV-ES, the hypervisor is not allowed to change the CR0 register
> to enable caching.
>
> Update the OVMF Sec support to enable caching in order to improve the
> boot speed.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
> OvmfPkg/Sec/SecMain.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> index 3914355cd17b..2448be0cd408 100644
> --- a/OvmfPkg/Sec/SecMain.c
> +++ b/OvmfPkg/Sec/SecMain.c
> @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
>
> ProcessLibraryConstructorList (NULL, NULL);
>
> + //
> + // Enable caching
> + //
> + AsmEnableCache ();
> +
> DEBUG ((EFI_D_INFO,
> "SecCoreStartupWithStack(0x%x, 0x%x)\n",
> (UINT32)(UINTN)BootFv,
>
This makes me uncomfortable. There used to be problems related to
caching when VFIO device assignment were used. My concern is admittedly
vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
"well what could break here", I'd answer "you never know, and the burden
of proof is not on me". :) Can we make this change conditional on SEV-ES?
Thanks
Laszlo
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase
2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-08-21 14:25 ` Laszlo Ersek
2019-08-21 21:29 ` Lendacky, Thomas
0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:25 UTC (permalink / raw)
To: devel, thomas.lendacky
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> A GHCB page is needed during the Sec phase, so this new page must be
> created. Since the GHCB must be marked as an un-encrypted, or shared,
> page, an additional pagetable page is required so break down the 2MB
> region where the GHCB page lives into 4K pagetable entries.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
> OvmfPkg/OvmfPkg.dec | 5 +++
> OvmfPkg/OvmfPkgX64.fdf | 11 ++++---
> OvmfPkg/PlatformPei/PlatformPei.inf | 2 ++
> OvmfPkg/ResetVector/ResetVector.inf | 2 ++
> UefiCpuPkg/Include/Register/Amd/Fam17Msr.h | 28 ++++++++++++++++
> OvmfPkg/ResetVector/Ia32/PageTables64.asm | 37 +++++++++++++++++++++-
> OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
> 7 files changed, 81 insertions(+), 6 deletions(-)
I've skipped patches 02 and 03 for now, because I'll have to go through
them with a fine toothed comb -- in a subsequent submission, most
probably. I'm just trying to provide formal comments, so that I do the
actual review more easily, later.
As I requested under the blurb, this patch should be split in at least
three parts, if possible -- OvmfPkg/PlatformPei, OvmfPkg/ResetVector,
UefiCpuPkg. (The DEC and FDF changes can be kept squashed with the
OvmfPkg patch that seems more suitable for that.)
... Having said that, why do you add PCDs to the PlatformPei INF file?
The code in PlatformPei doesn't change. Could be a leftover from an
earlier (abandoned) approach.
Thanks
Laszlo
>
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 9640360f6245..2ead9a944af4 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -218,6 +218,11 @@ [PcdsFixedAtBuild]
> # The value should be a multiple of 4KB.
> gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
>
> + ## Specify the GHCB base address and size.
> + # The value should be a multiple of 4KB for each.
> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x32
> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x33
> +
> [PcdsDynamic, PcdsDynamicEx]
> gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 74407072563b..2a2427092382 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -67,13 +67,16 @@ [FD.MEMFD]
> BlockSize = 0x10000
> NumBlocks = 0xC0
>
> -0x000000|0x006000
> +0x000000|0x007000
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>
> -0x006000|0x001000
> -gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
> -
> 0x007000|0x001000
> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
> +
> +0x008000|0x001000
> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
> +
> +0x009000|0x001000
> gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>
> 0x010000|0x010000
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index d9fd9c8f05b3..aed1f64b7c93 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -72,6 +72,8 @@ [Pcd]
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
> gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
> index 960b47cd0797..d66f4dc29737 100644
> --- a/OvmfPkg/ResetVector/ResetVector.inf
> +++ b/OvmfPkg/ResetVector/ResetVector.inf
> @@ -37,3 +37,5 @@ [Pcd]
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
> diff --git a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
> index 37b935dcdb30..55a5723e164e 100644
> --- a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
> +++ b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
> @@ -17,6 +17,34 @@
> #ifndef __FAM17_MSR_H__
> #define __FAM17_MSR_H__
>
> +/**
> + Secure Encrypted Virtualization - Encrypted State (SEV-ES) GHCB register
> +
> +**/
> +#define MSR_SEV_ES_GHCB 0xc0010130
> +
> +/**
> + MSR information returned for #MSR_SEV_ES_GHCB
> +**/
> +typedef union {
> + struct {
> + UINT32 GhcbNegotiateBit:1;
> +
> + UINT32 Reserved:31;
> + } Bits;
> +
> + struct {
> + UINT8 Reserved[3];
> + UINT8 SevEncryptionBitPos;
> + UINT16 SevEsProtocolMin;
> + UINT16 SevEsProtocolMax;
> + } GhcbProtocol;
> +
> + VOID *Ghcb;
> +
> + UINT64 GhcbPhysicalAddress;
> +} MSR_SEV_ES_GHCB_REGISTER;
> +
> /**
> Secure Encrypted Virtualization (SEV) status register
>
> diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> index c6071fe934de..fd4d5b1d8661 100644
> --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> @@ -21,6 +21,11 @@ BITS 32
> %define PAGE_2M_MBO 0x080
> %define PAGE_2M_PAT 0x01000
>
> +%define PAGE_4K_PDE_ATTR (PAGE_ACCESSED + \
> + PAGE_DIRTY + \
> + PAGE_READ_WRITE + \
> + PAGE_PRESENT)
> +
> %define PAGE_2M_PDE_ATTR (PAGE_2M_MBO + \
> PAGE_ACCESSED + \
> PAGE_DIRTY + \
> @@ -120,7 +125,7 @@ SevNotActive:
> ; more permanent location by DxeIpl.
> ;
>
> - mov ecx, 6 * 0x1000 / 4
> + mov ecx, 7 * 0x1000 / 4
> xor eax, eax
> clearPageTablesMemoryLoop:
> mov dword[ecx * 4 + PT_ADDR (0) - 4], eax
> @@ -157,6 +162,36 @@ pageTableEntriesLoop:
> mov [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
> loop pageTableEntriesLoop
>
> + ;
> + ; The GHCB will live at 0x807000 (just after the page tables)
> + ; and needs to be un-encrypted. This requires the 2MB page
> + ; (index 4 in the first 1GB page) for this range be broken down
> + ; into 512 4KB pages. All will be marked as encrypted, except
> + ; for the GHCB.
> + ;
> + mov ecx, 4
> + mov eax, PT_ADDR (0x6000) + PAGE_PDP_ATTR
> + mov [ecx * 8 + PT_ADDR (0x2000)], eax
> +
> + mov ecx, 512
> +pageTableEntries4kLoop:
> + mov eax, ecx
> + dec eax
> + shl eax, 12
> + add eax, 0x800000
> + add eax, PAGE_4K_PDE_ATTR
> + mov [ecx * 8 + PT_ADDR (0x6000 - 8)], eax
> + mov [(ecx * 8 + PT_ADDR (0x6000 - 8)) + 4], edx
> + loop pageTableEntries4kLoop
> +
> + ;
> + ; Clear the encryption bit from the GHCB entry (index 7 in the
> + ; new PTE table - (0x807000 - 0x800000) >> 12).
> + ;
> + mov ecx, 7
> + xor edx, edx
> + mov [(ecx * 8 + PT_ADDR (0x6000)) + 4], edx
> +
> ;
> ; Set CR3 now that the paging structures are available
> ;
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 3b213cd05ab2..56d9b86ed943 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -49,7 +49,7 @@
> %ifdef ARCH_X64
> #include <AutoGen.h>
>
> - %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x6000)
> + %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x7000)
> %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
> %endif
>
>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-08-21 14:31 ` Laszlo Ersek
2019-08-21 21:42 ` Lendacky, Thomas
0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:31 UTC (permalink / raw)
To: devel, thomas.lendacky
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> Allocate memory for the GHCB pages during SEV initialization for use
> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
> are created without the encryption bit set.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
> UefiCpuPkg/UefiCpuPkg.dec | 4 ++
> OvmfPkg/OvmfPkgX64.dsc | 4 ++
> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +
> OvmfPkg/PlatformPei/PlatformPei.inf | 2 +
> .../Core/DxeIplPeim/X64/VirtualMemory.h | 12 +++-
> .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 4 +-
> .../Core/DxeIplPeim/X64/DxeLoadFunc.c | 11 +++-
> .../Core/DxeIplPeim/X64/VirtualMemory.c | 49 ++++++++++----
> .../MemEncryptSevLibInternal.c | 1 -
> .../BaseMemEncryptSevLib/X64/VirtualMemory.c | 33 ++++++++--
> OvmfPkg/PlatformPei/AmdSev.c | 64 +++++++++++++++++++
> 11 files changed, 164 insertions(+), 23 deletions(-)
Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
In addition, MdeModulePkg content must not depend on UefiCpuPkg content
-- if modules under both packages need to consume a new PCD, then the
PCD should be declared under MdeModulePkg. The rough dependency order is:
- MdePkg (must be self-contained)
- MdeModulePkg (may consume MdePkg)
- UefiCpuPkg (may consume everything above, to my knowledge)
- OvmfPkg (may consume everything above)
Thanks
Laszlo
>
> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
> index 6ddf0cd22466..4d5a2593cf13 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dec
> +++ b/UefiCpuPkg/UefiCpuPkg.dec
> @@ -323,5 +323,9 @@ [PcdsDynamic, PcdsDynamicEx]
> # @ValidRange 0x80000001 | 0 - 1
> gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme|0x0|UINT8|0x60000015
>
> + ## Contains the GHCB page allocation information.<BR><BR>
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
> +
> [UserExtensions.TianoCore."ExtraFiles"]
> UefiCpuPkgExtra.uni
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index dda8dac18441..d6fc7cdf7da8 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -569,6 +569,10 @@ [PcdsDynamicDefault]
> # Set memory encryption mask
> gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>
> + # Set GHCB base address for SEV-ES
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0
> +
> !if $(SMM_REQUIRE) == TRUE
> gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
> gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> index abc3217b0179..b994398633e3 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> @@ -52,6 +52,7 @@ [Sources.ARM, Sources.AARCH64]
> [Packages]
> MdePkg/MdePkg.dec
> MdeModulePkg/MdeModulePkg.dec
> + UefiCpuPkg/UefiCpuPkg.dec
>
> [Packages.ARM, Packages.AARCH64]
> ArmPkg/ArmPkg.dec
> @@ -110,6 +111,8 @@ [Pcd.IA32,Pcd.X64]
> gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize ## CONSUMES
>
> [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
> gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index aed1f64b7c93..f53195e6dda5 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -102,6 +102,8 @@ [Pcd]
> gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
> gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
> gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
>
> [FixedPcd]
> gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> index 2d0493f109e8..6b7c38a441d6 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> @@ -201,6 +201,8 @@ EnableExecuteDisableBit (
> @param[in, out] PageEntry2M Pointer to 2M page entry.
> @param[in] StackBase Stack base address.
> @param[in] StackSize Stack size.
> + @param[in] GhcbBase GHCB page area base address.
> + @param[in] GhcbSize GHCB page area size.
>
> **/
> VOID
> @@ -208,7 +210,9 @@ Split2MPageTo4K (
> IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
> IN OUT UINT64 *PageEntry2M,
> IN EFI_PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbSize
> );
>
> /**
> @@ -217,6 +221,8 @@ Split2MPageTo4K (
>
> @param[in] StackBase Stack base address.
> @param[in] StackSize Stack size.
> + @param[in] GhcbBase GHCB page area base address.
> + @param[in] GhcbSize GHCB page area size.
>
> @return The address of 4 level page map.
>
> @@ -224,7 +230,9 @@ Split2MPageTo4K (
> UINTN
> CreateIdentityMappingPageTables (
> IN EFI_PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbkSize
> );
>
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> index 172d7cd1c60c..630a3503f6ba 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> @@ -123,7 +123,7 @@ Create4GPageTablesIa32Pae (
> //
> // Need to split this 2M page that covers stack range.
> //
> - Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
> + Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
> } else {
> //
> // Fill in the Page Directory entries
> @@ -278,7 +278,7 @@ HandOffToDxeCore (
> //
> // Create page table and save PageMapLevel4 to CR3
> //
> - PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);
> + PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
>
> //
> // End of PEI phase signal
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
> index 2867610bff4d..77da20e5c5c5 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
> @@ -35,6 +35,8 @@ HandOffToDxeCore (
> UINT32 Index;
> EFI_VECTOR_HANDOFF_INFO *VectorInfo;
> EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
> + VOID *GhcbBase;
> + UINTN GhcbSize;
>
> if (IsNullDetectionEnabled ()) {
> ClearFirst4KPage (HobList.Raw);
> @@ -77,12 +79,19 @@ HandOffToDxeCore (
> TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
> TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
>
> + //
> + // Get the address and size of the GHCB pages
> + //
> + GhcbBase = (VOID *) PcdGet64 (PcdGhcbBase);
> + GhcbSize = PcdGet64 (PcdGhcbSize);
> +
> PageTables = 0;
> if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
> //
> // Create page table and save PageMapLevel4 to CR3
> //
> - PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE);
> + PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE,
> + (EFI_PHYSICAL_ADDRESS) (UINTN) GhcbBase, GhcbSize);
> } else {
> //
> // Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> index edc38e4525c4..b3c3c3276e6a 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> @@ -180,6 +180,8 @@ EnableExecuteDisableBit (
> @param Size Size of the given physical memory.
> @param StackBase Base address of stack.
> @param StackSize Size of stack.
> + @param GhcbBase Base address of GHCB pages.
> + @param GhcbSize Size of GHCB area.
>
> @retval TRUE Page table should be split.
> @retval FALSE Page table should not be split.
> @@ -189,7 +191,9 @@ ToSplitPageTable (
> IN EFI_PHYSICAL_ADDRESS Address,
> IN UINTN Size,
> IN EFI_PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbSize
> )
> {
> if (IsNullDetectionEnabled () && Address == 0) {
> @@ -208,6 +212,12 @@ ToSplitPageTable (
> }
> }
>
> + if (GhcbBase) {
> + if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
> + return TRUE;
> + }
> + }
> +
> return FALSE;
> }
> /**
> @@ -321,6 +331,8 @@ AllocatePageTableMemory (
> @param[in, out] PageEntry2M Pointer to 2M page entry.
> @param[in] StackBase Stack base address.
> @param[in] StackSize Stack size.
> + @param[in] GhcbBase GHCB page area base address.
> + @param[in] GhcbSize GHCB page area size.
>
> **/
> VOID
> @@ -328,7 +340,9 @@ Split2MPageTo4K (
> IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
> IN OUT UINT64 *PageEntry2M,
> IN EFI_PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbSize
> )
> {
> EFI_PHYSICAL_ADDRESS PhysicalAddress4K;
> @@ -354,7 +368,12 @@ Split2MPageTo4K (
> //
> // Fill in the Page Table entries
> //
> - PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
> + PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
> + if (!GhcbBase
> + || (PhysicalAddress4K < GhcbBase)
> + || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
> + PageTableEntry->Uint64 |= AddressEncMask;
> + }
> PageTableEntry->Bits.ReadWrite = 1;
>
> if ((IsNullDetectionEnabled () && PhysicalAddress4K == 0) ||
> @@ -382,6 +401,8 @@ Split2MPageTo4K (
> @param[in, out] PageEntry1G Pointer to 1G page entry.
> @param[in] StackBase Stack base address.
> @param[in] StackSize Stack size.
> + @param[in] GhcbBase GHCB page area base address.
> + @param[in] GhcbSize GHCB page area size.
>
> **/
> VOID
> @@ -389,7 +410,9 @@ Split1GPageTo2M (
> IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
> IN OUT UINT64 *PageEntry1G,
> IN EFI_PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbSize
> )
> {
> EFI_PHYSICAL_ADDRESS PhysicalAddress2M;
> @@ -412,11 +435,11 @@ Split1GPageTo2M (
>
> PhysicalAddress2M = PhysicalAddress;
> for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
> - if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize)) {
> + if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
> //
> // Need to split this 2M page that covers NULL or stack range.
> //
> - Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
> + Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
> } else {
> //
> // Fill in the Page Directory entries
> @@ -615,6 +638,8 @@ EnablePageTableProtection (
>
> @param[in] StackBase Stack base address.
> @param[in] StackSize Stack size.
> + @param[in] GhcbBase GHCB base address.
> + @param[in] GhcbSize GHCB size.
>
> @return The address of 4 level page map.
>
> @@ -622,7 +647,9 @@ EnablePageTableProtection (
> UINTN
> CreateIdentityMappingPageTables (
> IN EFI_PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbSize
> )
> {
> UINT32 RegEax;
> @@ -734,8 +761,8 @@ CreateIdentityMappingPageTables (
> PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
>
> for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
> - if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
> - Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
> + if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
> + Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
> } else {
> //
> // Fill in the Page Directory entries
> @@ -763,11 +790,11 @@ CreateIdentityMappingPageTables (
> PageDirectoryPointerEntry->Bits.Present = 1;
>
> for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
> - if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
> + if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
> //
> // Need to split this 2M page that covers NULL or stack range.
> //
> - Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
> + Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
> } else {
> //
> // Fill in the Page Directory entries
> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
> index 9c1d68e017fe..1dce01dd7546 100644
> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
> @@ -109,7 +109,6 @@ MemEncryptSevIsEnabled (
> return mSevStatus;
> }
>
> -
> /**
> Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
> Save State Map.
> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
> index 5e110c84ff81..3a4f223f8a86 100644
> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
> @@ -183,6 +183,8 @@ AllocatePageTableMemory (
> @param[in, out] PageEntry2M Pointer to 2M page entry.
> @param[in] StackBase Stack base address.
> @param[in] StackSize Stack size.
> + @param[in] GhcbBase GHCB page area base address.
> + @param[in] GhcbSize GHCB page area size.
>
> **/
> STATIC
> @@ -191,7 +193,9 @@ Split2MPageTo4K (
> IN PHYSICAL_ADDRESS PhysicalAddress,
> IN OUT UINT64 *PageEntry2M,
> IN PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbSize
> )
> {
> PHYSICAL_ADDRESS PhysicalAddress4K;
> @@ -217,7 +221,12 @@ Split2MPageTo4K (
> //
> // Fill in the Page Table entries
> //
> - PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
> + PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
> + if (!GhcbBase
> + || (PhysicalAddress4K < GhcbBase)
> + || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
> + PageTableEntry->Uint64 |= AddressEncMask;
> + }
> PageTableEntry->Bits.ReadWrite = 1;
> PageTableEntry->Bits.Present = 1;
> if ((PhysicalAddress4K >= StackBase) &&
> @@ -417,6 +426,8 @@ EnablePageTableProtection (
> @param[in, out] PageEntry1G Pointer to 1G page entry.
> @param[in] StackBase Stack base address.
> @param[in] StackSize Stack size.
> + @param[in] GhcbBase GHCB page area base address.
> + @param[in] GhcbSize GHCB page area size.
>
> **/
> STATIC
> @@ -425,7 +436,9 @@ Split1GPageTo2M (
> IN PHYSICAL_ADDRESS PhysicalAddress,
> IN OUT UINT64 *PageEntry1G,
> IN PHYSICAL_ADDRESS StackBase,
> - IN UINTN StackSize
> + IN UINTN StackSize,
> + IN PHYSICAL_ADDRESS GhcbBase,
> + IN UINTN GhcbSize
> )
> {
> PHYSICAL_ADDRESS PhysicalAddress2M;
> @@ -450,8 +463,10 @@ Split1GPageTo2M (
> (IndexOfPageDirectoryEntries++,
> PageDirectoryEntry++,
> PhysicalAddress2M += SIZE_2MB)) {
> - if ((PhysicalAddress2M < StackBase + StackSize) &&
> - ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
> + if (((PhysicalAddress2M < StackBase + StackSize) &&
> + ((PhysicalAddress2M + SIZE_2MB) > StackBase)) ||
> + ((PhysicalAddress2M < GhcbBase + GhcbSize) &&
> + ((PhysicalAddress2M + SIZE_2MB) > GhcbBase))) {
> //
> // Need to split this 2M page that covers stack range.
> //
> @@ -459,7 +474,9 @@ Split1GPageTo2M (
> PhysicalAddress2M,
> (UINT64 *)PageDirectoryEntry,
> StackBase,
> - StackSize
> + StackSize,
> + GhcbBase,
> + GhcbSize
> );
> } else {
> //
> @@ -714,6 +731,8 @@ SetMemoryEncDec (
> (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
> (UINT64 *)PageDirectory1GEntry,
> 0,
> + 0,
> + 0,
> 0
> );
> continue;
> @@ -768,6 +787,8 @@ SetMemoryEncDec (
> (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
> (UINT64 *)PageDirectory2MEntry,
> 0,
> + 0,
> + 0,
> 0
> );
> continue;
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 2ae8126ccf8a..84896d4681f9 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -16,9 +16,68 @@
> #include <PiPei.h>
> #include <Register/Amd/Cpuid.h>
> #include <Register/Cpuid.h>
> +#include <Register/Amd/Msr.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
>
> #include "Platform.h"
>
> +/**
> +
> + Initialize SEV-ES support if running an SEV-ES guest.
> +
> + **/
> +STATIC
> +VOID
> +AmdSevEsInitialize (
> + VOID
> + )
> +{
> + VOID *GhcbBase;
> + PHYSICAL_ADDRESS GhcbBasePa;
> + UINTN GhcbPageCount;
> + RETURN_STATUS DecryptStatus, PcdStatus;
> +
> + if (!MemEncryptSevEsIsEnabled ()) {
> + return;
> + }
> +
> + GhcbPageCount = mMaxCpuCount;
> +
> + //
> + // Allocate GHCB pages.
> + //
> + GhcbBase = AllocatePages (GhcbPageCount);
> + ASSERT (GhcbBase);
> +
> + GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
> +
> + DecryptStatus = MemEncryptSevClearPageEncMask (
> + 0,
> + GhcbBasePa,
> + GhcbPageCount,
> + TRUE
> + );
> + ASSERT_RETURN_ERROR (DecryptStatus);
> +
> + BuildMemoryAllocationHob (
> + GhcbBasePa,
> + EFI_PAGES_TO_SIZE (GhcbPageCount),
> + EfiBootServicesData
> + );
> +
> + SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
> +
> + PcdStatus = PcdSet64S (PcdGhcbBase, (UINT64)GhcbBasePa);
> + ASSERT_RETURN_ERROR (PcdStatus);
> + PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
> + ASSERT_RETURN_ERROR (PcdStatus);
> +
> + DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
> +
> + AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
> +}
> +
> /**
>
> Function checks if SEV support is available, if present then it sets
> @@ -89,4 +148,9 @@ AmdSevInitialize (
> EfiBootServicesData // MemoryType
> );
> }
> +
> + //
> + // Check and perform SEV-ES initialization if required.
> + //
> + AmdSevEsInitialize ();
> }
>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
@ 2019-08-21 15:44 ` Laszlo Ersek
0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 15:44 UTC (permalink / raw)
To: devel, thomas.lendacky
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> The SEV support will clear the C-bit from non-RAM areas. The early GDT
> lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
> will be read as un-encrypted even though it is encrypted. This will result
> in a failure to be able to handle the exception.
>
> Move the GDT into RAM so it can be accessed without error when running as
> an SEV-ES guest.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
> OvmfPkg/PlatformPei/AmdSev.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 87ac842a1590..5f4983fd36d8 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -37,6 +37,8 @@ AmdSevEsInitialize (
> PHYSICAL_ADDRESS GhcbBasePa;
> UINTN GhcbPageCount;
> RETURN_STATUS DecryptStatus, PcdStatus;
> + IA32_DESCRIPTOR Gdtr;
> + VOID *Gdt;
>
> if (!MemEncryptSevEsIsEnabled ()) {
> return;
> @@ -76,6 +78,20 @@ AmdSevEsInitialize (
> DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
>
> AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
> +
> + //
> + // The SEV support will clear the C-bit from the non-RAM areas. Since
> + // the GDT initially lives in that area and it will be read when a #VC
> + // exception happens, it needs to be moved to RAM for an SEV-ES guest.
> + //
> + AsmReadGdtr (&Gdtr);
> +
> + Gdt = AllocatePool (Gdtr.Limit + 1);
> + ASSERT (Gdt);
> +
> + CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
> + Gdtr.Base = (UINTN) Gdt;
> + AsmWriteGdtr (&Gdtr);
> }
>
> /**
>
This doesn't look safe enough to me.
AllocatePool() in the PEI phase means the creation of an
EFI_HOB_TYPE_MEMORY_POOL HOB. The data allocated lives inside the HOB.
According to the PI spec v1.7, volume 3, section "4.5.2 HOB Construction
Rules":
3. HOBs may be relocated in system memory by the HOB consumer phase.
HOBs must not contain pointers to other data in the HOB list,
including that in other HOBs. The table must be able to be copied
without requiring internal pointer adjustment.
Additionally, in section "5.9 Memory Pool HOB",
[...] The HOB consumer phase should be able to ignore these HOBs [...]
which seems to imply that the HOB might not survive into DXE at all (the
memory could be released and repurposed).
I don't feel good about pointing the GDTR into such a possibly ephemeral
HOB, even if we reload the GDTR with a different GDT address at a later
time.
Instead, I suggest AllocatePages().
AmdSevEsInitialize() is invoked as part of AmdSevInitialize(), which in
turn is invoked after PublishPeiMemory() returns. Therefore, using
AllocatePages() instead of AllocatePool() should be safe -- the address
produced by AllocatePages() should be stable.
Namely, in PI v1.7, volume 1, section "4.6 PEI Memory Services",
AllocatePages() is specified as:
[...] Allocation made prior to permanent memory will be migrated to
permanent memory [...] After InstallPeiMemory() is called, PEI will
allocate pages within the region of memory provided by
InstallPeiMemory() service [...]
The edk2 code agrees -- PublishPeiMemory() in OVMF's PlatformPei
exercises PeiInstallPeiMemory()
[MdeModulePkg/Core/Pei/Memory/MemoryServices.c], which sets
"SwitchStackSignal". Although actual RAM migration doesn't happen until
after PlatformPei exits, PeiAllocatePages() explicitly looks for
(!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal)
so it will do the right thing. As a result, AllocatePages() *before*
actual RAM migration (from temporary to permanent), but *after*
PeiInstallPeiMemory(), will allocate permanent memory.
Thanks
Laszlo
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
2019-08-21 14:21 ` [edk2-devel] " Laszlo Ersek
@ 2019-08-21 21:25 ` Lendacky, Thomas
2019-08-21 21:51 ` Jordan Justen
1 sibling, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-21 21:25 UTC (permalink / raw)
To: Laszlo Ersek, devel@edk2.groups.io
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 8/21/19 9:21 AM, Laszlo Ersek wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> Currently, the OVMF code relies on the hypervisor to enable the cache
>> support on the processor in order to improve the boot speed. However,
>> with SEV-ES, the hypervisor is not allowed to change the CR0 register
>> to enable caching.
>>
>> Update the OVMF Sec support to enable caching in order to improve the
>> boot speed.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>> OvmfPkg/Sec/SecMain.c | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
>> index 3914355cd17b..2448be0cd408 100644
>> --- a/OvmfPkg/Sec/SecMain.c
>> +++ b/OvmfPkg/Sec/SecMain.c
>> @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
>>
>> ProcessLibraryConstructorList (NULL, NULL);
>>
>> + //
>> + // Enable caching
>> + //
>> + AsmEnableCache ();
>> +
>> DEBUG ((EFI_D_INFO,
>> "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>> (UINT32)(UINTN)BootFv,
>>
>
> This makes me uncomfortable. There used to be problems related to
> caching when VFIO device assignment were used. My concern is admittedly
> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
> "well what could break here", I'd answer "you never know, and the burden
> of proof is not on me". :) Can we make this change conditional on SEV-ES?
>
I'll look into that. Anything is possible, just might have to read an MSR
at this stage.
Thanks,
Tom
> Thanks
> Laszlo
>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase
2019-08-21 14:25 ` [edk2-devel] " Laszlo Ersek
@ 2019-08-21 21:29 ` Lendacky, Thomas
0 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-21 21:29 UTC (permalink / raw)
To: devel@edk2.groups.io, lersek@redhat.com
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 8/21/19 9:25 AM, Laszlo Ersek via Groups.Io wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> A GHCB page is needed during the Sec phase, so this new page must be
>> created. Since the GHCB must be marked as an un-encrypted, or shared,
>> page, an additional pagetable page is required so break down the 2MB
>> region where the GHCB page lives into 4K pagetable entries.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>> OvmfPkg/OvmfPkg.dec | 5 +++
>> OvmfPkg/OvmfPkgX64.fdf | 11 ++++---
>> OvmfPkg/PlatformPei/PlatformPei.inf | 2 ++
>> OvmfPkg/ResetVector/ResetVector.inf | 2 ++
>> UefiCpuPkg/Include/Register/Amd/Fam17Msr.h | 28 ++++++++++++++++
>> OvmfPkg/ResetVector/Ia32/PageTables64.asm | 37 +++++++++++++++++++++-
>> OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
>> 7 files changed, 81 insertions(+), 6 deletions(-)
>
> I've skipped patches 02 and 03 for now, because I'll have to go through
> them with a fine toothed comb -- in a subsequent submission, most
> probably. I'm just trying to provide formal comments, so that I do the
> actual review more easily, later.
>
> As I requested under the blurb, this patch should be split in at least
> three parts, if possible -- OvmfPkg/PlatformPei, OvmfPkg/ResetVector,
> UefiCpuPkg. (The DEC and FDF changes can be kept squashed with the
> OvmfPkg patch that seems more suitable for that.)
Ok.
>
> ... Having said that, why do you add PCDs to the PlatformPei INF file?
> The code in PlatformPei doesn't change. Could be a leftover from an
> earlier (abandoned) approach.
Yeah, most likely. I'll remove that.
Thanks,
Tom
>
> Thanks
> Laszlo
>
>>
>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
>> index 9640360f6245..2ead9a944af4 100644
>> --- a/OvmfPkg/OvmfPkg.dec
>> +++ b/OvmfPkg/OvmfPkg.dec
>> @@ -218,6 +218,11 @@ [PcdsFixedAtBuild]
>> # The value should be a multiple of 4KB.
>> gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
>>
>> + ## Specify the GHCB base address and size.
>> + # The value should be a multiple of 4KB for each.
>> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x32
>> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x33
>> +
>> [PcdsDynamic, PcdsDynamicEx]
>> gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>> index 74407072563b..2a2427092382 100644
>> --- a/OvmfPkg/OvmfPkgX64.fdf
>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>> @@ -67,13 +67,16 @@ [FD.MEMFD]
>> BlockSize = 0x10000
>> NumBlocks = 0xC0
>>
>> -0x000000|0x006000
>> +0x000000|0x007000
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>>
>> -0x006000|0x001000
>> -gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
>> -
>> 0x007000|0x001000
>> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>> +
>> +0x008000|0x001000
>> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
>> +
>> +0x009000|0x001000
>> gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>>
>> 0x010000|0x010000
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index d9fd9c8f05b3..aed1f64b7c93 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -72,6 +72,8 @@ [Pcd]
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
>> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
>> gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
>> index 960b47cd0797..d66f4dc29737 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.inf
>> +++ b/OvmfPkg/ResetVector/ResetVector.inf
>> @@ -37,3 +37,5 @@ [Pcd]
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>> gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
>> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>> diff --git a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
>> index 37b935dcdb30..55a5723e164e 100644
>> --- a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
>> +++ b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
>> @@ -17,6 +17,34 @@
>> #ifndef __FAM17_MSR_H__
>> #define __FAM17_MSR_H__
>>
>> +/**
>> + Secure Encrypted Virtualization - Encrypted State (SEV-ES) GHCB register
>> +
>> +**/
>> +#define MSR_SEV_ES_GHCB 0xc0010130
>> +
>> +/**
>> + MSR information returned for #MSR_SEV_ES_GHCB
>> +**/
>> +typedef union {
>> + struct {
>> + UINT32 GhcbNegotiateBit:1;
>> +
>> + UINT32 Reserved:31;
>> + } Bits;
>> +
>> + struct {
>> + UINT8 Reserved[3];
>> + UINT8 SevEncryptionBitPos;
>> + UINT16 SevEsProtocolMin;
>> + UINT16 SevEsProtocolMax;
>> + } GhcbProtocol;
>> +
>> + VOID *Ghcb;
>> +
>> + UINT64 GhcbPhysicalAddress;
>> +} MSR_SEV_ES_GHCB_REGISTER;
>> +
>> /**
>> Secure Encrypted Virtualization (SEV) status register
>>
>> diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> index c6071fe934de..fd4d5b1d8661 100644
>> --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> @@ -21,6 +21,11 @@ BITS 32
>> %define PAGE_2M_MBO 0x080
>> %define PAGE_2M_PAT 0x01000
>>
>> +%define PAGE_4K_PDE_ATTR (PAGE_ACCESSED + \
>> + PAGE_DIRTY + \
>> + PAGE_READ_WRITE + \
>> + PAGE_PRESENT)
>> +
>> %define PAGE_2M_PDE_ATTR (PAGE_2M_MBO + \
>> PAGE_ACCESSED + \
>> PAGE_DIRTY + \
>> @@ -120,7 +125,7 @@ SevNotActive:
>> ; more permanent location by DxeIpl.
>> ;
>>
>> - mov ecx, 6 * 0x1000 / 4
>> + mov ecx, 7 * 0x1000 / 4
>> xor eax, eax
>> clearPageTablesMemoryLoop:
>> mov dword[ecx * 4 + PT_ADDR (0) - 4], eax
>> @@ -157,6 +162,36 @@ pageTableEntriesLoop:
>> mov [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
>> loop pageTableEntriesLoop
>>
>> + ;
>> + ; The GHCB will live at 0x807000 (just after the page tables)
>> + ; and needs to be un-encrypted. This requires the 2MB page
>> + ; (index 4 in the first 1GB page) for this range be broken down
>> + ; into 512 4KB pages. All will be marked as encrypted, except
>> + ; for the GHCB.
>> + ;
>> + mov ecx, 4
>> + mov eax, PT_ADDR (0x6000) + PAGE_PDP_ATTR
>> + mov [ecx * 8 + PT_ADDR (0x2000)], eax
>> +
>> + mov ecx, 512
>> +pageTableEntries4kLoop:
>> + mov eax, ecx
>> + dec eax
>> + shl eax, 12
>> + add eax, 0x800000
>> + add eax, PAGE_4K_PDE_ATTR
>> + mov [ecx * 8 + PT_ADDR (0x6000 - 8)], eax
>> + mov [(ecx * 8 + PT_ADDR (0x6000 - 8)) + 4], edx
>> + loop pageTableEntries4kLoop
>> +
>> + ;
>> + ; Clear the encryption bit from the GHCB entry (index 7 in the
>> + ; new PTE table - (0x807000 - 0x800000) >> 12).
>> + ;
>> + mov ecx, 7
>> + xor edx, edx
>> + mov [(ecx * 8 + PT_ADDR (0x6000)) + 4], edx
>> +
>> ;
>> ; Set CR3 now that the paging structures are available
>> ;
>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>> index 3b213cd05ab2..56d9b86ed943 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>> @@ -49,7 +49,7 @@
>> %ifdef ARCH_X64
>> #include <AutoGen.h>
>>
>> - %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x6000)
>> + %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x7000)
>> %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
>> %endif
>>
>>
>
>
>
>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
2019-08-21 14:31 ` [edk2-devel] " Laszlo Ersek
@ 2019-08-21 21:42 ` Lendacky, Thomas
2019-08-22 14:12 ` Laszlo Ersek
0 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-21 21:42 UTC (permalink / raw)
To: Laszlo Ersek, devel@edk2.groups.io
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 8/21/19 9:31 AM, Laszlo Ersek wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> Allocate memory for the GHCB pages during SEV initialization for use
>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>> are created without the encryption bit set.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>> UefiCpuPkg/UefiCpuPkg.dec | 4 ++
>> OvmfPkg/OvmfPkgX64.dsc | 4 ++
>> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +
>> OvmfPkg/PlatformPei/PlatformPei.inf | 2 +
>> .../Core/DxeIplPeim/X64/VirtualMemory.h | 12 +++-
>> .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 4 +-
>> .../Core/DxeIplPeim/X64/DxeLoadFunc.c | 11 +++-
>> .../Core/DxeIplPeim/X64/VirtualMemory.c | 49 ++++++++++----
>> .../MemEncryptSevLibInternal.c | 1 -
>> .../BaseMemEncryptSevLib/X64/VirtualMemory.c | 33 ++++++++--
>> OvmfPkg/PlatformPei/AmdSev.c | 64 +++++++++++++++++++
>> 11 files changed, 164 insertions(+), 23 deletions(-)
>
> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
>
> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
> -- if modules under both packages need to consume a new PCD, then the
> PCD should be declared under MdeModulePkg. The rough dependency order is:
>
> - MdePkg (must be self-contained)
> - MdeModulePkg (may consume MdePkg)
> - UefiCpuPkg (may consume everything above, to my knowledge)
> - OvmfPkg (may consume everything above)
>
Ok, thanks for the guidance.
Ideally, I just would like to modify the newly created page tables after
the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
or callback or notification service so that the main changes would be
limited to the OvmfPkg files and would that be acceptable?
Thanks,
Tom
> Thanks
> Laszlo
>
>>
>> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
>> index 6ddf0cd22466..4d5a2593cf13 100644
>> --- a/UefiCpuPkg/UefiCpuPkg.dec
>> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>> @@ -323,5 +323,9 @@ [PcdsDynamic, PcdsDynamicEx]
>> # @ValidRange 0x80000001 | 0 - 1
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme|0x0|UINT8|0x60000015
>>
>> + ## Contains the GHCB page allocation information.<BR><BR>
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
>> +
>> [UserExtensions.TianoCore."ExtraFiles"]
>> UefiCpuPkgExtra.uni
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index dda8dac18441..d6fc7cdf7da8 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -569,6 +569,10 @@ [PcdsDynamicDefault]
>> # Set memory encryption mask
>> gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>>
>> + # Set GHCB base address for SEV-ES
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0
>> +
>> !if $(SMM_REQUIRE) == TRUE
>> gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>> index abc3217b0179..b994398633e3 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>> @@ -52,6 +52,7 @@ [Sources.ARM, Sources.AARCH64]
>> [Packages]
>> MdePkg/MdePkg.dec
>> MdeModulePkg/MdeModulePkg.dec
>> + UefiCpuPkg/UefiCpuPkg.dec
>>
>> [Packages.ARM, Packages.AARCH64]
>> ArmPkg/ArmPkg.dec
>> @@ -110,6 +111,8 @@ [Pcd.IA32,Pcd.X64]
>> gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
>> gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
>> gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize ## CONSUMES
>>
>> [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>> gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index aed1f64b7c93..f53195e6dda5 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -102,6 +102,8 @@ [Pcd]
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
>> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
>>
>> [FixedPcd]
>> gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>> index 2d0493f109e8..6b7c38a441d6 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>> @@ -201,6 +201,8 @@ EnableExecuteDisableBit (
>> @param[in, out] PageEntry2M Pointer to 2M page entry.
>> @param[in] StackBase Stack base address.
>> @param[in] StackSize Stack size.
>> + @param[in] GhcbBase GHCB page area base address.
>> + @param[in] GhcbSize GHCB page area size.
>>
>> **/
>> VOID
>> @@ -208,7 +210,9 @@ Split2MPageTo4K (
>> IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
>> IN OUT UINT64 *PageEntry2M,
>> IN EFI_PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbSize
>> );
>>
>> /**
>> @@ -217,6 +221,8 @@ Split2MPageTo4K (
>>
>> @param[in] StackBase Stack base address.
>> @param[in] StackSize Stack size.
>> + @param[in] GhcbBase GHCB page area base address.
>> + @param[in] GhcbSize GHCB page area size.
>>
>> @return The address of 4 level page map.
>>
>> @@ -224,7 +230,9 @@ Split2MPageTo4K (
>> UINTN
>> CreateIdentityMappingPageTables (
>> IN EFI_PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbkSize
>> );
>>
>>
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>> index 172d7cd1c60c..630a3503f6ba 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>> @@ -123,7 +123,7 @@ Create4GPageTablesIa32Pae (
>> //
>> // Need to split this 2M page that covers stack range.
>> //
>> - Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
>> + Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
>> } else {
>> //
>> // Fill in the Page Directory entries
>> @@ -278,7 +278,7 @@ HandOffToDxeCore (
>> //
>> // Create page table and save PageMapLevel4 to CR3
>> //
>> - PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);
>> + PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
>>
>> //
>> // End of PEI phase signal
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
>> index 2867610bff4d..77da20e5c5c5 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
>> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
>> @@ -35,6 +35,8 @@ HandOffToDxeCore (
>> UINT32 Index;
>> EFI_VECTOR_HANDOFF_INFO *VectorInfo;
>> EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
>> + VOID *GhcbBase;
>> + UINTN GhcbSize;
>>
>> if (IsNullDetectionEnabled ()) {
>> ClearFirst4KPage (HobList.Raw);
>> @@ -77,12 +79,19 @@ HandOffToDxeCore (
>> TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
>> TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
>>
>> + //
>> + // Get the address and size of the GHCB pages
>> + //
>> + GhcbBase = (VOID *) PcdGet64 (PcdGhcbBase);
>> + GhcbSize = PcdGet64 (PcdGhcbSize);
>> +
>> PageTables = 0;
>> if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
>> //
>> // Create page table and save PageMapLevel4 to CR3
>> //
>> - PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE);
>> + PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE,
>> + (EFI_PHYSICAL_ADDRESS) (UINTN) GhcbBase, GhcbSize);
>> } else {
>> //
>> // Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>> index edc38e4525c4..b3c3c3276e6a 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>> @@ -180,6 +180,8 @@ EnableExecuteDisableBit (
>> @param Size Size of the given physical memory.
>> @param StackBase Base address of stack.
>> @param StackSize Size of stack.
>> + @param GhcbBase Base address of GHCB pages.
>> + @param GhcbSize Size of GHCB area.
>>
>> @retval TRUE Page table should be split.
>> @retval FALSE Page table should not be split.
>> @@ -189,7 +191,9 @@ ToSplitPageTable (
>> IN EFI_PHYSICAL_ADDRESS Address,
>> IN UINTN Size,
>> IN EFI_PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbSize
>> )
>> {
>> if (IsNullDetectionEnabled () && Address == 0) {
>> @@ -208,6 +212,12 @@ ToSplitPageTable (
>> }
>> }
>>
>> + if (GhcbBase) {
>> + if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
>> + return TRUE;
>> + }
>> + }
>> +
>> return FALSE;
>> }
>> /**
>> @@ -321,6 +331,8 @@ AllocatePageTableMemory (
>> @param[in, out] PageEntry2M Pointer to 2M page entry.
>> @param[in] StackBase Stack base address.
>> @param[in] StackSize Stack size.
>> + @param[in] GhcbBase GHCB page area base address.
>> + @param[in] GhcbSize GHCB page area size.
>>
>> **/
>> VOID
>> @@ -328,7 +340,9 @@ Split2MPageTo4K (
>> IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
>> IN OUT UINT64 *PageEntry2M,
>> IN EFI_PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbSize
>> )
>> {
>> EFI_PHYSICAL_ADDRESS PhysicalAddress4K;
>> @@ -354,7 +368,12 @@ Split2MPageTo4K (
>> //
>> // Fill in the Page Table entries
>> //
>> - PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
>> + PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
>> + if (!GhcbBase
>> + || (PhysicalAddress4K < GhcbBase)
>> + || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
>> + PageTableEntry->Uint64 |= AddressEncMask;
>> + }
>> PageTableEntry->Bits.ReadWrite = 1;
>>
>> if ((IsNullDetectionEnabled () && PhysicalAddress4K == 0) ||
>> @@ -382,6 +401,8 @@ Split2MPageTo4K (
>> @param[in, out] PageEntry1G Pointer to 1G page entry.
>> @param[in] StackBase Stack base address.
>> @param[in] StackSize Stack size.
>> + @param[in] GhcbBase GHCB page area base address.
>> + @param[in] GhcbSize GHCB page area size.
>>
>> **/
>> VOID
>> @@ -389,7 +410,9 @@ Split1GPageTo2M (
>> IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
>> IN OUT UINT64 *PageEntry1G,
>> IN EFI_PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbSize
>> )
>> {
>> EFI_PHYSICAL_ADDRESS PhysicalAddress2M;
>> @@ -412,11 +435,11 @@ Split1GPageTo2M (
>>
>> PhysicalAddress2M = PhysicalAddress;
>> for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
>> - if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize)) {
>> + if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>> //
>> // Need to split this 2M page that covers NULL or stack range.
>> //
>> - Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
>> + Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>> } else {
>> //
>> // Fill in the Page Directory entries
>> @@ -615,6 +638,8 @@ EnablePageTableProtection (
>>
>> @param[in] StackBase Stack base address.
>> @param[in] StackSize Stack size.
>> + @param[in] GhcbBase GHCB base address.
>> + @param[in] GhcbSize GHCB size.
>>
>> @return The address of 4 level page map.
>>
>> @@ -622,7 +647,9 @@ EnablePageTableProtection (
>> UINTN
>> CreateIdentityMappingPageTables (
>> IN EFI_PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN EFI_PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbSize
>> )
>> {
>> UINT32 RegEax;
>> @@ -734,8 +761,8 @@ CreateIdentityMappingPageTables (
>> PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
>>
>> for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
>> - if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
>> - Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
>> + if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>> + Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>> } else {
>> //
>> // Fill in the Page Directory entries
>> @@ -763,11 +790,11 @@ CreateIdentityMappingPageTables (
>> PageDirectoryPointerEntry->Bits.Present = 1;
>>
>> for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
>> - if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
>> + if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>> //
>> // Need to split this 2M page that covers NULL or stack range.
>> //
>> - Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
>> + Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>> } else {
>> //
>> // Fill in the Page Directory entries
>> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
>> index 9c1d68e017fe..1dce01dd7546 100644
>> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
>> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
>> @@ -109,7 +109,6 @@ MemEncryptSevIsEnabled (
>> return mSevStatus;
>> }
>>
>> -
>> /**
>> Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
>> Save State Map.
>> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
>> index 5e110c84ff81..3a4f223f8a86 100644
>> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
>> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
>> @@ -183,6 +183,8 @@ AllocatePageTableMemory (
>> @param[in, out] PageEntry2M Pointer to 2M page entry.
>> @param[in] StackBase Stack base address.
>> @param[in] StackSize Stack size.
>> + @param[in] GhcbBase GHCB page area base address.
>> + @param[in] GhcbSize GHCB page area size.
>>
>> **/
>> STATIC
>> @@ -191,7 +193,9 @@ Split2MPageTo4K (
>> IN PHYSICAL_ADDRESS PhysicalAddress,
>> IN OUT UINT64 *PageEntry2M,
>> IN PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbSize
>> )
>> {
>> PHYSICAL_ADDRESS PhysicalAddress4K;
>> @@ -217,7 +221,12 @@ Split2MPageTo4K (
>> //
>> // Fill in the Page Table entries
>> //
>> - PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
>> + PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
>> + if (!GhcbBase
>> + || (PhysicalAddress4K < GhcbBase)
>> + || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
>> + PageTableEntry->Uint64 |= AddressEncMask;
>> + }
>> PageTableEntry->Bits.ReadWrite = 1;
>> PageTableEntry->Bits.Present = 1;
>> if ((PhysicalAddress4K >= StackBase) &&
>> @@ -417,6 +426,8 @@ EnablePageTableProtection (
>> @param[in, out] PageEntry1G Pointer to 1G page entry.
>> @param[in] StackBase Stack base address.
>> @param[in] StackSize Stack size.
>> + @param[in] GhcbBase GHCB page area base address.
>> + @param[in] GhcbSize GHCB page area size.
>>
>> **/
>> STATIC
>> @@ -425,7 +436,9 @@ Split1GPageTo2M (
>> IN PHYSICAL_ADDRESS PhysicalAddress,
>> IN OUT UINT64 *PageEntry1G,
>> IN PHYSICAL_ADDRESS StackBase,
>> - IN UINTN StackSize
>> + IN UINTN StackSize,
>> + IN PHYSICAL_ADDRESS GhcbBase,
>> + IN UINTN GhcbSize
>> )
>> {
>> PHYSICAL_ADDRESS PhysicalAddress2M;
>> @@ -450,8 +463,10 @@ Split1GPageTo2M (
>> (IndexOfPageDirectoryEntries++,
>> PageDirectoryEntry++,
>> PhysicalAddress2M += SIZE_2MB)) {
>> - if ((PhysicalAddress2M < StackBase + StackSize) &&
>> - ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
>> + if (((PhysicalAddress2M < StackBase + StackSize) &&
>> + ((PhysicalAddress2M + SIZE_2MB) > StackBase)) ||
>> + ((PhysicalAddress2M < GhcbBase + GhcbSize) &&
>> + ((PhysicalAddress2M + SIZE_2MB) > GhcbBase))) {
>> //
>> // Need to split this 2M page that covers stack range.
>> //
>> @@ -459,7 +474,9 @@ Split1GPageTo2M (
>> PhysicalAddress2M,
>> (UINT64 *)PageDirectoryEntry,
>> StackBase,
>> - StackSize
>> + StackSize,
>> + GhcbBase,
>> + GhcbSize
>> );
>> } else {
>> //
>> @@ -714,6 +731,8 @@ SetMemoryEncDec (
>> (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
>> (UINT64 *)PageDirectory1GEntry,
>> 0,
>> + 0,
>> + 0,
>> 0
>> );
>> continue;
>> @@ -768,6 +787,8 @@ SetMemoryEncDec (
>> (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
>> (UINT64 *)PageDirectory2MEntry,
>> 0,
>> + 0,
>> + 0,
>> 0
>> );
>> continue;
>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>> index 2ae8126ccf8a..84896d4681f9 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -16,9 +16,68 @@
>> #include <PiPei.h>
>> #include <Register/Amd/Cpuid.h>
>> #include <Register/Cpuid.h>
>> +#include <Register/Amd/Msr.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>>
>> #include "Platform.h"
>>
>> +/**
>> +
>> + Initialize SEV-ES support if running an SEV-ES guest.
>> +
>> + **/
>> +STATIC
>> +VOID
>> +AmdSevEsInitialize (
>> + VOID
>> + )
>> +{
>> + VOID *GhcbBase;
>> + PHYSICAL_ADDRESS GhcbBasePa;
>> + UINTN GhcbPageCount;
>> + RETURN_STATUS DecryptStatus, PcdStatus;
>> +
>> + if (!MemEncryptSevEsIsEnabled ()) {
>> + return;
>> + }
>> +
>> + GhcbPageCount = mMaxCpuCount;
>> +
>> + //
>> + // Allocate GHCB pages.
>> + //
>> + GhcbBase = AllocatePages (GhcbPageCount);
>> + ASSERT (GhcbBase);
>> +
>> + GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
>> +
>> + DecryptStatus = MemEncryptSevClearPageEncMask (
>> + 0,
>> + GhcbBasePa,
>> + GhcbPageCount,
>> + TRUE
>> + );
>> + ASSERT_RETURN_ERROR (DecryptStatus);
>> +
>> + BuildMemoryAllocationHob (
>> + GhcbBasePa,
>> + EFI_PAGES_TO_SIZE (GhcbPageCount),
>> + EfiBootServicesData
>> + );
>> +
>> + SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
>> +
>> + PcdStatus = PcdSet64S (PcdGhcbBase, (UINT64)GhcbBasePa);
>> + ASSERT_RETURN_ERROR (PcdStatus);
>> + PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
>> + ASSERT_RETURN_ERROR (PcdStatus);
>> +
>> + DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
>> +
>> + AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
>> +}
>> +
>> /**
>>
>> Function checks if SEV support is available, if present then it sets
>> @@ -89,4 +148,9 @@ AmdSevInitialize (
>> EfiBootServicesData // MemoryType
>> );
>> }
>> +
>> + //
>> + // Check and perform SEV-ES initialization if required.
>> + //
>> + AmdSevEsInitialize ();
>> }
>>
>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
2019-08-21 14:21 ` [edk2-devel] " Laszlo Ersek
2019-08-21 21:25 ` Lendacky, Thomas
@ 2019-08-21 21:51 ` Jordan Justen
2019-08-22 13:46 ` Laszlo Ersek
1 sibling, 1 reply; 46+ messages in thread
From: Jordan Justen @ 2019-08-21 21:51 UTC (permalink / raw)
To: Laszlo Ersek, devel, thomas.lendacky
Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
Singh, Brijesh, Fang, Peter, D Scott Phillips
On 2019-08-21 07:21:25, Laszlo Ersek wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
> > From: Tom Lendacky <thomas.lendacky@amd.com>
> >
> > Currently, the OVMF code relies on the hypervisor to enable the cache
> > support on the processor in order to improve the boot speed. However,
> > with SEV-ES, the hypervisor is not allowed to change the CR0 register
> > to enable caching.
> >
> > Update the OVMF Sec support to enable caching in order to improve the
> > boot speed.
> >
> > Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> > ---
> > OvmfPkg/Sec/SecMain.c | 5 +++++
> > 1 file changed, 5 insertions(+)
> >
> > diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> > index 3914355cd17b..2448be0cd408 100644
> > --- a/OvmfPkg/Sec/SecMain.c
> > +++ b/OvmfPkg/Sec/SecMain.c
> > @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
> >
> > ProcessLibraryConstructorList (NULL, NULL);
> >
> > + //
> > + // Enable caching
> > + //
> > + AsmEnableCache ();
> > +
> > DEBUG ((EFI_D_INFO,
> > "SecCoreStartupWithStack(0x%x, 0x%x)\n",
> > (UINT32)(UINTN)BootFv,
> >
>
> This makes me uncomfortable. There used to be problems related to
> caching when VFIO device assignment were used. My concern is admittedly
> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
> "well what could break here", I'd answer "you never know, and the burden
> of proof is not on me". :) Can we make this change conditional on SEV-ES?
This was also raised as an issue by Peter for the ACRN hypervisor and
Scott for the bhyve hypervisor.
I think it is rare for a platform to enable cache at this early of a
stage, but it is also rare to decompress a firmware volume at this
point.
It appears that it could be helpful to figure out how to safely enable
cache by default here, since it does seem to be impacting several
hypervisors.
-Jordan
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
2019-08-21 21:51 ` Jordan Justen
@ 2019-08-22 13:46 ` Laszlo Ersek
2019-08-22 20:44 ` Jordan Justen
0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-22 13:46 UTC (permalink / raw)
To: Jordan Justen, devel, thomas.lendacky
Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
Singh, Brijesh, Fang, Peter, D Scott Phillips
On 08/21/19 23:51, Jordan Justen wrote:
> On 2019-08-21 07:21:25, Laszlo Ersek wrote:
>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> Currently, the OVMF code relies on the hypervisor to enable the cache
>>> support on the processor in order to improve the boot speed. However,
>>> with SEV-ES, the hypervisor is not allowed to change the CR0 register
>>> to enable caching.
>>>
>>> Update the OVMF Sec support to enable caching in order to improve the
>>> boot speed.
>>>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>> OvmfPkg/Sec/SecMain.c | 5 +++++
>>> 1 file changed, 5 insertions(+)
>>>
>>> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
>>> index 3914355cd17b..2448be0cd408 100644
>>> --- a/OvmfPkg/Sec/SecMain.c
>>> +++ b/OvmfPkg/Sec/SecMain.c
>>> @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
>>>
>>> ProcessLibraryConstructorList (NULL, NULL);
>>>
>>> + //
>>> + // Enable caching
>>> + //
>>> + AsmEnableCache ();
>>> +
>>> DEBUG ((EFI_D_INFO,
>>> "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>>> (UINT32)(UINTN)BootFv,
>>>
>>
>> This makes me uncomfortable. There used to be problems related to
>> caching when VFIO device assignment were used. My concern is admittedly
>> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
>> "well what could break here", I'd answer "you never know, and the burden
>> of proof is not on me". :) Can we make this change conditional on SEV-ES?
>
> This was also raised as an issue by Peter for the ACRN hypervisor and
> Scott for the bhyve hypervisor.
>
> I think it is rare for a platform to enable cache at this early of a
> stage, but it is also rare to decompress a firmware volume at this
> point.
>
> It appears that it could be helpful to figure out how to safely enable
> cache by default here, since it does seem to be impacting several
> hypervisors.
I can't think of anything better than "trial and error". The issues that
used to pop up in the past, due to host kernel (KVM) changes,
particularly in connection with VFIO device assignment, have been
completely obscure and unpenetrable to me. Even though I've contributed
at least one KVM patch to mitigate those problems, they remain a mistery
to me, and I remain unable to *reason* about the problems or the fixes.
So I think we could only flip the behavior (enable cache by default) and
collect bug reports. But that's extremely annoying for end-users, and I
see "no regressions" as one of my top responsibilities.
Even if we provided an fw_cfg knob to disable the change, using
QemuFwCfgSecLib, similarly to commit ab081a50e565 ("OvmfPkg:
PlatformPei: take no-exec DXE settings from the QEMU command line",
2015-09-15), such fw_cfg knobs are difficult to use through layered
products, such as libvirt, proxmox, etc. And of course fw_cfg is only
available on QEMU.
Laszlo
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
2019-08-21 21:42 ` Lendacky, Thomas
@ 2019-08-22 14:12 ` Laszlo Ersek
2019-08-22 15:24 ` Lendacky, Thomas
0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-22 14:12 UTC (permalink / raw)
To: Lendacky, Thomas, devel@edk2.groups.io
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 08/21/19 23:42, Lendacky, Thomas wrote:
> On 8/21/19 9:31 AM, Laszlo Ersek wrote:
>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> Allocate memory for the GHCB pages during SEV initialization for use
>>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>>> are created without the encryption bit set.
>>>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>> UefiCpuPkg/UefiCpuPkg.dec | 4 ++
>>> OvmfPkg/OvmfPkgX64.dsc | 4 ++
>>> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +
>>> OvmfPkg/PlatformPei/PlatformPei.inf | 2 +
>>> .../Core/DxeIplPeim/X64/VirtualMemory.h | 12 +++-
>>> .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 4 +-
>>> .../Core/DxeIplPeim/X64/DxeLoadFunc.c | 11 +++-
>>> .../Core/DxeIplPeim/X64/VirtualMemory.c | 49 ++++++++++----
>>> .../MemEncryptSevLibInternal.c | 1 -
>>> .../BaseMemEncryptSevLib/X64/VirtualMemory.c | 33 ++++++++--
>>> OvmfPkg/PlatformPei/AmdSev.c | 64 +++++++++++++++++++
>>> 11 files changed, 164 insertions(+), 23 deletions(-)
>>
>> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
>> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
>>
>> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
>> -- if modules under both packages need to consume a new PCD, then the
>> PCD should be declared under MdeModulePkg. The rough dependency order is:
>>
>> - MdePkg (must be self-contained)
>> - MdeModulePkg (may consume MdePkg)
>> - UefiCpuPkg (may consume everything above, to my knowledge)
>> - OvmfPkg (may consume everything above)
>>
>
> Ok, thanks for the guidance.
>
> Ideally, I just would like to modify the newly created page tables after
> the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
> DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
> or callback or notification service so that the main changes would be
> limited to the OvmfPkg files and would that be acceptable?
* https://bugzilla.tianocore.org/show_bug.cgi?id=623
Reported on 2017-07-07, resolved as WONTFIX on 2019-07-30 ("no
resources").
And it's not like patches had not been proposed -- Leo had implemented
a notification service --; they were rejected.
* https://bugzilla.tianocore.org/show_bug.cgi?id=847
Reported on 2018-01-11, marked "not high priority" as of 2019-07-23
<https://www.mail-archive.com/devel@edk2.groups.io/msg05507.html>.
I don't know what to tell you. While nobody seems to disagree with the
necessity of such a service and/or library, core maintainers have
rejected all the code proposals thus far (= "don't do that"). And I'm
unaware of any constructive guidance (= "do this instead").
I suggest filing a Feature Request BZ for SEV-ES enablement (for
OvmfPkg), and referencing that as "dependent bug" in both of the
above-mentioned BZs. It might also help to dial in to the APAC/NAMO
design / bug triage meeting, and campaign for the feature there.
https://github.com/tianocore/tianocore.github.io/wiki/Bug-Triage
I have a bad track record at convincing core maintainers to do what they
don't want to do. And I see escalating such problems from email to phone
as a work-around, sort of "wear down your opponent by sheer
persistence". So I avoid that. But, I've seen the approach work for
others, so you might have better luck.
(The APAC/NAMO call is also at a bad time for me, in UTC+1 / UTC+2.)
I think the present RFC patches are a good way to re-raise these topics.
Laszlo
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
2019-08-22 14:12 ` Laszlo Ersek
@ 2019-08-22 15:24 ` Lendacky, Thomas
2019-08-23 13:26 ` Laszlo Ersek
0 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-22 15:24 UTC (permalink / raw)
To: Laszlo Ersek, devel@edk2.groups.io
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 8/22/19 9:12 AM, Laszlo Ersek wrote:
> On 08/21/19 23:42, Lendacky, Thomas wrote:
>> On 8/21/19 9:31 AM, Laszlo Ersek wrote:
>>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>
>>>> Allocate memory for the GHCB pages during SEV initialization for use
>>>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>>>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>>>> are created without the encryption bit set.
>>>>
>>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>>> ---
>>>> UefiCpuPkg/UefiCpuPkg.dec | 4 ++
>>>> OvmfPkg/OvmfPkgX64.dsc | 4 ++
>>>> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +
>>>> OvmfPkg/PlatformPei/PlatformPei.inf | 2 +
>>>> .../Core/DxeIplPeim/X64/VirtualMemory.h | 12 +++-
>>>> .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 4 +-
>>>> .../Core/DxeIplPeim/X64/DxeLoadFunc.c | 11 +++-
>>>> .../Core/DxeIplPeim/X64/VirtualMemory.c | 49 ++++++++++----
>>>> .../MemEncryptSevLibInternal.c | 1 -
>>>> .../BaseMemEncryptSevLib/X64/VirtualMemory.c | 33 ++++++++--
>>>> OvmfPkg/PlatformPei/AmdSev.c | 64 +++++++++++++++++++
>>>> 11 files changed, 164 insertions(+), 23 deletions(-)
>>>
>>> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
>>> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
>>>
>>> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
>>> -- if modules under both packages need to consume a new PCD, then the
>>> PCD should be declared under MdeModulePkg. The rough dependency order is:
>>>
>>> - MdePkg (must be self-contained)
>>> - MdeModulePkg (may consume MdePkg)
>>> - UefiCpuPkg (may consume everything above, to my knowledge)
>>> - OvmfPkg (may consume everything above)
>>>
>>
>> Ok, thanks for the guidance.
>>
>> Ideally, I just would like to modify the newly created page tables after
>> the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
>> DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
>> or callback or notification service so that the main changes would be
>> limited to the OvmfPkg files and would that be acceptable?
>
> * https://bugzilla.tianocore.org/show_bug.cgi?id=623
>
> Reported on 2017-07-07, resolved as WONTFIX on 2019-07-30 ("no
> resources").
>
> And it's not like patches had not been proposed -- Leo had implemented
> a notification service --; they were rejected.
>
> * https://bugzilla.tianocore.org/show_bug.cgi?id=847
>
> Reported on 2018-01-11, marked "not high priority" as of 2019-07-23
> <https://www.mail-archive.com/devel@edk2.groups.io/msg05507.html>.
>
> I don't know what to tell you. While nobody seems to disagree with the
> necessity of such a service and/or library, core maintainers have
> rejected all the code proposals thus far (= "don't do that"). And I'm
> unaware of any constructive guidance (= "do this instead").
This isn't on the level of a "notify every time something changes" type
of thing. This is more of a "hey, we built some new pagetables and are
about to make them active, but before we do have a look and change what
you think should be changed."
With that, I'd be able to remove the GhcbBase and GhcbSize that is
propogated on the ToSplit and Split functions.
I'll take a look and see what it would look like and go from there.
>
> I suggest filing a Feature Request BZ for SEV-ES enablement (for
> OvmfPkg), and referencing that as "dependent bug" in both of the
> above-mentioned BZs. It might also help to dial in to the APAC/NAMO
> design / bug triage meeting, and campaign for the feature there.
Yes, I need to file that Feature Request BZ anyway.
Thanks,
Tom
>
> https://github.com/tianocore/tianocore.github.io/wiki/Bug-Triage
>
> I have a bad track record at convincing core maintainers to do what they
> don't want to do. And I see escalating such problems from email to phone
> as a work-around, sort of "wear down your opponent by sheer
> persistence". So I avoid that. But, I've seen the approach work for
> others, so you might have better luck.
>
> (The APAC/NAMO call is also at a bad time for me, in UTC+1 / UTC+2.)
>
> I think the present RFC patches are a good way to re-raise these topics.
>
> Laszlo
>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
2019-08-22 13:46 ` Laszlo Ersek
@ 2019-08-22 20:44 ` Jordan Justen
2019-08-23 13:32 ` Laszlo Ersek
0 siblings, 1 reply; 46+ messages in thread
From: Jordan Justen @ 2019-08-22 20:44 UTC (permalink / raw)
To: Laszlo Ersek, devel, thomas.lendacky
Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
Singh, Brijesh, Fang, Peter, D Scott Phillips
On 2019-08-22 06:46:07, Laszlo Ersek wrote:
> On 08/21/19 23:51, Jordan Justen wrote:
> > On 2019-08-21 07:21:25, Laszlo Ersek wrote:
> >> On 08/19/19 23:35, Lendacky, Thomas wrote:
> >>> From: Tom Lendacky <thomas.lendacky@amd.com>
> >>>
> >>> + //
> >>> + // Enable caching
> >>> + //
> >>> + AsmEnableCache ();
> >>> +
> >>> DEBUG ((EFI_D_INFO,
> >>> "SecCoreStartupWithStack(0x%x, 0x%x)\n",
> >>> (UINT32)(UINTN)BootFv,
> >>>
> >>
> >> This makes me uncomfortable. There used to be problems related to
> >> caching when VFIO device assignment were used. My concern is admittedly
> >> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
> >> "well what could break here", I'd answer "you never know, and the burden
> >> of proof is not on me". :) Can we make this change conditional on SEV-ES?
> >
> > This was also raised as an issue by Peter for the ACRN hypervisor and
> > Scott for the bhyve hypervisor.
> >
> > I think it is rare for a platform to enable cache at this early of a
> > stage, but it is also rare to decompress a firmware volume at this
> > point.
> >
> > It appears that it could be helpful to figure out how to safely enable
> > cache by default here, since it does seem to be impacting several
> > hypervisors.
>
> I can't think of anything better than "trial and error".
Maybe we could try to detect kvm, and enable caching if !kvm.
Maybe we could enable it during the decompress of the PEI FV and
disable it afterward?
> The issues that
> used to pop up in the past, due to host kernel (KVM) changes,
> particularly in connection with VFIO device assignment, have been
> completely obscure and unpenetrable to me.
Don't we eventually enable caching during the boot, so how is VFIO not
affected by that?
> Even though I've contributed
> at least one KVM patch to mitigate those problems, they remain a mistery
> to me, and I remain unable to *reason* about the problems or the fixes.
If VFIO requires uncached access, then what mechanisms does kvm
support for accessing memory ranges uncached? I thought kvm simply
ignored the cache setting and always enabled caching, because this
section of boot is not particularly slow with kvm. But, if enabling
caching causes issues, then I guess it does something.
Does kvm support mtrr to uncache i/o ranges? I didn't think kvm
supported mtrrs in the past.
I hope we wouldn't have to use paging to disable caching for the
affected regions.
-Jordan
> So I think we could only flip the behavior (enable cache by default) and
> collect bug reports. But that's extremely annoying for end-users, and I
> see "no regressions" as one of my top responsibilities.
>
> Even if we provided an fw_cfg knob to disable the change, using
> QemuFwCfgSecLib, similarly to commit ab081a50e565 ("OvmfPkg:
> PlatformPei: take no-exec DXE settings from the QEMU command line",
> 2015-09-15), such fw_cfg knobs are difficult to use through layered
> products, such as libvirt, proxmox, etc. And of course fw_cfg is only
> available on QEMU.
>
> Laszlo
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
2019-08-22 15:24 ` Lendacky, Thomas
@ 2019-08-23 13:26 ` Laszlo Ersek
0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-23 13:26 UTC (permalink / raw)
To: Lendacky, Thomas, devel@edk2.groups.io
Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
Eric Dong, Ray Ni, Singh, Brijesh
On 08/22/19 17:24, Lendacky, Thomas wrote:
> On 8/22/19 9:12 AM, Laszlo Ersek wrote:
>> On 08/21/19 23:42, Lendacky, Thomas wrote:
>>> On 8/21/19 9:31 AM, Laszlo Ersek wrote:
>>>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>>
>>>>> Allocate memory for the GHCB pages during SEV initialization for use
>>>>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>>>>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>>>>> are created without the encryption bit set.
>>>>>
>>>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>>>> ---
>>>>> UefiCpuPkg/UefiCpuPkg.dec | 4 ++
>>>>> OvmfPkg/OvmfPkgX64.dsc | 4 ++
>>>>> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 3 +
>>>>> OvmfPkg/PlatformPei/PlatformPei.inf | 2 +
>>>>> .../Core/DxeIplPeim/X64/VirtualMemory.h | 12 +++-
>>>>> .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 4 +-
>>>>> .../Core/DxeIplPeim/X64/DxeLoadFunc.c | 11 +++-
>>>>> .../Core/DxeIplPeim/X64/VirtualMemory.c | 49 ++++++++++----
>>>>> .../MemEncryptSevLibInternal.c | 1 -
>>>>> .../BaseMemEncryptSevLib/X64/VirtualMemory.c | 33 ++++++++--
>>>>> OvmfPkg/PlatformPei/AmdSev.c | 64 +++++++++++++++++++
>>>>> 11 files changed, 164 insertions(+), 23 deletions(-)
>>>>
>>>> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
>>>> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
>>>>
>>>> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
>>>> -- if modules under both packages need to consume a new PCD, then the
>>>> PCD should be declared under MdeModulePkg. The rough dependency order is:
>>>>
>>>> - MdePkg (must be self-contained)
>>>> - MdeModulePkg (may consume MdePkg)
>>>> - UefiCpuPkg (may consume everything above, to my knowledge)
>>>> - OvmfPkg (may consume everything above)
>>>>
>>>
>>> Ok, thanks for the guidance.
>>>
>>> Ideally, I just would like to modify the newly created page tables after
>>> the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
>>> DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
>>> or callback or notification service so that the main changes would be
>>> limited to the OvmfPkg files and would that be acceptable?
>>
>> * https://bugzilla.tianocore.org/show_bug.cgi?id=623
>>
>> Reported on 2017-07-07, resolved as WONTFIX on 2019-07-30 ("no
>> resources").
>>
>> And it's not like patches had not been proposed -- Leo had implemented
>> a notification service --; they were rejected.
>>
>> * https://bugzilla.tianocore.org/show_bug.cgi?id=847
>>
>> Reported on 2018-01-11, marked "not high priority" as of 2019-07-23
>> <https://www.mail-archive.com/devel@edk2.groups.io/msg05507.html>.
>>
>> I don't know what to tell you. While nobody seems to disagree with the
>> necessity of such a service and/or library, core maintainers have
>> rejected all the code proposals thus far (= "don't do that"). And I'm
>> unaware of any constructive guidance (= "do this instead").
>
> This isn't on the level of a "notify every time something changes" type
> of thing. This is more of a "hey, we built some new pagetables and are
> about to make them active, but before we do have a look and change what
> you think should be changed."
>
> With that, I'd be able to remove the GhcbBase and GhcbSize that is
> propogated on the ToSplit and Split functions.
>
> I'll take a look and see what it would look like and go from there.
Maybe not the same kind of notification pattern (and the event
triggering the notification could be different), but the point is the
same -- the platform would like the core to call it back at various
stages / points of page table manipulation. How we implement that, is
"details" (edk2-specific (and versioned) protocol, provided by the
platform and called by the core; versus separate event groups, signaled
by the core; versus custom lib class, implemented by the platform;
versus custom status codes reported by the core; etc). What's important
is for core maintainers to finally accept that the facility *as such* is
needed.
>
>>
>> I suggest filing a Feature Request BZ for SEV-ES enablement (for
>> OvmfPkg), and referencing that as "dependent bug" in both of the
>> above-mentioned BZs. It might also help to dial in to the APAC/NAMO
>> design / bug triage meeting, and campaign for the feature there.
>
> Yes, I need to file that Feature Request BZ anyway.
Thanks.
Laszlo
>>
>> https://github.com/tianocore/tianocore.github.io/wiki/Bug-Triage
>>
>> I have a bad track record at convincing core maintainers to do what they
>> don't want to do. And I see escalating such problems from email to phone
>> as a work-around, sort of "wear down your opponent by sheer
>> persistence". So I avoid that. But, I've seen the approach work for
>> others, so you might have better luck.
>>
>> (The APAC/NAMO call is also at a bad time for me, in UTC+1 / UTC+2.)
>>
>> I think the present RFC patches are a good way to re-raise these topics.
>>
>> Laszlo
>>
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
2019-08-22 20:44 ` Jordan Justen
@ 2019-08-23 13:32 ` Laszlo Ersek
0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-23 13:32 UTC (permalink / raw)
To: Jordan Justen, devel, thomas.lendacky
Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
Singh, Brijesh, Fang, Peter, D Scott Phillips
On 08/22/19 22:44, Jordan Justen wrote:
> On 2019-08-22 06:46:07, Laszlo Ersek wrote:
>> On 08/21/19 23:51, Jordan Justen wrote:
>>> On 2019-08-21 07:21:25, Laszlo Ersek wrote:
>>>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>>
>>>>> + //
>>>>> + // Enable caching
>>>>> + //
>>>>> + AsmEnableCache ();
>>>>> +
>>>>> DEBUG ((EFI_D_INFO,
>>>>> "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>>>>> (UINT32)(UINTN)BootFv,
>>>>>
>>>>
>>>> This makes me uncomfortable. There used to be problems related to
>>>> caching when VFIO device assignment were used. My concern is admittedly
>>>> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
>>>> "well what could break here", I'd answer "you never know, and the burden
>>>> of proof is not on me". :) Can we make this change conditional on SEV-ES?
>>>
>>> This was also raised as an issue by Peter for the ACRN hypervisor and
>>> Scott for the bhyve hypervisor.
>>>
>>> I think it is rare for a platform to enable cache at this early of a
>>> stage, but it is also rare to decompress a firmware volume at this
>>> point.
>>>
>>> It appears that it could be helpful to figure out how to safely enable
>>> cache by default here, since it does seem to be impacting several
>>> hypervisors.
>>
>> I can't think of anything better than "trial and error".
>
> Maybe we could try to detect kvm, and enable caching if !kvm.
>
> Maybe we could enable it during the decompress of the PEI FV and
> disable it afterward?
>
>> The issues that
>> used to pop up in the past, due to host kernel (KVM) changes,
>> particularly in connection with VFIO device assignment, have been
>> completely obscure and unpenetrable to me.
>
> Don't we eventually enable caching during the boot, so how is VFIO not
> affected by that?
>
>> Even though I've contributed
>> at least one KVM patch to mitigate those problems, they remain a mistery
>> to me, and I remain unable to *reason* about the problems or the fixes.
>
> If VFIO requires uncached access, then what mechanisms does kvm
> support for accessing memory ranges uncached? I thought kvm simply
> ignored the cache setting and always enabled caching, because this
> section of boot is not particularly slow with kvm. But, if enabling
> caching causes issues, then I guess it does something.
>
> Does kvm support mtrr to uncache i/o ranges? I didn't think kvm
> supported mtrrs in the past.
>
> I hope we wouldn't have to use paging to disable caching for the
> affected regions.
All good questions, and I'm not equipped to answer them, unfortunately.
I'm happy to review and regression-test -- including GPU assignment, on
my workstation that's dedicated to that use case -- OvmfPkg patches, if
someone posts them.
This stuff is in constant flux in KVM. Recent example:
https://www.redhat.com/archives/vfio-users/2019-August/msg00016.html
Thanks
Laszlo
>> So I think we could only flip the behavior (enable cache by default) and
>> collect bug reports. But that's extremely annoying for end-users, and I
>> see "no regressions" as one of my top responsibilities.
>>
>> Even if we provided an fw_cfg knob to disable the change, using
>> QemuFwCfgSecLib, similarly to commit ab081a50e565 ("OvmfPkg:
>> PlatformPei: take no-exec DXE settings from the QEMU command line",
>> 2015-09-15), such fw_cfg knobs are difficult to use through layered
>> products, such as libvirt, proxmox, etc. And of course fw_cfg is only
>> available on QEMU.
>>
>> Laszlo
^ permalink raw reply [flat|nested] 46+ messages in thread
end of thread, other threads:[~2019-08-23 13:32 UTC | newest]
Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
2019-08-21 14:21 ` [edk2-devel] " Laszlo Ersek
2019-08-21 21:25 ` Lendacky, Thomas
2019-08-21 21:51 ` Jordan Justen
2019-08-22 13:46 ` Laszlo Ersek
2019-08-22 20:44 ` Jordan Justen
2019-08-23 13:32 ` Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
2019-08-21 14:25 ` [edk2-devel] " Laszlo Ersek
2019-08-21 21:29 ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
2019-08-21 14:31 ` [edk2-devel] " Laszlo Ersek
2019-08-21 21:42 ` Lendacky, Thomas
2019-08-22 14:12 ` Laszlo Ersek
2019-08-22 15:24 ` Lendacky, Thomas
2019-08-23 13:26 ` Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
2019-08-21 15:44 ` [edk2-devel] " Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
2019-08-19 21:47 ` Ni, Ray
2019-08-19 22:25 ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES Lendacky, Thomas
2019-08-21 14:17 ` [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support Laszlo Ersek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox