[RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
Lendacky, Thomas
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
|
|
[RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
Lendacky, Thomas
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
|
|
[RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage
#vc
Lendacky, Thomas
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
|
|
[RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
Lendacky, Thomas
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
|
|
[RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
Lendacky, Thomas
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
|
|
Re: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
Lendacky, Thomas
Hi Ray,
On 8/19/19 4:47 PM, Ni, Ray wrote: Tom,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
|
|
[RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES
Lendacky, Thomas
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
|
|
[RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES
Lendacky, Thomas
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
|
|
[RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
Lendacky, Thomas
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
|
|
[RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
Lendacky, Thomas
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
|
|
[RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active
Lendacky, Thomas
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
|
|
[RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases
#vc
Lendacky, Thomas
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
|
|
[RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE events
Lendacky, Thomas
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
|
|
[RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE events
Lendacky, Thomas
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
|
|
[RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
Lendacky, Thomas
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
|
|
Re: [PATCH v2 03/11] ShellPkg: acpiview: FADT: Validate global pointer before use
Sami Mujawar
Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
toggle quoted messageShow quoted text
Regards, Sami Mujawar
-----Original Message-----
From: Krzysztof Koch <krzysztof.koch@arm.com> Sent: 19 August 2019 09:25 AM To: devel@edk2.groups.io Cc: jaben.carsey@intel.com; ray.ni@intel.com; zhichao.gao@intel.com; Sami Mujawar <Sami.Mujawar@arm.com>; Matteo Carlini <Matteo.Carlini@arm.com>; nd <nd@arm.com> Subject: [PATCH v2 03/11] ShellPkg: acpiview: FADT: Validate global pointer before use Check if global pointers have been successfully updated before they are used for further table parsing. Signed-off-by: Krzysztof Koch <krzysztof.koch@arm.com> --- Changes can be seen at: https://github.com/KrzysztofKoch1/edk2/tree/612_add_pointer_validation_v2 Notes: v1: - Test against NULL pointers [Krzysztof] v2: - Do not require FadtMinorRevision and X_DsdtAddress pointers to be valid in order to process the remaining ACPI tables [Zhichao] ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c index e40c9ef8ee4b3285faf8c6edf3cb6236ee367397..6859c4824c2866fd3eb9a789a8dfc950724b27ca 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtPars +++ er.c @@ -204,9 +204,11 @@ ParseAcpiFadt ( ); if (Trace) { - Print (L"\nSummary:\n"); - PrintFieldName (2, L"FADT Version"); - Print (L"%d.%d\n", *AcpiHdrInfo.Revision, *FadtMinorRevision); + if (FadtMinorRevision != NULL) { + Print (L"\nSummary:\n"); + PrintFieldName (2, L"FADT Version"); + Print (L"%d.%d\n", *AcpiHdrInfo.Revision, *FadtMinorRevision); + } if (*GetAcpiXsdtHeaderInfo ()->OemTableId != *AcpiHdrInfo.OemTableId) { IncrementErrorCount (); @@ -214,21 +216,20 @@ ParseAcpiFadt ( } } - // If X_DSDT is not zero then use X_DSDT and ignore DSDT, - // else use DSDT. - if (*X_DsdtAddress != 0) { + // If X_DSDT is valid then use X_DSDT and ignore DSDT, else use DSDT. + if ((X_DsdtAddress != NULL) && (*X_DsdtAddress != 0)) { DsdtPtr = (UINT8*)(UINTN)(*X_DsdtAddress); - } else if (*DsdtAddress != 0) { + } else if ((DsdtAddress != NULL) && (*DsdtAddress != 0)) { DsdtPtr = (UINT8*)(UINTN)(*DsdtAddress); } else { - // Both DSDT and X_DSDT cannot be zero. + // Both DSDT and X_DSDT cannot be invalid. #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) if (Trace) { // The DSDT Table is mandatory for ARM systems // as the CPU information MUST be presented in // the DSDT. IncrementErrorCount (); - Print (L"ERROR: Both X_DSDT and DSDT are NULL.\n"); + Print (L"ERROR: Both X_DSDT and DSDT are invalid.\n"); } #endif return; -- 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'
|
|
Re: [PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15) TSC leaf
Donald Kuo
Hi Liming,
toggle quoted messageShow quoted text
Done. Patch is attached to https://bugzilla.tianocore.org/show_bug.cgi?id=1909 Another BZ to apply CpuTimerLib will be tracking on: https://bugzilla.tianocore.org/show_bug.cgi?id=2096 Thanks, Donald
-----Original Message-----
|
|
Re: [PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15) TSC leaf
Liming Gao
Donald:
toggle quoted messageShow quoted text
Please also attach the patch linker in BZs. And, please submit another BZ for edk2-platforms\Platform\Intel\KabylakeOpenBoardPkg to apply this new library instance. Thanks Liming
-----Original Message-----
|
|
Re: [PATCH V3] [edk2-stable201908] BaseTools: Update incorrect variable name 'DataPile'
Bob Feng
Pushed at 0970a80583a9a0595eb357f380e604b57136fa26
toggle quoted messageShow quoted text
Thanks, Bob
-----Original Message-----
From: Gao, Liming Sent: Tuesday, August 20, 2019 2:24 PM To: Feng, Bob C <bob.c.feng@intel.com>; Fan, ZhijuX <zhijux.fan@intel.com>; devel@edk2.groups.io Subject: RE: [PATCH V3] [edk2-stable201908] BaseTools: Update incorrect variable name 'DataPile' Reviewed-by: Liming Gao <liming.gao@intel.com> -----Original Message-----
|
|
Re: [PATCH V3] [edk2-stable201908] BaseTools: Update incorrect variable name 'DataPile'
Liming Gao
Reviewed-by: Liming Gao <liming.gao@intel.com>
toggle quoted messageShow quoted text
-----Original Message-----
|
|