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

Reply via email to