]> 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 5f13446015cc0482b1477836fbf5e73d64a37655..4baba1e9f8dc1bbd1a8925be4e6683338d1ffc8c 100644 (file)
@@ -113,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
@@ -731,9 +744,9 @@ PiCpuSmmEntry (
   //\r
   BufferPages = EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1));\r
   if ((FamilyId == 4) || (FamilyId == 5)) {\r
-    Buffer = AllocateAlignedPages (BufferPages, SIZE_32KB);\r
+    Buffer = AllocateAlignedCodePages (BufferPages, SIZE_32KB);\r
   } else {\r
-    Buffer = AllocateAlignedPages (BufferPages, SIZE_4KB);\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
@@ -842,6 +855,8 @@ PiCpuSmmEntry (
   //\r
   SmmCpuFeaturesSmmRelocationComplete ();\r
 \r
+  DEBUG ((DEBUG_INFO, "mXdSupported - 0x%x\n", mXdSupported));\r
+\r
   //\r
   // SMM Time initialization\r
   //\r
@@ -1137,6 +1152,17 @@ ConfigSmmCodeAccessCheck (
   }\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
@@ -1166,6 +1192,109 @@ AllocatePageTableMemory (
   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
   Perform the remaining tasks.\r
 \r
@@ -1186,6 +1315,17 @@ 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