]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
UefiCpuPkg/PiSmmCpuDxeSmm: Add support for PCD PcdPteMemoryEncryptionAddressOrMask
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / SmmCpuMemoryManagement.c
index d841dd014c4bfb236874d440a800dc2d0604d12d..a535389c26cebb6fe2ba068d930a4b671e4204c7 100644 (file)
@@ -16,6 +16,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
   ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))\r
 \r
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
+  ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
+\r
+EFI_MEMORY_DESCRIPTOR *mUefiMemoryMap;\r
+UINTN                 mUefiMemoryMapSize;\r
+UINTN                 mUefiDescriptorSize;\r
+\r
 PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {\r
   {Page4K,  SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},\r
   {Page2M,  SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},\r
@@ -112,7 +119,7 @@ GetPageTableEntry (
       return NULL;\r
     }\r
 \r
-    L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);\r
+    L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
   } else {\r
     L3PageTable = (UINT64 *)GetPageTableBase ();\r
   }\r
@@ -126,7 +133,7 @@ GetPageTableEntry (
     return &L3PageTable[Index3];\r
   }\r
 \r
-  L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);\r
+  L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
   if (L2PageTable[Index2] == 0) {\r
     *PageAttribute = PageNone;\r
     return NULL;\r
@@ -138,7 +145,7 @@ GetPageTableEntry (
   }\r
 \r
   // 4k\r
-  L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);\r
+  L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
   if ((L1PageTable[Index1] == 0) && (Address != 0)) {\r
     *PageAttribute = PageNone;\r
     return NULL;\r
@@ -297,9 +304,9 @@ SplitPage (
       }\r
       BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;\r
       for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
-        NewPageEntry[Index] = BaseAddress + SIZE_4KB * Index + ((*PageEntry) & PAGE_PROGATE_BITS);\r
+        NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | mAddressEncMask | ((*PageEntry) & PAGE_PROGATE_BITS);\r
       }\r
-      (*PageEntry) = (UINT64)(UINTN)NewPageEntry + PAGE_ATTRIBUTE_BITS;\r
+      (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
       return RETURN_SUCCESS;\r
     } else {\r
       return RETURN_UNSUPPORTED;\r
@@ -318,9 +325,9 @@ SplitPage (
       }\r
       BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;\r
       for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
-        NewPageEntry[Index] = BaseAddress + SIZE_2MB * Index + IA32_PG_PS + ((*PageEntry) & PAGE_PROGATE_BITS);\r
+        NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | mAddressEncMask | IA32_PG_PS | ((*PageEntry) & PAGE_PROGATE_BITS);\r
       }\r
-      (*PageEntry) = (UINT64)(UINTN)NewPageEntry + PAGE_ATTRIBUTE_BITS;\r
+      (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
       return RETURN_SUCCESS;\r
     } else {\r
       return RETURN_UNSUPPORTED;\r
@@ -684,7 +691,7 @@ PatchSmmSaveStateMap (
 \r
   TileCodeSize = GetSmiHandlerSize ();\r
   TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);\r
-  TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);\r
+  TileDataSize = (SMRAM_SAVE_STATE_MAP_OFFSET - SMM_PSD_OFFSET) + sizeof (SMRAM_SAVE_STATE_MAP);\r
   TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);\r
   TileSize = TileDataSize + TileCodeSize - 1;\r
   TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);\r
@@ -749,54 +756,6 @@ PatchSmmSaveStateMap (
     );\r
 }\r
 \r
-/**\r
-  This function sets GDT/IDT buffer to be RO and XP.\r
-**/\r
-VOID\r
-PatchGdtIdtMap (\r
-  VOID\r
-  )\r
-{\r
-  EFI_PHYSICAL_ADDRESS       BaseAddress;\r
-  UINTN                      Size;\r
-\r
-  //\r
-  // GDT\r
-  //\r
-  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));\r
-\r
-  BaseAddress = mGdtBuffer;\r
-  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);\r
-  SmmSetMemoryAttributes (\r
-    BaseAddress,\r
-    Size,\r
-    EFI_MEMORY_RO\r
-    );\r
-  SmmSetMemoryAttributes (\r
-    BaseAddress,\r
-    Size,\r
-    EFI_MEMORY_XP\r
-    );\r
-\r
-  //\r
-  // IDT\r
-  //\r
-  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));\r
-\r
-  BaseAddress = gcSmiIdtr.Base;\r
-  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);\r
-  SmmSetMemoryAttributes (\r
-    BaseAddress,\r
-    Size,\r
-    EFI_MEMORY_RO\r
-    );\r
-  SmmSetMemoryAttributes (\r
-    BaseAddress,\r
-    Size,\r
-    EFI_MEMORY_XP\r
-    );\r
-}\r
-\r
 /**\r
   This function sets memory attribute according to MemoryAttributesTable.\r
 **/\r
@@ -871,3 +830,274 @@ SetMemMapAttributes (
 \r
   return ;\r
 }\r
+\r
+/**\r
+  Sort memory map entries based upon PhysicalStart, from low to high.\r
+\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+VOID\r
+SortMemoryMap (\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN UINTN                      MemoryMapSize,\r
+  IN UINTN                      DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+  EFI_MEMORY_DESCRIPTOR       TempMemoryMap;\r
+\r
+  MemoryMapEntry = MemoryMap;\r
+  NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+  while (MemoryMapEntry < MemoryMapEnd) {\r
+    while (NextMemoryMapEntry < MemoryMapEnd) {\r
+      if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
+        CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+        CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+        CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+      }\r
+\r
+      NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+    }\r
+\r
+    MemoryMapEntry      = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+    NextMemoryMapEntry  = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  }\r
+}\r
+\r
+/**\r
+  Return if a UEFI memory page should be marked as not present in SMM page table.\r
+  If the memory map entries type is\r
+  EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,\r
+  EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.\r
+  Or return FALSE.\r
+\r
+  @param[in]  MemoryMap              A pointer to the memory descriptor.\r
+\r
+  @return TRUE  The memory described will be marked as not present in SMM page table.\r
+  @return FALSE The memory described will not be marked as not present in SMM page table.\r
+**/\r
+BOOLEAN\r
+IsUefiPageNotPresent (\r
+  IN EFI_MEMORY_DESCRIPTOR  *MemoryMap\r
+  )\r
+{\r
+  switch (MemoryMap->Type) {\r
+  case EfiLoaderCode:\r
+  case EfiLoaderData:\r
+  case EfiBootServicesCode:\r
+  case EfiBootServicesData:\r
+  case EfiConventionalMemory:\r
+  case EfiUnusableMemory:\r
+  case EfiACPIReclaimMemory:\r
+    return TRUE;\r
+  default:\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Merge continous memory map entries whose type is\r
+  EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,\r
+  EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by\r
+  these entries will be set as NOT present in SMM page table.\r
+\r
+  @param[in, out]  MemoryMap              A pointer to the buffer in which firmware places\r
+                                          the current memory map.\r
+  @param[in, out]  MemoryMapSize          A pointer to the size, in bytes, of the\r
+                                          MemoryMap buffer. On input, this is the size of\r
+                                          the current memory map.  On output,\r
+                                          it is the size of new memory map after merge.\r
+  @param[in]       DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+VOID\r
+MergeMemoryMapForNotPresentEntry (\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN OUT UINTN                  *MemoryMapSize,\r
+  IN UINTN                      DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+  UINT64                      MemoryBlockLength;\r
+  EFI_MEMORY_DESCRIPTOR       *NewMemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;\r
+\r
+  MemoryMapEntry = MemoryMap;\r
+  NewMemoryMapEntry = MemoryMap;\r
+  MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
+  while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+    CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+    NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+\r
+    do {\r
+      MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));\r
+      if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
+          IsUefiPageNotPresent(MemoryMapEntry) && IsUefiPageNotPresent(NextMemoryMapEntry) &&\r
+          ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
+        MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
+        if (NewMemoryMapEntry != MemoryMapEntry) {\r
+          NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
+        }\r
+\r
+        NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+        continue;\r
+      } else {\r
+        MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+        break;\r
+      }\r
+    } while (TRUE);\r
+\r
+    MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+    NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
+  }\r
+\r
+  *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  This function caches the UEFI memory map information.\r
+**/\r
+VOID\r
+GetUefiMemoryMap (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 MapKey;\r
+  UINT32                DescriptorVersion;\r
+  EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+  UINTN                 UefiMemoryMapSize;\r
+\r
+  DEBUG ((DEBUG_INFO, "GetUefiMemoryMap\n"));\r
+\r
+  UefiMemoryMapSize = 0;\r
+  MemoryMap = NULL;\r
+  Status = gBS->GetMemoryMap (\r
+                  &UefiMemoryMapSize,\r
+                  MemoryMap,\r
+                  &MapKey,\r
+                  &mUefiDescriptorSize,\r
+                  &DescriptorVersion\r
+                  );\r
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+  do {\r
+    Status = gBS->AllocatePool (EfiBootServicesData, UefiMemoryMapSize, (VOID **)&MemoryMap);\r
+    ASSERT (MemoryMap != NULL);\r
+    if (MemoryMap == NULL) {\r
+      return ;\r
+    }\r
+\r
+    Status = gBS->GetMemoryMap (\r
+                    &UefiMemoryMapSize,\r
+                    MemoryMap,\r
+                    &MapKey,\r
+                    &mUefiDescriptorSize,\r
+                    &DescriptorVersion\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->FreePool (MemoryMap);\r
+      MemoryMap = NULL;\r
+    }\r
+  } while (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+  if (MemoryMap == NULL) {\r
+    return ;\r
+  }\r
+\r
+  SortMemoryMap (MemoryMap, UefiMemoryMapSize, mUefiDescriptorSize);\r
+  MergeMemoryMapForNotPresentEntry (MemoryMap, &UefiMemoryMapSize, mUefiDescriptorSize);\r
+\r
+  mUefiMemoryMapSize = UefiMemoryMapSize;\r
+  mUefiMemoryMap = AllocateCopyPool (UefiMemoryMapSize, MemoryMap);\r
+  ASSERT (mUefiMemoryMap != NULL);\r
+\r
+  gBS->FreePool (MemoryMap);\r
+}\r
+\r
+/**\r
+  This function sets UEFI memory attribute according to UEFI memory map.\r
+\r
+  The normal memory region is marked as not present, such as\r
+  EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,\r
+  EfiUnusableMemory, EfiACPIReclaimMemory.\r
+**/\r
+VOID\r
+SetUefiMemMapAttributes (\r
+  VOID\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+  UINTN                 MemoryMapEntryCount;\r
+  UINTN                 Index;\r
+\r
+  DEBUG ((DEBUG_INFO, "SetUefiMemMapAttributes\n"));\r
+\r
+  if (mUefiMemoryMap == NULL) {\r
+    DEBUG ((DEBUG_INFO, "UefiMemoryMap - NULL\n"));\r
+    return ;\r
+  }\r
+\r
+  MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;\r
+  MemoryMap = mUefiMemoryMap;\r
+  for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
+    if (IsUefiPageNotPresent(MemoryMap)) {\r
+      DEBUG ((DEBUG_INFO, "UefiMemory protection: 0x%lx - 0x%lx\n", MemoryMap->PhysicalStart, MemoryMap->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages)));\r
+      SmmSetMemoryAttributes (\r
+        MemoryMap->PhysicalStart,\r
+        EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
+        EFI_MEMORY_RP\r
+        );\r
+    }\r
+    MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize);\r
+  }\r
+\r
+  //\r
+  // Do free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().\r
+  //\r
+}\r
+\r
+/**\r
+  Return if the Address is forbidden as SMM communication buffer.\r
+\r
+  @param[in] Address the address to be checked\r
+\r
+  @return TRUE  The address is forbidden as SMM communication buffer.\r
+  @return FALSE The address is allowed as SMM communication buffer.\r
+**/\r
+BOOLEAN\r
+IsSmmCommBufferForbiddenAddress (\r
+  IN UINT64  Address\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+  UINTN                 MemoryMapEntryCount;\r
+  UINTN                 Index;\r
+\r
+  if (mUefiMemoryMap == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  MemoryMap = mUefiMemoryMap;\r
+  MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;\r
+  for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
+    if (IsUefiPageNotPresent (MemoryMap)) {\r
+      if ((Address >= MemoryMap->PhysicalStart) &&\r
+          (Address < MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages)) ) {\r
+        return TRUE;\r
+      }\r
+    }\r
+    MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize);\r
+  }\r
+  return FALSE;\r
+}\r