]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Remove redundant CpuStateFinished State.
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
index 61b14c98438e85544ed63700923144f0b41d18e5..ff09a0e9e7e843f2332a0d78fb7b24a138414ee5 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   CPU MP Initialize Library common functions.\r
 \r
-  Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -195,6 +195,10 @@ SaveVolatileRegisters (
     VolatileRegisters->Dr6 = AsmReadDr6 ();\r
     VolatileRegisters->Dr7 = AsmReadDr7 ();\r
   }\r
+\r
+  AsmReadGdtr (&VolatileRegisters->Gdtr);\r
+  AsmReadIdtr (&VolatileRegisters->Idtr);\r
+  VolatileRegisters->Tr = AsmReadTr ();\r
 }\r
 \r
 /**\r
@@ -211,6 +215,7 @@ RestoreVolatileRegisters (
   )\r
 {\r
   CPUID_VERSION_INFO_EDX        VersionInfoEdx;\r
+  IA32_TSS_DESCRIPTOR           *Tss;\r
 \r
   AsmWriteCr0 (VolatileRegisters->Cr0);\r
   AsmWriteCr3 (VolatileRegisters->Cr3);\r
@@ -231,6 +236,18 @@ RestoreVolatileRegisters (
       AsmWriteDr7 (VolatileRegisters->Dr7);\r
     }\r
   }\r
+\r
+  AsmWriteGdtr (&VolatileRegisters->Gdtr);\r
+  AsmWriteIdtr (&VolatileRegisters->Idtr);\r
+  if (VolatileRegisters->Tr != 0 &&\r
+      VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit) {\r
+    Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base +\r
+                                  VolatileRegisters->Tr);\r
+    if (Tss->Bits.P == 1) {\r
+      Tss->Bits.Type &= 0xD;  // 1101 - Clear busy bit just in case\r
+      AsmWriteTr (VolatileRegisters->Tr);\r
+    }\r
+  }\r
 }\r
 \r
 /**\r
@@ -313,6 +330,7 @@ SortApicId (
   CPU_INFO_IN_HOB   CpuInfo;\r
   UINT32            ApCount;\r
   CPU_INFO_IN_HOB   *CpuInfoInHob;\r
+  volatile UINT32   *StartupApSignal;\r
 \r
   ApCount = CpuMpData->CpuCount - 1;\r
   CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
@@ -337,6 +355,14 @@ SortApicId (
           sizeof (CPU_INFO_IN_HOB)\r
           );\r
         CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));\r
+\r
+        //\r
+        // Also exchange the StartupApSignal.\r
+        //\r
+        StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;\r
+        CpuMpData->CpuData[Index3].StartupApSignal =\r
+          CpuMpData->CpuData[Index1].StartupApSignal;\r
+        CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;\r
       }\r
     }\r
 \r
@@ -384,7 +410,7 @@ ApInitializeSync (
   //\r
   // Load microcode on AP\r
   //\r
-  MicrocodeDetect (CpuMpData);\r
+  MicrocodeDetect (CpuMpData, FALSE);\r
   //\r
   // Sync BSP's MTRR table to AP\r
   //\r
@@ -409,16 +435,19 @@ GetProcessorNumber (
   UINTN                   TotalProcessorNumber;\r
   UINTN                   Index;\r
   CPU_INFO_IN_HOB         *CpuInfoInHob;\r
+  UINT32                  CurrentApicId;\r
 \r
   CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
 \r
   TotalProcessorNumber = CpuMpData->CpuCount;\r
+  CurrentApicId = GetApicId ();\r
   for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
-    if (CpuInfoInHob[Index].ApicId == GetApicId ()) {\r
+    if (CpuInfoInHob[Index].ApicId == CurrentApicId) {\r
       *ProcessorNumber = Index;\r
       return EFI_SUCCESS;\r
     }\r
   }\r
+\r
   return EFI_NOT_FOUND;\r
 }\r
 \r
@@ -565,6 +594,10 @@ ApWakeupFunction (
   // We need to re-initialize them at here\r
   //\r
   ProgramVirtualWireMode ();\r
+  //\r
+  // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.\r
+  //\r
+  DisableLvtInterrupts ();\r
   SyncLocalApicTimerSetting (CpuMpData);\r
 \r
   CurrentApicMode = GetApicMode ();\r
@@ -585,7 +618,9 @@ ApWakeupFunction (
       //\r
       ApInitializeSync (CpuMpData);\r
       //\r
-      // Sync BSP's Control registers to APs\r
+      // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,\r
+      //   to initialize AP in InitConfig path.\r
+      // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.\r
       //\r
       RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
       InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);\r
@@ -609,6 +644,13 @@ ApWakeupFunction (
         // Restore AP's volatile registers saved\r
         //\r
         RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
+      } else {\r
+        //\r
+        // The CPU driver might not flush TLB for APs on spot after updating\r
+        // page attributes. AP in mwait loop mode needs to take care of it when\r
+        // woken up.\r
+        //\r
+        CpuFlushTlb ();\r
       }\r
 \r
       if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
@@ -618,7 +660,7 @@ ApWakeupFunction (
           SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
           //\r
           // Enable source debugging on AP function\r
-          //         \r
+          //\r
           EnableDebugAgent ();\r
           //\r
           // Invoke AP function here\r
@@ -654,7 +696,7 @@ ApWakeupFunction (
             }\r
           }\r
         }\r
-        SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
+        SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
       }\r
     }\r
 \r
@@ -751,6 +793,8 @@ FillExchangeInfoData (
   )\r
 {\r
   volatile MP_CPU_EXCHANGE_INFO    *ExchangeInfo;\r
+  UINTN                            Size;\r
+  IA32_SEGMENT_DESCRIPTOR          *Selector;\r
 \r
   ExchangeInfo                  = CpuMpData->MpCpuExchangeInfo;\r
   ExchangeInfo->Lock            = 0;\r
@@ -780,6 +824,46 @@ FillExchangeInfoData (
   //\r
   AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
   AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
+\r
+  //\r
+  // Find a 32-bit code segment\r
+  //\r
+  Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;\r
+  Size = ExchangeInfo->GdtrProfile.Limit + 1;\r
+  while (Size > 0) {\r
+    if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) {\r
+      ExchangeInfo->ModeTransitionSegment =\r
+        (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);\r
+      break;\r
+    }\r
+    Selector += 1;\r
+    Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+  }\r
+\r
+  //\r
+  // Copy all 32-bit code and 64-bit code into memory with type of\r
+  // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.\r
+  //\r
+  if (CpuMpData->WakeupBufferHigh != 0) {\r
+    Size = CpuMpData->AddressMap.RendezvousFunnelSize -\r
+           CpuMpData->AddressMap.ModeTransitionOffset;\r
+    CopyMem (\r
+      (VOID *)CpuMpData->WakeupBufferHigh,\r
+      CpuMpData->AddressMap.RendezvousFunnelAddress +\r
+      CpuMpData->AddressMap.ModeTransitionOffset,\r
+      Size\r
+      );\r
+\r
+    ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;\r
+  } else {\r
+    ExchangeInfo->ModeTransitionMemory = (UINT32)\r
+      (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);\r
+  }\r
+\r
+  ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +\r
+                         (UINT32)ExchangeInfo->ModeOffset -\r
+                         (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;\r
+  ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;\r
 }\r
 \r
 /**\r
@@ -855,6 +939,10 @@ AllocateResetVector (
     CpuMpData->WakeupBuffer      = GetWakeupBuffer (ApResetVectorSize);\r
     CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
                     (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
+    CpuMpData->WakeupBufferHigh  = GetModeTransitionBuffer (\r
+                                    CpuMpData->AddressMap.RendezvousFunnelSize -\r
+                                    CpuMpData->AddressMap.ModeTransitionOffset\r
+                                    );\r
   }\r
   BackupAndPrepareWakeupBuffer (CpuMpData);\r
 }\r
@@ -900,13 +988,15 @@ WakeUpAP (
   CpuMpData->FinishedCount = 0;\r
   ResetVectorRequired = FALSE;\r
 \r
-  if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
+  if (CpuMpData->WakeUpByInitSipiSipi ||\r
       CpuMpData->InitFlag   != ApInitDone) {\r
     ResetVectorRequired = TRUE;\r
     AllocateResetVector (CpuMpData);\r
     FillExchangeInfoData (CpuMpData);\r
     SaveLocalApicTimerSetting (CpuMpData);\r
-  } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
+  }\r
+\r
+  if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
     //\r
     // Get AP target C-state each time when waking up AP,\r
     // for it maybe updated by platform again\r
@@ -991,6 +1081,13 @@ WakeUpAP (
   if (ResetVectorRequired) {\r
     FreeResetVector (CpuMpData);\r
   }\r
+\r
+  //\r
+  // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with\r
+  // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by\r
+  // S3SmmInitDone Ppi.\r
+  //\r
+  CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
 }\r
 \r
 /**\r
@@ -1032,7 +1129,7 @@ CalculateTimeout (
 \r
   //\r
   // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
-  // in Hz. \r
+  // in Hz.\r
   //\r
   TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);\r
 \r
@@ -1255,18 +1352,17 @@ CheckThisAP (
   CpuData   = &CpuMpData->CpuData[ProcessorNumber];\r
 \r
   //\r
-  //  Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+  //  Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
   //  Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
-  //  value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+  //  value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
   //\r
   //\r
   // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.\r
   //\r
-  if (GetApState(CpuData) == CpuStateFinished) {\r
+  if (GetApState(CpuData) == CpuStateIdle) {\r
     if (CpuData->Finished != NULL) {\r
       *(CpuData->Finished) = TRUE;\r
     }\r
-    SetApState (CpuData, CpuStateIdle);\r
     return EFI_SUCCESS;\r
   } else {\r
     //\r
@@ -1323,14 +1419,13 @@ CheckAllAPs (
 \r
     CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
     //\r
-    // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+    // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
     // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
-    // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+    // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
     //\r
-    if (GetApState(CpuData) == CpuStateFinished) {\r
+    if (GetApState(CpuData) == CpuStateIdle) {\r
       CpuMpData->RunningCount ++;\r
       CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
-      SetApState(CpuData, CpuStateIdle);\r
 \r
       //\r
       // If in Single Thread mode, then search for the next waiting AP for execution.\r
@@ -1423,6 +1518,7 @@ MpInitLibInitialize (
   UINT32                   MaxLogicalProcessorNumber;\r
   UINT32                   ApStackSize;\r
   MP_ASSEMBLY_ADDRESS_MAP  AddressMap;\r
+  CPU_VOLATILE_REGISTERS   VolatileRegisters;\r
   UINTN                    BufferSize;\r
   UINT32                   MonitorFilterSize;\r
   VOID                     *MpBuffer;\r
@@ -1433,6 +1529,8 @@ MpInitLibInitialize (
   UINTN                    Index;\r
   UINTN                    ApResetVectorSize;\r
   UINTN                    BackupBufferAddr;\r
+  UINTN                    ApIdtBase;\r
+  VOID                     *MicrocodePatchInRam;\r
 \r
   OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
   if (OldCpuMpData == NULL) {\r
@@ -1447,19 +1545,48 @@ MpInitLibInitialize (
   ApStackSize = PcdGet32(PcdCpuApStackSize);\r
   ApLoopMode  = GetApLoopMode (&MonitorFilterSize);\r
 \r
+  //\r
+  // Save BSP's Control registers for APs\r
+  //\r
+  SaveVolatileRegisters (&VolatileRegisters);\r
+\r
   BufferSize  = ApStackSize * MaxLogicalProcessorNumber;\r
   BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
-  BufferSize += sizeof (CPU_MP_DATA);\r
   BufferSize += ApResetVectorSize;\r
+  BufferSize  = ALIGN_VALUE (BufferSize, 8);\r
+  BufferSize += VolatileRegisters.Idtr.Limit + 1;\r
+  BufferSize += sizeof (CPU_MP_DATA);\r
   BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
   MpBuffer    = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
   ASSERT (MpBuffer != NULL);\r
   ZeroMem (MpBuffer, BufferSize);\r
   Buffer = (UINTN) MpBuffer;\r
 \r
+  //\r
+  //  The layout of the Buffer is as below:\r
+  //\r
+  //    +--------------------+ <-- Buffer\r
+  //        AP Stacks (N)\r
+  //    +--------------------+ <-- MonitorBuffer\r
+  //    AP Monitor Filters (N)\r
+  //    +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)\r
+  //         Backup Buffer\r
+  //    +--------------------+\r
+  //           Padding\r
+  //    +--------------------+ <-- ApIdtBase (8-byte boundary)\r
+  //           AP IDT          All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.\r
+  //    +--------------------+ <-- CpuMpData\r
+  //         CPU_MP_DATA\r
+  //    +--------------------+ <-- CpuMpData->CpuData\r
+  //        CPU_AP_DATA (N)\r
+  //    +--------------------+ <-- CpuMpData->CpuInfoInHob\r
+  //      CPU_INFO_IN_HOB (N)\r
+  //    +--------------------+\r
+  //\r
   MonitorBuffer    = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
   BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
-  CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
+  ApIdtBase        = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8);\r
+  CpuMpData        = (CPU_MP_DATA *) (ApIdtBase + VolatileRegisters.Idtr.Limit + 1);\r
   CpuMpData->Buffer           = Buffer;\r
   CpuMpData->CpuApStackSize   = ApStackSize;\r
   CpuMpData->BackupBuffer     = BackupBufferAddr;\r
@@ -1471,17 +1598,57 @@ MpInitLibInitialize (
   CpuMpData->SwitchBspFlag    = FALSE;\r
   CpuMpData->CpuData          = (CPU_AP_DATA *) (CpuMpData + 1);\r
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
-  CpuMpData->MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
   CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
+  //\r
+  // If platform has more than one CPU, relocate microcode to memory to reduce\r
+  // loading microcode time.\r
+  //\r
+  MicrocodePatchInRam = NULL;\r
+  if (MaxLogicalProcessorNumber > 1) {\r
+    MicrocodePatchInRam = AllocatePages (\r
+                            EFI_SIZE_TO_PAGES (\r
+                              (UINTN)CpuMpData->MicrocodePatchRegionSize\r
+                              )\r
+                            );\r
+  }\r
+  if (MicrocodePatchInRam == NULL) {\r
+    //\r
+    // there is only one processor, or no microcode patch is available, or\r
+    // memory allocation failed\r
+    //\r
+    CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
+  } else {\r
+    //\r
+    // there are multiple processors, and a microcode patch is available, and\r
+    // memory allocation succeeded\r
+    //\r
+    CopyMem (\r
+      MicrocodePatchInRam,\r
+      (VOID *)(UINTN)PcdGet64 (PcdCpuMicrocodePatchAddress),\r
+      (UINTN)CpuMpData->MicrocodePatchRegionSize\r
+      );\r
+    CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;\r
+  }\r
+\r
   InitializeSpinLock(&CpuMpData->MpLock);\r
+\r
   //\r
-  // Save BSP's Control registers to APs\r
+  // Make sure no memory usage outside of the allocated buffer.\r
   //\r
-  SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
+  ASSERT ((CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==\r
+          Buffer + BufferSize);\r
+\r
+  //\r
+  // Duplicate BSP's IDT to APs.\r
+  // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1\r
+  //\r
+  CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);\r
+  VolatileRegisters.Idtr.Base = ApIdtBase;\r
+  CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));\r
   //\r
   // Set BSP basic information\r
   //\r
-  InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer);\r
+  InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);\r
   //\r
   // Save assembly code information\r
   //\r
@@ -1491,6 +1658,9 @@ MpInitLibInitialize (
   //\r
   CpuMpData->ApLoopMode = ApLoopMode;\r
   DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
+\r
+  CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
+\r
   //\r
   // Set up APs wakeup signal buffer\r
   //\r
@@ -1501,7 +1671,7 @@ MpInitLibInitialize (
   //\r
   // Load Microcode on BSP\r
   //\r
-  MicrocodeDetect (CpuMpData);\r
+  MicrocodeDetect (CpuMpData, TRUE);\r
   //\r
   // Store BSP's MTRR setting\r
   //\r
@@ -1535,11 +1705,7 @@ MpInitLibInitialize (
       }\r
       CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;\r
       CpuMpData->CpuData[Index].ApFunction = 0;\r
-      CopyMem (\r
-        &CpuMpData->CpuData[Index].VolatileRegisters,\r
-        &CpuMpData->CpuData[0].VolatileRegisters,\r
-        sizeof (CPU_VOLATILE_REGISTERS)\r
-        );\r
+      CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (CPU_VOLATILE_REGISTERS));\r
     }\r
     if (MaxLogicalProcessorNumber > 1) {\r
       //\r
@@ -1654,7 +1820,7 @@ MpInitLibGetProcessorInfo (
                                enabled AP. Otherwise, it will be disabled.\r
 \r
   @retval EFI_SUCCESS          BSP successfully switched.\r
-  @retval others               Failed to switch BSP. \r
+  @retval others               Failed to switch BSP.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1750,11 +1916,12 @@ SwitchBSPWorker (
   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
   ApicBaseMsr.Bits.BSP = 1;\r
   AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+  ProgramVirtualWireMode ();\r
 \r
   //\r
   // Wait for old BSP finished AP task\r
   //\r
-  while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {\r
+  while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateIdle) {\r
     CpuPause ();\r
   }\r
 \r