From: "Lendacky, Thomas" <thomas.lendacky@amd.com>
To: "Dong, Eric" <eric.dong@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Justen, Jordan L" <jordan.l.justen@intel.com>,
Laszlo Ersek <lersek@redhat.com>,
Ard Biesheuvel <ard.biesheuvel@linaro.org>,
"Kinney, Michael D" <michael.d.kinney@intel.com>,
"Gao, Liming" <liming.gao@intel.com>,
"Ni, Ray" <ray.ni@intel.com>,
Brijesh Singh <brijesh.singh@amd.com>
Subject: Re: [PATCH v8 42/46] UefiCpuPkg: Allow AP booting under SEV-ES
Date: Mon, 1 Jun 2020 11:10:27 -0500 [thread overview]
Message-ID: <220c9b8f-19ee-7aa9-f364-bae85c33e4fa@amd.com> (raw)
In-Reply-To: <DM6PR11MB3274B6E7D9A2AA03F40483C0FE8A0@DM6PR11MB3274.namprd11.prod.outlook.com>
On 6/1/20 1:17 AM, Dong, Eric wrote:
> Hi Tom,
Hi Eric,
>
>> -----Original Message-----
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>> Sent: Wednesday, May 20, 2020 5:51 AM
>> To: devel@edk2.groups.io
>> Cc: Justen, Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek
>> <lersek@redhat.com>; Ard Biesheuvel <ard.biesheuvel@linaro.org>; Kinney,
>> Michael D <michael.d.kinney@intel.com>; Gao, Liming
>> <liming.gao@intel.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
>> <ray.ni@intel.com>; Brijesh Singh <brijesh.singh@amd.com>
>> Subject: [PATCH v8 42/46] UefiCpuPkg: Allow AP booting under SEV-ES
>>
>> BZ: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2198&data=02%7C01%7Cthomas.lendacky%40amd.com%7C7f0288f6b6964c30b79808d805f3719d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637265890432557809&sdata=t8Gz8tXGoSpO3N5BDGCyRp%2FqH3PF6xitfIzV27rGSe0%3D&reserved=0
>>
>> 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, the firmware will provide a build time reserved area
>> that can be used as the initial IP value. The hypervisor can extract this
>> location value by checking for the SEV-ES reset block GUID that must be
>> located 48-bytes from the end of the firmware. The format of the SEV-ES
>> reset block area is:
>>
>> 0x00 - 0x01 - SEV-ES Reset IP
>> 0x02 - 0x03 - SEV-ES Reset CS Segment Base[31:16]
>> 0x04 - 0x05 - Size of the SEV-ES reset block
>> 0x06 - 0x15 - SEV-ES Reset Block GUID
>> (00f771de-1a7e-4fcb-890e-68c77e2fb44e)
>>
>> The total size is 22 bytes. Any expansion to this block must be done
>> by adding new values before existing values.
>>
>> The hypervisor will use the IP and CS values obtained from the SEV-ES reset
>> block to set as the AP's initial values. The CS Segment Base represents the
>> upper 16 bits of the CS segment base and must be left shifted by 16 bits to
>> form the complete CS segment base value.
>>
>> Before booting the AP for the first time, the BSP must initialize the SEV-ES
>> reset area. This consists of programming a FAR JMP instruction to the
>> contents of a memory location that is also located in the SEV-ES reset area.
>> The BSP must program the IP and CS values for the FAR JMP based on values
>> drived 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 new 16-bit protected mode GDT entry is used 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.
>>
>> Cc: Eric Dong <eric.dong@intel.com>
>> Cc: Ray Ni <ray.ni@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>> UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
>> UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 +
>> UefiCpuPkg/Library/MpInitLib/MpLib.h | 60 ++++
>> UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 70 +++-
>> UefiCpuPkg/Library/MpInitLib/MpLib.c | 312 +++++++++++++++++-
>> UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 19 ++
>> UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c | 2 +-
>> UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 2 +-
>> .../Library/MpInitLib/Ia32/MpFuncs.nasm | 15 +
>> UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 4 +-
>> UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 239 ++++++++++++++
>> 11 files changed, 714 insertions(+), 15 deletions(-)
>>
>> diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> index 583276595619..1771575c69c1 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> @@ -52,6 +52,7 @@ [LibraryClasses]
>> DebugAgentLib
>> SynchronizationLib
>> PcdLib
>> + VmgExitLib
>>
>> [Protocols]
>> gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES
>> @@ -72,4 +73,6 @@ [Pcd]
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ##
>> SOMETIMES_CONSUMES
>>
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds
>> ## CONSUMES
>> gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ##
>> CONSUMES
>> + gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ##
>> SOMETIMES_CONSUMES
>> gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ##
>> CONSUMES
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ##
>> CONSUMES
>> diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
>> b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
>> index 4b3d39fbf36c..34abf25d43cd 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
>> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
>> @@ -51,6 +51,7 @@ [LibraryClasses]
>> SynchronizationLib
>> PeiServicesLib
>> PcdLib
>> + VmgExitLib
>>
>> [Pcd]
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ##
>> CONSUMES
>> @@ -62,6 +63,8 @@ [Pcd]
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ##
>> CONSUMES
>> gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ##
>> SOMETIMES_CONSUMES
>> gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ## CONSUMES
>> + gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ##
>> SOMETIMES_CONSUMES
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ##
>> CONSUMES
>>
>> [Ppis]
>> gEdkiiPeiShadowMicrocodePpiGuid ## SOMETIMES_CONSUMES
>> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> b/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> index 5b46c295b6b2..f0cbb3763b5d 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> @@ -173,6 +173,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; @@ -211,6 +216,8 @@
>> typedef struct {
>> // Enable5LevelPaging indicates whether 5-level paging is enabled in long
>> mode.
>> //
>> BOOLEAN Enable5LevelPaging;
>> + BOOLEAN SevEsIsEnabled;
>> + UINTN GhcbBase;
>> } MP_CPU_EXCHANGE_INFO;
>>
>> #pragma pack()
>> @@ -257,6 +264,7 @@ struct _CPU_MP_DATA {
>> UINT8 ApLoopMode;
>> UINT8 ApTargetCState;
>> UINT16 PmCodeSegment;
>> + UINT16 Pm16CodeSegment;
>> CPU_AP_DATA *CpuData;
>> volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
>>
>> @@ -278,8 +286,47 @@ struct _CPU_MP_DATA {
>> BOOLEAN WakeUpByInitSipiSipi;
>>
>> BOOLEAN SevEsIsEnabled;
>> + UINTN SevEsAPBuffer;
>> + UINTN SevEsAPResetStackStart;
>> + CPU_MP_DATA *NewCpuMpData;
>> +
>> + UINT64 GhcbBase;
>> };
>>
>> +#define AP_RESET_STACK_SIZE 64
>> +
>> +#pragma pack(1)
>> +
>> +typedef struct {
>> + UINT8 InsnBuffer[8];
>> + UINT16 Rip;
>> + UINT16 Segment;
>> +} SEV_ES_AP_JMP_FAR;
>> +
>> +#pragma pack()
>> +
>> +/**
>> + 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;
>>
>> /**
>> @@ -385,6 +432,19 @@ GetModeTransitionBuffer (
>> IN UINTN BufferSize
>> );
>>
>> +/**
>> + Return the address of the SEV-ES AP jump table.
>> +
>> + This buffer is required in order for an SEV-ES guest to transition
>> + from UEFI into an OS.
>> +
>> + @retval other Return SEV-ES AP jump table buffer
>> +**/
>> +UINTN
>> +GetSevEsAPMemory (
>> + VOID
>> + );
>> +
>> /**
>> This function will be called by BSP to wakeup AP.
>>
>> diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
>> b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
>> index 8ccddf8e9f9c..19527300ff3a 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>
>>
>> @@ -144,6 +146,39 @@ GetModeTransitionBuffer (
>> return (UINTN)StartAddress;
>> }
>>
>> +/**
>> + Return the address of the SEV-ES AP jump table.
>> +
>> + This buffer is required in order for an SEV-ES guest to transition
>> + from UEFI into an OS.
>> +
>> + @retval other Return SEV-ES AP jump table 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.
>>
>> @@ -218,6 +253,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.
>>
>> @@ -238,7 +305,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;
>> }
>> }
>> @@ -300,6 +367,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 a8b605f569bf..aeab575bb525 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
>> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
>> @@ -9,6 +9,9 @@
>> **/
>>
>> #include "MpLib.h"
>> +#include <Library/VmgExitLib.h>
>> +#include <Register/Amd/Fam17Msr.h>
>> +#include <Register/Amd/Ghcb.h>
>>
>> EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
>>
>> @@ -314,6 +317,14 @@ GetApLoopMode (
>> //
>> ApLoopMode = ApInHltLoop;
>> }
>> +
>> + if (PcdGetBool (PcdSevEsIsEnabled)) {
>> + //
>> + // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
>> + // protocol for starting APs
>> + //
>> + ApLoopMode = ApInHltLoop;
>> + }
>> }
>>
>> if (ApLoopMode != ApInMwaitLoop) {
>> @@ -610,6 +621,112 @@ 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.
>> +
>> + If successful, this function never returns.
>> +
>> + @param[in] Ghcb Pointer to the GHCB
>> + @param[in] CpuMpData Pointer to CPU MP Data
>> +
>> +**/
>> +STATIC
>> +VOID
>> +MpInitLibSevEsAPReset (
>> + IN GHCB *Ghcb,
>> + IN 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.
>>
>> @@ -671,7 +788,14 @@ ApWakeupFunction (
>> InitializeApData (CpuMpData, ProcessorNumber, BistData,
>> ApTopOfStack);
>> ApStartupSignalBuffer = CpuMpData-
>>> CpuData[ProcessorNumber].StartupApSignal;
>>
>> - InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo-
>>> NumApsExecuting);
>> + //
>> + // Delay decrementing the APs executing count when SEV-ES is enabled
>> + // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
>> + // performs another INIT-SIPI-SIPI sequence.
>> + //
>> + if (!CpuMpData->SevEsIsEnabled) {
>> + InterlockedDecrement ((UINT32 *) &CpuMpData-
>>> MpCpuExchangeInfo->NumApsExecuting);
>> + }
>> } else {
>> //
>> // Execute AP function if AP is ready @@ -778,7 +902,52 @@
>> ApWakeupFunction (
>> //
>> while (TRUE) {
>> DisableInterrupts ();
>> - CpuSleep ();
>> + if (CpuMpData->SevEsIsEnabled) {
>> + MSR_SEV_ES_GHCB_REGISTER Msr;
>> + GHCB *Ghcb;
>> + UINT64 Status;
>> + BOOLEAN DoDecrement;
>> +
>> + if (CpuMpData->InitFlag == ApInitConfig) {
>> + DoDecrement = TRUE;
>> + }
>> +
>> + while (TRUE) {
>> + Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
>> + Ghcb = Msr.Ghcb;
>> +
>> + VmgInit (Ghcb);
>> +
>> + if (DoDecrement) {
>> + DoDecrement = FALSE;
>> +
>> + //
>> + // Perform the delayed decrement just before issuing the first
>> + // VMGEXIT with AP_RESET_HOLD.
>> + //
>> + InterlockedDecrement ((UINT32 *) &CpuMpData-
>>> MpCpuExchangeInfo->NumApsExecuting);
>> + }
>> +
>> + Status = VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0);
>> + if ((Status == 0) && (Ghcb->SaveArea.SwExitInfo2 != 0)) {
>> + VmgDone (Ghcb);
>> + break;
>> + }
>> +
>> + VmgDone (Ghcb);
>> + }
>> +
>> + //
>> + // Awakened in a new phase? Use the new CpuMpData
>> + //
>> + if (CpuMpData->NewCpuMpData) {
>> + CpuMpData = CpuMpData->NewCpuMpData;
>> + }
>> +
>> + MpInitLibSevEsAPReset (Ghcb, CpuMpData);
>> + } else {
>> + CpuSleep ();
>> + }
>> CpuPause ();
>> }
>> }
>> @@ -891,6 +1060,9 @@ FillExchangeInfoData (
>> ExchangeInfo->Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
>> DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName,
>> ExchangeInfo->Enable5LevelPaging));
>>
>> + ExchangeInfo->SevEsIsEnabled = CpuMpData->SevEsIsEnabled;
>> + ExchangeInfo->GhcbBase = (UINTN) CpuMpData->GhcbBase;
>> +
>> //
>> // Get the BSP's data of GDT and IDT
>> //
>> @@ -917,8 +1089,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 + @@ -971,7
>> +1144,8 @@ BackupAndPrepareWakeupBuffer(
>> CopyMem (
>> (VOID *) CpuMpData->WakeupBuffer,
>> (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
>> - CpuMpData->AddressMap.RendezvousFunnelSize
>> + CpuMpData->AddressMap.RendezvousFunnelSize +
>> + CpuMpData->AddressMap.SwitchToRealSize
>> );
>> }
>>
>> @@ -992,6 +1166,44 @@ RestoreWakeupBuffer(
>> );
>> }
>>
>> +/**
>> + Calculate the size of the reset stack.
>> +
>> + @retval Total amount of memory required for stacks
>> +**/
>> +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.
>> +
>> + @retval Total amount of memory required for the AP reset area
>> +**/
>> +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.
>>
>> @@ -1005,16 +1217,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); } @@ -1029,7 +1247,31
>> @@ FreeResetVector (
>> IN CPU_MP_DATA *CpuMpData
>> )
>> {
>> - RestoreWakeupBuffer (CpuMpData);
>> + //
>> + // If SEV-ES is enabled, 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->SevEsIsEnabled) {
>> + RestoreWakeupBuffer (CpuMpData);
>> + }
>> +}
>> +
>> +/**
>> + Allocate the SEV-ES AP jump table buffer.
>> +
>> + @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->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
>> + }
>> }
>>
>> /**
>> @@ -1066,6 +1308,7 @@ WakeUpAP (
>> CpuMpData->InitFlag != ApInitDone) {
>> ResetVectorRequired = TRUE;
>> AllocateResetVector (CpuMpData);
>> + AllocateSevEsAPMemory (CpuMpData);
>> FillExchangeInfoData (CpuMpData);
>> SaveLocalApicTimerSetting (CpuMpData);
>> }
>> @@ -1102,6 +1345,50 @@ WakeUpAP (
>> }
>> }
>> if (ResetVectorRequired) {
>> + //
>> + // For SEV-ES, the initial AP boot address will be defined by
>> + // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
>> + // from the original INIT-SIPI-SIPI.
>> + //
>> + if (CpuMpData->SevEsIsEnabled) {
>> + SEV_ES_AP_JMP_FAR *JmpFar;
>> + UINT32 Offset, InsnByte;
>> + UINT8 LoNib, HiNib;
>> +
>> + JmpFar = (SEV_ES_AP_JMP_FAR *) FixedPcdGet32
>> (PcdSevEsWorkAreaBase);
>> + ASSERT (JmpFar != NULL);
>> +
>> + //
>> + // Obtain the address of the Segment/Rip location in the workarea.
>> + // This will be set to a value derived from the SIPI vector and will
>> + // be the memory address used for the far jump below.
>> + //
>> + Offset = FixedPcdGet32 (PcdSevEsWorkAreaBase);
>> + Offset += sizeof (JmpFar->InsnBuffer);
>> + LoNib = (UINT8) Offset;
>> + HiNib = (UINT8) (Offset >> 8);
>> +
>> + //
>> + // Program the workarea (which is the initial AP boot address) with
>> + // far jump to the SIPI vector (where XX and YY represent the
>> + // address of where the SIPI vector is stored.
>> + //
>> + // JMP FAR [CS:XXYY] => 2E FF 2E YY XX
>> + //
>> + InsnByte = 0;
>> + JmpFar->InsnBuffer[InsnByte++] = 0x2E; // CS override prefix
>> + JmpFar->InsnBuffer[InsnByte++] = 0xFF; // JMP (FAR)
>> + JmpFar->InsnBuffer[InsnByte++] = 0x2E; // ModRM (JMP memory
>> location)
>> + JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...
>> + JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...
>> +
>> + //
>> + // Program the Segment/Rip based on the SIPI vector (always at least
>> + // 16-byte aligned, so Rip is set to 0).
>> + //
>> + JmpFar->Rip = 0;
>> + JmpFar->Segment = (UINT16) (ExchangeInfo->BufferStart >> 4);
>> + }
>
> For this wake-up process, current code just handles the broadcast type. I think it also needs to handle wake-up specific AP case. Right?
Yes, it should be. I never encountered a non-broadcast call under OVMF,
but it should be supported for error cases, etc. and for any future
changes in support.
I'll add it and make the above code a function so as not to duplicate it.
Thanks,
Tom
>
> Thanks,
> Eric
>> //
>> // Wakeup all APs
>> //
>> @@ -1669,7 +1956,7 @@ MpInitLibInitialize (
>> ASSERT (MaxLogicalProcessorNumber != 0);
>>
>> AsmGetAddressMap (&AddressMap);
>> - ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof
>> (MP_CPU_EXCHANGE_INFO);
>> + ApResetVectorSize = GetApResetVectorSize (&AddressMap);
>> ApStackSize = PcdGet32(PcdCpuApStackSize);
>> ApLoopMode = GetApLoopMode (&MonitorFilterSize);
>>
>> @@ -1728,6 +2015,8 @@ MpInitLibInitialize (
>> CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData
>> + MaxLogicalProcessorNumber);
>> InitializeSpinLock(&CpuMpData->MpLock);
>> CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
>> + CpuMpData->SevEsAPBuffer = (UINTN) -1;
>> + CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
>>
>> //
>> // Make sure no memory usage outside of the allocated buffer.
>> @@ -1786,6 +2075,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->CpuInfoInHob = OldCpuMpData->CpuInfoInHob; diff --git
>> a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
>> b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
>> index a548fed23fa7..e17a351e5cfd 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
>> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
>> @@ -280,6 +280,25 @@ GetModeTransitionBuffer (
>> return 0;
>> }
>>
>> +/**
>> + Return the address of the SEV-ES AP jump table.
>> +
>> + This buffer is required in order for an SEV-ES guest to transition
>> + from UEFI into an OS.
>> +
>> + @retval other Return SEV-ES AP jump table buffer
>> +**/
>> +UINTN
>> +GetSevEsAPMemory (
>> + VOID
>> + )
>> +{
>> + //
>> + // PEI phase doesn't need to do such transition. 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/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
>> b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
>> index efb1bc2bf7cb..4f5a7c859a56 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
>> 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 58ef369342a7..c92daaaffd6b 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
>> @@ -41,3 +41,5 @@ ModeTransitionSegmentLocation equ LockLocation +
>> 98h
>> ModeHighMemoryLocation equ LockLocation + 9Ah
>> ModeHighSegmentLocation equ LockLocation + 9Eh
>> Enable5LevelPagingLocation equ LockLocation + 0A0h
>> +SevEsIsEnabledLocation equ LockLocation + 0A1h
>> +GhcbBaseLocation equ LockLocation + 0A2h
>> diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
>> b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
>> index 87f2523e856f..6956b408d004 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
>> +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
>> @@ -184,9 +184,97 @@ Releaselock:
>> add edi, StackStartAddressLocation
>> add rax, qword [edi]
>> mov rsp, rax
>> +
>> + lea edi, [esi + SevEsIsEnabledLocation]
>> + cmp byte [edi], 1 ; SevEsIsEnabled
>> + 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 + SevEsIsEnabledLocation]
>> + cmp byte [edi], 1 ; SevEsIsEnabled
>> + 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
>> @@ -253,12 +341,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)--
>> @@ -324,6 +558,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
>>
>> ;-------------------------------------------------------------------------------------
>> --
>> 2.17.1
>
next prev parent reply other threads:[~2020-06-01 16:10 UTC|newest]
Thread overview: 100+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-19 21:50 [PATCH v8 00/46] SEV-ES guest support Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 01/46] MdeModulePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 02/46] UefiCpuPkg: Create PCD " Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 03/46] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 04/46] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 05/46] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 06/46] MdePkg/BaseLib: Add support for the XGETBV instruction Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 07/46] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 08/46] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 09/46] OvmfPkg: Prepare OvmfPkg to use the VmgExitLib library Lendacky, Thomas
2020-05-21 16:42 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 10/46] UefiPayloadPkg: Prepare UefiPayloadPkg " Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 11/46] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 12/46] OvmfPkg/VmgExitLib: Implement library support for VmgExitLib in OVMF Lendacky, Thomas
2020-05-21 16:52 ` [edk2-devel] " Laszlo Ersek
2020-05-21 17:08 ` Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 13/46] OvmfPkg/VmgExitLib: Add support for IOIO_PROT NAE events Lendacky, Thomas
2020-05-21 17:25 ` [edk2-devel] " Laszlo Ersek
2020-05-22 10:05 ` Laszlo Ersek
2020-05-22 13:41 ` Lendacky, Thomas
2020-05-22 13:40 ` Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 14/46] OvmfPkg/VmgExitLib: Support string IO " Lendacky, Thomas
2020-05-22 10:14 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 15/46] OvmfPkg/VmgExitLib: Add support for CPUID " Lendacky, Thomas
2020-05-22 10:27 ` [edk2-devel] " Laszlo Ersek
2020-05-22 19:02 ` Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 16/46] OvmfPkg/VmgExitLib: Add support for MSR_PROT " Lendacky, Thomas
2020-05-22 10:31 ` [edk2-devel] " Laszlo Ersek
2020-05-22 19:06 ` Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 17/46] OvmfPkg/VmgExitLib: Add support for NPF NAE events (MMIO) Lendacky, Thomas
2020-05-22 14:14 ` [edk2-devel] " Laszlo Ersek
2020-05-22 14:31 ` Laszlo Ersek
2020-05-22 20:41 ` Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 18/46] OvmfPkg/VmgExitLib: Add support for WBINVD NAE events Lendacky, Thomas
2020-05-22 14:19 ` [edk2-devel] " Laszlo Ersek
2020-05-22 20:51 ` Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 19/46] OvmfPkg/VmgExitLib: Add support for RDTSC " Lendacky, Thomas
2020-05-22 14:42 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 20/46] OvmfPkg/VmgExitLib: Add support for RDPMC " Lendacky, Thomas
2020-05-22 14:43 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 21/46] OvmfPkg/VmgExitLib: Add support for INVD " Lendacky, Thomas
2020-05-22 14:46 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 22/46] OvmfPkg/VmgExitLib: Add support for VMMCALL " Lendacky, Thomas
2020-05-22 14:48 ` [edk2-devel] " Laszlo Ersek
2020-05-22 14:50 ` Laszlo Ersek
2020-05-22 21:18 ` Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 23/46] OvmfPkg/VmgExitLib: Add support for RDTSCP " Lendacky, Thomas
2020-05-22 14:52 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 24/46] OvmfPkg/VmgExitLib: Add support for MONITOR/MONITORX " Lendacky, Thomas
2020-05-22 14:55 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 25/46] OvmfPkg/VmgExitLib: Add support for MWAIT/MWAITX " Lendacky, Thomas
2020-05-22 14:56 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 26/46] OvmfPkg/VmgExitLib: Add support for DR7 Read/Write " Lendacky, Thomas
2020-05-22 14:59 ` [edk2-devel] " Laszlo Ersek
2020-05-25 14:47 ` Laszlo Ersek
2020-05-26 15:06 ` Lendacky, Thomas
2020-05-27 11:54 ` Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 27/46] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 28/46] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 29/46] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
2020-05-25 15:07 ` [edk2-devel] " Laszlo Ersek
2020-05-26 15:41 ` Lendacky, Thomas
2020-05-26 15:45 ` Lendacky, Thomas
2020-05-27 11:45 ` Laszlo Ersek
2020-05-19 21:50 ` [PATCH v8 30/46] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
2020-05-19 21:50 ` [PATCH v8 31/46] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
2020-05-25 15:21 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:51 ` [PATCH v8 32/46] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
2020-05-19 21:51 ` [PATCH v8 33/46] UefiCpuPkg: Create an SEV-ES workarea PCD Lendacky, Thomas
2020-05-19 21:51 ` [PATCH v8 34/46] OvmfPkg: Reserve a page in memory for the SEV-ES usage Lendacky, Thomas
2020-05-25 16:00 ` [edk2-devel] " Laszlo Ersek
2020-05-26 14:28 ` Lendacky, Thomas
2020-05-26 21:47 ` Lendacky, Thomas
2020-05-27 11:50 ` Laszlo Ersek
2020-05-19 21:51 ` [PATCH v8 35/46] OvmfPkg/PlatformPei: Reserve SEV-ES work area if S3 is supported Lendacky, Thomas
2020-05-26 7:53 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:51 ` [PATCH v8 36/46] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
2020-05-25 16:50 ` [edk2-devel] " Laszlo Ersek
2020-05-26 16:31 ` Lendacky, Thomas
2020-05-27 11:59 ` Laszlo Ersek
2020-05-19 21:51 ` [PATCH v8 37/46] OvmfPkg/Sec: Add #VC exception handling for Sec phase Lendacky, Thomas
2020-05-26 13:58 ` [edk2-devel] " Laszlo Ersek
2020-05-19 21:51 ` [PATCH v8 38/46] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
2020-05-19 21:51 ` [PATCH v8 39/46] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES Lendacky, Thomas
2020-05-26 14:07 ` [edk2-devel] " Laszlo Ersek
2020-05-20 4:46 ` [PATCH v8 00/46] SEV-ES guest support Lendacky, Thomas
2020-05-20 16:56 ` [PATCH v8 40/46] UefiCpuPkg: Add a 16-bit protected mode code segment descriptor Lendacky, Thomas
2020-05-20 16:56 ` [PATCH v8 41/46] UefiCpuPkg/MpInitLib: Add CPU MP data flag to indicate if SEV-ES is enabled Lendacky, Thomas
2020-05-20 16:56 ` [PATCH v8 42/46] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
2020-06-01 6:17 ` Dong, Eric
2020-06-01 16:10 ` Lendacky, Thomas [this message]
2020-06-05 6:13 ` Dong, Eric
2020-06-01 7:28 ` Dong, Eric
2020-06-01 16:58 ` Lendacky, Thomas
2020-05-20 16:56 ` [PATCH v8 43/46] OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset vector Lendacky, Thomas
2020-05-20 16:56 ` [PATCH v8 44/46] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
2020-05-20 16:56 ` [PATCH v8 45/46] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
2020-05-20 16:56 ` [PATCH v8 46/46] Maintainers.txt: Add reviewers for the OvmfPkg SEV-related files Lendacky, Thomas
2020-05-19 21:54 ` Brijesh Singh
2020-05-26 14:12 ` [edk2-devel] " Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=220c9b8f-19ee-7aa9-f364-bae85c33e4fa@amd.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox