#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/DebugAgentLib.h>\r
#include <Library/DxeServicesTableLib.h>\r
+#include <Library/VmgExitLib.h>\r
#include <Register/Amd/Fam17Msr.h>\r
#include <Register/Amd/Ghcb.h>\r
\r
{\r
EFI_STATUS Status;\r
EFI_PHYSICAL_ADDRESS StartAddress;\r
+ EFI_MEMORY_TYPE MemoryType;\r
+\r
+ if (PcdGetBool (PcdSevEsIsEnabled)) {\r
+ MemoryType = EfiReservedMemoryType;\r
+ } else {\r
+ MemoryType = EfiBootServicesData;\r
+ }\r
\r
//\r
// Try to allocate buffer below 1M for waking vector.\r
StartAddress = 0x88000;\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
- EfiBootServicesData,\r
+ MemoryType,\r
EFI_SIZE_TO_PAGES (WakeupBufferSize),\r
&StartAddress\r
);\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS StartAddress;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS StartAddress;\r
+ MSR_SEV_ES_GHCB_REGISTER Msr;\r
+ GHCB *Ghcb;\r
\r
//\r
// Allocate 1 page for AP jump table page\r
\r
DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN) StartAddress));\r
\r
+ //\r
+ // Save the SevEsAPMemory as the AP jump table.\r
+ //\r
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+ Ghcb = Msr.Ghcb;\r
+\r
+ VmgInit (Ghcb);\r
+ VmgExit (Ghcb, SVM_EXIT_AP_JUMP_TABLE, 0, (UINT64) (UINTN) StartAddress);\r
+ VmgDone (Ghcb);\r
+\r
return (UINTN) StartAddress;\r
}\r
\r
BOOLEAN MwaitSupport;\r
ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
UINTN ProcessorNumber;\r
+ UINTN StackStart;\r
\r
MpInitLibWhoAmI (&ProcessorNumber);\r
CpuMpData = GetCpuMpData ();\r
MwaitSupport = IsMwaitSupport ();\r
+ if (CpuMpData->SevEsIsEnabled) {\r
+ StackStart = CpuMpData->SevEsAPResetStackStart;\r
+ } else {\r
+ StackStart = mReservedTopOfApStack;\r
+ }\r
AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;\r
AsmRelocateApLoopFunc (\r
MwaitSupport,\r
CpuMpData->ApTargetCState,\r
CpuMpData->PmCodeSegment,\r
- mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
- (UINTN) &mNumberToFinish\r
+ StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
+ (UINTN) &mNumberToFinish,\r
+ CpuMpData->Pm16CodeSegment,\r
+ CpuMpData->SevEsAPBuffer,\r
+ CpuMpData->WakeupBuffer\r
);\r
//\r
// It should never reach here\r
while (mNumberToFinish > 0) {\r
CpuPause ();\r
}\r
+\r
+ if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN) -1)) {\r
+ //\r
+ // There are APs present. Re-use reserved memory area below 1MB from\r
+ // WakeupBuffer as the area to be used for transitioning to 16-bit mode\r
+ // in support of booting of the AP by an OS.\r
+ //\r
+ CopyMem (\r
+ (VOID *) CpuMpData->WakeupBuffer,\r
+ (VOID *) (CpuMpData->AddressMap.RendezvousFunnelAddress +\r
+ CpuMpData->AddressMap.SwitchToRealPM16ModeOffset),\r
+ CpuMpData->AddressMap.SwitchToRealPM16ModeSize\r
+ );\r
+ }\r
+\r
DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));\r
}\r
\r
SwitchToRealProcEnd:\r
\r
;-------------------------------------------------------------------------------------\r
-; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);\r
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
+;\r
+; The last three parameters (Pm16CodeSegment, SevEsAPJumpTable and WakeupBuffer) are\r
+; specific to SEV-ES support and are not applicable on IA32.\r
;-------------------------------------------------------------------------------------\r
global ASM_PFX(AsmRelocateApLoop)\r
ASM_PFX(AsmRelocateApLoop):\r
UINT64 GhcbBase;\r
};\r
\r
-#define AP_RESET_STACK_SIZE 64\r
+#define AP_SAFE_STACK_SIZE 128\r
+#define AP_RESET_STACK_SIZE AP_SAFE_STACK_SIZE\r
\r
#pragma pack(1)\r
\r
IN UINTN ApTargetCState,\r
IN UINTN PmCodeSegment,\r
IN UINTN TopOfApStack,\r
- IN UINTN NumberToFinish\r
+ IN UINTN NumberToFinish,\r
+ IN UINTN Pm16CodeSegment,\r
+ IN UINTN SevEsAPJumpTable,\r
+ IN UINTN WakeupBuffer\r
);\r
\r
/**\r
; - IP for Real Mode (two bytes)\r
; - CS for Real Mode (two bytes)\r
;\r
+ ; This label is also used with AsmRelocateApLoop. During MP finalization,\r
+ ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of\r
+ ; the WakeupBuffer, allowing a parked AP to be booted by an OS.\r
+ ;\r
PM16Mode:\r
mov eax, cr0 ; Read CR0\r
btr eax, 0 ; Set PE=0\r
SwitchToRealProcEnd:\r
\r
;-------------------------------------------------------------------------------------\r
-; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);\r
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
;-------------------------------------------------------------------------------------\r
global ASM_PFX(AsmRelocateApLoop)\r
ASM_PFX(AsmRelocateApLoop):\r
AsmRelocateApLoopStart:\r
BITS 64\r
+ cmp qword [rsp + 56], 0 ; SevEsAPJumpTable\r
+ je NoSevEs\r
+\r
+ ;\r
+ ; Perform some SEV-ES related setup before leaving 64-bit mode\r
+ ;\r
+ push rcx\r
+ push rdx\r
+\r
+ ;\r
+ ; Get the RDX reset value using CPUID\r
+ ;\r
+ mov rax, 1\r
+ cpuid\r
+ mov rsi, rax ; Save off the reset value for RDX\r
+\r
+ ;\r
+ ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call\r
+ ; - Must be done while in 64-bit long mode so that writes to\r
+ ; the GHCB memory will be unencrypted.\r
+ ; - No NAE events can be generated once this is set otherwise\r
+ ; the AP_RESET_HOLD SW_EXITCODE will be overwritten.\r
+ ;\r
+ mov rcx, 0xc0010130\r
+ rdmsr ; Retrieve current GHCB address\r
+ shl rdx, 32\r
+ or rdx, rax\r
+\r
+ mov rdi, rdx\r
+ xor rax, rax\r
+ mov rcx, 0x800\r
+ shr rcx, 3\r
+ rep stosq ; Clear the GHCB\r
+\r
+ mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD\r
+ mov [rdx + 0x390], rax\r
+\r
+ pop rdx\r
+ pop rcx\r
+\r
+NoSevEs:\r
cli ; Disable interrupt before switching to 32-bit mode\r
mov rax, [rsp + 40] ; CountTofinish\r
lock dec dword [rax] ; (*CountTofinish)--\r
- mov rsp, r9\r
- push rcx\r
- push rdx\r
\r
- lea rsi, [PmEntry] ; rsi <- The start address of transition code\r
+ mov r10, [rsp + 48] ; Pm16CodeSegment\r
+ mov rax, [rsp + 56] ; SevEsAPJumpTable\r
+ mov rbx, [rsp + 64] ; WakeupBuffer\r
+ mov rsp, r9 ; TopOfApStack\r
+\r
+ push rax ; Save SevEsAPJumpTable\r
+ push rbx ; Save WakeupBuffer\r
+ push r10 ; Save Pm16CodeSegment\r
+ push rcx ; Save MwaitSupport\r
+ push rdx ; Save ApTargetCState\r
+\r
+ lea rax, [PmEntry] ; rax <- The start address of transition code\r
\r
push r8\r
- push rsi\r
- DB 0x48\r
- retf\r
+ push rax\r
+\r
+ ;\r
+ ; Clear R8 - R15, for reset, before going into 32-bit mode\r
+ ;\r
+ xor r8, r8\r
+ xor r9, r9\r
+ xor r10, r10\r
+ xor r11, r11\r
+ xor r12, r12\r
+ xor r13, r13\r
+ xor r14, r14\r
+ xor r15, r15\r
+\r
+ ;\r
+ ; Far return into 32-bit mode\r
+ ;\r
+o64 retf\r
+\r
BITS 32\r
PmEntry:\r
mov eax, cr0\r
btr eax, 31 ; Clear CR0.PG\r
mov cr0, eax ; Disable paging and caches\r
\r
- mov ebx, edx ; Save EntryPoint to rbx, for rdmsr will overwrite rdx\r
mov ecx, 0xc0000080\r
rdmsr\r
and ah, ~ 1 ; Clear LME\r
add esp, 4\r
pop ecx,\r
add esp, 4\r
+\r
+MwaitCheck:\r
cmp cl, 1 ; Check mwait-monitor support\r
jnz HltLoop\r
mov ebx, edx ; Save C-State to ebx\r
shl eax, 4\r
mwait\r
jmp MwaitLoop\r
+\r
HltLoop:\r
+ pop edx ; PM16CodeSegment\r
+ add esp, 4\r
+ pop ebx ; WakeupBuffer\r
+ add esp, 4\r
+ pop eax ; SevEsAPJumpTable\r
+ add esp, 4\r
+ cmp eax, 0 ; Check for SEV-ES\r
+ je DoHlt\r
+\r
+ cli\r
+ ;\r
+ ; SEV-ES is enabled, use VMGEXIT (GHCB information already\r
+ ; set by caller)\r
+ ;\r
+BITS 64\r
+ rep vmmcall\r
+BITS 32\r
+\r
+ ;\r
+ ; Back from VMGEXIT AP_HLT_LOOP\r
+ ; Push the FLAGS/CS/IP values to use\r
+ ;\r
+ push word 0x0002 ; EFLAGS\r
+ xor ecx, ecx\r
+ mov cx, [eax + 2] ; CS\r
+ push cx\r
+ mov cx, [eax] ; IP\r
+ push cx\r
+ push word 0x0000 ; For alignment, will be discarded\r
+\r
+ push edx\r
+ push ebx\r
+\r
+ mov edx, esi ; Restore RDX reset value\r
+\r
+ retf\r
+\r
+DoHlt:\r
cli\r
hlt\r
- jmp HltLoop\r
+ jmp DoHlt\r
+\r
BITS 64\r
AsmRelocateApLoopEnd:\r
\r