diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm index 1d67f510e9..bfcdbd31c1 100644 --- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm +++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm @@ -179,6 +179,14 @@ ProgramStack: mov esp, dword [edi + CPU_INFO_IN_HOB.ApTopOfStack] CProcedureInvoke: + ; + ; Reserve 4 bytes for CpuMpData. + ; When the AP wakes up again via INIT-SIPI-SIPI, push 0 will cause the existing CpuMpData to be overwritten with 0. + ; CpuMpData is filled in via InitializeApData() during the first time INIT-SIPI-SIPI, + ; while overwirrten may occurs when under ApInHltLoop but InitFlag is not set to ApInitConfig. + ; Therefore reservation is implemented by sub esp instead of push 0. + ; + sub esp, 4 push ebp ; push BIST data at top of AP stack xor ebp, ebp ; clear ebp for call stack trace push ebp diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 041a32e659..1c053f87a4 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -599,6 +599,7 @@ InitializeApData ( { CPU_INFO_IN_HOB *CpuInfoInHob; MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr; + AP_STACK_DATA *ApStackData; CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId (); @@ -606,6 +607,12 @@ InitializeApData ( CpuInfoInHob[ProcessorNumber].Health = BistData; CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack; + // + // AP_STACK_DATA is stored at the top of AP Stack + // + ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA)); + ApStackData->MpData = CpuMpData; + CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE; CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE; @@ -651,6 +658,7 @@ ApWakeupFunction ( CPU_INFO_IN_HOB *CpuInfoInHob; UINT64 ApTopOfStack; UINTN CurrentApicMode; + AP_STACK_DATA *ApStackData; // // AP finished assembly code and begin to execute C code @@ -676,7 +684,9 @@ ApWakeupFunction ( // This is first time AP wakeup, get BIST information from AP stack // ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize; - BistData = *(UINT32 *)((UINTN)ApTopOfStack - sizeof (UINTN)); + ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA)); + BistData = (UINT32)ApStackData->Bist; + // // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment, // to initialize AP in InitConfig path. @@ -1824,14 +1834,22 @@ MpInitLibInitialize ( AsmGetAddressMap (&AddressMap); GetApResetVectorSize (&AddressMap, &ApResetVectorSizeBelow1Mb, &ApResetVectorSizeAbove1Mb); ApStackSize = PcdGet32 (PcdCpuApStackSize); - ApLoopMode = GetApLoopMode (&MonitorFilterSize); + // + // ApStackSize must be power of 2 + // + ASSERT ((ApStackSize & (ApStackSize - 1)) == 0); + ApLoopMode = GetApLoopMode (&MonitorFilterSize); // // Save BSP's Control registers for APs. // SaveVolatileRegisters (&VolatileRegisters); - BufferSize = ApStackSize * MaxLogicalProcessorNumber; + BufferSize = ApStackSize * MaxLogicalProcessorNumber; + // + // Allocate extra ApStackSize to let AP stack align on ApStackSize bounday + // + BufferSize += ApStackSize; BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber; BufferSize += ApResetVectorSizeBelow1Mb; BufferSize = ALIGN_VALUE (BufferSize, 8); @@ -1841,13 +1859,13 @@ MpInitLibInitialize ( MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize)); ASSERT (MpBuffer != NULL); ZeroMem (MpBuffer, BufferSize); - Buffer = (UINTN)MpBuffer; + Buffer = ALIGN_VALUE ((UINTN)MpBuffer, ApStackSize); // - // The layout of the Buffer is as below: + // The layout of the Buffer is as below (lower address on top): // - // +--------------------+ <-- Buffer - // AP Stacks (N) + // +--------------------+ <-- Buffer (Pointer of CpuMpData is stored in the top of each AP's stack.) + // AP Stacks (N) (StackTop = (RSP + ApStackSize) & ~ApStackSize)) // +--------------------+ <-- MonitorBuffer // AP Monitor Filters (N) // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer) @@ -1855,7 +1873,7 @@ MpInitLibInitialize ( // +--------------------+ // Padding // +--------------------+ <-- ApIdtBase (8-byte boundary) - // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base. + // AP IDT All APs share one separate IDT. // +--------------------+ <-- CpuMpData // CPU_MP_DATA // +--------------------+ <-- CpuMpData->CpuData @@ -1892,10 +1910,11 @@ MpInitLibInitialize ( // // Make sure no memory usage outside of the allocated buffer. + // (ApStackSize - (Buffer - (UINTN)MpBuffer)) is the redundant caused by alignment // ASSERT ( (CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) == - Buffer + BufferSize + (UINTN)MpBuffer + BufferSize - (ApStackSize - Buffer + (UINTN)MpBuffer) ); // diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index 47b722cb2f..f5086e497e 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -301,6 +301,14 @@ struct _CPU_MP_DATA { UINT64 GhcbBase; }; +// +// AP_STACK_DATA is stored at the top of each AP stack. +// +typedef struct { + UINTN Bist; + CPU_MP_DATA *MpData; +} AP_STACK_DATA; + #define AP_SAFE_STACK_SIZE 128 #define AP_RESET_STACK_SIZE AP_SAFE_STACK_SIZE diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c index 65400b95a2..e732371ddd 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c @@ -89,7 +89,7 @@ EnableDebugAgent ( /** Get pointer to CPU MP Data structure. For BSP, the pointer is retrieved from HOB. - For AP, the structure is just after IDT. + For AP, the structure is stored in the top of each AP's stack. @return The pointer to CPU MP Data structure. **/ @@ -100,15 +100,17 @@ GetCpuMpData ( { CPU_MP_DATA *CpuMpData; MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr; - IA32_DESCRIPTOR Idtr; + UINTN ApTopOfStack; + AP_STACK_DATA *ApStackData; ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE); if (ApicBaseMsr.Bits.BSP == 1) { CpuMpData = GetCpuMpDataFromGuidedHob (); ASSERT (CpuMpData != NULL); } else { - AsmReadIdtr (&Idtr); - CpuMpData = (CPU_MP_DATA *)(Idtr.Base + Idtr.Limit + 1); + ApTopOfStack = ALIGN_VALUE ((UINTN)&ApTopOfStack, (UINTN)PcdGet32 (PcdCpuApStackSize)); + ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack- sizeof (AP_STACK_DATA)); + CpuMpData = (CPU_MP_DATA *)ApStackData->MpData; } return CpuMpData; diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm index b7f8d48504..5d71995bf8 100644 --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm @@ -239,11 +239,20 @@ ProgramStack: mov rsp, qword [rdi + CPU_INFO_IN_HOB.ApTopOfStack] CProcedureInvoke: + ; + ; Reserve 8 bytes for CpuMpData. + ; When the AP wakes up again via INIT-SIPI-SIPI, push 0 will cause the existing CpuMpData to be overwritten with 0. + ; CpuMpData is filled in via InitializeApData() during the first time INIT-SIPI-SIPI, + ; while overwirrten may occurs when under ApInHltLoop but InitFlag is not set to ApInitConfig. + ; Therefore reservation is implemented by sub rsp instead of push 0. + ; + sub rsp, 8 push rbp ; Push BIST data at top of AP stack xor rbp, rbp ; Clear ebp for call stack trace push rbp mov rbp, rsp + push qword 0 ; Push 8 bytes for alignment mov rax, qword [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitializeFloatingPointUnits)] sub rsp, 20h call rax ; Call assembly function to initialize FPU per UEFI spec