UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198 Before UEFI transfers control to the OS, it must park the AP. This is done using the AsmRelocateApLoop function to transition into 32-bit non-paging mode. For an SEV-ES guest, a few additional things must be done: - AsmRelocateApLoop must be updated to support SEV-ES. This means performing a VMGEXIT AP Reset Hold instead of an MWAIT or HLT loop. - Since the AP must transition to real mode, a small routine is copied to the WakeupBuffer area. Since the WakeupBuffer will be used by the AP during OS booting, it must be placed in reserved memory. Additionally, the AP stack must be located where it can be accessed in real mode. - Once the AP is in real mode it will transfer control to the destination specified by the OS in the SEV-ES AP Jump Table. The SEV-ES AP Jump Table address is saved by the hypervisor for the OS using the GHCB VMGEXIT AP Jump Table exit code. Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
committed by
mergify[bot]
parent
3b49d0a598
commit
20da7ca42a
@@ -12,6 +12,7 @@
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DebugAgentLib.h>
|
||||
#include <Library/DxeServicesTableLib.h>
|
||||
#include <Library/VmgExitLib.h>
|
||||
#include <Register/Amd/Fam17Msr.h>
|
||||
#include <Register/Amd/Ghcb.h>
|
||||
|
||||
@@ -85,6 +86,13 @@ GetWakeupBuffer (
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS StartAddress;
|
||||
EFI_MEMORY_TYPE MemoryType;
|
||||
|
||||
if (PcdGetBool (PcdSevEsIsEnabled)) {
|
||||
MemoryType = EfiReservedMemoryType;
|
||||
} else {
|
||||
MemoryType = EfiBootServicesData;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to allocate buffer below 1M for waking vector.
|
||||
@@ -97,7 +105,7 @@ GetWakeupBuffer (
|
||||
StartAddress = 0x88000;
|
||||
Status = gBS->AllocatePages (
|
||||
AllocateMaxAddress,
|
||||
EfiBootServicesData,
|
||||
MemoryType,
|
||||
EFI_SIZE_TO_PAGES (WakeupBufferSize),
|
||||
&StartAddress
|
||||
);
|
||||
@@ -159,8 +167,10 @@ GetSevEsAPMemory (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS StartAddress;
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS StartAddress;
|
||||
MSR_SEV_ES_GHCB_REGISTER Msr;
|
||||
GHCB *Ghcb;
|
||||
|
||||
//
|
||||
// Allocate 1 page for AP jump table page
|
||||
@@ -176,6 +186,16 @@ GetSevEsAPMemory (
|
||||
|
||||
DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN) StartAddress));
|
||||
|
||||
//
|
||||
// Save the SevEsAPMemory as the AP jump table.
|
||||
//
|
||||
Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
|
||||
Ghcb = Msr.Ghcb;
|
||||
|
||||
VmgInit (Ghcb);
|
||||
VmgExit (Ghcb, SVM_EXIT_AP_JUMP_TABLE, 0, (UINT64) (UINTN) StartAddress);
|
||||
VmgDone (Ghcb);
|
||||
|
||||
return (UINTN) StartAddress;
|
||||
}
|
||||
|
||||
@@ -330,17 +350,26 @@ RelocateApLoop (
|
||||
BOOLEAN MwaitSupport;
|
||||
ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;
|
||||
UINTN ProcessorNumber;
|
||||
UINTN StackStart;
|
||||
|
||||
MpInitLibWhoAmI (&ProcessorNumber);
|
||||
CpuMpData = GetCpuMpData ();
|
||||
MwaitSupport = IsMwaitSupport ();
|
||||
if (CpuMpData->SevEsIsEnabled) {
|
||||
StackStart = CpuMpData->SevEsAPResetStackStart;
|
||||
} else {
|
||||
StackStart = mReservedTopOfApStack;
|
||||
}
|
||||
AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;
|
||||
AsmRelocateApLoopFunc (
|
||||
MwaitSupport,
|
||||
CpuMpData->ApTargetCState,
|
||||
CpuMpData->PmCodeSegment,
|
||||
mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,
|
||||
(UINTN) &mNumberToFinish
|
||||
StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
|
||||
(UINTN) &mNumberToFinish,
|
||||
CpuMpData->Pm16CodeSegment,
|
||||
CpuMpData->SevEsAPBuffer,
|
||||
CpuMpData->WakeupBuffer
|
||||
);
|
||||
//
|
||||
// It should never reach here
|
||||
@@ -374,6 +403,21 @@ MpInitChangeApLoopCallback (
|
||||
while (mNumberToFinish > 0) {
|
||||
CpuPause ();
|
||||
}
|
||||
|
||||
if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
|
||||
//
|
||||
// There are APs present. Re-use reserved memory area below 1MB from
|
||||
// WakeupBuffer as the area to be used for transitioning to 16-bit mode
|
||||
// in support of booting of the AP by an OS.
|
||||
//
|
||||
CopyMem (
|
||||
(VOID *) CpuMpData->WakeupBuffer,
|
||||
(VOID *) (CpuMpData->AddressMap.RendezvousFunnelAddress +
|
||||
CpuMpData->AddressMap.SwitchToRealPM16ModeOffset),
|
||||
CpuMpData->AddressMap.SwitchToRealPM16ModeSize
|
||||
);
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user