]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
IntelSiliconPkg IntelVTdDxe: Support early SetAttributes()
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / DmaProtection.c
index d9b8885d7ace66f5793aef3b2055c9e74bed9197..557c18aa547cb8a85951db0a70b8de658fc66636 100644 (file)
@@ -18,6 +18,151 @@ UINT64                                  mAbove4GMemoryLimit;
 \r
 EDKII_PLATFORM_VTD_POLICY_PROTOCOL      *mPlatformVTdPolicy;\r
 \r
+VTD_ACCESS_REQUEST                      *mAccessRequest = NULL;\r
+UINTN                                   mAccessRequestCount = 0;\r
+UINTN                                   mAccessRequestMaxCount = 0;\r
+\r
+/**\r
+  Append VTd Access Request to global.\r
+\r
+  @param[in]  Segment           The Segment used to identify a VTd engine.\r
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.\r
+  @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.\r
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.\r
+  @param[in]  IoMmuAccess       The IOMMU access.\r
+\r
+  @retval EFI_SUCCESS           The IoMmuAccess is set for the memory range specified by BaseAddress and Length.\r
+  @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.\r
+  @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.\r
+  @retval EFI_INVALID_PARAMETER Length is 0.\r
+  @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
+  @retval EFI_UNSUPPORTED       The bit mask of IoMmuAccess is not supported by the IOMMU.\r
+  @retval EFI_UNSUPPORTED       The IOMMU does not support the memory range specified by BaseAddress and Length.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to modify the IOMMU access.\r
+  @retval EFI_DEVICE_ERROR      The IOMMU device reported an error while attempting the operation.\r
+\r
+**/\r
+EFI_STATUS\r
+RequestAccessAttribute (\r
+  IN UINT16                 Segment,\r
+  IN VTD_SOURCE_ID          SourceId,\r
+  IN UINT64                 BaseAddress,\r
+  IN UINT64                 Length,\r
+  IN UINT64                 IoMmuAccess\r
+  )\r
+{\r
+  VTD_ACCESS_REQUEST        *NewAccessRequest;\r
+  UINTN                     Index;\r
+\r
+  //\r
+  // Optimization for memory.\r
+  //\r
+  // If the last record is to IoMmuAccess=0,\r
+  // Check previous records and remove the matched entry.\r
+  //\r
+  if (IoMmuAccess == 0) {\r
+    for (Index = 0; Index < mAccessRequestCount; Index++) {\r
+      if ((mAccessRequest[Index].Segment == Segment) &&\r
+          (mAccessRequest[Index].SourceId.Uint16 == SourceId.Uint16) &&\r
+          (mAccessRequest[Index].BaseAddress == BaseAddress) &&\r
+          (mAccessRequest[Index].Length == Length) &&\r
+          (mAccessRequest[Index].IoMmuAccess != 0)) {\r
+        //\r
+        // Remove this record [Index].\r
+        // No need to add the new record.\r
+        //\r
+        if (Index != mAccessRequestCount - 1) {\r
+          CopyMem (\r
+            &mAccessRequest[Index],\r
+            &mAccessRequest[Index + 1],\r
+            sizeof (VTD_ACCESS_REQUEST) * (mAccessRequestCount - 1 - Index)\r
+            );\r
+        }\r
+        ZeroMem (&mAccessRequest[mAccessRequestCount - 1], sizeof(VTD_ACCESS_REQUEST));\r
+        mAccessRequestCount--;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (mAccessRequestCount >= mAccessRequestMaxCount) {\r
+    NewAccessRequest = AllocateZeroPool (sizeof(*NewAccessRequest) * (mAccessRequestMaxCount + MAX_VTD_ACCESS_REQUEST));\r
+    if (NewAccessRequest == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    mAccessRequestMaxCount += MAX_VTD_ACCESS_REQUEST;\r
+    if (mAccessRequest != NULL) {\r
+      CopyMem (NewAccessRequest, mAccessRequest, sizeof(*NewAccessRequest) * mAccessRequestCount);\r
+      FreePool (mAccessRequest);\r
+    }\r
+    mAccessRequest = NewAccessRequest;\r
+  }\r
+\r
+  ASSERT (mAccessRequestCount < mAccessRequestMaxCount);\r
+\r
+  mAccessRequest[mAccessRequestCount].Segment = Segment;\r
+  mAccessRequest[mAccessRequestCount].SourceId = SourceId;\r
+  mAccessRequest[mAccessRequestCount].BaseAddress = BaseAddress;\r
+  mAccessRequest[mAccessRequestCount].Length = Length;\r
+  mAccessRequest[mAccessRequestCount].IoMmuAccess = IoMmuAccess;\r
+\r
+  mAccessRequestCount++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Process Access Requests from before DMAR table is installed.\r
+\r
+**/\r
+VOID\r
+ProcessRequestedAccessAttribute (\r
+  VOID\r
+  )\r
+{\r
+  UINTN       Index;\r
+  EFI_STATUS  Status;\r
+\r
+  DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute ...\n"));\r
+\r
+  for (Index = 0; Index < mAccessRequestCount; Index++) {\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "PCI(S%x.B%x.D%x.F%x) ",\r
+      mAccessRequest[Index].Segment,\r
+      mAccessRequest[Index].SourceId.Bits.Bus,\r
+      mAccessRequest[Index].SourceId.Bits.Device,\r
+      mAccessRequest[Index].SourceId.Bits.Function\r
+      ));\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "(0x%lx~0x%lx) - %lx\n",\r
+      mAccessRequest[Index].BaseAddress,\r
+      mAccessRequest[Index].Length,\r
+      mAccessRequest[Index].IoMmuAccess\r
+      ));\r
+    Status = SetAccessAttribute (\r
+               mAccessRequest[Index].Segment,\r
+               mAccessRequest[Index].SourceId,\r
+               mAccessRequest[Index].BaseAddress,\r
+               mAccessRequest[Index].Length,\r
+               mAccessRequest[Index].IoMmuAccess\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "SetAccessAttribute %r: ", Status));\r
+    }\r
+  }\r
+\r
+  if (mAccessRequest != NULL) {\r
+    FreePool (mAccessRequest);\r
+  }\r
+  mAccessRequest = NULL;\r
+  mAccessRequestCount = 0;\r
+  mAccessRequestMaxCount = 0;\r
+\r
+  DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute Done\n"));\r
+}\r
+\r
 /**\r
   return the UEFI memory information.\r
 \r
@@ -370,6 +515,8 @@ SetupVtd (
 \r
   ParseDmarAcpiTableRmrr ();\r
 \r
+  ProcessRequestedAccessAttribute ();\r
+\r
   for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
     DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));\r
     if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {\r