]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / MpService.c
index 730c32df0a254bdde82472187a2218cc29db858b..64fb4d6344d5f2aa2ff2fe54ecd1d507996cc443 100644 (file)
@@ -1,14 +1,10 @@
 /** @file\r
 SMM MP service implementation\r
 \r
-Copyright (c) 2009 - 2015, 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
-http://opensource.org/licenses/bsd-license.php\r
+Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
 \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -17,10 +13,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 // Slots for all MTRR( FIXED MTRR + VARIABLE MTRR + MTRR_LIB_IA32_MTRR_DEF_TYPE)\r
 //\r
-UINT64                                      gSmiMtrrs[MTRR_NUMBER_OF_FIXED_MTRR + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];\r
+MTRR_SETTINGS                               gSmiMtrrs;\r
 UINT64                                      gPhyMask;\r
 SMM_DISPATCHER_MP_SYNC_DATA                 *mSmmMpSyncData = NULL;\r
 UINTN                                       mSmmMpSyncDataSize;\r
+SMM_CPU_SEMAPHORES                          mSmmCpuSemaphores;\r
+UINTN                                       mSemaphoreSize;\r
+SPIN_LOCK                                   *mPFLock = NULL;\r
+SMM_CPU_SYNC_MODE                           mCpuSmmSyncMode;\r
+BOOLEAN                                     mMachineCheckSupported = FALSE;\r
 \r
 /**\r
   Performs an atomic compare exchange operation to get semaphore.\r
@@ -120,7 +121,7 @@ WaitForAllAPs (
 \r
   BspIndex = mSmmMpSyncData->BspIndex;\r
   while (NumberOfAPs-- > 0) {\r
-    WaitForSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);\r
+    WaitForSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
   }\r
 }\r
 \r
@@ -139,8 +140,8 @@ ReleaseAllAPs (
 \r
   BspIndex = mSmmMpSyncData->BspIndex;\r
   for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
-    if (Index != BspIndex && mSmmMpSyncData->CpuData[Index].Present) {\r
-      ReleaseSemaphore (&mSmmMpSyncData->CpuData[Index].Run);\r
+    if (Index != BspIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {\r
+      ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);\r
     }\r
   }\r
 }\r
@@ -163,16 +164,16 @@ AllCpusInSmmWithExceptions (
   SMM_CPU_DATA_BLOCK                *CpuData;\r
   EFI_PROCESSOR_INFORMATION         *ProcessorInfo;\r
 \r
-  ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus);\r
+  ASSERT (*mSmmMpSyncData->Counter <= mNumberOfCpus);\r
 \r
-  if (mSmmMpSyncData->Counter == mNumberOfCpus) {\r
+  if (*mSmmMpSyncData->Counter == mNumberOfCpus) {\r
     return TRUE;\r
   }\r
 \r
   CpuData = mSmmMpSyncData->CpuData;\r
   ProcessorInfo = gSmmCpuPrivate->ProcessorInfo;\r
   for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
-    if (!CpuData[Index].Present && ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) {\r
+    if (!(*(CpuData[Index].Present)) && ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) {\r
       if (((Exceptions & ARRIVAL_EXCEPTION_DELAYED) != 0) && SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmDelayed) != 0) {\r
         continue;\r
       }\r
@@ -190,6 +191,56 @@ AllCpusInSmmWithExceptions (
   return TRUE;\r
 }\r
 \r
+/**\r
+  Has OS enabled Lmce in the MSR_IA32_MCG_EXT_CTL\r
+\r
+  @retval TRUE     Os enable lmce.\r
+  @retval FALSE    Os not enable lmce.\r
+\r
+**/\r
+BOOLEAN\r
+IsLmceOsEnabled (\r
+  VOID\r
+  )\r
+{\r
+  MSR_IA32_MCG_CAP_REGISTER          McgCap;\r
+  MSR_IA32_FEATURE_CONTROL_REGISTER  FeatureCtrl;\r
+  MSR_IA32_MCG_EXT_CTL_REGISTER      McgExtCtrl;\r
+\r
+  McgCap.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_CAP);\r
+  if (McgCap.Bits.MCG_LMCE_P == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  FeatureCtrl.Uint64 = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL);\r
+  if (FeatureCtrl.Bits.LmceOn == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  McgExtCtrl.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_EXT_CTL);\r
+  return (BOOLEAN) (McgExtCtrl.Bits.LMCE_EN == 1);\r
+}\r
+\r
+/**\r
+  Return if Local machine check exception signaled.\r
+\r
+  Indicates (when set) that a local machine check exception was generated. This indicates that the current machine-check event was\r
+  delivered to only the logical processor.\r
+\r
+  @retval TRUE    LMCE was signaled.\r
+  @retval FALSE   LMCE was not signaled.\r
+\r
+**/\r
+BOOLEAN\r
+IsLmceSignaled (\r
+  VOID\r
+  )\r
+{\r
+  MSR_IA32_MCG_STATUS_REGISTER McgStatus;\r
+\r
+  McgStatus.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_STATUS);\r
+  return (BOOLEAN) (McgStatus.Bits.LMCE_S == 1);\r
+}\r
 \r
 /**\r
   Given timeout constraint, wait for all APs to arrive, and insure when this function returns, no AP will execute normal mode code before\r
@@ -203,8 +254,17 @@ SmmWaitForApArrival (
 {\r
   UINT64                            Timer;\r
   UINTN                             Index;\r
+  BOOLEAN                           LmceEn;\r
+  BOOLEAN                           LmceSignal;\r
+\r
+  ASSERT (*mSmmMpSyncData->Counter <= mNumberOfCpus);\r
 \r
-  ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus);\r
+  LmceEn     = FALSE;\r
+  LmceSignal = FALSE;\r
+  if (mMachineCheckSupported) {\r
+    LmceEn     = IsLmceOsEnabled ();\r
+    LmceSignal = IsLmceSignaled();\r
+  }\r
 \r
   //\r
   // Platform implementor should choose a timeout value appropriately:\r
@@ -221,7 +281,7 @@ SmmWaitForApArrival (
   // Sync with APs 1st timeout\r
   //\r
   for (Timer = StartSyncTimer ();\r
-       !IsSyncTimerTimeout (Timer) &&\r
+       !IsSyncTimerTimeout (Timer) && !(LmceEn && LmceSignal) &&\r
        !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED );\r
        ) {\r
     CpuPause ();\r
@@ -243,12 +303,12 @@ SmmWaitForApArrival (
   //    - In relaxed flow, CheckApArrival() will check SMI disabling status before calling this function.\r
   //    In both cases, adding SMI-disabling checking code increases overhead.\r
   //\r
-  if (mSmmMpSyncData->Counter < mNumberOfCpus) {\r
+  if (*mSmmMpSyncData->Counter < mNumberOfCpus) {\r
     //\r
     // Send SMI IPIs to bring outside processors in\r
     //\r
     for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
-      if (!mSmmMpSyncData->CpuData[Index].Present && gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) {\r
+      if (!(*(mSmmMpSyncData->CpuData[Index].Present)) && gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) {\r
         SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);\r
       }\r
     }\r
@@ -279,20 +339,12 @@ ReplaceOSMtrrs (
   IN      UINTN                     CpuIndex\r
   )\r
 {\r
-  PROCESSOR_SMM_DESCRIPTOR       *Psd;\r
-  UINT64                         *SmiMtrrs;\r
-  MTRR_SETTINGS                  *BiosMtrr;\r
-\r
-  Psd = (PROCESSOR_SMM_DESCRIPTOR*)(mCpuHotPlugData.SmBase[CpuIndex] + SMM_PSD_OFFSET);\r
-  SmiMtrrs = (UINT64*)(UINTN)Psd->MtrrBaseMaskPtr;\r
-\r
   SmmCpuFeaturesDisableSmrr ();\r
 \r
   //\r
   // Replace all MTRRs registers\r
   //\r
-  BiosMtrr  = (MTRR_SETTINGS*)SmiMtrrs;\r
-  MtrrSetAllMtrrs(BiosMtrr);\r
+  MtrrSetAllMtrrs (&gSmiMtrrs);\r
 }\r
 \r
 /**\r
@@ -320,7 +372,7 @@ BSPHandler (
   //\r
   // Flag BSP's presence\r
   //\r
-  mSmmMpSyncData->InsideSmm = TRUE;\r
+  *mSmmMpSyncData->InsideSmm = TRUE;\r
 \r
   //\r
   // Initialize Debug Agent to start source level debug in BSP handler\r
@@ -330,7 +382,7 @@ BSPHandler (
   //\r
   // Mark this processor's presence\r
   //\r
-  mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE;\r
+  *(mSmmMpSyncData->CpuData[CpuIndex].Present) = TRUE;\r
 \r
   //\r
   // Clear platform top level SMI status bit before calling SMI handlers. If\r
@@ -358,8 +410,8 @@ BSPHandler (
     //\r
     // Lock the counter down and retrieve the number of APs\r
     //\r
-    mSmmMpSyncData->AllCpusInSync = TRUE;\r
-    ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1;\r
+    *mSmmMpSyncData->AllCpusInSync = TRUE;\r
+    ApCount = LockdownSemaphore (mSmmMpSyncData->Counter) - 1;\r
 \r
     //\r
     // Wait for all APs to get ready for programming MTRRs\r
@@ -409,18 +461,12 @@ BSPHandler (
   //\r
   // The BUSY lock is initialized to Acquired state\r
   //\r
-  AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+  AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
 \r
   //\r
-  // Restore SMM Configuration in S3 boot path.\r
+  // Perform the pre tasks\r
   //\r
-  if (mRestoreSmmConfigurationInS3) {\r
-    //\r
-    // Configure SMM Code Access Check feature if available.\r
-    //\r
-    ConfigSmmCodeAccessCheck ();\r
-    mRestoreSmmConfigurationInS3 = FALSE;\r
-  }\r
+  PerformPreTasks ();\r
 \r
   //\r
   // Invoke SMM Foundation EntryPoint with the processor information context.\r
@@ -431,9 +477,9 @@ BSPHandler (
   // Make sure all APs have completed their pending none-block tasks\r
   //\r
   for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
-    if (Index != CpuIndex && mSmmMpSyncData->CpuData[Index].Present) {\r
-      AcquireSpinLock (&mSmmMpSyncData->CpuData[Index].Busy);\r
-      ReleaseSpinLock (&mSmmMpSyncData->CpuData[Index].Busy);;\r
+    if (Index != CpuIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {\r
+      AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
+      ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
     }\r
   }\r
 \r
@@ -452,15 +498,15 @@ BSPHandler (
     //\r
     // Lock the counter down and retrieve the number of APs\r
     //\r
-    mSmmMpSyncData->AllCpusInSync = TRUE;\r
-    ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1;\r
+    *mSmmMpSyncData->AllCpusInSync = TRUE;\r
+    ApCount = LockdownSemaphore (mSmmMpSyncData->Counter) - 1;\r
     //\r
     // Make sure all APs have their Present flag set\r
     //\r
     while (TRUE) {\r
       PresentCount = 0;\r
       for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
-        if (mSmmMpSyncData->CpuData[Index].Present) {\r
+        if (*(mSmmMpSyncData->CpuData[Index].Present)) {\r
           PresentCount ++;\r
         }\r
       }\r
@@ -473,7 +519,7 @@ BSPHandler (
   //\r
   // Notify all APs to exit\r
   //\r
-  mSmmMpSyncData->InsideSmm = FALSE;\r
+  *mSmmMpSyncData->InsideSmm = FALSE;\r
   ReleaseAllAPs ();\r
 \r
   //\r
@@ -518,7 +564,7 @@ BSPHandler (
   //\r
   // Clear the Present flag of BSP\r
   //\r
-  mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE;\r
+  *(mSmmMpSyncData->CpuData[CpuIndex].Present) = FALSE;\r
 \r
   //\r
   // Gather APs to exit SMM synchronously. Note the Present flag is cleared by now but\r
@@ -536,8 +582,8 @@ BSPHandler (
   //\r
   // Allow APs to check in from this point on\r
   //\r
-  mSmmMpSyncData->Counter = 0;\r
-  mSmmMpSyncData->AllCpusInSync = FALSE;\r
+  *mSmmMpSyncData->Counter = 0;\r
+  *mSmmMpSyncData->AllCpusInSync = FALSE;\r
 }\r
 \r
 /**\r
@@ -564,12 +610,12 @@ APHandler (
   //\r
   for (Timer = StartSyncTimer ();\r
        !IsSyncTimerTimeout (Timer) &&\r
-       !mSmmMpSyncData->InsideSmm;\r
+       !(*mSmmMpSyncData->InsideSmm);\r
        ) {\r
     CpuPause ();\r
   }\r
 \r
-  if (!mSmmMpSyncData->InsideSmm) {\r
+  if (!(*mSmmMpSyncData->InsideSmm)) {\r
     //\r
     // BSP timeout in the first round\r
     //\r
@@ -590,23 +636,23 @@ APHandler (
       //\r
       for (Timer = StartSyncTimer ();\r
            !IsSyncTimerTimeout (Timer) &&\r
-           !mSmmMpSyncData->InsideSmm;\r
+           !(*mSmmMpSyncData->InsideSmm);\r
            ) {\r
         CpuPause ();\r
       }\r
 \r
-      if (!mSmmMpSyncData->InsideSmm) {\r
+      if (!(*mSmmMpSyncData->InsideSmm)) {\r
         //\r
         // Give up since BSP is unable to enter SMM\r
         // and signal the completion of this AP\r
-        WaitForSemaphore (&mSmmMpSyncData->Counter);\r
+        WaitForSemaphore (mSmmMpSyncData->Counter);\r
         return;\r
       }\r
     } else {\r
       //\r
       // Don't know BSP index. Give up without sending IPI to BSP.\r
       //\r
-      WaitForSemaphore (&mSmmMpSyncData->Counter);\r
+      WaitForSemaphore (mSmmMpSyncData->Counter);\r
       return;\r
     }\r
   }\r
@@ -620,20 +666,20 @@ APHandler (
   //\r
   // Mark this processor's presence\r
   //\r
-  mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE;\r
+  *(mSmmMpSyncData->CpuData[CpuIndex].Present) = TRUE;\r
 \r
   if (SyncMode == SmmCpuSyncModeTradition || SmmCpuFeaturesNeedConfigureMtrrs()) {\r
     //\r
     // Notify BSP of arrival at this point\r
     //\r
-    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);\r
+    ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
   }\r
 \r
   if (SmmCpuFeaturesNeedConfigureMtrrs()) {\r
     //\r
     // Wait for the signal from BSP to backup MTRRs\r
     //\r
-    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);\r
+    WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
     //\r
     // Backup OS MTRRs\r
@@ -643,12 +689,12 @@ APHandler (
     //\r
     // Signal BSP the completion of this AP\r
     //\r
-    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);\r
+    ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
 \r
     //\r
     // Wait for BSP's signal to program MTRRs\r
     //\r
-    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);\r
+    WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
     //\r
     // Replace OS MTRRs with SMI MTRRs\r
@@ -658,19 +704,19 @@ APHandler (
     //\r
     // Signal BSP the completion of this AP\r
     //\r
-    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);\r
+    ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
   }\r
 \r
   while (TRUE) {\r
     //\r
     // Wait for something to happen\r
     //\r
-    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);\r
+    WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
     //\r
     // Check if BSP wants to exit SMM\r
     //\r
-    if (!mSmmMpSyncData->InsideSmm) {\r
+    if (!(*mSmmMpSyncData->InsideSmm)) {\r
       break;\r
     }\r
 \r
@@ -678,7 +724,7 @@ APHandler (
     // BUSY should be acquired by SmmStartupThisAp()\r
     //\r
     ASSERT (\r
-      !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy)\r
+      !AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)\r
       );\r
 \r
     //\r
@@ -691,19 +737,19 @@ APHandler (
     //\r
     // Release BUSY\r
     //\r
-    ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+    ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
   }\r
 \r
   if (SmmCpuFeaturesNeedConfigureMtrrs()) {\r
     //\r
     // Notify BSP the readiness of this AP to program MTRRs\r
     //\r
-    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);\r
+    ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
 \r
     //\r
     // Wait for the signal from BSP to program MTRRs\r
     //\r
-    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);\r
+    WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
     //\r
     // Restore OS MTRRs\r
@@ -715,35 +761,35 @@ APHandler (
   //\r
   // Notify BSP the readiness of this AP to Reset states/semaphore for this processor\r
   //\r
-  ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);\r
+  ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
 \r
   //\r
   // Wait for the signal from BSP to Reset states/semaphore for this processor\r
   //\r
-  WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);\r
+  WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
   //\r
   // Reset states/semaphore for this processor\r
   //\r
-  mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE;\r
+  *(mSmmMpSyncData->CpuData[CpuIndex].Present) = FALSE;\r
 \r
   //\r
   // Notify BSP the readiness of this AP to exit SMM\r
   //\r
-  ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);\r
+  ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
 \r
 }\r
 \r
 /**\r
   Create 4G PageTable in SMRAM.\r
 \r
-  @param          ExtraPages       Additional page numbers besides for 4G memory\r
+  @param[in]      Is32BitPageTable Whether the page table is 32-bit PAE\r
   @return         PageTable Address\r
 \r
 **/\r
 UINT32\r
 Gen4GPageTable (\r
-  IN      UINTN                     ExtraPages\r
+  IN      BOOLEAN                   Is32BitPageTable\r
   )\r
 {\r
   VOID    *PageTable;\r
@@ -776,10 +822,10 @@ Gen4GPageTable (
   //\r
   // Allocate the page table\r
   //\r
-  PageTable = AllocatePages (ExtraPages + 5 + PagesNeeded);\r
+  PageTable = AllocatePageTableMemory (5 + PagesNeeded);\r
   ASSERT (PageTable != NULL);\r
 \r
-  PageTable = (VOID *)((UINTN)PageTable + EFI_PAGES_TO_SIZE (ExtraPages));\r
+  PageTable = (VOID *)((UINTN)PageTable);\r
   Pte = (UINT64*)PageTable;\r
 \r
   //\r
@@ -791,7 +837,8 @@ Gen4GPageTable (
   // Set Page Directory Pointers\r
   //\r
   for (Index = 0; Index < 4; Index++) {\r
-    Pte[Index] = (UINTN)PageTable + EFI_PAGE_SIZE * (Index + 1) + IA32_PG_P;\r
+    Pte[Index] = ((UINTN)PageTable + EFI_PAGE_SIZE * (Index + 1)) | mAddressEncMask |\r
+                   (Is32BitPageTable ? IA32_PAE_PDPTE_ATTRIBUTE_BITS : PAGE_ATTRIBUTE_BITS);\r
   }\r
   Pte += EFI_PAGE_SIZE / sizeof (*Pte);\r
 \r
@@ -799,16 +846,16 @@ Gen4GPageTable (
   // Fill in Page Directory Entries\r
   //\r
   for (Index = 0; Index < EFI_PAGE_SIZE * 4 / sizeof (*Pte); Index++) {\r
-    Pte[Index] = (Index << 21) + IA32_PG_PS + IA32_PG_RW + IA32_PG_P;\r
+    Pte[Index] = (Index << 21) | mAddressEncMask | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
   }\r
 \r
+  Pdpte = (UINT64*)PageTable;\r
   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
     Pages = (UINTN)PageTable + EFI_PAGES_TO_SIZE (5);\r
     GuardPage = mSmmStackArrayBase + EFI_PAGE_SIZE;\r
-    Pdpte = (UINT64*)PageTable;\r
     for (PageIndex = Low2MBoundary; PageIndex <= High2MBoundary; PageIndex += SIZE_2MB) {\r
-      Pte = (UINT64*)(UINTN)(Pdpte[BitFieldRead32 ((UINT32)PageIndex, 30, 31)] & ~(EFI_PAGE_SIZE - 1));\r
-      Pte[BitFieldRead32 ((UINT32)PageIndex, 21, 29)] = (UINT64)Pages + IA32_PG_RW + IA32_PG_P;\r
+      Pte = (UINT64*)(UINTN)(Pdpte[BitFieldRead32 ((UINT32)PageIndex, 30, 31)] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1));\r
+      Pte[BitFieldRead32 ((UINT32)PageIndex, 21, 29)] = (UINT64)Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
       //\r
       // Fill in Page Table Entries\r
       //\r
@@ -819,13 +866,13 @@ Gen4GPageTable (
           //\r
           // Mark the guard page as non-present\r
           //\r
-          Pte[Index] = PageAddress;\r
+          Pte[Index] = PageAddress | mAddressEncMask;\r
           GuardPage += mSmmStackSize;\r
           if (GuardPage > mSmmStackArrayEnd) {\r
             GuardPage = 0;\r
           }\r
         } else {\r
-          Pte[Index] = PageAddress + IA32_PG_RW + IA32_PG_P;\r
+          Pte[Index] = PageAddress | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
         }\r
         PageAddress+= EFI_PAGE_SIZE;\r
       }\r
@@ -833,78 +880,124 @@ Gen4GPageTable (
     }\r
   }\r
 \r
+  if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) {\r
+    Pte = (UINT64*)(UINTN)(Pdpte[0] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1));\r
+    if ((Pte[0] & IA32_PG_PS) == 0) {\r
+      // 4K-page entries are already mapped. Just hide the first one anyway.\r
+      Pte = (UINT64*)(UINTN)(Pte[0] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1));\r
+      Pte[0] &= ~(UINT64)IA32_PG_P; // Hide page 0\r
+    } else {\r
+      // Create 4K-page entries\r
+      Pages = (UINTN)AllocatePageTableMemory (1);\r
+      ASSERT (Pages != 0);\r
+\r
+      Pte[0] = (UINT64)(Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS);\r
+\r
+      Pte = (UINT64*)Pages;\r
+      PageAddress = 0;\r
+      Pte[0] = PageAddress | mAddressEncMask; // Hide page 0 but present left\r
+      for (Index = 1; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) {\r
+        PageAddress += EFI_PAGE_SIZE;\r
+        Pte[Index] = PageAddress | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
+      }\r
+    }\r
+  }\r
+\r
   return (UINT32)(UINTN)PageTable;\r
 }\r
 \r
 /**\r
-  Set memory cache ability.\r
+  Schedule a procedure to run on the specified CPU.\r
+\r
+  @param[in]       Procedure                The address of the procedure to run\r
+  @param[in]       CpuIndex                 Target CPU Index\r
+  @param[in, out]  ProcArguments            The parameter to pass to the procedure\r
+  @param[in]       BlockingMode             Startup AP in blocking mode or not\r
 \r
-  @param    PageTable              PageTable Address\r
-  @param    Address                Memory Address to change cache ability\r
-  @param    Cacheability           Cache ability to set\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber not valid\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber did not enter SMM\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber is busy\r
+  @retval EFI_SUCCESS              The procedure has been successfully scheduled\r
 \r
 **/\r
-VOID\r
-SetCacheability (\r
-  IN      UINT64                    *PageTable,\r
-  IN      UINTN                     Address,\r
-  IN      UINT8                     Cacheability\r
+EFI_STATUS\r
+InternalSmmStartupThisAp (\r
+  IN      EFI_AP_PROCEDURE          Procedure,\r
+  IN      UINTN                     CpuIndex,\r
+  IN OUT  VOID                      *ProcArguments OPTIONAL,\r
+  IN      BOOLEAN                   BlockingMode\r
   )\r
 {\r
-  UINTN   PTIndex;\r
-  VOID    *NewPageTableAddress;\r
-  UINT64  *NewPageTable;\r
-  UINTN   Index;\r
-\r
-  ASSERT ((Address & EFI_PAGE_MASK) == 0);\r
-\r
-  if (sizeof (UINTN) == sizeof (UINT64)) {\r
-    PTIndex = (UINTN)RShiftU64 (Address, 39) & 0x1ff;\r
-    ASSERT (PageTable[PTIndex] & IA32_PG_P);\r
-    PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);\r
+  if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {\r
+    DEBUG((DEBUG_ERROR, "CpuIndex(%d) >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus(%d)\n", CpuIndex, gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {\r
+    DEBUG((DEBUG_ERROR, "CpuIndex(%d) == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu\n", CpuIndex));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId == INVALID_APIC_ID) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (!(*(mSmmMpSyncData->CpuData[CpuIndex].Present))) {\r
+    if (mSmmMpSyncData->EffectiveSyncMode == SmmCpuSyncModeTradition) {\r
+      DEBUG((DEBUG_ERROR, "!mSmmMpSyncData->CpuData[%d].Present\n", CpuIndex));\r
+    }\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove) {\r
+    if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
+      DEBUG((DEBUG_ERROR, "gSmmCpuPrivate->Operation[%d] == SmmCpuRemove\n", CpuIndex));\r
+    }\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  PTIndex = (UINTN)RShiftU64 (Address, 30) & 0x1ff;\r
-  ASSERT (PageTable[PTIndex] & IA32_PG_P);\r
-  PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);\r
+  if (BlockingMode) {\r
+    AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+  } else {\r
+    if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {\r
+      DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
 \r
-  //\r
-  // A perfect implementation should check the original cacheability with the\r
-  // one being set, and break a 2M page entry into pieces only when they\r
-  // disagreed.\r
-  //\r
-  PTIndex = (UINTN)RShiftU64 (Address, 21) & 0x1ff;\r
-  if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {\r
-    //\r
-    // Allocate a page from SMRAM\r
-    //\r
-    NewPageTableAddress = AllocatePages (1);\r
-    ASSERT (NewPageTableAddress != NULL);\r
+  mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;\r
+  mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;\r
+  ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
 \r
-    NewPageTable = (UINT64 *)NewPageTableAddress;\r
+  if (BlockingMode) {\r
+    AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+    ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
 \r
-    for (Index = 0; Index < 0x200; Index++) {\r
-      NewPageTable[Index] = PageTable[PTIndex];\r
-      if ((NewPageTable[Index] & IA32_PG_PAT_2M) != 0) {\r
-        NewPageTable[Index] &= ~((UINT64)IA32_PG_PAT_2M);\r
-        NewPageTable[Index] |= (UINT64)IA32_PG_PAT_4K;\r
-      }\r
-      NewPageTable[Index] |= (UINT64)(Index << EFI_PAGE_SHIFT);\r
-    }\r
+/**\r
+  Schedule a procedure to run on the specified CPU in blocking mode.\r
 \r
-    PageTable[PTIndex] = ((UINTN)NewPageTableAddress & gPhyMask) | IA32_PG_P;\r
-  }\r
+  @param[in]       Procedure                The address of the procedure to run\r
+  @param[in]       CpuIndex                 Target CPU Index\r
+  @param[in, out]  ProcArguments            The parameter to pass to the procedure\r
 \r
-  ASSERT (PageTable[PTIndex] & IA32_PG_P);\r
-  PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber not valid\r
+  @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber did not enter SMM\r
+  @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber is busy\r
+  @retval EFI_SUCCESS              The procedure has been successfully scheduled\r
 \r
-  PTIndex = (UINTN)RShiftU64 (Address, 12) & 0x1ff;\r
-  ASSERT (PageTable[PTIndex] & IA32_PG_P);\r
-  PageTable[PTIndex] &= ~((UINT64)((IA32_PG_PAT_4K | IA32_PG_CD | IA32_PG_WT)));\r
-  PageTable[PTIndex] |= (UINT64)Cacheability;\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBlockingStartupThisAp (\r
+  IN      EFI_AP_PROCEDURE          Procedure,\r
+  IN      UINTN                     CpuIndex,\r
+  IN OUT  VOID                      *ProcArguments OPTIONAL\r
+  )\r
+{\r
+  return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, TRUE);\r
 }\r
 \r
-\r
 /**\r
   Schedule a procedure to run on the specified CPU.\r
 \r
@@ -927,23 +1020,68 @@ SmmStartupThisAp (
   IN OUT  VOID                      *ProcArguments OPTIONAL\r
   )\r
 {\r
-  if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus ||\r
-      CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu ||\r
-      !mSmmMpSyncData->CpuData[CpuIndex].Present ||\r
-      gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove ||\r
-      !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy)) {\r
-    return EFI_INVALID_PARAMETER;\r
+  return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, FeaturePcdGet (PcdCpuSmmBlockStartupThisAp));\r
+}\r
+\r
+/**\r
+  This function sets DR6 & DR7 according to SMM save state, before running SMM C code.\r
+  They are useful when you want to enable hardware breakpoints in SMM without entry SMM mode.\r
+\r
+  NOTE: It might not be appreciated in runtime since it might\r
+        conflict with OS debugging facilities. Turn them off in RELEASE.\r
+\r
+  @param    CpuIndex              CPU Index\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuSmmDebugEntry (\r
+  IN UINTN  CpuIndex\r
+  )\r
+{\r
+  SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
+\r
+  if (FeaturePcdGet (PcdCpuSmmDebug)) {\r
+    ASSERT(CpuIndex < mMaxNumberOfCpus);\r
+    CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];\r
+    if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
+      AsmWriteDr6 (CpuSaveState->x86._DR6);\r
+      AsmWriteDr7 (CpuSaveState->x86._DR7);\r
+    } else {\r
+      AsmWriteDr6 ((UINTN)CpuSaveState->x64._DR6);\r
+      AsmWriteDr7 ((UINTN)CpuSaveState->x64._DR7);\r
+    }\r
   }\r
+}\r
 \r
-  mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;\r
-  mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;\r
-  ReleaseSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);\r
+/**\r
+  This function restores DR6 & DR7 to SMM save state.\r
+\r
+  NOTE: It might not be appreciated in runtime since it might\r
+        conflict with OS debugging facilities. Turn them off in RELEASE.\r
+\r
+  @param    CpuIndex              CPU Index\r
 \r
-  if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) {\r
-    AcquireSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
-    ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuSmmDebugExit (\r
+  IN UINTN  CpuIndex\r
+  )\r
+{\r
+  SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
+\r
+  if (FeaturePcdGet (PcdCpuSmmDebug)) {\r
+    ASSERT(CpuIndex < mMaxNumberOfCpus);\r
+    CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];\r
+    if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
+      CpuSaveState->x86._DR7 = (UINT32)AsmReadDr7 ();\r
+      CpuSaveState->x86._DR6 = (UINT32)AsmReadDr6 ();\r
+    } else {\r
+      CpuSaveState->x64._DR7 = AsmReadDr7 ();\r
+      CpuSaveState->x64._DR6 = AsmReadDr6 ();\r
+    }\r
   }\r
-  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -958,17 +1096,21 @@ SmiRendezvous (
   IN      UINTN                     CpuIndex\r
   )\r
 {\r
-  EFI_STATUS        Status;\r
-  BOOLEAN           ValidSmi;\r
-  BOOLEAN           IsBsp;\r
-  BOOLEAN           BspInProgress;\r
-  UINTN             Index;\r
-  UINTN             Cr2;\r
+  EFI_STATUS                     Status;\r
+  BOOLEAN                        ValidSmi;\r
+  BOOLEAN                        IsBsp;\r
+  BOOLEAN                        BspInProgress;\r
+  UINTN                          Index;\r
+  UINTN                          Cr2;\r
+\r
+  ASSERT(CpuIndex < mMaxNumberOfCpus);\r
 \r
   //\r
-  // Save Cr2 because Page Fault exception in SMM may override its value\r
+  // Save Cr2 because Page Fault exception in SMM may override its value,\r
+  // when using on-demand paging for above 4G memory.\r
   //\r
-  Cr2 = AsmReadCr2 ();\r
+  Cr2 = 0;\r
+  SaveCr2 (&Cr2);\r
 \r
   //\r
   // Perform CPU specific entry hooks\r
@@ -984,7 +1126,7 @@ SmiRendezvous (
   // Determine if BSP has been already in progress. Note this must be checked after\r
   // ValidSmi because BSP may clear a valid SMI source after checking in.\r
   //\r
-  BspInProgress = mSmmMpSyncData->InsideSmm;\r
+  BspInProgress = *mSmmMpSyncData->InsideSmm;\r
 \r
   if (!BspInProgress && !ValidSmi) {\r
     //\r
@@ -999,7 +1141,7 @@ SmiRendezvous (
     //\r
     // Signal presence of this processor\r
     //\r
-    if (ReleaseSemaphore (&mSmmMpSyncData->Counter) == 0) {\r
+    if (ReleaseSemaphore (mSmmMpSyncData->Counter) == 0) {\r
       //\r
       // BSP has already ended the synchronization, so QUIT!!!\r
       //\r
@@ -1007,7 +1149,7 @@ SmiRendezvous (
       //\r
       // Wait for BSP's signal to finish SMI\r
       //\r
-      while (mSmmMpSyncData->AllCpusInSync) {\r
+      while (*mSmmMpSyncData->AllCpusInSync) {\r
         CpuPause ();\r
       }\r
       goto Exit;\r
@@ -1019,14 +1161,7 @@ SmiRendezvous (
       // E.g., with Relaxed AP flow, SmmStartupThisAp() may be called immediately\r
       // after AP's present flag is detected.\r
       //\r
-      InitializeSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
-    }\r
-\r
-    //\r
-    // Try to enable NX\r
-    //\r
-    if (mXdSupported) {\r
-      ActivateXd ();\r
+      InitializeSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
     }\r
 \r
     if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
@@ -1097,30 +1232,85 @@ SmiRendezvous (
         // BSP Handler is always called with a ValidSmi == TRUE\r
         //\r
         BSPHandler (CpuIndex, mSmmMpSyncData->EffectiveSyncMode);\r
-\r
       } else {\r
         APHandler (CpuIndex, ValidSmi, mSmmMpSyncData->EffectiveSyncMode);\r
       }\r
     }\r
 \r
-    ASSERT (mSmmMpSyncData->CpuData[CpuIndex].Run == 0);\r
+    ASSERT (*mSmmMpSyncData->CpuData[CpuIndex].Run == 0);\r
 \r
     //\r
     // Wait for BSP's signal to exit SMI\r
     //\r
-    while (mSmmMpSyncData->AllCpusInSync) {\r
+    while (*mSmmMpSyncData->AllCpusInSync) {\r
       CpuPause ();\r
     }\r
   }\r
 \r
 Exit:\r
   SmmCpuFeaturesRendezvousExit (CpuIndex);\r
+\r
   //\r
   // Restore Cr2\r
   //\r
-  AsmWriteCr2 (Cr2);\r
+  RestoreCr2 (Cr2);\r
 }\r
 \r
+/**\r
+  Allocate buffer for all semaphores and spin locks.\r
+\r
+**/\r
+VOID\r
+InitializeSmmCpuSemaphores (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                      ProcessorCount;\r
+  UINTN                      TotalSize;\r
+  UINTN                      GlobalSemaphoresSize;\r
+  UINTN                      CpuSemaphoresSize;\r
+  UINTN                      SemaphoreSize;\r
+  UINTN                      Pages;\r
+  UINTN                      *SemaphoreBlock;\r
+  UINTN                      SemaphoreAddr;\r
+\r
+  SemaphoreSize   = GetSpinLockProperties ();\r
+  ProcessorCount = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+  GlobalSemaphoresSize = (sizeof (SMM_CPU_SEMAPHORE_GLOBAL) / sizeof (VOID *)) * SemaphoreSize;\r
+  CpuSemaphoresSize    = (sizeof (SMM_CPU_SEMAPHORE_CPU) / sizeof (VOID *)) * ProcessorCount * SemaphoreSize;\r
+  TotalSize = GlobalSemaphoresSize + CpuSemaphoresSize;\r
+  DEBUG((EFI_D_INFO, "One Semaphore Size    = 0x%x\n", SemaphoreSize));\r
+  DEBUG((EFI_D_INFO, "Total Semaphores Size = 0x%x\n", TotalSize));\r
+  Pages = EFI_SIZE_TO_PAGES (TotalSize);\r
+  SemaphoreBlock = AllocatePages (Pages);\r
+  ASSERT (SemaphoreBlock != NULL);\r
+  ZeroMem (SemaphoreBlock, TotalSize);\r
+\r
+  SemaphoreAddr = (UINTN)SemaphoreBlock;\r
+  mSmmCpuSemaphores.SemaphoreGlobal.Counter       = (UINT32 *)SemaphoreAddr;\r
+  SemaphoreAddr += SemaphoreSize;\r
+  mSmmCpuSemaphores.SemaphoreGlobal.InsideSmm     = (BOOLEAN *)SemaphoreAddr;\r
+  SemaphoreAddr += SemaphoreSize;\r
+  mSmmCpuSemaphores.SemaphoreGlobal.AllCpusInSync = (BOOLEAN *)SemaphoreAddr;\r
+  SemaphoreAddr += SemaphoreSize;\r
+  mSmmCpuSemaphores.SemaphoreGlobal.PFLock        = (SPIN_LOCK *)SemaphoreAddr;\r
+  SemaphoreAddr += SemaphoreSize;\r
+  mSmmCpuSemaphores.SemaphoreGlobal.CodeAccessCheckLock\r
+                                                  = (SPIN_LOCK *)SemaphoreAddr;\r
+  SemaphoreAddr += SemaphoreSize;\r
+\r
+  SemaphoreAddr = (UINTN)SemaphoreBlock + GlobalSemaphoresSize;\r
+  mSmmCpuSemaphores.SemaphoreCpu.Busy    = (SPIN_LOCK *)SemaphoreAddr;\r
+  SemaphoreAddr += ProcessorCount * SemaphoreSize;\r
+  mSmmCpuSemaphores.SemaphoreCpu.Run     = (UINT32 *)SemaphoreAddr;\r
+  SemaphoreAddr += ProcessorCount * SemaphoreSize;\r
+  mSmmCpuSemaphores.SemaphoreCpu.Present = (BOOLEAN *)SemaphoreAddr;\r
+\r
+  mPFLock                       = mSmmCpuSemaphores.SemaphoreGlobal.PFLock;\r
+  mConfigSmmCodeAccessCheckLock = mSmmCpuSemaphores.SemaphoreGlobal.CodeAccessCheckLock;\r
+\r
+  mSemaphoreSize = SemaphoreSize;\r
+}\r
 \r
 /**\r
   Initialize un-cacheable data.\r
@@ -1132,7 +1322,13 @@ InitializeMpSyncData (
   VOID\r
   )\r
 {\r
+  UINTN                      CpuIndex;\r
+\r
   if (mSmmMpSyncData != NULL) {\r
+    //\r
+    // mSmmMpSyncDataSize includes one structure of SMM_DISPATCHER_MP_SYNC_DATA, one\r
+    // CpuData array of SMM_CPU_DATA_BLOCK and one CandidateBsp array of BOOLEAN.\r
+    //\r
     ZeroMem (mSmmMpSyncData, mSmmMpSyncDataSize);\r
     mSmmMpSyncData->CpuData = (SMM_CPU_DATA_BLOCK *)((UINT8 *)mSmmMpSyncData + sizeof (SMM_DISPATCHER_MP_SYNC_DATA));\r
     mSmmMpSyncData->CandidateBsp = (BOOLEAN *)(mSmmMpSyncData->CpuData + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
@@ -1142,32 +1338,72 @@ InitializeMpSyncData (
       //\r
       mSmmMpSyncData->BspIndex = (UINT32)-1;\r
     }\r
-    mSmmMpSyncData->EffectiveSyncMode = (SMM_CPU_SYNC_MODE) PcdGet8 (PcdCpuSmmSyncMode);\r
+    mSmmMpSyncData->EffectiveSyncMode = mCpuSmmSyncMode;\r
+\r
+    mSmmMpSyncData->Counter       = mSmmCpuSemaphores.SemaphoreGlobal.Counter;\r
+    mSmmMpSyncData->InsideSmm     = mSmmCpuSemaphores.SemaphoreGlobal.InsideSmm;\r
+    mSmmMpSyncData->AllCpusInSync = mSmmCpuSemaphores.SemaphoreGlobal.AllCpusInSync;\r
+    ASSERT (mSmmMpSyncData->Counter != NULL && mSmmMpSyncData->InsideSmm != NULL &&\r
+            mSmmMpSyncData->AllCpusInSync != NULL);\r
+    *mSmmMpSyncData->Counter       = 0;\r
+    *mSmmMpSyncData->InsideSmm     = FALSE;\r
+    *mSmmMpSyncData->AllCpusInSync = FALSE;\r
+\r
+    for (CpuIndex = 0; CpuIndex < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; CpuIndex ++) {\r
+      mSmmMpSyncData->CpuData[CpuIndex].Busy    =\r
+        (SPIN_LOCK *)((UINTN)mSmmCpuSemaphores.SemaphoreCpu.Busy + mSemaphoreSize * CpuIndex);\r
+      mSmmMpSyncData->CpuData[CpuIndex].Run     =\r
+        (UINT32 *)((UINTN)mSmmCpuSemaphores.SemaphoreCpu.Run + mSemaphoreSize * CpuIndex);\r
+      mSmmMpSyncData->CpuData[CpuIndex].Present =\r
+        (BOOLEAN *)((UINTN)mSmmCpuSemaphores.SemaphoreCpu.Present + mSemaphoreSize * CpuIndex);\r
+      *(mSmmMpSyncData->CpuData[CpuIndex].Busy)    = 0;\r
+      *(mSmmMpSyncData->CpuData[CpuIndex].Run)     = 0;\r
+      *(mSmmMpSyncData->CpuData[CpuIndex].Present) = FALSE;\r
+    }\r
   }\r
 }\r
 \r
 /**\r
   Initialize global data for MP synchronization.\r
 \r
-  @param Stacks       Base address of SMI stack buffer for all processors.\r
-  @param StackSize    Stack size for each processor in SMM.\r
+  @param Stacks             Base address of SMI stack buffer for all processors.\r
+  @param StackSize          Stack size for each processor in SMM.\r
+  @param ShadowStackSize    Shadow Stack size for each processor in SMM.\r
 \r
 **/\r
 UINT32\r
 InitializeMpServiceData (\r
   IN VOID        *Stacks,\r
-  IN UINTN       StackSize\r
+  IN UINTN       StackSize,\r
+  IN UINTN       ShadowStackSize\r
   )\r
 {\r
   UINT32                    Cr3;\r
   UINTN                     Index;\r
-  MTRR_SETTINGS             *Mtrr;\r
-  PROCESSOR_SMM_DESCRIPTOR  *Psd;\r
-  UINTN                     GdtTssTableSize;\r
   UINT8                     *GdtTssTables;\r
-  IA32_SEGMENT_DESCRIPTOR   *GdtDescriptor;\r
-  UINTN                     TssBase;\r
   UINTN                     GdtTableStepSize;\r
+  CPUID_VERSION_INFO_EDX    RegEdx;\r
+\r
+  //\r
+  // Determine if this CPU supports machine check\r
+  //\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx.Uint32);\r
+  mMachineCheckSupported = (BOOLEAN)(RegEdx.Bits.MCA == 1);\r
+\r
+  //\r
+  // Allocate memory for all locks and semaphores\r
+  //\r
+  InitializeSmmCpuSemaphores ();\r
+\r
+  //\r
+  // Initialize mSmmMpSyncData\r
+  //\r
+  mSmmMpSyncDataSize = sizeof (SMM_DISPATCHER_MP_SYNC_DATA) +\r
+                       (sizeof (SMM_CPU_DATA_BLOCK) + sizeof (BOOLEAN)) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+  mSmmMpSyncData = (SMM_DISPATCHER_MP_SYNC_DATA*) AllocatePages (EFI_SIZE_TO_PAGES (mSmmMpSyncDataSize));\r
+  ASSERT (mSmmMpSyncData != NULL);\r
+  mCpuSmmSyncMode = (SMM_CPU_SYNC_MODE)PcdGet8 (PcdCpuSmmSyncMode);\r
+  InitializeMpSyncData ();\r
 \r
   //\r
   // Initialize physical address mask\r
@@ -1182,122 +1418,30 @@ InitializeMpServiceData (
   //\r
   Cr3 = SmmInitPageTable ();\r
 \r
-  GdtTssTables    = NULL;\r
-  GdtTssTableSize = 0;\r
-  GdtTableStepSize = 0;\r
-  //\r
-  // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention\r
-  // on each SMI entry.\r
-  //\r
-  if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64)) {\r
-    GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned\r
-    GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
-    ASSERT (GdtTssTables != NULL);\r
-    GdtTableStepSize = GdtTssTableSize;\r
-\r
-    for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
-      CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);\r
-      if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
-        //\r
-        // Setup top of known good stack as IST1 for each processor.\r
-        //\r
-        *(UINTN *)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1 + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);\r
-      }\r
-    }\r
-  } else if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
-\r
-    //\r
-    // For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS.\r
-    // in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention\r
-    // on each SMI entry.\r
-    //\r
-\r
-    //\r
-    // Enlarge GDT to contain 2 TSS descriptors\r
-    //\r
-    gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));\r
-\r
-    GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned\r
-    GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
-    ASSERT (GdtTssTables != NULL);\r
-    GdtTableStepSize = GdtTssTableSize;\r
-\r
-    for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
-      CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2);\r
-      //\r
-      // Fixup TSS descriptors\r
-      //\r
-      TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);\r
-      GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;\r
-      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;\r
-      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
-      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);\r
-\r
-      TssBase += TSS_SIZE;\r
-      GdtDescriptor++;\r
-      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;\r
-      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
-      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);\r
-      //\r
-      // Fixup TSS segments\r
-      //\r
-      // ESP as known good stack\r
-      //\r
-      *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) =  mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;\r
-      *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;\r
-    }\r
-  }\r
+  GdtTssTables = InitGdt (Cr3, &GdtTableStepSize);\r
 \r
   //\r
-  // Initialize PROCESSOR_SMM_DESCRIPTOR for each CPU\r
+  // Install SMI handler for each CPU\r
   //\r
   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
-    Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(mCpuHotPlugData.SmBase[Index] + SMM_PSD_OFFSET);\r
-    CopyMem (Psd, &gcPsd, sizeof (gcPsd));\r
-    if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EFI_IMAGE_MACHINE_X64)) {\r
-      //\r
-      // For X64 SMM, set GDT to the copy allocated above.\r
-      //\r
-      Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTableStepSize * Index);\r
-    } else if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
-      //\r
-      // For IA32 SMM, if SMM Stack Guard feature is enabled, set GDT to the copy allocated above.\r
-      //\r
-      Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTableStepSize * Index);\r
-      Psd->SmmGdtSize = gcSmiGdtr.Limit + 1;\r
-    }\r
-\r
-    //\r
-    // Install SMI handler\r
-    //\r
     InstallSmiHandler (\r
       Index,\r
       (UINT32)mCpuHotPlugData.SmBase[Index],\r
-      (VOID*)((UINTN)Stacks + (StackSize * Index)),\r
+      (VOID*)((UINTN)Stacks + (StackSize + ShadowStackSize) * Index),\r
       StackSize,\r
-      (UINTN)Psd->SmmGdtPtr,\r
-      Psd->SmmGdtSize,\r
+      (UINTN)(GdtTssTables + GdtTableStepSize * Index),\r
+      gcSmiGdtr.Limit + 1,\r
       gcSmiIdtr.Base,\r
       gcSmiIdtr.Limit + 1,\r
       Cr3\r
       );\r
   }\r
 \r
-  //\r
-  // Initialize mSmmMpSyncData\r
-  //\r
-  mSmmMpSyncDataSize = sizeof (SMM_DISPATCHER_MP_SYNC_DATA) +\r
-                       (sizeof (SMM_CPU_DATA_BLOCK) + sizeof (BOOLEAN)) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
-  mSmmMpSyncData = (SMM_DISPATCHER_MP_SYNC_DATA*) AllocatePages (EFI_SIZE_TO_PAGES (mSmmMpSyncDataSize));\r
-  ASSERT (mSmmMpSyncData != NULL);\r
-  InitializeMpSyncData ();\r
-\r
   //\r
   // Record current MTRR settings\r
   //\r
-  ZeroMem(gSmiMtrrs, sizeof (gSmiMtrrs));\r
-  Mtrr =  (MTRR_SETTINGS*)gSmiMtrrs;\r
-  MtrrGetAllMtrrs (Mtrr);\r
+  ZeroMem (&gSmiMtrrs, sizeof (gSmiMtrrs));\r
+  MtrrGetAllMtrrs (&gSmiMtrrs);\r
 \r
   return Cr3;\r
 }\r