## @file\r
# MP Initialize Library instance for DXE driver.\r
#\r
-# Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
##\r
[Sources.IA32]\r
Ia32/AmdSev.c\r
Ia32/MpFuncs.nasm\r
+ Ia32/CreatePageTable.c\r
\r
[Sources.X64]\r
X64/AmdSev.c\r
+ X64/CreatePageTable.c\r
X64/MpFuncs.nasm\r
\r
[Sources.common]\r
CcExitLib\r
MicrocodeLib\r
\r
+[LibraryClasses.X64]\r
+ CpuPageTableLib\r
+\r
[Protocols]\r
gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES\r
\r
VOID *mReservedApLoopFunc = NULL;\r
UINTN mReservedTopOfApStack;\r
volatile UINT32 mNumberToFinish = 0;\r
+UINTN mApPageTable;\r
\r
//\r
// Begin wakeup buffer allocation below 0x88000\r
AsmRelocateApLoopFunc (\r
MwaitSupport,\r
CpuMpData->ApTargetCState,\r
- CpuMpData->PmCodeSegment,\r
StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
(UINTN)&mNumberToFinish,\r
- CpuMpData->Pm16CodeSegment,\r
- CpuMpData->SevEsAPBuffer,\r
- CpuMpData->WakeupBuffer\r
+ mApPageTable\r
);\r
}\r
\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS Address;\r
UINTN ApSafeBufferSize;\r
UINTN Index;\r
EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
// Allocating it in advance since memory services are not available in\r
// Exit Boot Services callback function.\r
//\r
- ApSafeBufferSize = EFI_PAGES_TO_SIZE (\r
- EFI_SIZE_TO_PAGES (\r
- CpuMpData->AddressMap.RelocateApLoopFuncSize\r
- )\r
- );\r
- Address = BASE_4GB - 1;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiReservedMemoryType,\r
- EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
- &Address\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- mReservedApLoopFunc = (VOID *)(UINTN)Address;\r
- ASSERT (mReservedApLoopFunc != NULL);\r
-\r
- //\r
- // Make sure that the buffer memory is executable if NX protection is enabled\r
- // for EfiReservedMemoryType.\r
- //\r
- // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD\r
- // service.\r
+ // +------------+\r
+ // | Ap Loop |\r
+ // +------------+\r
+ // | Stack * N |\r
+ // +------------+ (low address)\r
//\r
- Status = gDS->GetMemorySpaceDescriptor (Address, &MemDesc);\r
- if (!EFI_ERROR (Status)) {\r
- gDS->SetMemorySpaceAttributes (\r
- Address,\r
- ApSafeBufferSize,\r
- MemDesc.Attributes & (~EFI_MEMORY_XP)\r
- );\r
- }\r
-\r
ApSafeBufferSize = EFI_PAGES_TO_SIZE (\r
EFI_SIZE_TO_PAGES (\r
CpuMpData->CpuCount * AP_SAFE_STACK_SIZE\r
+ + CpuMpData->AddressMap.RelocateApLoopFuncSize\r
)\r
);\r
- Address = BASE_4GB - 1;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiReservedMemoryType,\r
- EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
- &Address\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
\r
- mReservedTopOfApStack = (UINTN)Address + ApSafeBufferSize;\r
+ mReservedTopOfApStack = (UINTN)AllocateReservedPages (EFI_SIZE_TO_PAGES (ApSafeBufferSize));\r
+ ASSERT (mReservedTopOfApStack != 0);\r
ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
- CopyMem (\r
- mReservedApLoopFunc,\r
- CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
- CpuMpData->AddressMap.RelocateApLoopFuncSize\r
- );\r
+ ASSERT ((AP_SAFE_STACK_SIZE & (CPU_STACK_ALIGNMENT - 1)) == 0);\r
+\r
+ mReservedApLoopFunc = (VOID *)(mReservedTopOfApStack + CpuMpData->CpuCount * AP_SAFE_STACK_SIZE);\r
+ if (StandardSignatureIsAuthenticAMD ()) {\r
+ CopyMem (\r
+ mReservedApLoopFunc,\r
+ CpuMpData->AddressMap.RelocateApLoopFuncAddressAmd,\r
+ CpuMpData->AddressMap.RelocateApLoopFuncSizeAmd\r
+ );\r
+ } else {\r
+ CopyMem (\r
+ mReservedApLoopFunc,\r
+ CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
+ CpuMpData->AddressMap.RelocateApLoopFuncSize\r
+ );\r
+\r
+ mApPageTable = CreatePageTable (\r
+ mReservedTopOfApStack,\r
+ ApSafeBufferSize\r
+ );\r
+ }\r
+\r
+ mReservedTopOfApStack += CpuMpData->CpuCount * AP_SAFE_STACK_SIZE;\r
\r
Status = gBS->CreateEvent (\r
EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
--- /dev/null
+/** @file\r
+ Function to create page talbe.\r
+ Only create page table for x64, and leave the CreatePageTable empty for Ia32.\r
+\r
+ Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+\r
+/**\r
+ Only create page table for x64, and leave the CreatePageTable empty for Ia32.\r
+\r
+ @param[in] LinearAddress The start of the linear address range.\r
+ @param[in] Length The length of the linear address range.\r
+\r
+ @return The page table to be created.\r
+**/\r
+UINTN\r
+CreatePageTable (\r
+ IN UINTN Address,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ return 0;\r
+}\r
(EFIAPI *ASM_RELOCATE_AP_LOOP)(\r
IN BOOLEAN MwaitSupport,\r
IN UINTN ApTargetCState,\r
- IN UINTN PmCodeSegment,\r
IN UINTN TopOfApStack,\r
IN UINTN NumberToFinish,\r
- IN UINTN Pm16CodeSegment,\r
- IN UINTN SevEsAPJumpTable,\r
- IN UINTN WakeupBuffer\r
+ IN UINTN Cr3\r
);\r
\r
/**\r
IN BOOLEAN WakeUpDisabledAps\r
);\r
\r
+/**\r
+ Create 1:1 mapping page table in reserved memory to map the specified address range.\r
+\r
+ @param[in] LinearAddress The start of the linear address range.\r
+ @param[in] Length The length of the linear address range.\r
+\r
+ @return The page table to be created.\r
+**/\r
+UINTN\r
+CreatePageTable (\r
+ IN UINTN Address,\r
+ IN UINTN Length\r
+ );\r
+\r
/**\r
Initialize global data for MP support.\r
\r
--- /dev/null
+/** @file\r
+ Function to create page talbe.\r
+ Only create page table for x64, and leave the CreatePageTable empty for Ia32.\r
+\r
+ Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#include <Library/CpuPageTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Base.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+/**\r
+ Create 1:1 mapping page table in reserved memory to map the specified address range.\r
+\r
+ @param[in] LinearAddress The start of the linear address range.\r
+ @param[in] Length The length of the linear address range.\r
+\r
+ @return The page table to be created.\r
+**/\r
+UINTN\r
+CreatePageTable (\r
+ IN UINTN Address,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *PageTableBuffer;\r
+ UINTN PageTableBufferSize;\r
+ UINTN PageTable;\r
+\r
+ IA32_MAP_ATTRIBUTE MapAttribute;\r
+ IA32_MAP_ATTRIBUTE MapMask;\r
+\r
+ MapAttribute.Uint64 = Address;\r
+ MapAttribute.Bits.Present = 1;\r
+ MapAttribute.Bits.ReadWrite = 1;\r
+\r
+ MapMask.Bits.PageTableBaseAddress = 1;\r
+ MapMask.Bits.Present = 1;\r
+ MapMask.Bits.ReadWrite = 1;\r
+\r
+ PageTable = 0;\r
+ PageTableBufferSize = 0;\r
+\r
+ Status = PageTableMap (\r
+ &PageTable,\r
+ Paging4Level,\r
+ NULL,\r
+ &PageTableBufferSize,\r
+ Address,\r
+ Length,\r
+ &MapAttribute,\r
+ &MapMask\r
+ );\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+ DEBUG ((DEBUG_INFO, "AP Page Table Buffer Size = %x\n", PageTableBufferSize));\r
+\r
+ PageTableBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (PageTableBufferSize));\r
+ ASSERT (PageTableBuffer != NULL);\r
+ Status = PageTableMap (\r
+ &PageTable,\r
+ Paging4Level,\r
+ PageTableBuffer,\r
+ &PageTableBufferSize,\r
+ Address,\r
+ Length,\r
+ &MapAttribute,\r
+ &MapMask\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ return PageTable;\r
+}\r
RendezvousFunnelProcEnd:\r
\r
;-------------------------------------------------------------------------------------\r
-; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, TopOfApStack, CountTofinish, Cr3);\r
+; This function is called during the finalizaiton of Mp initialization before booting\r
+; to OS, and aim to put Aps either in Mwait or HLT.\r
;-------------------------------------------------------------------------------------\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
- mov rax, 114 ; Set SwExitCode valid bit\r
- bts [rdx + 0x3f0], rax\r
- inc rax ; Set SwExitInfo1 valid bit\r
- bts [rdx + 0x3f0], rax\r
- inc rax ; Set SwExitInfo2 valid bit\r
- bts [rdx + 0x3f0], rax\r
+; +----------------+\r
+; | Cr3 | rsp+40\r
+; +----------------+\r
+; | CountTofinish | r9\r
+; +----------------+\r
+; | TopOfApStack | r8\r
+; +----------------+\r
+; | ApTargetCState | rdx\r
+; +----------------+\r
+; | MwaitSupport | rcx\r
+; +----------------+\r
+; | the return |\r
+; +----------------+ low address\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
+AsmRelocateApLoopStart:\r
+ mov rax, r9 ; CountTofinish\r
lock dec dword [rax] ; (*CountTofinish)--\r
\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 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
- retfq\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 ecx, 0xc0000080\r
- rdmsr\r
- and ah, ~ 1 ; Clear LME\r
- wrmsr\r
- mov eax, cr4\r
- and al, ~ (1 << 5) ; Clear PAE\r
- mov cr4, eax\r
-\r
- pop edx\r
- add esp, 4\r
- pop ecx,\r
- add esp, 4\r
+ mov rax, [rsp + 40] ; Cr3\r
+ ; Do not push on old stack, since old stack is not mapped\r
+ ; in the page table pointed by cr3\r
+ mov cr3, rax\r
+ mov rsp, r8 ; TopOfApStack\r
\r
MwaitCheck:\r
cmp cl, 1 ; Check mwait-monitor support\r
jnz HltLoop\r
- mov ebx, edx ; Save C-State to ebx\r
+ mov rbx, rdx ; Save C-State to ebx\r
+\r
MwaitLoop:\r
cli\r
- mov eax, esp ; Set Monitor Address\r
+ mov rax, rsp ; Set Monitor Address\r
xor ecx, ecx ; ecx = 0\r
xor edx, edx ; edx = 0\r
monitor\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 DoHlt\r
+ jmp HltLoop\r
\r
-BITS 64\r
AsmRelocateApLoopEnd:\r
\r
;-------------------------------------------------------------------------------------\r
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf\r
+ CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf\r
MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf\r
RegisterCpuFeaturesLib|UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf\r
CpuCacheInfoLib|UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf\r