UefiCpuPkg/MpInitLib: Program AP stack in fixed address
authorJeff Fan <jeff.fan@intel.com>
Mon, 14 Nov 2016 03:38:25 +0000 (11:38 +0800)
committerJeff Fan <jeff.fan@intel.com>
Wed, 16 Nov 2016 08:28:22 +0000 (16:28 +0800)
Currently, MpInitLib will program AP stack in dynamic address. Each processor
will calculate its stack address by adding stack size based on the last stack
address. That means AP may have the different stack address everytime it is
wakeup by INIT-SIPI-SIPI.

When all APs have wakeup to execute AP task, each each has been assigned one
stack address. Once the timeout happened on some of APs, BSP will send INIT-
SIPI-SIPI to wake up APs. We need to re-assign stack for APs. Based on the
current implementation, we might assign one stack address used by other APs.
It will cause the unexpected stack overlapped issue.

This fix changed the stack assignment policy. We will record the stack address
assigned to AP at first time AP wakeup. When AP failed on AP task, BSP could
reassigned the same stack for it.

Getting initial APIC ID in assembly code could help AP to get saved its stack
address.

Cc: Feng Tian <feng.tian@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/Library/MpInitLib/MpLib.h
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm

index 8f6f0bfd5b935b297fc34a0b73c86c9ffcd39f2e..4bfa084c85a91457a1e60bc5cb5be217ca6fb3a7 100644 (file)
@@ -114,7 +114,12 @@ Flat32Start:                                   ; protected mode entry point
     mov         cr0, eax\r
 \r
 SkipEnableExecuteDisable:\r
+    mov        edi, esi\r
+    add        edi, InitFlagLocation\r
+    cmp        dword [edi], 1       ; 1 == ApInitConfig\r
+    jnz        GetApicId\r
 \r
+    ; AP init\r
     mov        edi, esi\r
     add        edi, LockLocation\r
     mov        eax, NotVacantFlag\r
@@ -124,27 +129,65 @@ TestLock:
     cmp        eax, NotVacantFlag\r
     jz         TestLock\r
 \r
-    mov        edi, esi\r
-    add        edi, NumApsExecutingLocation\r
-    inc        dword [edi]\r
-    mov        ebx, [edi]\r
+    mov        ecx, esi\r
+    add        ecx, NumApsExecutingLocation\r
+    inc        dword [ecx]\r
+    mov        ebx, [ecx]\r
+\r
+Releaselock:\r
+    mov        eax, VacantFlag\r
+    xchg       [edi], eax\r
 \r
-ProgramStack:\r
     mov        edi, esi\r
     add        edi, StackSizeLocation\r
     mov        eax, [edi]\r
+    mov        ecx, ebx\r
+    inc        ecx\r
+    mul        ecx                               ; EAX = StackSize * (CpuNumber + 1)\r
     mov        edi, esi\r
     add        edi, StackStartAddressLocation\r
     add        eax, [edi]\r
     mov        esp, eax\r
-    mov        [edi], eax\r
+    jmp        CProcedureInvoke\r
+\r
+GetApicId:\r
+    mov        eax, 0\r
+    cpuid\r
+    cmp        eax, 0bh\r
+    jnb        X2Apic\r
+    ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
+    mov        eax, 1\r
+    cpuid\r
+    shr        ebx, 24\r
+    mov        edx, ebx\r
+    jmp        GetProcessorNumber\r
+\r
+X2Apic:\r
+    ; Processor is x2APIC capable, so get 32-bit x2APIC ID\r
+    mov        eax, 0bh\r
+    xor        ecx, ecx\r
+    cpuid                   \r
+    ; edx save x2APIC ID\r
+    \r
+GetProcessorNumber:\r
+    ;\r
+    ; Get processor number for this AP\r
+    ; Note that BSP may become an AP due to SwitchBsp()\r
+    ;\r
+    xor         ebx, ebx\r
+    lea         eax, [esi + CpuInfoLocation]\r
+    mov         edi, [eax]\r
 \r
-Releaselock:\r
-    mov        eax, VacantFlag\r
-    mov        edi, esi\r
-    add        edi, LockLocation\r
-    xchg       [edi], eax\r
+GetNextProcNumber:\r
+    cmp         [edi], edx                       ; APIC ID match?\r
+    jz          ProgramStack\r
+    add         edi, 16\r
+    inc         ebx\r
+    jmp         GetNextProcNumber    \r
 \r
+ProgramStack:\r
+    mov         esp, [edi + 12]\r
+   \r
 CProcedureInvoke:\r
     push       ebp               ; push BIST data at top of AP stack\r
     xor        ebp, ebp          ; clear ebp for call stack trace\r
index 2fde765744eabd0fa14cec00e9576f555a714a67..fd32482d5515413044fa46821dd9b000cd471a4e 100644 (file)
@@ -432,7 +432,8 @@ VOID
 InitializeApData (\r
   IN OUT CPU_MP_DATA      *CpuMpData,\r
   IN     UINTN            ProcessorNumber,\r
-  IN     UINT32           BistData\r
+  IN     UINT32           BistData,\r
+  IN     UINTN            ApTopOfStack\r
   )\r
 {\r
   CPU_INFO_IN_HOB          *CpuInfoInHob;\r
@@ -441,6 +442,7 @@ InitializeApData (
   CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
   CpuInfoInHob[ProcessorNumber].ApicId        = GetApicId ();\r
   CpuInfoInHob[ProcessorNumber].Health        = BistData;\r
+  CpuInfoInHob[ProcessorNumber].ApTopOfStack  = (UINT32) ApTopOfStack;\r
 \r
   CpuMpData->CpuData[ProcessorNumber].Waiting    = FALSE;\r
   CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
@@ -478,6 +480,7 @@ ApWakeupFunction (
   UINT32                     BistData;\r
   volatile UINT32            *ApStartupSignalBuffer;\r
   CPU_INFO_IN_HOB            *CpuInfoInHob;\r
+  UINTN                      ApTopOfStack;\r
 \r
   //\r
   // AP finished assembly code and begin to execute C code\r
@@ -496,7 +499,8 @@ ApWakeupFunction (
       //\r
       // This is first time AP wakeup, get BIST information from AP stack\r
       //\r
-      BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));\r
+      ApTopOfStack  = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;\r
+      BistData = *(UINT32 *) (ApTopOfStack - sizeof (UINTN));\r
       //\r
       // Do some AP initialize sync\r
       //\r
@@ -505,7 +509,7 @@ ApWakeupFunction (
       // Sync BSP's Control registers to APs\r
       //\r
       RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
-      InitializeApData (CpuMpData, ProcessorNumber, BistData);\r
+      InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);\r
       ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
     } else {\r
       //\r
@@ -1194,7 +1198,7 @@ MpInitLibInitialize (
   //\r
   // Set BSP basic information\r
   //\r
-  InitializeApData (CpuMpData, 0, 0);\r
+  InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer);\r
   //\r
   // Save assembly code information\r
   //\r
index a58c855a6c2012973d10206e29637658a9e7e160..f81c819c3445a6c15cbca9e409d1f9d2b270cef4 100644 (file)
@@ -133,6 +133,7 @@ typedef struct {
   UINT32                         InitialApicId;\r
   UINT32                         ApicId;\r
   UINT32                         Health;\r
+  UINT32                         ApTopOfStack;\r
 } CPU_INFO_IN_HOB;\r
 \r
 //\r
index 090e9fae07cd793d2266939aee0f2b11f75877f4..bfc3ff1f5c7af7122a6a2546ff795169936720c1 100644 (file)
@@ -119,6 +119,12 @@ LongModeStart:
     mov        es,  ax\r
     mov        ss,  ax\r
 \r
+    mov        esi, ebx\r
+    lea        edi, [esi + InitFlagLocation]\r
+    cmp        qword [edi], 1       ; ApInitConfig\r
+    jnz        GetApicId\r
+\r
+    ; AP init\r
     mov        esi, ebx\r
     mov        edi, esi\r
     add        edi, LockLocation\r
@@ -129,26 +135,64 @@ TestLock:
     cmp        rax, NotVacantFlag\r
     jz         TestLock\r
 \r
-    mov        edi, esi\r
-    add        edi, NumApsExecutingLocation\r
-    inc        dword [edi]\r
-    mov        ebx, [edi]\r
+    lea        ecx, [esi + InitFlagLocation]\r
+    inc        dword [ecx]\r
+    mov        ebx, [ecx]\r
 \r
-ProgramStack:\r
+Releaselock:\r
+    mov        rax, VacantFlag\r
+    xchg       qword [edi], rax\r
+    ; program stack\r
     mov        edi, esi\r
     add        edi, StackSizeLocation\r
-    mov        rax, qword [edi]\r
+    mov        eax, dword [edi]\r
+    mov        ecx, ebx\r
+    inc        ecx\r
+    mul        ecx                               ; EAX = StackSize * (CpuNumber + 1)\r
     mov        edi, esi\r
     add        edi, StackStartAddressLocation\r
     add        rax, qword [edi]\r
     mov        rsp, rax\r
-    mov        qword [edi], rax\r
+    jmp        CProcedureInvoke\r
+\r
+GetApicId:\r
+    mov        eax, 0\r
+    cpuid\r
+    cmp        eax, 0bh\r
+    jnb        X2Apic\r
+    ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
+    mov        eax, 1\r
+    cpuid\r
+    shr        ebx, 24\r
+    mov        edx, ebx\r
+    jmp        GetProcessorNumber\r
+\r
+X2Apic:\r
+    ; Processor is x2APIC capable, so get 32-bit x2APIC ID\r
+    mov        eax, 0bh\r
+    xor        ecx, ecx\r
+    cpuid                   \r
+    ; edx save x2APIC ID\r
+    \r
+GetProcessorNumber:\r
+    ;\r
+    ; Get processor number for this AP\r
+    ; Note that BSP may become an AP due to SwitchBsp()\r
+    ;\r
+    xor         ebx, ebx\r
+    lea         eax, [esi + CpuInfoLocation]\r
+    mov         edi, [eax]\r
 \r
-Releaselock:\r
-    mov        rax, VacantFlag\r
-    mov        edi, esi\r
-    add        edi, LockLocation\r
-    xchg       qword [edi], rax\r
+GetNextProcNumber:\r
+    cmp         dword [edi], edx                      ; APIC ID match?\r
+    jz          ProgramStack\r
+    add         edi, 16\r
+    inc         ebx\r
+    jmp         GetNextProcNumber    \r
+\r
+ProgramStack:\r
+    xor         rsp, rsp\r
+    mov         esp, dword [edi + 12]\r
 \r
 CProcedureInvoke:\r
     push       rbp               ; Push BIST data at top of AP stack\r