All APs use the same common stack to initialization. after initialization, APs should switch to the stack of its own. the sequences are: 1. BSP detects AP count 2. BSP allocates AP stack spaces 3. AP grabs a lock 4. AP SwitchStack 5. AP releases lock
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chen Fan <[email protected]> --- UefiCpuPkg/CpuDxe/CpuMp.c | 45 +++++++++++++++++++++++++++++++---- UefiCpuPkg/CpuDxe/CpuMp.h | 33 ++++++++++++++++++++++++++ UefiCpuPkg/CpuDxe/Ia32/MpAsm.S | 48 ++++++++++++++++++++++++++++++++++++- UefiCpuPkg/CpuDxe/Ia32/MpAsm.nasm | 47 ++++++++++++++++++++++++++++++++++++ UefiCpuPkg/CpuDxe/X64/MpAsm.S | 50 ++++++++++++++++++++++++++++++++++++++- UefiCpuPkg/CpuDxe/X64/MpAsm.nasm | 45 +++++++++++++++++++++++++++++++++++ 6 files changed, 261 insertions(+), 7 deletions(-) diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c index 536f998..9a9c26c 100644 --- a/UefiCpuPkg/CpuDxe/CpuMp.c +++ b/UefiCpuPkg/CpuDxe/CpuMp.c @@ -17,10 +17,34 @@ VOID *mCommonStack = 0; VOID *mTopOfApCommonStack = 0; +VOID *mApStackStart = 0; +UINTN mApStackSize = 0; UINTN mNumberOfProcessors; +UINTN volatile mIndexOfProcessors; BOOLEAN volatile mAllApsInitFinished = FALSE; +UINTN volatile mApDoneCount = 0; +CPU_EXCHANGE_DATA mCpuExchangeData; + +/** + Application Processors do loop routine + after swtich to its own stack + +**/ +VOID +ProcessorToIdleState ( + VOID + ) +{ + DEBUG ((DEBUG_INFO, "detect Apic id: %d\n", + GetApicId())); + + mApDoneCount++; + AsmApReleaseLock (); + + CpuDeadLoop (); +} /** Application Processor C code entry point @@ -38,6 +62,11 @@ ApEntryPointInC ( /* Wait for all Aps complete to initialization */ while (!mAllApsInitFinished); + /* Switch to stack of the Ap's own */ + AsmApSwitchStack (); + + /* never be here */ + ASSERT (FALSE); CpuDeadLoop (); } @@ -51,13 +80,14 @@ InitializeMpSupport ( VOID ) { - mCommonStack = AllocatePages (EFI_SIZE_TO_PAGES (SIZE_64KB)); - mTopOfApCommonStack = (VOID*) ((UINTN)mCommonStack + SIZE_64KB); + mCommonStack = AllocatePages (EFI_SIZE_TO_PAGES (AP_STACK_SIZE)); + mTopOfApCommonStack = (VOID*) ((UINTN)mCommonStack + AP_STACK_SIZE); if (mCommonStack == NULL) { return; } mNumberOfProcessors = 1; + mIndexOfProcessors = 1; StartApsStackless (AsmApEntryPoint); @@ -65,15 +95,20 @@ InitializeMpSupport ( goto EXIT; } - DEBUG ((DEBUG_ERROR, "Detect CPU count: %d\n", mNumberOfProcessors)); + mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES ((mNumberOfProcessors - 1) * AP_STACK_SIZE)); + mApStackSize = AP_STACK_SIZE; + + DEBUG ((DEBUG_ERROR, "Detect CPU count: %d %p\n", mNumberOfProcessors, mApStackStart)); + mCpuExchangeData.ApEntryPoint = (VOID *) (UINTN) ProcessorToIdleState; + mCpuExchangeData.StackStart = (UINTN) mApStackStart; mAllApsInitFinished = TRUE; - CpuDeadLoop (); + while (mApDoneCount != (mNumberOfProcessors - 1)); EXIT: mTopOfApCommonStack = NULL; - FreePages (mCommonStack, EFI_SIZE_TO_PAGES (SIZE_64KB)); + FreePages (mCommonStack, EFI_SIZE_TO_PAGES (AP_STACK_SIZE)); mCommonStack = NULL; } diff --git a/UefiCpuPkg/CpuDxe/CpuMp.h b/UefiCpuPkg/CpuDxe/CpuMp.h index d7bd825..6f0620e 100644 --- a/UefiCpuPkg/CpuDxe/CpuMp.h +++ b/UefiCpuPkg/CpuDxe/CpuMp.h @@ -15,6 +15,8 @@ #ifndef _CPU_MP_H_ #define _CPU_MP_H_ +#define AP_STACK_SIZE SIZE_64KB + /** Initialize Multi-processor support @@ -75,5 +77,36 @@ AsmApDoneWithCommonStack ( VOID ); +typedef struct { + VOID *ApEntryPoint; + UINTN StackStart; +} CPU_EXCHANGE_DATA; + +/** + Switch the common stack of the APs to its own stack which is + calculated by StackStart saved in CPU_EXCHANGE_DATA, and + then call the routine ApEntryPoint in CPU_EXCHANGE_DATA. + + there will hold a AP lock, so should call AsmApReleaseLock to + let others APs run. + +**/ +VOID +EFIAPI +AsmApSwitchStack ( + VOID + ); + +/** + Release the AP lock. + +**/ +VOID +EFIAPI +AsmApReleaseLock ( + VOID + ); + + #endif // _CPU_MP_H_ diff --git a/UefiCpuPkg/CpuDxe/Ia32/MpAsm.S b/UefiCpuPkg/CpuDxe/Ia32/MpAsm.S index bc42c38..8738ade 100644 --- a/UefiCpuPkg/CpuDxe/Ia32/MpAsm.S +++ b/UefiCpuPkg/CpuDxe/Ia32/MpAsm.S @@ -10,7 +10,7 @@ # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # # - +#include "CpuMp.h" # # point to the external interrupt vector table @@ -61,3 +61,49 @@ ASM_PFX(AsmApDoneWithCommonStack): lock btcl $0, ApStackLock ret +#------------------------------------------------------------------------------ +# VOID +# EFIAPI +# AsmApSwitchStack ( +# VOID +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmApSwitchStack) +ASM_PFX(AsmApSwitchStack): + pushl %ebp + movl %esp, %ebp + +AsmApAquireStackLock: +lock btsl $0, ApStackLock + pause + jc AsmApAquireStackLock + + movl (ASM_PFX(mCpuExchangeData) + 04h), %eax + # calculate the new stack top address of each AP's: + # %rsp = NewStack + AP_STACK_SIZE * mIndexOfProcessors + # + movl $AP_STACK_SIZE, %edi + movl ASM_PFX(mIndexOfProcessors), %ebx + imul %edi, %ebx + addl %ebx, %eax + + incl ASM_PFX(mIndexOfProcessors) + + movl %eax, %esp # switch stack + subl $8, %esp + + pushl $0 # keeps gdb from unwinding stack + jmp *(ASM_PFX(mCpuExchangeData)) # call and never return + +#------------------------------------------------------------------------------ +# VOID +# EFIAPI +# AsmApReleaseLock ( +# VOID +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmApReleaseLock) +ASM_PFX(AsmApReleaseLock): +lock btcl $0, ApStackLock + ret + diff --git a/UefiCpuPkg/CpuDxe/Ia32/MpAsm.nasm b/UefiCpuPkg/CpuDxe/Ia32/MpAsm.nasm index 8e0b23f..154b3a5 100644 --- a/UefiCpuPkg/CpuDxe/Ia32/MpAsm.nasm +++ b/UefiCpuPkg/CpuDxe/Ia32/MpAsm.nasm @@ -10,10 +10,13 @@ ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. ; ;------------------------------------------------------------------------------ +#include "CpuMp.h" extern ASM_PFX(mTopOfApCommonStack) extern ASM_PFX(ApEntryPointInC) extern ASM_PFX(mNumberOfProcessors) +extern ASM_PFX(mIndexOfProcessors) +extern ASM_PFX(mCpuExchangeData) ; ; point to the external interrupt vector table @@ -64,3 +67,47 @@ ASM_PFX(AsmApDoneWithCommonStack): lock btc dword [ApStackLock], 0 ret +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmApSwitchStack ( +; VOID +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(AsmApSwitchStack) +ASM_PFX(AsmApSwitchStack): +AsmApAquireStackLock: +lock bts dword [ApStackLock], 0 + pause + jc AsmApAquireStackLock + + ; calculate the new stack top address of each AP's: + ; %rsp = NewStack + AP_STACK_SIZE * mIndexOfProcessors + ; + mov eax, [ASM_PFX(mCpuExchangeData) + 04h] + mov edi, AP_STACK_SIZE + mov ebx, [ASM_PFX(mIndexOfProcessors)] + imul ebx, edi + add eax, ebx + + inc word [ASM_PFX(mIndexOfProcessors)] + + mov esp, eax + sub esp, 8 + + call [ASM_PFX(mCpuExchangeData)] + + ret + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmApReleaseLock ( +; VOID +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(AsmApReleaseLock) +ASM_PFX(AsmApReleaseLock): +lock btc dword[ApStackLock], 0 + ret + diff --git a/UefiCpuPkg/CpuDxe/X64/MpAsm.S b/UefiCpuPkg/CpuDxe/X64/MpAsm.S index bf488d3..83d45e0 100644 --- a/UefiCpuPkg/CpuDxe/X64/MpAsm.S +++ b/UefiCpuPkg/CpuDxe/X64/MpAsm.S @@ -10,7 +10,7 @@ # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # # - +#include "CpuMp.h" # # point to the external interrupt vector table @@ -61,3 +61,51 @@ ASM_PFX(AsmApDoneWithCommonStack): lock btcl $0, ApStackLock ret +#------------------------------------------------------------------------------ +# VOID +# EFIAPI +# AsmApSwitchStack ( +# VOID +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmApSwitchStack) +ASM_PFX(AsmApSwitchStack): + pushq %rbp + movq %rsp, %rbp + +AsmApAquireStackLock: +lock btsl $0, ApStackLock + pause + jc AsmApAquireStackLock + + movl (ASM_PFX(mCpuExchangeData) + 08h), %r9 + # calculate the new stack top address of each AP's: + # %rsp = NewStack + AP_STACK_SIZE * mIndexOfProcessors + # + movl $AP_STACK_SIZE, %edi + movl ASM_PFX(mIndexOfProcessors), %ebx + imul %edi, %ebx + addq %rbx, %r9 + + incl ASM_PFX(mIndexOfProcessors) + # + # Reserve space for register parameters (rcx, rdx, r8 & r9) on the stack, + # in case the caller wishes to spill them. + # + lea -0x20(%r9), %rsp + pushq $0 # keeps gdb from unwinding stack + + jmp *(ASM_PFX(mCpuExchangeData)) # call EntryPoint () + +#------------------------------------------------------------------------------ +# VOID +# EFIAPI +# AsmApReleaseLock ( +# VOID +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmApReleaseLock) +ASM_PFX(AsmApReleaseLock): +lock btcl $0, ApStackLock + ret + diff --git a/UefiCpuPkg/CpuDxe/X64/MpAsm.nasm b/UefiCpuPkg/CpuDxe/X64/MpAsm.nasm index 2de5e9c..46ed107 100644 --- a/UefiCpuPkg/CpuDxe/X64/MpAsm.nasm +++ b/UefiCpuPkg/CpuDxe/X64/MpAsm.nasm @@ -10,10 +10,13 @@ ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. ; ;------------------------------------------------------------------------------ +#include "CpuMp.h" extern ASM_PFX(mTopOfApCommonStack) extern ASM_PFX(ApEntryPointInC) extern ASM_PFX(mNumberOfProcessors) +extern ASM_PFX(mIndexOfProcessors) +extern ASM_PFX(mCpuExchangeData) ; ; point to the external interrupt vector table @@ -64,3 +67,45 @@ ASM_PFX(AsmApDoneWithCommonStack): lock btc dword [ApStackLock], 0 ret +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmApSwitchStack ( +; VOID +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(AsmApSwitchStack) +ASM_PFX(AsmApSwitchStack): +AsmApAquireStackLock: +lock bts dword [ApStackLock], 0 + pause + jc AsmApAquireStackLock + + ; calculate the new stack top address of each AP's: + ; %rsp = NewStack + AP_STACK_SIZE * mIndexOfProcessors + ; + mov r9, [ASM_PFX(mCpuExchangeData) + 08h] + mov edi, AP_STACK_SIZE + mov ebx, [ASM_PFX(mIndexOfProcessors)] + imul ebx, edi + add r9, rbx + + inc dword [ASM_PFX(mIndexOfProcessors)] + + lea rsp, [r9 - 20h] + call [ASM_PFX(mCpuExchangeData)] + + ret + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmApReleaseLock ( +; VOID +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(AsmApReleaseLock) +ASM_PFX(AsmApReleaseLock): +lock btc dword[ApStackLock], 0 + ret + -- 1.9.3 ------------------------------------------------------------------------------ Want excitement? Manually upgrade your production database. When you want reliability, choose Perforce Perforce version control. Predictably reliable. http://pubads.g.doubleclick.net/gampad/clk?id=157508191&iu=/4140/ostg.clktrk _______________________________________________ edk2-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/edk2-devel
