From: "Dong, Eric" <eric.dong@intel.com>
To: Tom Lendacky <thomas.lendacky@amd.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: Brijesh Singh <brijesh.singh@amd.com>,
Ard Biesheuvel <ard.biesheuvel@arm.com>,
"Justen, Jordan L" <jordan.l.justen@intel.com>,
Laszlo Ersek <lersek@redhat.com>,
"Gao, Liming" <liming.gao@intel.com>,
"Kinney, Michael D" <michael.d.kinney@intel.com>,
"Ni, Ray" <ray.ni@intel.com>
Subject: Re: [PATCH v10 42/46] UefiCpuPkg: Allow AP booting under SEV-ES
Date: Wed, 15 Jul 2020 05:23:13 +0000 [thread overview]
Message-ID: <DM6PR11MB327443BAF0138B126CE9C3C8FE7E0@DM6PR11MB3274.namprd11.prod.outlook.com> (raw)
In-Reply-To: <1dab98378f132f176345756ed09a602c86dab6d6.1594736896.git.thomas.lendacky@amd.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Tuesday, July 14, 2020 10:38 PM
> To: devel@edk2.groups.io
> Cc: Brijesh Singh <brijesh.singh@amd.com>; Ard Biesheuvel
> <ard.biesheuvel@arm.com>; Dong, Eric <eric.dong@intel.com>; Justen,
> Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek <lersek@redhat.com>;
> Gao, Liming <liming.gao@intel.com>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>
> Subject: [PATCH v10 42/46] UefiCpuPkg: Allow AP booting under SEV-ES
>
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>
> 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 | 336 +++++++++++++++++-
> 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, 738 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..b1a9d99cb3eb 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.
> +
> + @return 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..9115ff9e3e30 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.
> +
> + @return 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 2a3fbeef35f7..90416c81b616 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;
>
> @@ -291,6 +294,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) {
> @@ -587,6 +598,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.
>
> @@ -648,7 +765,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 @@ -755,7 +879,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 != NULL) {
> + CpuMpData = CpuMpData->NewCpuMpData;
> + }
> +
> + MpInitLibSevEsAPReset (Ghcb, CpuMpData);
> + } else {
> + CpuSleep ();
> + }
> CpuPause ();
> }
> }
> @@ -868,6 +1037,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
> //
> @@ -894,8 +1066,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 + @@ -948,7
> +1121,8 @@ BackupAndPrepareWakeupBuffer(
> CopyMem (
> (VOID *) CpuMpData->WakeupBuffer,
> (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
> - CpuMpData->AddressMap.RendezvousFunnelSize
> + CpuMpData->AddressMap.RendezvousFunnelSize +
> + CpuMpData->AddressMap.SwitchToRealSize
> );
> }
>
> @@ -969,6 +1143,44 @@ RestoreWakeupBuffer(
> );
> }
>
> +/**
> + Calculate the size of the reset stack.
> +
> + @return 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.
> +
> + @return 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.
>
> @@ -982,16 +1194,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); } @@ -1006,7 +1224,80
> @@ 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;
> + }
> +}
> +
> +/**
> + Program the SEV-ES AP jump table buffer.
> +
> + @param[in] SipiVector The SIPI vector used for the AP Reset **/
> +VOID SetSevEsJumpTable (
> + IN UINTN SipiVector
> + )
> +{
> + 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) (SipiVector >> 4);
> }
>
> /**
> @@ -1043,6 +1334,7 @@ WakeUpAP (
> CpuMpData->InitFlag != ApInitDone) {
> ResetVectorRequired = TRUE;
> AllocateResetVector (CpuMpData);
> + AllocateSevEsAPMemory (CpuMpData);
> FillExchangeInfoData (CpuMpData);
> SaveLocalApicTimerSetting (CpuMpData);
> }
> @@ -1079,6 +1371,15 @@ 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) {
> + SetSevEsJumpTable (ExchangeInfo->BufferStart);
> + }
> +
> //
> // Wakeup all APs
> //
> @@ -1170,6 +1471,16 @@ WakeUpAP (
> *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
> if (ResetVectorRequired) {
> CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData-
> >CpuInfoInHob;
> +
> + //
> + // 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) {
> + SetSevEsJumpTable (ExchangeInfo->BufferStart);
> + }
> +
> SendInitSipiSipi (
> CpuInfoInHob[ProcessorNumber].ApicId,
> (UINT32) ExchangeInfo->BufferStart @@ -1646,7 +1957,7 @@
> MpInitLibInitialize (
> ASSERT (MaxLogicalProcessorNumber != 0);
>
> AsmGetAddressMap (&AddressMap);
> - ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof
> (MP_CPU_EXCHANGE_INFO);
> + ApResetVectorSize = GetApResetVectorSize (&AddressMap);
> ApStackSize = PcdGet32(PcdCpuApStackSize);
> ApLoopMode = GetApLoopMode (&MonitorFilterSize);
>
> @@ -1705,6 +2016,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.
> @@ -1763,6 +2076,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..3989bd6a7a9f 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.
> +
> + @return 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.27.0
next prev parent reply other threads:[~2020-07-15 5:23 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-14 14:27 [PATCH v10 00/46] SEV-ES guest support Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 01/46] MdeModulePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 02/46] UefiCpuPkg: Create PCD " Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 03/46] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 04/46] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 05/46] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 06/46] MdePkg/BaseLib: Add support for the XGETBV instruction Lendacky, Thomas
2020-07-15 15:55 ` [edk2-devel] " Laszlo Ersek
2020-07-15 16:17 ` Lendacky, Thomas
2020-07-17 15:46 ` Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 07/46] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 08/46] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 09/46] OvmfPkg: Prepare OvmfPkg to use the VmgExitLib library Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 10/46] UefiPayloadPkg: Prepare UefiPayloadPkg " Lendacky, Thomas
2020-07-20 15:27 ` [edk2-devel] " Ma, Maurice
2020-07-14 14:27 ` [PATCH v10 11/46] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
2020-07-14 14:27 ` [PATCH v10 12/46] OvmfPkg/VmgExitLib: Implement library support for VmgExitLib in OVMF Lendacky, Thomas
2020-07-15 16:06 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 13/46] OvmfPkg/VmgExitLib: Add support for IOIO_PROT NAE events Lendacky, Thomas
2020-07-15 16:08 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 14/46] OvmfPkg/VmgExitLib: Support string IO " Lendacky, Thomas
2020-07-15 16:09 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 15/46] OvmfPkg/VmgExitLib: Add support for CPUID " Lendacky, Thomas
2020-07-15 16:10 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 16/46] OvmfPkg/VmgExitLib: Add support for MSR_PROT " Lendacky, Thomas
2020-07-15 16:11 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 17/46] OvmfPkg/VmgExitLib: Add support for NPF NAE events (MMIO) Lendacky, Thomas
2020-07-15 16:19 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 18/46] OvmfPkg/VmgExitLib: Add support for WBINVD NAE events Lendacky, Thomas
2020-07-15 16:21 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 19/46] OvmfPkg/VmgExitLib: Add support for RDTSC " Lendacky, Thomas
2020-07-15 16:21 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 20/46] OvmfPkg/VmgExitLib: Add support for RDPMC " Lendacky, Thomas
2020-07-15 16:21 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 21/46] OvmfPkg/VmgExitLib: Add support for INVD " Lendacky, Thomas
2020-07-15 16:21 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 22/46] OvmfPkg/VmgExitLib: Add support for VMMCALL " Lendacky, Thomas
2020-07-15 16:21 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 23/46] OvmfPkg/VmgExitLib: Add support for RDTSCP " Lendacky, Thomas
2020-07-15 16:21 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:27 ` [PATCH v10 24/46] OvmfPkg/VmgExitLib: Add support for MONITOR/MONITORX " Lendacky, Thomas
2020-07-15 16:21 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:37 ` [PATCH v10 25/46] OvmfPkg/VmgExitLib: Add support for MWAIT/MWAITX " Lendacky, Thomas
2020-07-15 16:22 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:37 ` [PATCH v10 26/46] OvmfPkg/VmgExitLib: Add support for DR7 Read/Write " Lendacky, Thomas
2020-07-15 16:25 ` [edk2-devel] " Laszlo Ersek
2020-07-14 14:37 ` [PATCH v10 27/46] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 28/46] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 29/46] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 30/46] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 31/46] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 32/46] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 33/46] UefiCpuPkg: Create an SEV-ES workarea PCD Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 34/46] OvmfPkg: Reserve a page in memory for the SEV-ES usage Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 35/46] OvmfPkg/PlatformPei: Reserve SEV-ES work area if S3 is supported Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 36/46] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 37/46] OvmfPkg/Sec: Add #VC exception handling for Sec phase Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 38/46] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
2020-07-14 14:37 ` [PATCH v10 39/46] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES Lendacky, Thomas
2020-07-14 19:50 ` [PATCH v10 40/46] UefiCpuPkg: Add a 16-bit protected mode code segment descriptor Lendacky, Thomas
2020-07-14 19:50 ` [PATCH v10 41/46] UefiCpuPkg/MpInitLib: Add CPU MP data flag to indicate if SEV-ES is enabled Lendacky, Thomas
2020-07-14 19:50 ` [PATCH v10 42/46] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
2020-07-15 5:23 ` Dong, Eric [this message]
2020-07-14 19:50 ` [PATCH v10 43/46] OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset vector Lendacky, Thomas
2020-07-14 19:50 ` [PATCH v10 44/46] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
2020-07-14 19:50 ` [PATCH v10 45/46] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
2020-07-15 5:55 ` Dong, Eric
2020-07-14 19:50 ` [PATCH v10 46/46] Maintainers.txt: Add reviewers for the OvmfPkg SEV-related files Lendacky, Thomas
2020-07-15 16:31 ` [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=DM6PR11MB327443BAF0138B126CE9C3C8FE7E0@DM6PR11MB3274.namprd11.prod.outlook.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