## @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 - 2023, 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/MpFuncs.nasm\r
+ X64/CreatePageTable.c\r
\r
[Sources.common]\r
AmdSev.c\r
PcdLib\r
CcExitLib\r
MicrocodeLib\r
+[LibraryClasses.X64]\r
+ CpuPageTableLib\r
\r
[Protocols]\r
gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES\r
RELOCATE_AP_LOOP_ENTRY mReservedApLoop;\r
UINTN mReservedTopOfApStack;\r
volatile UINT32 mNumberToFinish = 0;\r
+UINTN mApPageTable;\r
\r
//\r
// Begin wakeup buffer allocation below 0x88000\r
mReservedApLoop.GenericEntry (\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
EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
UINTN StackBase;\r
CPU_INFO_IN_HOB *CpuInfoInHob;\r
+ MP_ASSEMBLY_ADDRESS_MAP *AddressMap;\r
+ UINT8 *ApLoopFunc;\r
+ UINTN ApLoopFuncSize;\r
UINTN StackPages;\r
UINTN FuncPages;\r
\r
}\r
}\r
\r
+ AddressMap = &CpuMpData->AddressMap;\r
+ if (CpuMpData->UseSevEsAPMethod) {\r
+ //\r
+ // 64-bit AMD processors with SEV-ES\r
+ //\r
+ Address = BASE_4GB - 1;\r
+ ApLoopFunc = AddressMap->RelocateApLoopFuncAddress;\r
+ ApLoopFuncSize = AddressMap->RelocateApLoopFuncSize;\r
+ } else {\r
+ //\r
+ // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES\r
+ //\r
+ Address = MAX_ADDRESS;\r
+ ApLoopFunc = AddressMap->RelocateApLoopFuncAddressGeneric;\r
+ ApLoopFuncSize = AddressMap->RelocateApLoopFuncSizeGeneric;\r
+ }\r
+\r
//\r
// Avoid APs access invalid buffer data which allocated by BootServices,\r
// so we will allocate reserved data for AP loop code. We also need to\r
//\r
\r
StackPages = EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * AP_SAFE_STACK_SIZE);\r
- FuncPages = EFI_SIZE_TO_PAGES (CpuMpData->AddressMap.RelocateApLoopFuncSize);\r
-\r
- Address = BASE_4GB - 1;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiReservedMemoryType,\r
- StackPages + FuncPages,\r
- &Address\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
+ FuncPages = EFI_SIZE_TO_PAGES (ApLoopFuncSize);\r
\r
- mReservedApLoop.Data = (VOID *)(UINTN)Address;\r
- ASSERT (mReservedApLoop.Data != NULL);\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiReservedMemoryType,\r
+ StackPages + FuncPages,\r
+ &Address\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
\r
//\r
// Make sure that the buffer memory is executable if NX protection is enabled\r
\r
mReservedTopOfApStack = (UINTN)Address + EFI_PAGES_TO_SIZE (StackPages+FuncPages);\r
ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
- CopyMem (\r
- mReservedApLoop.Data,\r
- CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
- CpuMpData->AddressMap.RelocateApLoopFuncSize\r
- );\r
+ mReservedApLoop.Data = (VOID *)(UINTN)Address;\r
+ ASSERT (mReservedApLoop.Data != NULL);\r
+ CopyMem (mReservedApLoop.Data, ApLoopFunc, ApLoopFuncSize);\r
+ if (!CpuMpData->UseSevEsAPMethod) {\r
+ //\r
+ // processors without SEV-ES\r
+ //\r
+ mApPageTable = CreatePageTable (\r
+ (UINTN)Address,\r
+ EFI_PAGES_TO_SIZE (StackPages+FuncPages)\r
+ );\r
+ }\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
+ Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Base.h>\r
+\r
+/**\r
+ Only create page table for x64, and leave the CreatePageTable empty for Ia32.\r
+ @param[in] LinearAddress The start of the linear address range.\r
+ @param[in] Length The length of the linear address range.\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
;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.<BR>\r
; SPDX-License-Identifier: BSD-2-Clause-Patent\r
;\r
; Module Name:\r
RendezvousFunnelProcEnd:\r
\r
;-------------------------------------------------------------------------------------\r
-; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);\r
+; AsmRelocateApLoopGeneric (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
-AsmRelocateApLoopStart:\r
+AsmRelocateApLoopGenericStart:\r
mov eax, esp\r
- mov esp, [eax + 16] ; TopOfApStack\r
+ mov esp, [eax + 12] ; TopOfApStack\r
push dword [eax] ; push return address for stack trace\r
push ebp\r
mov ebp, esp\r
mov ebx, [eax + 8] ; ApTargetCState\r
mov ecx, [eax + 4] ; MwaitSupport\r
- mov eax, [eax + 20] ; CountTofinish\r
+ mov eax, [eax + 16] ; CountTofinish\r
lock dec dword [eax] ; (*CountTofinish)--\r
cmp cl, 1 ; Check mwait-monitor support\r
- jnz HltLoop\r
-MwaitLoop:\r
+ jnz HltLoopGeneric\r
+MwaitLoopGeneric:\r
cli\r
mov eax, esp\r
xor ecx, ecx\r
mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]\r
shl eax, 4\r
mwait\r
- jmp MwaitLoop\r
-HltLoop:\r
+ jmp MwaitLoopGeneric\r
+HltLoopGeneric:\r
cli\r
hlt\r
- jmp HltLoop\r
-AsmRelocateApLoopEnd:\r
+ jmp HltLoopGeneric\r
+AsmRelocateApLoopGenericEnd:\r
\r
;-------------------------------------------------------------------------------------\r
; AsmGetAddressMap (&AddressMap);\r
mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], RendezvousFunnelProcStart\r
mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], Flat32Start - RendezvousFunnelProcStart\r
mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
- mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], AsmRelocateApLoopStart\r
- mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddressGeneric], AsmRelocateApLoopGenericStart\r
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSizeGeneric], AsmRelocateApLoopGenericEnd - AsmRelocateApLoopGenericStart\r
mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart\r
mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start\r
mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], 0\r
;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.<BR>\r
; SPDX-License-Identifier: BSD-2-Clause-Patent\r
;\r
; Module Name:\r
; Equivalent NASM structure of MP_ASSEMBLY_ADDRESS_MAP\r
;\r
struc MP_ASSEMBLY_ADDRESS_MAP\r
- .RendezvousFunnelAddress CTYPE_UINTN 1\r
- .ModeEntryOffset CTYPE_UINTN 1\r
- .RendezvousFunnelSize CTYPE_UINTN 1\r
- .RelocateApLoopFuncAddress CTYPE_UINTN 1\r
- .RelocateApLoopFuncSize CTYPE_UINTN 1\r
- .ModeTransitionOffset CTYPE_UINTN 1\r
- .SwitchToRealNoNxOffset CTYPE_UINTN 1\r
- .SwitchToRealPM16ModeOffset CTYPE_UINTN 1\r
- .SwitchToRealPM16ModeSize CTYPE_UINTN 1\r
+ .RendezvousFunnelAddress CTYPE_UINTN 1\r
+ .ModeEntryOffset CTYPE_UINTN 1\r
+ .RendezvousFunnelSize CTYPE_UINTN 1\r
+ .RelocateApLoopFuncAddressGeneric CTYPE_UINTN 1\r
+ .RelocateApLoopFuncSizeGeneric CTYPE_UINTN 1\r
+ .RelocateApLoopFuncAddress CTYPE_UINTN 1\r
+ .RelocateApLoopFuncSize CTYPE_UINTN 1\r
+ .ModeTransitionOffset CTYPE_UINTN 1\r
+ .SwitchToRealNoNxOffset CTYPE_UINTN 1\r
+ .SwitchToRealPM16ModeOffset CTYPE_UINTN 1\r
+ .SwitchToRealPM16ModeSize CTYPE_UINTN 1\r
endstruc\r
\r
;\r
UINT8 *RendezvousFunnelAddress;\r
UINTN ModeEntryOffset;\r
UINTN RendezvousFunnelSize;\r
+ UINT8 *RelocateApLoopFuncAddressGeneric;\r
+ UINTN RelocateApLoopFuncSizeGeneric;\r
UINT8 *RelocateApLoopFuncAddress;\r
UINTN RelocateApLoopFuncSize;\r
UINTN ModeTransitionOffset;\r
@param[in] ApTargetCState Target C-State value.\r
@param[in] PmCodeSegment Protected mode code segment value.\r
**/\r
+typedef\r
+ VOID\r
+(EFIAPI *ASM_RELOCATE_AP_LOOP_GENERIC)(\r
+ IN BOOLEAN MwaitSupport,\r
+ IN UINTN ApTargetCState,\r
+ IN UINTN TopOfApStack,\r
+ IN UINTN NumberToFinish,\r
+ IN UINTN Cr3\r
+ );\r
+\r
+/**\r
+ Assembly code to place AP into safe loop mode for Amd processors\r
+ with Sev enabled.\r
+ Place AP into targeted C-State if MONITOR is supported, otherwise\r
+ place AP into hlt state.\r
+ Place AP in protected mode if the current is long mode. Due to AP maybe\r
+ wakeup by some hardware event. It could avoid accessing page table that\r
+ may not available during booting to OS.\r
+ @param[in] MwaitSupport TRUE indicates MONITOR is supported.\r
+ FALSE indicates MONITOR is not supported.\r
+ @param[in] ApTargetCState Target C-State value.\r
+ @param[in] PmCodeSegment Protected mode code segment value.\r
+**/\r
typedef\r
VOID\r
(EFIAPI *ASM_RELOCATE_AP_LOOP)(\r
);\r
\r
typedef union {\r
- VOID *Data;\r
- ASM_RELOCATE_AP_LOOP AmdSevEntry; // 64-bit AMD Sev processors\r
- ASM_RELOCATE_AP_LOOP GenericEntry; // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or AMD non-Sev processors\r
+ VOID *Data;\r
+ ASM_RELOCATE_AP_LOOP AmdSevEntry; // 64-bit AMD Sev processors\r
+ ASM_RELOCATE_AP_LOOP_GENERIC GenericEntry; // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or AMD non-Sev processors\r
} RELOCATE_AP_LOOP_ENTRY;\r
\r
/**\r
VOID\r
);\r
\r
+/**\r
+ Create 1:1 mapping page table in reserved memory to map the specified address range.\r
+ @param[in] LinearAddress The start of the linear address range.\r
+ @param[in] Length The length of the linear address range.\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
This function will be called by BSP to wakeup AP.\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
+ Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\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
+#include <Library/BaseLib.h>\r
+\r
+/**\r
+ Create 1:1 mapping page table in reserved memory to map the specified address range.\r
+ @param[in] LinearAddress The start of the linear address range.\r
+ @param[in] Length The length of the linear address range.\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
+ PAGING_MODE PagingMode;\r
+ IA32_CR4 Cr4;\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
+ Cr4.UintN = AsmReadCr4 ();\r
+\r
+ if (Cr4.Bits.LA57 == 1) {\r
+ PagingMode = Paging5Level;\r
+ } else {\r
+ PagingMode = Paging4Level;\r
+ }\r
+\r
+ Status = PageTableMap (\r
+ &PageTable,\r
+ PagingMode,\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
+ PagingMode,\r
+ PageTableBuffer,\r
+ &PageTableBufferSize,\r
+ Address,\r
+ Length,\r
+ &MapAttribute,\r
+ &MapMask\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ return PageTable;\r
+}\r
;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.<BR>\r
; SPDX-License-Identifier: BSD-2-Clause-Patent\r
;\r
; Module Name:\r
BITS 64\r
AsmRelocateApLoopEnd:\r
\r
+;-------------------------------------------------------------------------------------\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
+; +----------------+\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
+AsmRelocateApLoopGenericStart:\r
+ mov rax, r9 ; CountTofinish\r
+ lock dec dword [rax] ; (*CountTofinish)--\r
+\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
+MwaitCheckGeneric:\r
+ cmp cl, 1 ; Check mwait-monitor support\r
+ jnz HltLoopGeneric\r
+ mov rbx, rdx ; Save C-State to ebx\r
+\r
+MwaitLoopGeneric:\r
+ cli\r
+ mov rax, rsp ; Set Monitor Address\r
+ xor ecx, ecx ; ecx = 0\r
+ xor edx, edx ; edx = 0\r
+ monitor\r
+ mov rax, rbx ; Mwait Cx, Target C-State per eax[7:4]\r
+ shl eax, 4\r
+ mwait\r
+ jmp MwaitLoopGeneric\r
+\r
+HltLoopGeneric:\r
+ cli\r
+ hlt\r
+ jmp HltLoopGeneric\r
+\r
+AsmRelocateApLoopGenericEnd:\r
+\r
;-------------------------------------------------------------------------------------\r
; AsmGetAddressMap (&AddressMap);\r
;-------------------------------------------------------------------------------------\r
mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], rax\r
mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], LongModeStart - RendezvousFunnelProcStart\r
mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
+lea rax, [AsmRelocateApLoopGenericStart]\r
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddressGeneric], rax\r
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSizeGeneric], AsmRelocateApLoopGenericEnd - AsmRelocateApLoopGenericStart\r
lea rax, [AsmRelocateApLoopStart]\r
mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], rax\r
mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r