public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] UefiCpuPkg/PiSmmCpu: Fixed #double fault on #page fault.
@ 2016-11-23 14:54 Jiewen Yao
  2016-11-23 22:28 ` Laszlo Ersek
  0 siblings, 1 reply; 3+ messages in thread
From: Jiewen Yao @ 2016-11-23 14:54 UTC (permalink / raw)
  To: edk2-devel; +Cc: Laszlo Ersek, Jeff Fan, Michael D Kinney

This patch fixes https://bugzilla.tianocore.org/show_bug.cgi?id=246

Previously, when SMM exception happens after EndOfDxe,
with StackGuard enabled on IA32, the #double fault exception
is reported instead of #page fault.

Root cause is below:

Current EDKII SMM page protection will lock GDT.
If IA32 stack guard is enabled, the page fault handler will do task switch.
This task switch need write busy flag in GDT, and write TSS.

However, the GDT and TSS is locked at that time, so the
double fault happens.

This issue does not exist on X64, or IA32 without StackGuard.

In this enhanced solution, we create a special GDT whose CS/DS is
at read-only page, and whose TSS segment is at read-write page.
We also put TSS into a read-write page.

The detail is at UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c.

Then the normal code can being protected, because it does not touch TSS.
When page fault happens, the TSS region can be written.

This fix is IA32 StackGuard specific.

Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Jeff Fan <jeff.fan@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S          |   2 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm        |   2 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm       |   2 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S      |   4 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm    |   4 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm   |   4 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c      | 207 ++++++++++++++++----
 UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c              |   7 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h         |  78 +++++++-
 UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c |  48 -----
 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c       |  67 ++++++-
 11 files changed, 311 insertions(+), 114 deletions(-)

diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
index 0c07558..e27080d 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
@@ -41,7 +41,7 @@ ASM_GLOBAL  ASM_PFX(gSmiHandlerIdtr)
 
 .equ            PROTECT_MODE_CS, 0x08
 .equ            PROTECT_MODE_DS, 0x20
-.equ            TSS_SEGMENT,     0x40
+.equ            TSS_SEGMENT,     0x1000
 
     .text
 
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
index eda1708..e1ab470 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
@@ -36,7 +36,7 @@ DSC_OTHERSEG  EQU     20
 
 PROTECT_MODE_CS EQU   08h
 PROTECT_MODE_DS EQU   20h
-TSS_SEGMENT     EQU   40h
+TSS_SEGMENT     EQU   1000h
 
 SmiRendezvous      PROTO   C
 CpuSmmDebugEntry   PROTO   C
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
index d50a317..ccfb0d4 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
@@ -32,7 +32,7 @@
 
 %define PROTECT_MODE_CS 0x8
 %define PROTECT_MODE_DS 0x20
-%define TSS_SEGMENT 0x40
+%define TSS_SEGMENT 0x1000
 
 extern ASM_PFX(SmiRendezvous)
 extern ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
index cf5ef82..30dd25e 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
@@ -99,8 +99,8 @@ ExceptionTssSeg:
 
 .equ  CODE_SEL,          CodeSeg32 - NullSeg
 .equ  DATA_SEL,          DataSeg32 - NullSeg
-.equ  TSS_SEL,           TssSeg - NullSeg
-.equ  EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
+.equ  TSS_SEL,           0x1000
+.equ  EXCEPTION_TSS_SEL, 0x1008
 
 # IA32 TSS fields
 .equ  TSS_ESP0,          4
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
index 7b162f8..740e4a5 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
@@ -102,8 +102,8 @@ ExceptionTssSeg     LABEL   QWORD
 
 CODE_SEL          = offset CodeSeg32 - offset NullSeg
 DATA_SEL          = offset DataSeg32 - offset NullSeg
-TSS_SEL           = offset TssSeg - offset NullSeg
-EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
+TSS_SEL               EQU   1000h
+EXCEPTION_TSS_SEL     EQU   1008h
 
 IA32_TSS STRUC
                     DW ?
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
index 4d58999..a6dcf47 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
@@ -98,8 +98,8 @@ ExceptionTssSeg:
 
 CODE_SEL          equ CodeSeg32 - NullSeg
 DATA_SEL          equ DataSeg32 - NullSeg
-TSS_SEL           equ TssSeg - NullSeg
-EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg
+%define TSS_SEL           0x1000
+%define EXCEPTION_TSS_SEL 0x1008
 
 struc IA32_TSS
                     resw 1
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
index f4db6c8..8e25b49 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
@@ -43,17 +43,15 @@ InitializeIDTSmmStackGuard (
 
 /**
   Initialize Gdt for all processors.
-  
+
   @param[in]   Cr3          CR3 value.
-  @param[out]  GdtStepSize  The step size for GDT table.
 
-  @return GdtBase for processor 0.
-          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
+  @return A GdtArray to hold all base of Gdt Table for all processors.
+          GdtBase for processor X is: GdtArray[X]
 **/
-VOID *
+UINTN *
 InitGdt (
-  IN  UINTN  Cr3,
-  OUT UINTN  *GdtStepSize
+  IN  UINTN  Cr3
   )
 {
   UINTN                     Index;
@@ -62,6 +60,16 @@ InitGdt (
   UINTN                     GdtTssTableSize;
   UINT8                     *GdtTssTables;
   UINTN                     GdtTableStepSize;
+  UINTN                     *GdtArray;
+  UINTN                     GdtCountPerPage;
+  UINTN                     BundleCount;
+  UINTN                     BundleIndex;
+  UINT8                     *BundleBase;
+  UINTN                     GdtIndex;
+  UINTN                     CountMax;
+
+  GdtArray = AllocatePool (sizeof(UINTN) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
+  ASSERT (GdtArray != NULL);
 
   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
     //
@@ -71,41 +79,92 @@ InitGdt (
     //
 
     //
-    // Enlarge GDT to contain 2 TSS descriptors
+    // We must separate normal GDT entry from GDT_TSS entry.
+    // The formal could be read only, and the later must be readwrite.
+    // The final layout is below:
+    //
+    // |<------ Read Only Bundle ------>|<--------- Read Write Bundle -------------->|
+    // |                                |                                            |
+    // +--------------------------------+============================================+--------------+==================+
+    // | GDT(0) | GDT(1) | ... | GDT(n) | GDT_TSS(0) | GDT_TSS(1) | ... | GDT_TSS(n) | GDT(n+1) |...| GDT_TSS(n+1) |...|
+    // +--------------------------------+============================================+--------------+==================+
+    // |                                     |       |
+    // |<------------ Gdt.Limit ------------>|<-TSS->|
     //
-    gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
 
-    GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
-    mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
-    GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
+    GdtTableStepSize = (2 * sizeof (IA32_SEGMENT_DESCRIPTOR) + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
+    if (GdtTableStepSize < (UINTN)(gcSmiGdtr.Limit + 1)) {
+      GdtTableStepSize = gcSmiGdtr.Limit + 1;
+    }
+    GdtCountPerPage = EFI_PAGE_SIZE / GdtTableStepSize;
+    BundleCount = (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus + GdtCountPerPage - 1) / GdtCountPerPage;
+    mGdtBufferSize = EFI_PAGES_TO_SIZE(BundleCount * 2);
+
+    GdtTssTables = (UINT8*)AllocateCodePages (BundleCount * 2);
     ASSERT (GdtTssTables != NULL);
+    ZeroMem ((VOID *)GdtTssTables, EFI_PAGES_TO_SIZE(BundleCount * 2));
     mGdtBuffer = (UINTN)GdtTssTables;
-    GdtTableStepSize = GdtTssTableSize;
 
-    for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
-      CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2);
-      //
-      // Fixup TSS descriptors
-      //
-      TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
-      GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
-      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
-      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
-      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
-
-      TssBase += TSS_SIZE;
-      GdtDescriptor++;
-      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
-      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
-      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
-      //
-      // Fixup TSS segments
-      //
-      // ESP as known good stack
-      //
-      *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) =  mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
-      *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
+    Index = 0;
+    for (BundleIndex = 0; BundleIndex < BundleCount; BundleIndex++) {
+      CountMax = GdtCountPerPage;
+      if (BundleIndex == BundleCount - 1) {
+        CountMax = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus - GdtCountPerPage * BundleIndex;
+      }
+      BundleBase = GdtTssTables + EFI_PAGE_SIZE * 2 * BundleIndex;
+      for (GdtIndex = 0; GdtIndex < CountMax; GdtIndex++, Index++) {
+        GdtArray[Index] = (UINTN)BundleBase + GdtTableStepSize * GdtIndex;
+        //
+        // Copy Basic GDT
+        //
+        CopyMem (
+          (VOID *)GdtArray[Index],
+          (VOID*)(UINTN)gcSmiGdtr.Base,
+          gcSmiGdtr.Limit + 1
+          );
+        //
+        // Copy GDT TSS segment
+        //
+        CopyMem (
+          (VOID *)(GdtArray[Index] + EFI_PAGE_SIZE),
+          (VOID*)((UINTN)gcSmiGdtr.Base + gcSmiGdtr.Limit + 1),
+          sizeof(IA32_SEGMENT_DESCRIPTOR) * 2
+          );
+        //
+        // Copy TSS
+        //
+        TssBase = (UINTN)(GdtArray[Index] + EFI_PAGE_SIZE + sizeof(IA32_SEGMENT_DESCRIPTOR) * 2);
+        CopyMem (
+          (VOID *)(TssBase),
+          (VOID*)((UINTN)gcSmiGdtr.Base + gcSmiGdtr.Limit + 1 + sizeof(IA32_SEGMENT_DESCRIPTOR) * 2),
+          TSS_SIZE * 2
+          );
+        //
+        // Fixup TSS descriptors
+        //
+        GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
+        GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
+        GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
+        GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
+
+        TssBase += TSS_SIZE;
+        GdtDescriptor++;
+        GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
+        GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
+        GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
+        //
+        // Fixup TSS segments
+        //
+        // ESP as known good stack
+        //
+        *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) =  mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
+        *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
+      }
     }
+    //
+    // Enlarge GDT to contain 1 page plus 2 TSS descriptors
+    //
+    gcSmiGdtr.Limit = (UINT16)(EFI_PAGE_SIZE + 2 * sizeof (IA32_SEGMENT_DESCRIPTOR) - 1);
   } else {
     //
     // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
@@ -119,11 +178,83 @@ InitGdt (
 
     for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
       CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);
+      GdtArray[Index] = (UINTN)GdtTssTables + GdtTableStepSize * Index;
+    }
+  }
+
+  return GdtArray;
+}
+
+/**
+  This function sets GDT/IDT buffer to be RO and XP.
+**/
+VOID
+PatchGdtIdtMap (
+  VOID
+  )
+{
+  EFI_PHYSICAL_ADDRESS       BaseAddress;
+  UINTN                      Size;
+  UINTN                      Index;
+  UINTN                      BundleCount;
+
+  //
+  // GDT
+  //
+  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
+
+  if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+    BaseAddress = mGdtBuffer;
+    Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
+    SmmSetMemoryAttributes (
+      BaseAddress,
+      Size,
+      EFI_MEMORY_XP
+      );
+    BundleCount = EFI_SIZE_TO_PAGES(mGdtBufferSize)/2;
+    for (Index = 0; Index < BundleCount; Index++) {
+      SmmSetMemoryAttributes (
+        BaseAddress + EFI_PAGE_SIZE * Index * 2,
+        EFI_PAGE_SIZE,
+        EFI_MEMORY_RO
+        );
+      SmmClearMemoryAttributes (
+        BaseAddress + EFI_PAGE_SIZE * (Index * 2 + 1),
+        EFI_PAGE_SIZE,
+        EFI_MEMORY_RO
+        );
     }
+  } else {
+    BaseAddress = mGdtBuffer;
+    Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
+    SmmSetMemoryAttributes (
+      BaseAddress,
+      Size,
+      EFI_MEMORY_RO
+      );
+    SmmSetMemoryAttributes (
+      BaseAddress,
+      Size,
+      EFI_MEMORY_XP
+      );
   }
+  //
+  // IDT
+  //
+  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
 
-  *GdtStepSize = GdtTableStepSize;
-  return GdtTssTables;
+  BaseAddress = gcSmiIdtr.Base;
+  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
+  SmmSetMemoryAttributes (
+    BaseAddress,
+    Size,
+    EFI_MEMORY_RO
+    );
+  SmmSetMemoryAttributes (
+    BaseAddress,
+    Size,
+    EFI_MEMORY_XP
+    );
 }
 
 /**
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
index 9b8db90..591a18c 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
@@ -1377,8 +1377,7 @@ InitializeMpServiceData (
   UINTN                     Index;
   MTRR_SETTINGS             *Mtrr;
   PROCESSOR_SMM_DESCRIPTOR  *Psd;
-  UINT8                     *GdtTssTables;
-  UINTN                     GdtTableStepSize;
+  UINTN                     *GdtArray;
 
   //
   // Allocate memory for all locks and semaphores
@@ -1407,7 +1406,7 @@ InitializeMpServiceData (
   //
   Cr3 = SmmInitPageTable ();
 
-  GdtTssTables = InitGdt (Cr3, &GdtTableStepSize);
+  GdtArray = InitGdt (Cr3);
 
   //
   // Initialize PROCESSOR_SMM_DESCRIPTOR for each CPU
@@ -1415,7 +1414,7 @@ InitializeMpServiceData (
   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
     Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(mCpuHotPlugData.SmBase[Index] + SMM_PSD_OFFSET);
     CopyMem (Psd, &gcPsd, sizeof (gcPsd));
-    Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTableStepSize * Index);
+    Psd->SmmGdtPtr = (UINT64)(UINTN)GdtArray[Index];
     Psd->SmmGdtSize = gcSmiGdtr.Limit + 1;
 
     //
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
index abe5cc6..9e00022 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
@@ -512,15 +512,21 @@ InitializeIDTSmmStackGuard (
   Initialize Gdt for all processors.
 
   @param[in]   Cr3          CR3 value.
-  @param[out]  GdtStepSize  The step size for GDT table.
 
-  @return GdtBase for processor 0.
-          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
+  @return A GdtArray to hold all base of Gdt Table for all processors.
+          GdtBase for processor X is: GdtArray[X]
 **/
-VOID *
+UINTN *
 InitGdt (
-  IN  UINTN  Cr3,
-  OUT UINTN  *GdtStepSize
+  IN  UINTN  Cr3
+  );
+
+/**
+  This function sets GDT/IDT buffer to be RO and XP.
+**/
+VOID
+PatchGdtIdtMap (
+  VOID
   );
 
 /**
@@ -596,6 +602,66 @@ SmmBlockingStartupThisAp (
   );
 
 /**
+  This function sets the attributes for the memory region specified by BaseAddress and
+  Length from their current attributes to the attributes specified by Attributes.
+
+  @param[in]  BaseAddress      The physical address that is the start address of a memory region.
+  @param[in]  Length           The size in bytes of the memory region.
+  @param[in]  Attributes       The bit mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+                                Attributes specified an illegal combination of attributes that
+                                cannot be set together.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+                                The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmSetMemoryAttributes (
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
+  IN  UINT64                                     Length,
+  IN  UINT64                                     Attributes
+  );
+
+/**
+  This function clears the attributes for the memory region specified by BaseAddress and
+  Length from their current attributes to the attributes specified by Attributes.
+
+  @param[in]  BaseAddress      The physical address that is the start address of a memory region.
+  @param[in]  Length           The size in bytes of the memory region.
+  @param[in]  Attributes       The bit mask of attributes to clear for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were cleared for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+                                Attributes specified an illegal combination of attributes that
+                                cannot be set together.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+                                The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmClearMemoryAttributes (
+  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
+  IN  UINT64                                     Length,
+  IN  UINT64                                     Attributes
+  );
+
+/**
   Initialize MP synchronization data.
 
 **/
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
index c85e025..fc440e4 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
@@ -750,54 +750,6 @@ PatchSmmSaveStateMap (
 }
 
 /**
-  This function sets GDT/IDT buffer to be RO and XP.
-**/
-VOID
-PatchGdtIdtMap (
-  VOID
-  )
-{
-  EFI_PHYSICAL_ADDRESS       BaseAddress;
-  UINTN                      Size;
-
-  //
-  // GDT
-  //
-  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
-
-  BaseAddress = mGdtBuffer;
-  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
-  SmmSetMemoryAttributes (
-    BaseAddress,
-    Size,
-    EFI_MEMORY_RO
-    );
-  SmmSetMemoryAttributes (
-    BaseAddress,
-    Size,
-    EFI_MEMORY_XP
-    );
-
-  //
-  // IDT
-  //
-  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
-
-  BaseAddress = gcSmiIdtr.Base;
-  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
-  SmmSetMemoryAttributes (
-    BaseAddress,
-    Size,
-    EFI_MEMORY_RO
-    );
-  SmmSetMemoryAttributes (
-    BaseAddress,
-    Size,
-    EFI_MEMORY_XP
-    );
-}
-
-/**
   This function sets memory attribute according to MemoryAttributesTable.
 **/
 VOID
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
index 9fc00c1..baeec4a 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
@@ -42,15 +42,13 @@ InitializeIDTSmmStackGuard (
   Initialize Gdt for all processors.
   
   @param[in]   Cr3          CR3 value.
-  @param[out]  GdtStepSize  The step size for GDT table.
 
-  @return GdtBase for processor 0.
-          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
+  @return A GdtArray to hold all base of Gdt Table for all processors.
+          GdtBase for processor X is: GdtArray[X]
 **/
-VOID *
+UINTN *
 InitGdt (
-  IN  UINTN  Cr3,
-  OUT UINTN  *GdtStepSize
+  IN  UINTN  Cr3
   )
 {
   UINTN                     Index;
@@ -59,6 +57,10 @@ InitGdt (
   UINTN                     GdtTssTableSize;
   UINT8                     *GdtTssTables;
   UINTN                     GdtTableStepSize;
+  UINTN                     *GdtArray;
+
+  GdtArray = AllocatePool (sizeof(UINTN) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
+  ASSERT (GdtArray != NULL);
 
   //
   // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
@@ -89,10 +91,58 @@ InitGdt (
       //
       *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);
     }
+    GdtArray[Index] = (UINTN)GdtTssTables + GdtTableStepSize * Index;
   }
 
-  *GdtStepSize = GdtTableStepSize;
-  return GdtTssTables;
+  return GdtArray;
+}
+
+/**
+  This function sets GDT/IDT buffer to be RO and XP.
+**/
+VOID
+PatchGdtIdtMap (
+  VOID
+  )
+{
+  EFI_PHYSICAL_ADDRESS       BaseAddress;
+  UINTN                      Size;
+
+  //
+  // GDT
+  //
+  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
+
+  BaseAddress = mGdtBuffer;
+  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
+  SmmSetMemoryAttributes (
+    BaseAddress,
+    Size,
+    EFI_MEMORY_RO
+    );
+  SmmSetMemoryAttributes (
+    BaseAddress,
+    Size,
+    EFI_MEMORY_XP
+    );
+
+  //
+  // IDT
+  //
+  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
+
+  BaseAddress = gcSmiIdtr.Base;
+  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
+  SmmSetMemoryAttributes (
+    BaseAddress,
+    Size,
+    EFI_MEMORY_RO
+    );
+  SmmSetMemoryAttributes (
+    BaseAddress,
+    Size,
+    EFI_MEMORY_XP
+    );
 }
 
 /**
@@ -154,4 +204,3 @@ TransferApToSafeState (
   ASSERT (FALSE);
 }
 
-
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] UefiCpuPkg/PiSmmCpu: Fixed #double fault on #page fault.
  2016-11-23 14:54 [PATCH] UefiCpuPkg/PiSmmCpu: Fixed #double fault on #page fault Jiewen Yao
@ 2016-11-23 22:28 ` Laszlo Ersek
       [not found]   ` <ED077930C258884BBCB450DB737E6622486AB46E@shsmsx102.ccr.corp.intel.com>
  0 siblings, 1 reply; 3+ messages in thread
From: Laszlo Ersek @ 2016-11-23 22:28 UTC (permalink / raw)
  To: Jiewen Yao, edk2-devel; +Cc: Michael D Kinney, Jeff Fan

On 11/23/16 15:54, Jiewen Yao wrote:
> This patch fixes https://bugzilla.tianocore.org/show_bug.cgi?id=246
> 
> Previously, when SMM exception happens after EndOfDxe,
> with StackGuard enabled on IA32, the #double fault exception
> is reported instead of #page fault.
> 
> Root cause is below:
> 
> Current EDKII SMM page protection will lock GDT.
> If IA32 stack guard is enabled, the page fault handler will do task switch.
> This task switch need write busy flag in GDT, and write TSS.
> 
> However, the GDT and TSS is locked at that time, so the
> double fault happens.
> 
> This issue does not exist on X64, or IA32 without StackGuard.
> 
> In this enhanced solution, we create a special GDT whose CS/DS is
> at read-only page, and whose TSS segment is at read-write page.
> We also put TSS into a read-write page.
> 
> The detail is at UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c.
> 
> Then the normal code can being protected, because it does not touch TSS.
> When page fault happens, the TSS region can be written.
> 
> This fix is IA32 StackGuard specific.
> 
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Jeff Fan <jeff.fan@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
> ---
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S          |   2 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm        |   2 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm       |   2 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S      |   4 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm    |   4 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm   |   4 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c      | 207 ++++++++++++++++----
>  UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c              |   7 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h         |  78 +++++++-
>  UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c |  48 -----
>  UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c       |  67 ++++++-
>  11 files changed, 311 insertions(+), 114 deletions(-)

I'm not volunteering for a review (I have no clue what a task switch
is). I've done regression testing with Ia32 and Ia32X64 OVMF, including
repeated suspend/resume.

Regression-tested-by: Laszlo Ersek <lersek@redhat.com>

In addition, let me point out that my recent testing of the patch that
improves the SMM exception messages:

[edk2] [PATCH] UefiCpuPkg/PiSmmCpu: Correct exception message
[edk2] [PATCH V3] UefiCpuPkg/PiSmmCpu: Correct exception message.

covered the SMM stack overflow case, but -- as I stated explicitly --
only in the Ia32X64 build. See bullet (2) in
<https://lists.01.org/pipermail/edk2-devel/2016-November/005078.html>.

The reason is that the SMM stack overflow has occurred to us only when
running the EnrollDefaultKeys.efi application, and for that app we only
have a "production use" under Ia32X64, not Ia32.

Anyway, I have now applied your

  [edk2] [PATCH V3] UefiCpuPkg/PiSmmCpu: Correct exception message.

together with this patch, and attempted to trigger SMM stack overflow on
both Ia32 and Ia32X64.

- I confirm that the Ia32X64 case continues to work, like before:
<https://lists.01.org/pipermail/edk2-devel/2016-November/005133.html>.
For that,

Regression-tested-by: Laszlo Ersek <lersek@redhat.com>

- Regarding the Ia32 case, which I haven't tested before, I couldn't
trigger an SMM stack overflow with EnrollDefaultKeys.efi, even after
reverting the patch that increased the SMM stack size in OVMF
(0d0c245dfb14). So, I think I cannot give my Tested-by (I couldn't test
the actual new functionality), just my Regression-tested-by (see above).

Thanks
Laszlo

> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
> index 0c07558..e27080d 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
> @@ -41,7 +41,7 @@ ASM_GLOBAL  ASM_PFX(gSmiHandlerIdtr)
>  
>  .equ            PROTECT_MODE_CS, 0x08
>  .equ            PROTECT_MODE_DS, 0x20
> -.equ            TSS_SEGMENT,     0x40
> +.equ            TSS_SEGMENT,     0x1000
>  
>      .text
>  
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
> index eda1708..e1ab470 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
> @@ -36,7 +36,7 @@ DSC_OTHERSEG  EQU     20
>  
>  PROTECT_MODE_CS EQU   08h
>  PROTECT_MODE_DS EQU   20h
> -TSS_SEGMENT     EQU   40h
> +TSS_SEGMENT     EQU   1000h
>  
>  SmiRendezvous      PROTO   C
>  CpuSmmDebugEntry   PROTO   C
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
> index d50a317..ccfb0d4 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
> @@ -32,7 +32,7 @@
>  
>  %define PROTECT_MODE_CS 0x8
>  %define PROTECT_MODE_DS 0x20
> -%define TSS_SEGMENT 0x40
> +%define TSS_SEGMENT 0x1000
>  
>  extern ASM_PFX(SmiRendezvous)
>  extern ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
> index cf5ef82..30dd25e 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
> @@ -99,8 +99,8 @@ ExceptionTssSeg:
>  
>  .equ  CODE_SEL,          CodeSeg32 - NullSeg
>  .equ  DATA_SEL,          DataSeg32 - NullSeg
> -.equ  TSS_SEL,           TssSeg - NullSeg
> -.equ  EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
> +.equ  TSS_SEL,           0x1000
> +.equ  EXCEPTION_TSS_SEL, 0x1008
>  
>  # IA32 TSS fields
>  .equ  TSS_ESP0,          4
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
> index 7b162f8..740e4a5 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
> @@ -102,8 +102,8 @@ ExceptionTssSeg     LABEL   QWORD
>  
>  CODE_SEL          = offset CodeSeg32 - offset NullSeg
>  DATA_SEL          = offset DataSeg32 - offset NullSeg
> -TSS_SEL           = offset TssSeg - offset NullSeg
> -EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
> +TSS_SEL               EQU   1000h
> +EXCEPTION_TSS_SEL     EQU   1008h
>  
>  IA32_TSS STRUC
>                      DW ?
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
> index 4d58999..a6dcf47 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
> @@ -98,8 +98,8 @@ ExceptionTssSeg:
>  
>  CODE_SEL          equ CodeSeg32 - NullSeg
>  DATA_SEL          equ DataSeg32 - NullSeg
> -TSS_SEL           equ TssSeg - NullSeg
> -EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg
> +%define TSS_SEL           0x1000
> +%define EXCEPTION_TSS_SEL 0x1008
>  
>  struc IA32_TSS
>                      resw 1
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
> index f4db6c8..8e25b49 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
> @@ -43,17 +43,15 @@ InitializeIDTSmmStackGuard (
>  
>  /**
>    Initialize Gdt for all processors.
> -  
> +
>    @param[in]   Cr3          CR3 value.
> -  @param[out]  GdtStepSize  The step size for GDT table.
>  
> -  @return GdtBase for processor 0.
> -          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
> +  @return A GdtArray to hold all base of Gdt Table for all processors.
> +          GdtBase for processor X is: GdtArray[X]
>  **/
> -VOID *
> +UINTN *
>  InitGdt (
> -  IN  UINTN  Cr3,
> -  OUT UINTN  *GdtStepSize
> +  IN  UINTN  Cr3
>    )
>  {
>    UINTN                     Index;
> @@ -62,6 +60,16 @@ InitGdt (
>    UINTN                     GdtTssTableSize;
>    UINT8                     *GdtTssTables;
>    UINTN                     GdtTableStepSize;
> +  UINTN                     *GdtArray;
> +  UINTN                     GdtCountPerPage;
> +  UINTN                     BundleCount;
> +  UINTN                     BundleIndex;
> +  UINT8                     *BundleBase;
> +  UINTN                     GdtIndex;
> +  UINTN                     CountMax;
> +
> +  GdtArray = AllocatePool (sizeof(UINTN) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
> +  ASSERT (GdtArray != NULL);
>  
>    if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
>      //
> @@ -71,41 +79,92 @@ InitGdt (
>      //
>  
>      //
> -    // Enlarge GDT to contain 2 TSS descriptors
> +    // We must separate normal GDT entry from GDT_TSS entry.
> +    // The formal could be read only, and the later must be readwrite.
> +    // The final layout is below:
> +    //
> +    // |<------ Read Only Bundle ------>|<--------- Read Write Bundle -------------->|
> +    // |                                |                                            |
> +    // +--------------------------------+============================================+--------------+==================+
> +    // | GDT(0) | GDT(1) | ... | GDT(n) | GDT_TSS(0) | GDT_TSS(1) | ... | GDT_TSS(n) | GDT(n+1) |...| GDT_TSS(n+1) |...|
> +    // +--------------------------------+============================================+--------------+==================+
> +    // |                                     |       |
> +    // |<------------ Gdt.Limit ------------>|<-TSS->|
>      //
> -    gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
>  
> -    GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
> -    mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
> -    GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
> +    GdtTableStepSize = (2 * sizeof (IA32_SEGMENT_DESCRIPTOR) + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
> +    if (GdtTableStepSize < (UINTN)(gcSmiGdtr.Limit + 1)) {
> +      GdtTableStepSize = gcSmiGdtr.Limit + 1;
> +    }
> +    GdtCountPerPage = EFI_PAGE_SIZE / GdtTableStepSize;
> +    BundleCount = (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus + GdtCountPerPage - 1) / GdtCountPerPage;
> +    mGdtBufferSize = EFI_PAGES_TO_SIZE(BundleCount * 2);
> +
> +    GdtTssTables = (UINT8*)AllocateCodePages (BundleCount * 2);
>      ASSERT (GdtTssTables != NULL);
> +    ZeroMem ((VOID *)GdtTssTables, EFI_PAGES_TO_SIZE(BundleCount * 2));
>      mGdtBuffer = (UINTN)GdtTssTables;
> -    GdtTableStepSize = GdtTssTableSize;
>  
> -    for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
> -      CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2);
> -      //
> -      // Fixup TSS descriptors
> -      //
> -      TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
> -      GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
> -      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> -      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> -      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> -
> -      TssBase += TSS_SIZE;
> -      GdtDescriptor++;
> -      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> -      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> -      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> -      //
> -      // Fixup TSS segments
> -      //
> -      // ESP as known good stack
> -      //
> -      *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) =  mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
> -      *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
> +    Index = 0;
> +    for (BundleIndex = 0; BundleIndex < BundleCount; BundleIndex++) {
> +      CountMax = GdtCountPerPage;
> +      if (BundleIndex == BundleCount - 1) {
> +        CountMax = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus - GdtCountPerPage * BundleIndex;
> +      }
> +      BundleBase = GdtTssTables + EFI_PAGE_SIZE * 2 * BundleIndex;
> +      for (GdtIndex = 0; GdtIndex < CountMax; GdtIndex++, Index++) {
> +        GdtArray[Index] = (UINTN)BundleBase + GdtTableStepSize * GdtIndex;
> +        //
> +        // Copy Basic GDT
> +        //
> +        CopyMem (
> +          (VOID *)GdtArray[Index],
> +          (VOID*)(UINTN)gcSmiGdtr.Base,
> +          gcSmiGdtr.Limit + 1
> +          );
> +        //
> +        // Copy GDT TSS segment
> +        //
> +        CopyMem (
> +          (VOID *)(GdtArray[Index] + EFI_PAGE_SIZE),
> +          (VOID*)((UINTN)gcSmiGdtr.Base + gcSmiGdtr.Limit + 1),
> +          sizeof(IA32_SEGMENT_DESCRIPTOR) * 2
> +          );
> +        //
> +        // Copy TSS
> +        //
> +        TssBase = (UINTN)(GdtArray[Index] + EFI_PAGE_SIZE + sizeof(IA32_SEGMENT_DESCRIPTOR) * 2);
> +        CopyMem (
> +          (VOID *)(TssBase),
> +          (VOID*)((UINTN)gcSmiGdtr.Base + gcSmiGdtr.Limit + 1 + sizeof(IA32_SEGMENT_DESCRIPTOR) * 2),
> +          TSS_SIZE * 2
> +          );
> +        //
> +        // Fixup TSS descriptors
> +        //
> +        GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
> +        GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> +        GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> +        GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> +
> +        TssBase += TSS_SIZE;
> +        GdtDescriptor++;
> +        GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> +        GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> +        GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> +        //
> +        // Fixup TSS segments
> +        //
> +        // ESP as known good stack
> +        //
> +        *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) =  mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
> +        *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
> +      }
>      }
> +    //
> +    // Enlarge GDT to contain 1 page plus 2 TSS descriptors
> +    //
> +    gcSmiGdtr.Limit = (UINT16)(EFI_PAGE_SIZE + 2 * sizeof (IA32_SEGMENT_DESCRIPTOR) - 1);
>    } else {
>      //
>      // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
> @@ -119,11 +178,83 @@ InitGdt (
>  
>      for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
>        CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);
> +      GdtArray[Index] = (UINTN)GdtTssTables + GdtTableStepSize * Index;
> +    }
> +  }
> +
> +  return GdtArray;
> +}
> +
> +/**
> +  This function sets GDT/IDT buffer to be RO and XP.
> +**/
> +VOID
> +PatchGdtIdtMap (
> +  VOID
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS       BaseAddress;
> +  UINTN                      Size;
> +  UINTN                      Index;
> +  UINTN                      BundleCount;
> +
> +  //
> +  // GDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
> +
> +  if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
> +    BaseAddress = mGdtBuffer;
> +    Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> +    SmmSetMemoryAttributes (
> +      BaseAddress,
> +      Size,
> +      EFI_MEMORY_XP
> +      );
> +    BundleCount = EFI_SIZE_TO_PAGES(mGdtBufferSize)/2;
> +    for (Index = 0; Index < BundleCount; Index++) {
> +      SmmSetMemoryAttributes (
> +        BaseAddress + EFI_PAGE_SIZE * Index * 2,
> +        EFI_PAGE_SIZE,
> +        EFI_MEMORY_RO
> +        );
> +      SmmClearMemoryAttributes (
> +        BaseAddress + EFI_PAGE_SIZE * (Index * 2 + 1),
> +        EFI_PAGE_SIZE,
> +        EFI_MEMORY_RO
> +        );
>      }
> +  } else {
> +    BaseAddress = mGdtBuffer;
> +    Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> +    SmmSetMemoryAttributes (
> +      BaseAddress,
> +      Size,
> +      EFI_MEMORY_RO
> +      );
> +    SmmSetMemoryAttributes (
> +      BaseAddress,
> +      Size,
> +      EFI_MEMORY_XP
> +      );
>    }
> +  //
> +  // IDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
>  
> -  *GdtStepSize = GdtTableStepSize;
> -  return GdtTssTables;
> +  BaseAddress = gcSmiIdtr.Base;
> +  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_RO
> +    );
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_XP
> +    );
>  }
>  
>  /**
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> index 9b8db90..591a18c 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> @@ -1377,8 +1377,7 @@ InitializeMpServiceData (
>    UINTN                     Index;
>    MTRR_SETTINGS             *Mtrr;
>    PROCESSOR_SMM_DESCRIPTOR  *Psd;
> -  UINT8                     *GdtTssTables;
> -  UINTN                     GdtTableStepSize;
> +  UINTN                     *GdtArray;
>  
>    //
>    // Allocate memory for all locks and semaphores
> @@ -1407,7 +1406,7 @@ InitializeMpServiceData (
>    //
>    Cr3 = SmmInitPageTable ();
>  
> -  GdtTssTables = InitGdt (Cr3, &GdtTableStepSize);
> +  GdtArray = InitGdt (Cr3);
>  
>    //
>    // Initialize PROCESSOR_SMM_DESCRIPTOR for each CPU
> @@ -1415,7 +1414,7 @@ InitializeMpServiceData (
>    for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
>      Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(mCpuHotPlugData.SmBase[Index] + SMM_PSD_OFFSET);
>      CopyMem (Psd, &gcPsd, sizeof (gcPsd));
> -    Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTableStepSize * Index);
> +    Psd->SmmGdtPtr = (UINT64)(UINTN)GdtArray[Index];
>      Psd->SmmGdtSize = gcSmiGdtr.Limit + 1;
>  
>      //
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> index abe5cc6..9e00022 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> @@ -512,15 +512,21 @@ InitializeIDTSmmStackGuard (
>    Initialize Gdt for all processors.
>  
>    @param[in]   Cr3          CR3 value.
> -  @param[out]  GdtStepSize  The step size for GDT table.
>  
> -  @return GdtBase for processor 0.
> -          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
> +  @return A GdtArray to hold all base of Gdt Table for all processors.
> +          GdtBase for processor X is: GdtArray[X]
>  **/
> -VOID *
> +UINTN *
>  InitGdt (
> -  IN  UINTN  Cr3,
> -  OUT UINTN  *GdtStepSize
> +  IN  UINTN  Cr3
> +  );
> +
> +/**
> +  This function sets GDT/IDT buffer to be RO and XP.
> +**/
> +VOID
> +PatchGdtIdtMap (
> +  VOID
>    );
>  
>  /**
> @@ -596,6 +602,66 @@ SmmBlockingStartupThisAp (
>    );
>  
>  /**
> +  This function sets the attributes for the memory region specified by BaseAddress and
> +  Length from their current attributes to the attributes specified by Attributes.
> +
> +  @param[in]  BaseAddress      The physical address that is the start address of a memory region.
> +  @param[in]  Length           The size in bytes of the memory region.
> +  @param[in]  Attributes       The bit mask of attributes to set for the memory region.
> +
> +  @retval EFI_SUCCESS           The attributes were set for the memory region.
> +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
> +                                BaseAddress and Length cannot be modified.
> +  @retval EFI_INVALID_PARAMETER Length is zero.
> +                                Attributes specified an illegal combination of attributes that
> +                                cannot be set together.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
> +                                the memory resource range.
> +  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
> +                                resource range specified by BaseAddress and Length.
> +                                The bit mask of attributes is not support for the memory resource
> +                                range specified by BaseAddress and Length.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmSetMemoryAttributes (
> +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> +  IN  UINT64                                     Length,
> +  IN  UINT64                                     Attributes
> +  );
> +
> +/**
> +  This function clears the attributes for the memory region specified by BaseAddress and
> +  Length from their current attributes to the attributes specified by Attributes.
> +
> +  @param[in]  BaseAddress      The physical address that is the start address of a memory region.
> +  @param[in]  Length           The size in bytes of the memory region.
> +  @param[in]  Attributes       The bit mask of attributes to clear for the memory region.
> +
> +  @retval EFI_SUCCESS           The attributes were cleared for the memory region.
> +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
> +                                BaseAddress and Length cannot be modified.
> +  @retval EFI_INVALID_PARAMETER Length is zero.
> +                                Attributes specified an illegal combination of attributes that
> +                                cannot be set together.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
> +                                the memory resource range.
> +  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
> +                                resource range specified by BaseAddress and Length.
> +                                The bit mask of attributes is not support for the memory resource
> +                                range specified by BaseAddress and Length.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmClearMemoryAttributes (
> +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> +  IN  UINT64                                     Length,
> +  IN  UINT64                                     Attributes
> +  );
> +
> +/**
>    Initialize MP synchronization data.
>  
>  **/
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> index c85e025..fc440e4 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> @@ -750,54 +750,6 @@ PatchSmmSaveStateMap (
>  }
>  
>  /**
> -  This function sets GDT/IDT buffer to be RO and XP.
> -**/
> -VOID
> -PatchGdtIdtMap (
> -  VOID
> -  )
> -{
> -  EFI_PHYSICAL_ADDRESS       BaseAddress;
> -  UINTN                      Size;
> -
> -  //
> -  // GDT
> -  //
> -  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
> -
> -  BaseAddress = mGdtBuffer;
> -  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_RO
> -    );
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_XP
> -    );
> -
> -  //
> -  // IDT
> -  //
> -  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
> -
> -  BaseAddress = gcSmiIdtr.Base;
> -  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_RO
> -    );
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_XP
> -    );
> -}
> -
> -/**
>    This function sets memory attribute according to MemoryAttributesTable.
>  **/
>  VOID
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
> index 9fc00c1..baeec4a 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
> @@ -42,15 +42,13 @@ InitializeIDTSmmStackGuard (
>    Initialize Gdt for all processors.
>    
>    @param[in]   Cr3          CR3 value.
> -  @param[out]  GdtStepSize  The step size for GDT table.
>  
> -  @return GdtBase for processor 0.
> -          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
> +  @return A GdtArray to hold all base of Gdt Table for all processors.
> +          GdtBase for processor X is: GdtArray[X]
>  **/
> -VOID *
> +UINTN *
>  InitGdt (
> -  IN  UINTN  Cr3,
> -  OUT UINTN  *GdtStepSize
> +  IN  UINTN  Cr3
>    )
>  {
>    UINTN                     Index;
> @@ -59,6 +57,10 @@ InitGdt (
>    UINTN                     GdtTssTableSize;
>    UINT8                     *GdtTssTables;
>    UINTN                     GdtTableStepSize;
> +  UINTN                     *GdtArray;
> +
> +  GdtArray = AllocatePool (sizeof(UINTN) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
> +  ASSERT (GdtArray != NULL);
>  
>    //
>    // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
> @@ -89,10 +91,58 @@ InitGdt (
>        //
>        *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);
>      }
> +    GdtArray[Index] = (UINTN)GdtTssTables + GdtTableStepSize * Index;
>    }
>  
> -  *GdtStepSize = GdtTableStepSize;
> -  return GdtTssTables;
> +  return GdtArray;
> +}
> +
> +/**
> +  This function sets GDT/IDT buffer to be RO and XP.
> +**/
> +VOID
> +PatchGdtIdtMap (
> +  VOID
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS       BaseAddress;
> +  UINTN                      Size;
> +
> +  //
> +  // GDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
> +
> +  BaseAddress = mGdtBuffer;
> +  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_RO
> +    );
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_XP
> +    );
> +
> +  //
> +  // IDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
> +
> +  BaseAddress = gcSmiIdtr.Base;
> +  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_RO
> +    );
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_XP
> +    );
>  }
>  
>  /**
> @@ -154,4 +204,3 @@ TransferApToSafeState (
>    ASSERT (FALSE);
>  }
>  
> -
> 



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] UefiCpuPkg/PiSmmCpu: Fixed #double fault on #page fault.
       [not found]   ` <ED077930C258884BBCB450DB737E6622486AB46E@shsmsx102.ccr.corp.intel.com>
@ 2016-11-24  0:45     ` Yao, Jiewen
  0 siblings, 0 replies; 3+ messages in thread
From: Yao, Jiewen @ 2016-11-24  0:45 UTC (permalink / raw)
  To: edk2-devel@ml01.01.org, Laszlo Ersek (lersek@redhat.com)
  Cc: Kinney, Michael D, Fan, Jeff

Thank you, Laszlo.

I will check in debug message enhancement at first, with your suggestion to remove the last superfluous argument and use small 'x' consistently. :)


Your regression test is very nice.
For this patch, I will invite more people to review and validation to see if there is other concern.



Thank you
Yao Jiewen


-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Laszlo Ersek
Sent: Thursday, November 24, 2016 6:29 AM
To: Yao, Jiewen; edk2-devel@ml01.01.org<mailto:edk2-devel@ml01.01.org>
Cc: Kinney, Michael D; Fan, Jeff
Subject: Re: [edk2] [PATCH] UefiCpuPkg/PiSmmCpu: Fixed #double fault on #page fault.

On 11/23/16 15:54, Jiewen Yao wrote:
> This patch fixes https://bugzilla.tianocore.org/show_bug.cgi?id=246
>
> Previously, when SMM exception happens after EndOfDxe,
> with StackGuard enabled on IA32, the #double fault exception
> is reported instead of #page fault.
>
> Root cause is below:
>
> Current EDKII SMM page protection will lock GDT.
> If IA32 stack guard is enabled, the page fault handler will do task switch.
> This task switch need write busy flag in GDT, and write TSS.
>
> However, the GDT and TSS is locked at that time, so the
> double fault happens.
>
> This issue does not exist on X64, or IA32 without StackGuard.
>
> In this enhanced solution, we create a special GDT whose CS/DS is
> at read-only page, and whose TSS segment is at read-write page.
> We also put TSS into a read-write page.
>
> The detail is at UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c.
>
> Then the normal code can being protected, because it does not touch TSS.
> When page fault happens, the TSS region can be written.
>
> This fix is IA32 StackGuard specific.
>
> Cc: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>
> Cc: Jeff Fan <jeff.fan@intel.com<mailto:jeff.fan@intel.com>>
> Cc: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <jiewen.yao@intel.com<mailto:jiewen.yao@intel.com>>
> ---
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S          |   2 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm        |   2 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm       |   2 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S      |   4 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm    |   4 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm   |   4 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c      | 207 ++++++++++++++++----
>  UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c              |   7 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h         |  78 +++++++-
>  UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c |  48 -----
>  UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c       |  67 ++++++-
>  11 files changed, 311 insertions(+), 114 deletions(-)

I'm not volunteering for a review (I have no clue what a task switch
is). I've done regression testing with Ia32 and Ia32X64 OVMF, including
repeated suspend/resume.

Regression-tested-by: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>

In addition, let me point out that my recent testing of the patch that
improves the SMM exception messages:

[edk2] [PATCH] UefiCpuPkg/PiSmmCpu: Correct exception message
[edk2] [PATCH V3] UefiCpuPkg/PiSmmCpu: Correct exception message.

covered the SMM stack overflow case, but -- as I stated explicitly --
only in the Ia32X64 build. See bullet (2) in
<https://lists.01.org/pipermail/edk2-devel/2016-November/005078.html>.

The reason is that the SMM stack overflow has occurred to us only when
running the EnrollDefaultKeys.efi application, and for that app we only
have a "production use" under Ia32X64, not Ia32.

Anyway, I have now applied your

  [edk2] [PATCH V3] UefiCpuPkg/PiSmmCpu: Correct exception message.

together with this patch, and attempted to trigger SMM stack overflow on
both Ia32 and Ia32X64.

- I confirm that the Ia32X64 case continues to work, like before:
<https://lists.01.org/pipermail/edk2-devel/2016-November/005133.html>.
For that,

Regression-tested-by: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>

- Regarding the Ia32 case, which I haven't tested before, I couldn't
trigger an SMM stack overflow with EnrollDefaultKeys.efi, even after
reverting the patch that increased the SMM stack size in OVMF
(0d0c245dfb14). So, I think I cannot give my Tested-by (I couldn't test
the actual new functionality), just my Regression-tested-by (see above).

Thanks
Laszlo

> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
> index 0c07558..e27080d 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
> @@ -41,7 +41,7 @@ ASM_GLOBAL  ASM_PFX(gSmiHandlerIdtr)
>
>  .equ            PROTECT_MODE_CS, 0x08
>  .equ            PROTECT_MODE_DS, 0x20
> -.equ            TSS_SEGMENT,     0x40
> +.equ            TSS_SEGMENT,     0x1000
>
>      .text
>
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
> index eda1708..e1ab470 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
> @@ -36,7 +36,7 @@ DSC_OTHERSEG  EQU     20
>
>  PROTECT_MODE_CS EQU   08h
>  PROTECT_MODE_DS EQU   20h
> -TSS_SEGMENT     EQU   40h
> +TSS_SEGMENT     EQU   1000h
>
>  SmiRendezvous      PROTO   C
>  CpuSmmDebugEntry   PROTO   C
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
> index d50a317..ccfb0d4 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
> @@ -32,7 +32,7 @@
>
>  %define PROTECT_MODE_CS 0x8
>  %define PROTECT_MODE_DS 0x20
> -%define TSS_SEGMENT 0x40
> +%define TSS_SEGMENT 0x1000
>
>  extern ASM_PFX(SmiRendezvous)
>  extern ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
> index cf5ef82..30dd25e 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S
> @@ -99,8 +99,8 @@ ExceptionTssSeg:
>
>  .equ  CODE_SEL,          CodeSeg32 - NullSeg
>  .equ  DATA_SEL,          DataSeg32 - NullSeg
> -.equ  TSS_SEL,           TssSeg - NullSeg
> -.equ  EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
> +.equ  TSS_SEL,           0x1000
> +.equ  EXCEPTION_TSS_SEL, 0x1008
>
>  # IA32 TSS fields
>  .equ  TSS_ESP0,          4
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
> index 7b162f8..740e4a5 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm
> @@ -102,8 +102,8 @@ ExceptionTssSeg     LABEL   QWORD
>
>  CODE_SEL          = offset CodeSeg32 - offset NullSeg
>  DATA_SEL          = offset DataSeg32 - offset NullSeg
> -TSS_SEL           = offset TssSeg - offset NullSeg
> -EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
> +TSS_SEL               EQU   1000h
> +EXCEPTION_TSS_SEL     EQU   1008h
>
>  IA32_TSS STRUC
>                      DW ?
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
> index 4d58999..a6dcf47 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
> @@ -98,8 +98,8 @@ ExceptionTssSeg:
>
>  CODE_SEL          equ CodeSeg32 - NullSeg
>  DATA_SEL          equ DataSeg32 - NullSeg
> -TSS_SEL           equ TssSeg - NullSeg
> -EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg
> +%define TSS_SEL           0x1000
> +%define EXCEPTION_TSS_SEL 0x1008
>
>  struc IA32_TSS
>                      resw 1
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
> index f4db6c8..8e25b49 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
> @@ -43,17 +43,15 @@ InitializeIDTSmmStackGuard (
>
>  /**
>    Initialize Gdt for all processors.
> -
> +
>    @param[in]   Cr3          CR3 value.
> -  @param[out]  GdtStepSize  The step size for GDT table.
>
> -  @return GdtBase for processor 0.
> -          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
> +  @return A GdtArray to hold all base of Gdt Table for all processors.
> +          GdtBase for processor X is: GdtArray[X]
>  **/
> -VOID *
> +UINTN *
>  InitGdt (
> -  IN  UINTN  Cr3,
> -  OUT UINTN  *GdtStepSize
> +  IN  UINTN  Cr3
>    )
>  {
>    UINTN                     Index;
> @@ -62,6 +60,16 @@ InitGdt (
>    UINTN                     GdtTssTableSize;
>    UINT8                     *GdtTssTables;
>    UINTN                     GdtTableStepSize;
> +  UINTN                     *GdtArray;
> +  UINTN                     GdtCountPerPage;
> +  UINTN                     BundleCount;
> +  UINTN                     BundleIndex;
> +  UINT8                     *BundleBase;
> +  UINTN                     GdtIndex;
> +  UINTN                     CountMax;
> +
> +  GdtArray = AllocatePool (sizeof(UINTN) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
> +  ASSERT (GdtArray != NULL);
>
>    if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
>      //
> @@ -71,41 +79,92 @@ InitGdt (
>      //
>
>      //
> -    // Enlarge GDT to contain 2 TSS descriptors
> +    // We must separate normal GDT entry from GDT_TSS entry.
> +    // The formal could be read only, and the later must be readwrite.
> +    // The final layout is below:
> +    //
> +    // |<------ Read Only Bundle ------>|<--------- Read Write Bundle -------------->|
> +    // |                                |                                            |
> +    // +--------------------------------+============================================+--------------+==================+
> +    // | GDT(0) | GDT(1) | ... | GDT(n) | GDT_TSS(0) | GDT_TSS(1) | ... | GDT_TSS(n) | GDT(n+1) |...| GDT_TSS(n+1) |...|
> +    // +--------------------------------+============================================+--------------+==================+
> +    // |                                     |       |
> +    // |<------------ Gdt.Limit ------------>|<-TSS->|
>      //
> -    gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
>
> -    GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
> -    mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
> -    GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
> +    GdtTableStepSize = (2 * sizeof (IA32_SEGMENT_DESCRIPTOR) + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
> +    if (GdtTableStepSize < (UINTN)(gcSmiGdtr.Limit + 1)) {
> +      GdtTableStepSize = gcSmiGdtr.Limit + 1;
> +    }
> +    GdtCountPerPage = EFI_PAGE_SIZE / GdtTableStepSize;
> +    BundleCount = (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus + GdtCountPerPage - 1) / GdtCountPerPage;
> +    mGdtBufferSize = EFI_PAGES_TO_SIZE(BundleCount * 2);
> +
> +    GdtTssTables = (UINT8*)AllocateCodePages (BundleCount * 2);
>      ASSERT (GdtTssTables != NULL);
> +    ZeroMem ((VOID *)GdtTssTables, EFI_PAGES_TO_SIZE(BundleCount * 2));
>      mGdtBuffer = (UINTN)GdtTssTables;
> -    GdtTableStepSize = GdtTssTableSize;
>
> -    for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
> -      CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2);
> -      //
> -      // Fixup TSS descriptors
> -      //
> -      TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
> -      GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
> -      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> -      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> -      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> -
> -      TssBase += TSS_SIZE;
> -      GdtDescriptor++;
> -      GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> -      GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> -      GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> -      //
> -      // Fixup TSS segments
> -      //
> -      // ESP as known good stack
> -      //
> -      *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) =  mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
> -      *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
> +    Index = 0;
> +    for (BundleIndex = 0; BundleIndex < BundleCount; BundleIndex++) {
> +      CountMax = GdtCountPerPage;
> +      if (BundleIndex == BundleCount - 1) {
> +        CountMax = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus - GdtCountPerPage * BundleIndex;
> +      }
> +      BundleBase = GdtTssTables + EFI_PAGE_SIZE * 2 * BundleIndex;
> +      for (GdtIndex = 0; GdtIndex < CountMax; GdtIndex++, Index++) {
> +        GdtArray[Index] = (UINTN)BundleBase + GdtTableStepSize * GdtIndex;
> +        //
> +        // Copy Basic GDT
> +        //
> +        CopyMem (
> +          (VOID *)GdtArray[Index],
> +          (VOID*)(UINTN)gcSmiGdtr.Base,
> +          gcSmiGdtr.Limit + 1
> +          );
> +        //
> +        // Copy GDT TSS segment
> +        //
> +        CopyMem (
> +          (VOID *)(GdtArray[Index] + EFI_PAGE_SIZE),
> +          (VOID*)((UINTN)gcSmiGdtr.Base + gcSmiGdtr.Limit + 1),
> +          sizeof(IA32_SEGMENT_DESCRIPTOR) * 2
> +          );
> +        //
> +        // Copy TSS
> +        //
> +        TssBase = (UINTN)(GdtArray[Index] + EFI_PAGE_SIZE + sizeof(IA32_SEGMENT_DESCRIPTOR) * 2);
> +        CopyMem (
> +          (VOID *)(TssBase),
> +          (VOID*)((UINTN)gcSmiGdtr.Base + gcSmiGdtr.Limit + 1 + sizeof(IA32_SEGMENT_DESCRIPTOR) * 2),
> +          TSS_SIZE * 2
> +          );
> +        //
> +        // Fixup TSS descriptors
> +        //
> +        GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
> +        GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> +        GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> +        GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> +
> +        TssBase += TSS_SIZE;
> +        GdtDescriptor++;
> +        GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
> +        GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
> +        GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
> +        //
> +        // Fixup TSS segments
> +        //
> +        // ESP as known good stack
> +        //
> +        *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) =  mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
> +        *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
> +      }
>      }
> +    //
> +    // Enlarge GDT to contain 1 page plus 2 TSS descriptors
> +    //
> +    gcSmiGdtr.Limit = (UINT16)(EFI_PAGE_SIZE + 2 * sizeof (IA32_SEGMENT_DESCRIPTOR) - 1);
>    } else {
>      //
>      // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
> @@ -119,11 +178,83 @@ InitGdt (
>
>      for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
>        CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);
> +      GdtArray[Index] = (UINTN)GdtTssTables + GdtTableStepSize * Index;
> +    }
> +  }
> +
> +  return GdtArray;
> +}
> +
> +/**
> +  This function sets GDT/IDT buffer to be RO and XP.
> +**/
> +VOID
> +PatchGdtIdtMap (
> +  VOID
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS       BaseAddress;
> +  UINTN                      Size;
> +  UINTN                      Index;
> +  UINTN                      BundleCount;
> +
> +  //
> +  // GDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
> +
> +  if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
> +    BaseAddress = mGdtBuffer;
> +    Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> +    SmmSetMemoryAttributes (
> +      BaseAddress,
> +      Size,
> +      EFI_MEMORY_XP
> +      );
> +    BundleCount = EFI_SIZE_TO_PAGES(mGdtBufferSize)/2;
> +    for (Index = 0; Index < BundleCount; Index++) {
> +      SmmSetMemoryAttributes (
> +        BaseAddress + EFI_PAGE_SIZE * Index * 2,
> +        EFI_PAGE_SIZE,
> +        EFI_MEMORY_RO
> +        );
> +      SmmClearMemoryAttributes (
> +        BaseAddress + EFI_PAGE_SIZE * (Index * 2 + 1),
> +        EFI_PAGE_SIZE,
> +        EFI_MEMORY_RO
> +        );
>      }
> +  } else {
> +    BaseAddress = mGdtBuffer;
> +    Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> +    SmmSetMemoryAttributes (
> +      BaseAddress,
> +      Size,
> +      EFI_MEMORY_RO
> +      );
> +    SmmSetMemoryAttributes (
> +      BaseAddress,
> +      Size,
> +      EFI_MEMORY_XP
> +      );
>    }
> +  //
> +  // IDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
>
> -  *GdtStepSize = GdtTableStepSize;
> -  return GdtTssTables;
> +  BaseAddress = gcSmiIdtr.Base;
> +  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_RO
> +    );
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_XP
> +    );
>  }
>
>  /**
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> index 9b8db90..591a18c 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> @@ -1377,8 +1377,7 @@ InitializeMpServiceData (
>    UINTN                     Index;
>    MTRR_SETTINGS             *Mtrr;
>    PROCESSOR_SMM_DESCRIPTOR  *Psd;
> -  UINT8                     *GdtTssTables;
> -  UINTN                     GdtTableStepSize;
> +  UINTN                     *GdtArray;
>
>    //
>    // Allocate memory for all locks and semaphores
> @@ -1407,7 +1406,7 @@ InitializeMpServiceData (
>    //
>    Cr3 = SmmInitPageTable ();
>
> -  GdtTssTables = InitGdt (Cr3, &GdtTableStepSize);
> +  GdtArray = InitGdt (Cr3);
>
>    //
>    // Initialize PROCESSOR_SMM_DESCRIPTOR for each CPU
> @@ -1415,7 +1414,7 @@ InitializeMpServiceData (
>    for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
>      Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(mCpuHotPlugData.SmBase[Index] + SMM_PSD_OFFSET);
>      CopyMem (Psd, &gcPsd, sizeof (gcPsd));
> -    Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTableStepSize * Index);
> +    Psd->SmmGdtPtr = (UINT64)(UINTN)GdtArray[Index];
>      Psd->SmmGdtSize = gcSmiGdtr.Limit + 1;
>
>      //
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> index abe5cc6..9e00022 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> @@ -512,15 +512,21 @@ InitializeIDTSmmStackGuard (
>    Initialize Gdt for all processors.
>
>    @param[in]   Cr3          CR3 value.
> -  @param[out]  GdtStepSize  The step size for GDT table.
>
> -  @return GdtBase for processor 0.
> -          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
> +  @return A GdtArray to hold all base of Gdt Table for all processors.
> +          GdtBase for processor X is: GdtArray[X]
>  **/
> -VOID *
> +UINTN *
>  InitGdt (
> -  IN  UINTN  Cr3,
> -  OUT UINTN  *GdtStepSize
> +  IN  UINTN  Cr3
> +  );
> +
> +/**
> +  This function sets GDT/IDT buffer to be RO and XP.
> +**/
> +VOID
> +PatchGdtIdtMap (
> +  VOID
>    );
>
>  /**
> @@ -596,6 +602,66 @@ SmmBlockingStartupThisAp (
>    );
>
>  /**
> +  This function sets the attributes for the memory region specified by BaseAddress and
> +  Length from their current attributes to the attributes specified by Attributes.
> +
> +  @param[in]  BaseAddress      The physical address that is the start address of a memory region.
> +  @param[in]  Length           The size in bytes of the memory region.
> +  @param[in]  Attributes       The bit mask of attributes to set for the memory region.
> +
> +  @retval EFI_SUCCESS           The attributes were set for the memory region.
> +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
> +                                BaseAddress and Length cannot be modified.
> +  @retval EFI_INVALID_PARAMETER Length is zero.
> +                                Attributes specified an illegal combination of attributes that
> +                                cannot be set together.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
> +                                the memory resource range.
> +  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
> +                                resource range specified by BaseAddress and Length.
> +                                The bit mask of attributes is not support for the memory resource
> +                                range specified by BaseAddress and Length.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmSetMemoryAttributes (
> +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> +  IN  UINT64                                     Length,
> +  IN  UINT64                                     Attributes
> +  );
> +
> +/**
> +  This function clears the attributes for the memory region specified by BaseAddress and
> +  Length from their current attributes to the attributes specified by Attributes.
> +
> +  @param[in]  BaseAddress      The physical address that is the start address of a memory region.
> +  @param[in]  Length           The size in bytes of the memory region.
> +  @param[in]  Attributes       The bit mask of attributes to clear for the memory region.
> +
> +  @retval EFI_SUCCESS           The attributes were cleared for the memory region.
> +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
> +                                BaseAddress and Length cannot be modified.
> +  @retval EFI_INVALID_PARAMETER Length is zero.
> +                                Attributes specified an illegal combination of attributes that
> +                                cannot be set together.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
> +                                the memory resource range.
> +  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
> +                                resource range specified by BaseAddress and Length.
> +                                The bit mask of attributes is not support for the memory resource
> +                                range specified by BaseAddress and Length.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmClearMemoryAttributes (
> +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> +  IN  UINT64                                     Length,
> +  IN  UINT64                                     Attributes
> +  );
> +
> +/**
>    Initialize MP synchronization data.
>
>  **/
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> index c85e025..fc440e4 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> @@ -750,54 +750,6 @@ PatchSmmSaveStateMap (
>  }
>
>  /**
> -  This function sets GDT/IDT buffer to be RO and XP.
> -**/
> -VOID
> -PatchGdtIdtMap (
> -  VOID
> -  )
> -{
> -  EFI_PHYSICAL_ADDRESS       BaseAddress;
> -  UINTN                      Size;
> -
> -  //
> -  // GDT
> -  //
> -  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
> -
> -  BaseAddress = mGdtBuffer;
> -  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_RO
> -    );
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_XP
> -    );
> -
> -  //
> -  // IDT
> -  //
> -  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
> -
> -  BaseAddress = gcSmiIdtr.Base;
> -  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_RO
> -    );
> -  SmmSetMemoryAttributes (
> -    BaseAddress,
> -    Size,
> -    EFI_MEMORY_XP
> -    );
> -}
> -
> -/**
>    This function sets memory attribute according to MemoryAttributesTable.
>  **/
>  VOID
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
> index 9fc00c1..baeec4a 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
> @@ -42,15 +42,13 @@ InitializeIDTSmmStackGuard (
>    Initialize Gdt for all processors.
>
>    @param[in]   Cr3          CR3 value.
> -  @param[out]  GdtStepSize  The step size for GDT table.
>
> -  @return GdtBase for processor 0.
> -          GdtBase for processor X is: GdtBase + (GdtStepSize * X)
> +  @return A GdtArray to hold all base of Gdt Table for all processors.
> +          GdtBase for processor X is: GdtArray[X]
>  **/
> -VOID *
> +UINTN *
>  InitGdt (
> -  IN  UINTN  Cr3,
> -  OUT UINTN  *GdtStepSize
> +  IN  UINTN  Cr3
>    )
>  {
>    UINTN                     Index;
> @@ -59,6 +57,10 @@ InitGdt (
>    UINTN                     GdtTssTableSize;
>    UINT8                     *GdtTssTables;
>    UINTN                     GdtTableStepSize;
> +  UINTN                     *GdtArray;
> +
> +  GdtArray = AllocatePool (sizeof(UINTN) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
> +  ASSERT (GdtArray != NULL);
>
>    //
>    // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
> @@ -89,10 +91,58 @@ InitGdt (
>        //
>        *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);
>      }
> +    GdtArray[Index] = (UINTN)GdtTssTables + GdtTableStepSize * Index;
>    }
>
> -  *GdtStepSize = GdtTableStepSize;
> -  return GdtTssTables;
> +  return GdtArray;
> +}
> +
> +/**
> +  This function sets GDT/IDT buffer to be RO and XP.
> +**/
> +VOID
> +PatchGdtIdtMap (
> +  VOID
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS       BaseAddress;
> +  UINTN                      Size;
> +
> +  //
> +  // GDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
> +
> +  BaseAddress = mGdtBuffer;
> +  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_RO
> +    );
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_XP
> +    );
> +
> +  //
> +  // IDT
> +  //
> +  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
> +
> +  BaseAddress = gcSmiIdtr.Base;
> +  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_RO
> +    );
> +  SmmSetMemoryAttributes (
> +    BaseAddress,
> +    Size,
> +    EFI_MEMORY_XP
> +    );
>  }
>
>  /**
> @@ -154,4 +204,3 @@ TransferApToSafeState (
>    ASSERT (FALSE);
>  }
>
> -
>

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
https://lists.01.org/mailman/listinfo/edk2-devel


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-11-24  0:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-11-23 14:54 [PATCH] UefiCpuPkg/PiSmmCpu: Fixed #double fault on #page fault Jiewen Yao
2016-11-23 22:28 ` Laszlo Ersek
     [not found]   ` <ED077930C258884BBCB450DB737E6622486AB46E@shsmsx102.ccr.corp.intel.com>
2016-11-24  0:45     ` Yao, Jiewen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox