]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
UefiCpuPkg/PiSmmCpuDxeSmm: Add paging protection.
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / PiSmmCpuDxeSmm.c
index c351875262b495728b795e96883a671fa9b83518..4baba1e9f8dc1bbd1a8925be4e6683338d1ffc8c 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.\r
 \r
-Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2016, 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
@@ -76,13 +76,6 @@ EFI_SMM_CPU_PROTOCOL  mSmmCpu  = {
 \r
 EFI_CPU_INTERRUPT_HANDLER   mExternalVectorTable[EXCEPTION_VECTOR_NUMBER];\r
 \r
-///\r
-/// SMM CPU Save State Protocol instance\r
-///\r
-EFI_SMM_CPU_SAVE_STATE_PROTOCOL  mSmmCpuSaveState = {\r
-  NULL\r
-};\r
-\r
 //\r
 // SMM stack information\r
 //\r
@@ -90,11 +83,6 @@ UINTN mSmmStackArrayBase;
 UINTN mSmmStackArrayEnd;\r
 UINTN mSmmStackSize;\r
 \r
-//\r
-// Pointer to structure used during S3 Resume\r
-//\r
-SMM_S3_RESUME_STATE *mSmmS3ResumeState = NULL;\r
-\r
 UINTN mMaxNumberOfCpus = 1;\r
 UINTN mNumberOfCpus = 1;\r
 \r
@@ -111,7 +99,7 @@ BOOLEAN                  mSmmCodeAccessCheckEnable = FALSE;
 //\r
 // Spin lock used to serialize setting of SMM Code Access Check feature\r
 //\r
-SPIN_LOCK                mConfigSmmCodeAccessCheckLock;\r
+SPIN_LOCK                *mConfigSmmCodeAccessCheckLock = NULL;\r
 \r
 /**\r
   Initialize IDT to setup exception handlers for SMM.\r
@@ -125,6 +113,19 @@ InitializeSmmIdt (
   EFI_STATUS               Status;\r
   BOOLEAN                  InterruptState;\r
   IA32_DESCRIPTOR          DxeIdtr;\r
+\r
+  //\r
+  // There are 32 (not 255) entries in it since only processor\r
+  // generated exceptions will be handled.\r
+  //\r
+  gcSmiIdtr.Limit = (sizeof(IA32_IDT_GATE_DESCRIPTOR) * 32) - 1;\r
+  //\r
+  // Allocate page aligned IDT, because it might be set as read only.\r
+  //\r
+  gcSmiIdtr.Base = (UINTN)AllocateCodePages (EFI_SIZE_TO_PAGES(gcSmiIdtr.Limit + 1));\r
+  ASSERT (gcSmiIdtr.Base != 0);\r
+  ZeroMem ((VOID *)gcSmiIdtr.Base, gcSmiIdtr.Limit + 1);\r
+\r
   //\r
   // Disable Interrupt and save DXE IDT table\r
   //\r
@@ -253,7 +254,7 @@ SmmReadSaveState (
     // the pseudo register value for EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID is returned in Buffer.\r
     // Otherwise, EFI_NOT_FOUND is returned.\r
     //\r
-    if (mSmmMpSyncData->CpuData[CpuIndex].Present) {\r
+    if (*(mSmmMpSyncData->CpuData[CpuIndex].Present)) {\r
       *(UINT64 *)Buffer = gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId;\r
       return EFI_SUCCESS;\r
     } else {\r
@@ -261,7 +262,7 @@ SmmReadSaveState (
     }\r
   }\r
 \r
-  if (!mSmmMpSyncData->CpuData[CpuIndex].Present) {\r
+  if (!(*(mSmmMpSyncData->CpuData[CpuIndex].Present))) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -357,6 +358,13 @@ SmmInitHandler (
         &mCpuHotPlugData\r
         );\r
 \r
+      if (!mSmmS3Flag) {\r
+        //\r
+        // Check XD and BTS features on each processor on normal boot\r
+        //\r
+        CheckFeatureSupported ();\r
+      }\r
+\r
       if (mIsBsp) {\r
         //\r
         // BSP rebase is already done above.\r
@@ -473,190 +481,6 @@ SmmRelocateBases (
   CopyMem (U8Ptr, BakBuf, sizeof (BakBuf));\r
 }\r
 \r
-/**\r
-  Perform SMM initialization for all processors in the S3 boot path.\r
-\r
-  For a native platform, MP initialization in the S3 boot path is also performed in this function.\r
-**/\r
-VOID\r
-EFIAPI\r
-SmmRestoreCpu (\r
-  VOID\r
-  )\r
-{\r
-  SMM_S3_RESUME_STATE           *SmmS3ResumeState;\r
-  IA32_DESCRIPTOR               Ia32Idtr;\r
-  IA32_DESCRIPTOR               X64Idtr;\r
-  IA32_IDT_GATE_DESCRIPTOR      IdtEntryTable[EXCEPTION_VECTOR_NUMBER];\r
-  EFI_STATUS                    Status;\r
-\r
-  DEBUG ((EFI_D_INFO, "SmmRestoreCpu()\n"));\r
-\r
-  //\r
-  // See if there is enough context to resume PEI Phase\r
-  //\r
-  if (mSmmS3ResumeState == NULL) {\r
-    DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));\r
-    CpuDeadLoop ();\r
-  }\r
-\r
-  SmmS3ResumeState = mSmmS3ResumeState;\r
-  ASSERT (SmmS3ResumeState != NULL);\r
-\r
-  if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {\r
-    //\r
-    // Save the IA32 IDT Descriptor\r
-    //\r
-    AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);\r
-\r
-    //\r
-    // Setup X64 IDT table\r
-    //\r
-    ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32);\r
-    X64Idtr.Base = (UINTN) IdtEntryTable;\r
-    X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1);\r
-    AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr);\r
-\r
-    //\r
-    // Setup the default exception handler\r
-    //\r
-    Status = InitializeCpuExceptionHandlers (NULL);\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    //\r
-    // Initialize Debug Agent to support source level debug\r
-    //\r
-    InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL);\r
-  }\r
-\r
-  //\r
-  // Do below CPU things for native platform only\r
-  //\r
-  if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {\r
-    //\r
-    // Skip initialization if mAcpiCpuData is not valid\r
-    //\r
-    if (mAcpiCpuData.NumberOfCpus > 0) {\r
-      //\r
-      // First time microcode load and restore MTRRs\r
-      //\r
-      EarlyInitializeCpu ();\r
-    }\r
-  }\r
-\r
-  //\r
-  // Restore SMBASE for BSP and all APs\r
-  //\r
-  SmmRelocateBases ();\r
-\r
-  //\r
-  // Do below CPU things for native platform only\r
-  //\r
-  if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {\r
-    //\r
-    // Skip initialization if mAcpiCpuData is not valid\r
-    //\r
-    if (mAcpiCpuData.NumberOfCpus > 0) {\r
-      //\r
-      // Restore MSRs for BSP and all APs\r
-      //\r
-      InitializeCpu ();\r
-    }\r
-  }\r
-\r
-  //\r
-  // Set a flag to restore SMM configuration in S3 path.\r
-  //\r
-  mRestoreSmmConfigurationInS3 = TRUE;\r
-\r
-  DEBUG (( EFI_D_INFO, "SMM S3 Return CS                = %x\n", SmmS3ResumeState->ReturnCs));\r
-  DEBUG (( EFI_D_INFO, "SMM S3 Return Entry Point       = %x\n", SmmS3ResumeState->ReturnEntryPoint));\r
-  DEBUG (( EFI_D_INFO, "SMM S3 Return Context1          = %x\n", SmmS3ResumeState->ReturnContext1));\r
-  DEBUG (( EFI_D_INFO, "SMM S3 Return Context2          = %x\n", SmmS3ResumeState->ReturnContext2));\r
-  DEBUG (( EFI_D_INFO, "SMM S3 Return Stack Pointer     = %x\n", SmmS3ResumeState->ReturnStackPointer));\r
-\r
-  //\r
-  // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase\r
-  //\r
-  if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {\r
-    DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));\r
-\r
-    SwitchStack (\r
-      (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint,\r
-      (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1,\r
-      (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2,\r
-      (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer\r
-      );\r
-  }\r
-\r
-  //\r
-  // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase\r
-  //\r
-  if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {\r
-    DEBUG ((EFI_D_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));\r
-    //\r
-    // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.\r
-    //\r
-    SaveAndSetDebugTimerInterrupt (FALSE);\r
-    //\r
-    // Restore IA32 IDT table\r
-    //\r
-    AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);\r
-    AsmDisablePaging64 (\r
-      SmmS3ResumeState->ReturnCs,\r
-      (UINT32)SmmS3ResumeState->ReturnEntryPoint,\r
-      (UINT32)SmmS3ResumeState->ReturnContext1,\r
-      (UINT32)SmmS3ResumeState->ReturnContext2,\r
-      (UINT32)SmmS3ResumeState->ReturnStackPointer\r
-      );\r
-  }\r
-\r
-  //\r
-  // Can not resume PEI Phase\r
-  //\r
-  DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));\r
-  CpuDeadLoop ();\r
-}\r
-\r
-/**\r
-  Copy register table from ACPI NVS memory into SMRAM.\r
-\r
-  @param[in] DestinationRegisterTableList  Points to destination register table.\r
-  @param[in] SourceRegisterTableList       Points to source register table.\r
-  @param[in] NumberOfCpus                  Number of CPUs.\r
-\r
-**/\r
-VOID\r
-CopyRegisterTable (\r
-  IN CPU_REGISTER_TABLE         *DestinationRegisterTableList,\r
-  IN CPU_REGISTER_TABLE         *SourceRegisterTableList,\r
-  IN UINT32                     NumberOfCpus\r
-  )\r
-{\r
-  UINTN                      Index;\r
-  UINTN                      Index1;\r
-  CPU_REGISTER_TABLE_ENTRY   *RegisterTableEntry;\r
-\r
-  CopyMem (DestinationRegisterTableList, SourceRegisterTableList, NumberOfCpus * sizeof (CPU_REGISTER_TABLE));\r
-  for (Index = 0; Index < NumberOfCpus; Index++) {\r
-    DestinationRegisterTableList[Index].RegisterTableEntry = AllocatePool (DestinationRegisterTableList[Index].AllocatedSize);\r
-    ASSERT (DestinationRegisterTableList[Index].RegisterTableEntry != NULL);\r
-    CopyMem (DestinationRegisterTableList[Index].RegisterTableEntry, SourceRegisterTableList[Index].RegisterTableEntry, DestinationRegisterTableList[Index].AllocatedSize);\r
-    //\r
-    // Go though all MSRs in register table to initialize MSR spin lock\r
-    //\r
-    RegisterTableEntry = DestinationRegisterTableList[Index].RegisterTableEntry;\r
-    for (Index1 = 0; Index1 < DestinationRegisterTableList[Index].TableLength; Index1++, RegisterTableEntry++) {\r
-      if ((RegisterTableEntry->RegisterType == Msr) && (RegisterTableEntry->ValidBitLength < 64)) {\r
-        //\r
-        // Initialize MSR spin lock only for those MSRs need bit field writing\r
-        //\r
-        InitMsrSpinLockByIndex (RegisterTableEntry->Index);\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
 /**\r
   SMM Ready To Lock event notification handler.\r
 \r
@@ -677,84 +501,8 @@ SmmReadyToLockEventNotify (
   IN EFI_HANDLE      Handle\r
   )\r
 {\r
-  ACPI_CPU_DATA              *AcpiCpuData;\r
-  IA32_DESCRIPTOR            *Gdtr;\r
-  IA32_DESCRIPTOR            *Idtr;\r
-\r
-  //\r
-  // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0\r
-  //\r
-  mAcpiCpuData.NumberOfCpus = 0;\r
-\r
-  //\r
-  // If FrameworkCompatibilitySspport is enabled, then do not copy CPU S3 Data into SMRAM\r
-  //\r
-  if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
-    goto Done;\r
-  }\r
-\r
-  //\r
-  // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM\r
-  //\r
-  AcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);\r
-  if (AcpiCpuData == 0) {\r
-    goto Done;\r
-  }\r
-\r
-  //\r
-  // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume.\r
-  //\r
-  CopyMem (&mAcpiCpuData, AcpiCpuData, sizeof (mAcpiCpuData));\r
-\r
-  mAcpiCpuData.MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (MTRR_SETTINGS));\r
-  ASSERT (mAcpiCpuData.MtrrTable != 0);\r
-\r
-  CopyMem ((VOID *)(UINTN)mAcpiCpuData.MtrrTable, (VOID *)(UINTN)AcpiCpuData->MtrrTable, sizeof (MTRR_SETTINGS));\r
-\r
-  mAcpiCpuData.GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));\r
-  ASSERT (mAcpiCpuData.GdtrProfile != 0);\r
-\r
-  CopyMem ((VOID *)(UINTN)mAcpiCpuData.GdtrProfile, (VOID *)(UINTN)AcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR));\r
-\r
-  mAcpiCpuData.IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));\r
-  ASSERT (mAcpiCpuData.IdtrProfile != 0);\r
+  GetAcpiCpuData ();\r
 \r
-  CopyMem ((VOID *)(UINTN)mAcpiCpuData.IdtrProfile, (VOID *)(UINTN)AcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR));\r
-\r
-  mAcpiCpuData.PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));\r
-  ASSERT (mAcpiCpuData.PreSmmInitRegisterTable != 0);\r
-\r
-  CopyRegisterTable (\r
-    (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.PreSmmInitRegisterTable,\r
-    (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->PreSmmInitRegisterTable,\r
-    mAcpiCpuData.NumberOfCpus\r
-    );\r
-\r
-  mAcpiCpuData.RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));\r
-  ASSERT (mAcpiCpuData.RegisterTable != 0);\r
-\r
-  CopyRegisterTable (\r
-    (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.RegisterTable,\r
-    (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable,\r
-    mAcpiCpuData.NumberOfCpus\r
-    );\r
-\r
-  //\r
-  // Copy AP's GDT, IDT and Machine Check handler into SMRAM.\r
-  //\r
-  Gdtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.GdtrProfile;\r
-  Idtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.IdtrProfile;\r
-\r
-  mGdtForAp = AllocatePool ((Gdtr->Limit + 1) + (Idtr->Limit + 1) +  mAcpiCpuData.ApMachineCheckHandlerSize);\r
-  ASSERT (mGdtForAp != NULL);\r
-  mIdtForAp = (VOID *) ((UINTN)mGdtForAp + (Gdtr->Limit + 1));\r
-  mMachineCheckHandlerForAp = (VOID *) ((UINTN)mIdtForAp + (Idtr->Limit + 1));\r
-\r
-  CopyMem (mGdtForAp, (VOID *)Gdtr->Base, Gdtr->Limit + 1);\r
-  CopyMem (mIdtForAp, (VOID *)Idtr->Base, Idtr->Limit + 1);\r
-  CopyMem (mMachineCheckHandlerForAp, (VOID *)(UINTN)mAcpiCpuData.ApMachineCheckHandlerBase, mAcpiCpuData.ApMachineCheckHandlerSize);\r
-\r
-Done:\r
   //\r
   // Set SMM ready to lock flag and return\r
   //\r
@@ -784,10 +532,10 @@ PiCpuSmmEntry (
   UINTN                      NumberOfEnabledProcessors;\r
   UINTN                      Index;\r
   VOID                       *Buffer;\r
+  UINTN                      BufferPages;\r
+  UINTN                      TileCodeSize;\r
+  UINTN                      TileDataSize;\r
   UINTN                      TileSize;\r
-  VOID                       *GuidHob;\r
-  EFI_SMRAM_DESCRIPTOR       *SmramDescriptor;\r
-  SMM_S3_RESUME_STATE        *SmmS3ResumeState;\r
   UINT8                      *Stacks;\r
   VOID                       *Registration;\r
   UINT32                     RegEax;\r
@@ -934,13 +682,18 @@ PiCpuSmmEntry (
   //\r
   // Retrieve CPU Family\r
   //\r
-  AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);\r
+  AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
   FamilyId = (RegEax >> 8) & 0xf;\r
   ModelId = (RegEax >> 4) & 0xf;\r
   if (FamilyId == 0x06 || FamilyId == 0x0f) {\r
     ModelId = ModelId | ((RegEax >> 12) & 0xf0);\r
   }\r
 \r
+  RegEdx = 0;\r
+  AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
+  if (RegEax >= CPUID_EXTENDED_CPU_SIG) {\r
+    AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
+  }\r
   //\r
   // Determine the mode of the CPU at the time an SMI occurs\r
   //   Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
@@ -961,9 +714,13 @@ PiCpuSmmEntry (
   // specific context in a PROCESSOR_SMM_DESCRIPTOR, and the SMI entry point.  This size\r
   // is rounded up to nearest power of 2.\r
   //\r
-  TileSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR) + GetSmiHandlerSize () - 1;\r
+  TileCodeSize = GetSmiHandlerSize ();\r
+  TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);\r
+  TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);\r
+  TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);\r
+  TileSize = TileDataSize + TileCodeSize - 1;\r
   TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);\r
-  DEBUG ((EFI_D_INFO, "SMRAM TileSize = %08x\n", TileSize));\r
+  DEBUG ((EFI_D_INFO, "SMRAM TileSize = 0x%08x (0x%08x, 0x%08x)\n", TileSize, TileCodeSize, TileDataSize));\r
 \r
   //\r
   // If the TileSize is larger than space available for the SMI Handler of CPU[i],\r
@@ -985,12 +742,14 @@ PiCpuSmmEntry (
   // Intel486 processors: FamilyId is 4\r
   // Pentium processors : FamilyId is 5\r
   //\r
+  BufferPages = EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1));\r
   if ((FamilyId == 4) || (FamilyId == 5)) {\r
-    Buffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1)), SIZE_32KB);\r
+    Buffer = AllocateAlignedCodePages (BufferPages, SIZE_32KB);\r
   } else {\r
-    Buffer = AllocatePages (EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1)));\r
+    Buffer = AllocateAlignedCodePages (BufferPages, SIZE_4KB);\r
   }\r
   ASSERT (Buffer != NULL);\r
+  DEBUG ((EFI_D_INFO, "SMRAM SaveState Buffer (0x%08x, 0x%08x)\n", Buffer, EFI_PAGES_TO_SIZE(BufferPages)));\r
 \r
   //\r
   // Allocate buffer for pointers to array in  SMM_CPU_PRIVATE_DATA.\r
@@ -1009,7 +768,6 @@ PiCpuSmmEntry (
 \r
   mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveStateSize = gSmmCpuPrivate->CpuSaveStateSize;\r
   mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveState     = gSmmCpuPrivate->CpuSaveState;\r
-  mSmmCpuSaveState.CpuSaveState = (EFI_SMM_CPU_STATE **)gSmmCpuPrivate->CpuSaveState;\r
 \r
   //\r
   // Allocate buffer for pointers to array in CPU_HOT_PLUG_DATA.\r
@@ -1097,6 +855,8 @@ PiCpuSmmEntry (
   //\r
   SmmCpuFeaturesSmmRelocationComplete ();\r
 \r
+  DEBUG ((DEBUG_INFO, "mXdSupported - 0x%x\n", mXdSupported));\r
+\r
   //\r
   // SMM Time initialization\r
   //\r
@@ -1150,25 +910,6 @@ PiCpuSmmEntry (
   Status = InitializeSmmCpuServices (mSmmCpuHandle);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
-    //\r
-    // Install Framework SMM Save State Protocol into UEFI protocol database for backward compatibility\r
-    //\r
-    Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (\r
-                                          &gSmmCpuPrivate->SmmCpuHandle,\r
-                                          &gEfiSmmCpuSaveStateProtocolGuid,\r
-                                          &mSmmCpuSaveState,\r
-                                          NULL\r
-                                          );\r
-    ASSERT_EFI_ERROR (Status);\r
-    //\r
-    // The SmmStartupThisAp service in Framework SMST should always be non-null.\r
-    // Update SmmStartupThisAp pointer in PI SMST here so that PI/Framework SMM thunk\r
-    // can have it ready when constructing Framework SMST.\r
-    //\r
-    gSmst->SmmStartupThisAp = SmmStartupThisAp;\r
-  }\r
-\r
   //\r
   // register SMM Ready To Lock Protocol notification\r
   //\r
@@ -1179,53 +920,13 @@ PiCpuSmmEntry (
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);\r
-  if (GuidHob != NULL) {\r
-    SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);\r
-\r
-    DEBUG ((EFI_D_INFO, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor));\r
-    DEBUG ((EFI_D_INFO, "SMM S3 Structure = %x\n", SmramDescriptor->CpuStart));\r
-\r
-    SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;\r
-    ZeroMem (SmmS3ResumeState, sizeof (SMM_S3_RESUME_STATE));\r
-\r
-    mSmmS3ResumeState = SmmS3ResumeState;\r
-    SmmS3ResumeState->Smst = (EFI_PHYSICAL_ADDRESS)(UINTN)gSmst;\r
-\r
-    SmmS3ResumeState->SmmS3ResumeEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)SmmRestoreCpu;\r
-\r
-    SmmS3ResumeState->SmmS3StackSize = SIZE_32KB;\r
-    SmmS3ResumeState->SmmS3StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)SmmS3ResumeState->SmmS3StackSize));\r
-    if (SmmS3ResumeState->SmmS3StackBase == 0) {\r
-      SmmS3ResumeState->SmmS3StackSize = 0;\r
-    }\r
-\r
-    SmmS3ResumeState->SmmS3Cr0 = gSmmCr0;\r
-    SmmS3ResumeState->SmmS3Cr3 = Cr3;\r
-    SmmS3ResumeState->SmmS3Cr4 = gSmmCr4;\r
-\r
-    if (sizeof (UINTN) == sizeof (UINT64)) {\r
-      SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_64;\r
-    }\r
-    if (sizeof (UINTN) == sizeof (UINT32)) {\r
-      SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_32;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Check XD and BTS features\r
-  //\r
-  CheckProcessorFeature ();\r
-\r
   //\r
   // Initialize SMM Profile feature\r
   //\r
   InitSmmProfile (Cr3);\r
 \r
-  //\r
-  // Patch SmmS3ResumeState->SmmS3Cr3\r
-  //\r
-  InitSmmS3Cr3 ();\r
+  GetAcpiS3EnableFlag ();\r
+  InitSmmS3ResumeState (Cr3);\r
 \r
   DEBUG ((EFI_D_INFO, "SMM CPU Module exit from SMRAM with EFI_SUCCESS\n"));\r
 \r
@@ -1318,6 +1019,7 @@ FindSmramInfo (
     }\r
   } while (Found);\r
 \r
+  FreePool (SmramRanges);\r
   DEBUG ((EFI_D_INFO, "SMRR Base: 0x%x, SMRR Size: 0x%x\n", *SmrrBase, *SmrrSize));\r
 }\r
 \r
@@ -1353,9 +1055,9 @@ ConfigSmmCodeAccessCheckOnCurrentProcessor (
   NewSmmFeatureControlMsr = SmmFeatureControlMsr;\r
   if (mSmmCodeAccessCheckEnable) {\r
     NewSmmFeatureControlMsr |= SMM_CODE_CHK_EN_BIT;\r
-  }\r
-  if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {\r
-    NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT;\r
+    if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {\r
+      NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT;\r
+    }\r
   }\r
 \r
   //\r
@@ -1368,7 +1070,7 @@ ConfigSmmCodeAccessCheckOnCurrentProcessor (
   //\r
   // Release the spin lock user to serialize the updates to the SMM Feature Control MSR\r
   //\r
-  ReleaseSpinLock (&mConfigSmmCodeAccessCheckLock);\r
+  ReleaseSpinLock (mConfigSmmCodeAccessCheckLock);\r
 }\r
 \r
 /**\r
@@ -1398,26 +1100,19 @@ ConfigSmmCodeAccessCheck (
   //\r
   if ((AsmReadMsr64 (EFI_MSR_SMM_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) == 0) {\r
     mSmmCodeAccessCheckEnable = FALSE;\r
-  }\r
-\r
-  //\r
-  // If the SMM Code Access Check feature is disabled and the Feature Control MSR\r
-  // is not being locked, then no additional work is required\r
-  //\r
-  if (!mSmmCodeAccessCheckEnable && !FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {\r
     return;\r
   }\r
 \r
   //\r
   // Initialize the lock used to serialize the MSR programming in BSP and all APs\r
   //\r
-  InitializeSpinLock (&mConfigSmmCodeAccessCheckLock);\r
+  InitializeSpinLock (mConfigSmmCodeAccessCheckLock);\r
 \r
   //\r
   // Acquire Config SMM Code Access Check spin lock.  The BSP will release the\r
   // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().\r
   //\r
-  AcquireSpinLock (&mConfigSmmCodeAccessCheckLock);\r
+  AcquireSpinLock (mConfigSmmCodeAccessCheckLock);\r
 \r
   //\r
   // Enable SMM Code Access Check feature on the BSP.\r
@@ -1434,7 +1129,7 @@ ConfigSmmCodeAccessCheck (
       // Acquire Config SMM Code Access Check spin lock.  The AP will release the\r
       // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().\r
       //\r
-      AcquireSpinLock (&mConfigSmmCodeAccessCheckLock);\r
+      AcquireSpinLock (mConfigSmmCodeAccessCheckLock);\r
 \r
       //\r
       // Call SmmStartupThisAp() to enable SMM Code Access Check on an AP.\r
@@ -1445,16 +1140,159 @@ ConfigSmmCodeAccessCheck (
       //\r
       // Wait for the AP to release the Config SMM Code Access Check spin lock.\r
       //\r
-      while (!AcquireSpinLockOrFail (&mConfigSmmCodeAccessCheckLock)) {\r
+      while (!AcquireSpinLockOrFail (mConfigSmmCodeAccessCheckLock)) {\r
         CpuPause ();\r
       }\r
 \r
       //\r
       // Release the Config SMM Code Access Check spin lock.\r
       //\r
-      ReleaseSpinLock (&mConfigSmmCodeAccessCheckLock);\r
+      ReleaseSpinLock (mConfigSmmCodeAccessCheckLock);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Set code region to be read only and data region to be execute disable.\r
+**/\r
+VOID\r
+SetRegionAttributes (\r
+  VOID\r
+  )\r
+{\r
+  SetMemMapAttributes ();\r
+}\r
+\r
+/**\r
+  This API provides a way to allocate memory for page table.\r
+\r
+  This API can be called more once to allocate memory for page tables.\r
+\r
+  Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the\r
+  allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL\r
+  is returned.  If there is not enough memory remaining to satisfy the request, then NULL is\r
+  returned.\r
+\r
+  @param  Pages                 The number of 4 KB pages to allocate.\r
+\r
+  @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+AllocatePageTableMemory (\r
+  IN UINTN           Pages\r
+  )\r
+{\r
+  VOID  *Buffer;\r
+\r
+  Buffer = SmmCpuFeaturesAllocatePageTableMemory (Pages);\r
+  if (Buffer != NULL) {\r
+    return Buffer;\r
+  }\r
+  return AllocatePages (Pages);\r
+}\r
+\r
+/**\r
+  Allocate pages for code.\r
+\r
+  @param[in]  Pages Number of pages to be allocated.\r
+\r
+  @return Allocated memory.\r
+**/\r
+VOID *\r
+AllocateCodePages (\r
+  IN UINTN           Pages\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Memory;\r
+\r
+  if (Pages == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  return (VOID *) (UINTN) Memory;\r
+}\r
+\r
+/**\r
+  Allocate aligned pages for code.\r
+\r
+  @param[in]  Pages                 Number of pages to be allocated.\r
+  @param[in]  Alignment             The requested alignment of the allocation.\r
+                                    Must be a power of two.\r
+                                    If Alignment is zero, then byte alignment is used.\r
+\r
+  @return Allocated memory.\r
+**/\r
+VOID *\r
+AllocateAlignedCodePages (\r
+  IN UINTN            Pages,\r
+  IN UINTN            Alignment\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Memory;\r
+  UINTN                 AlignedMemory;\r
+  UINTN                 AlignmentMask;\r
+  UINTN                 UnalignedPages;\r
+  UINTN                 RealPages;\r
+\r
+  //\r
+  // Alignment must be a power of two or zero.\r
+  //\r
+  ASSERT ((Alignment & (Alignment - 1)) == 0);\r
+\r
+  if (Pages == 0) {\r
+    return NULL;\r
+  }\r
+  if (Alignment > EFI_PAGE_SIZE) {\r
+    //\r
+    // Calculate the total number of pages since alignment is larger than page size.\r
+    //\r
+    AlignmentMask  = Alignment - 1;\r
+    RealPages      = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
+    //\r
+    // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
+    //\r
+    ASSERT (RealPages > Pages);\r
+\r
+    Status         = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, RealPages, &Memory);\r
+    if (EFI_ERROR (Status)) {\r
+      return NULL;\r
+    }\r
+    AlignedMemory  = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+    UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
+    if (UnalignedPages > 0) {\r
+      //\r
+      // Free first unaligned page(s).\r
+      //\r
+      Status = gSmst->SmmFreePages (Memory, UnalignedPages);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    Memory         = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
+    UnalignedPages = RealPages - Pages - UnalignedPages;\r
+    if (UnalignedPages > 0) {\r
+      //\r
+      // Free last unaligned page(s).\r
+      //\r
+      Status = gSmst->SmmFreePages (Memory, UnalignedPages);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+  } else {\r
+    //\r
+    // Do not over-allocate pages in this case.\r
+    //\r
+    Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);\r
+    if (EFI_ERROR (Status)) {\r
+      return NULL;\r
     }\r
+    AlignedMemory  = (UINTN) Memory;\r
   }\r
+  return (VOID *) AlignedMemory;\r
 }\r
 \r
 /**\r
@@ -1477,14 +1315,39 @@ PerformRemainingTasks (
     // Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.\r
     //\r
     InitPaging ();\r
+\r
+    //\r
+    // Mark critical region to be read-only in page table\r
+    //\r
+    SetRegionAttributes ();\r
+\r
+    //\r
+    // Set page table itself to be read-only\r
+    //\r
+    SetPageTableAttributes ();\r
+\r
     //\r
     // Configure SMM Code Access Check feature if available.\r
     //\r
     ConfigSmmCodeAccessCheck ();\r
 \r
+    SmmCpuFeaturesCompleteSmmReadyToLock ();\r
+\r
     //\r
     // Clean SMM ready to lock flag\r
     //\r
     mSmmReadyToLock = FALSE;\r
   }\r
 }\r
+\r
+/**\r
+  Perform the pre tasks.\r
+\r
+**/\r
+VOID\r
+PerformPreTasks (\r
+  VOID\r
+  )\r
+{\r
+  RestoreSmmConfigurationInS3 ();\r
+}\r