IntelSiliconPkg/Vtd: Add MapHandleInfo in VtdDxe.
authorJiewen Yao <jiewen.yao@intel.com>
Thu, 8 Mar 2018 11:42:49 +0000 (19:42 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Fri, 9 Mar 2018 02:27:52 +0000 (10:27 +0800)
This information is to record which device requested which DMA buffer.
It can be used for DMA buffer analysis.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
IntelSiliconPkg/Feature/VTd/IntelVTdDxe/BmDma.c
IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c

index 57e086a..bf3c1ed 100644 (file)
 #define DMA_MEMORY_TOP          MAX_UINTN\r
 //#define DMA_MEMORY_TOP          0x0000000001FFFFFFULL\r
 \r
+#define MAP_HANDLE_INFO_SIGNATURE  SIGNATURE_32 ('H', 'M', 'A', 'P')\r
+typedef struct {\r
+  UINT32                                    Signature;\r
+  LIST_ENTRY                                Link;\r
+  EFI_HANDLE                                DeviceHandle;\r
+  UINT64                                    IoMmuAccess;\r
+} MAP_HANDLE_INFO;\r
+#define MAP_HANDLE_INFO_FROM_LINK(a) CR (a, MAP_HANDLE_INFO, Link, MAP_HANDLE_INFO_SIGNATURE)\r
+\r
 #define MAP_INFO_SIGNATURE  SIGNATURE_32 ('D', 'M', 'A', 'P')\r
 typedef struct {\r
   UINT32                                    Signature;\r
@@ -27,11 +36,95 @@ typedef struct {
   UINTN                                     NumberOfPages;\r
   EFI_PHYSICAL_ADDRESS                      HostAddress;\r
   EFI_PHYSICAL_ADDRESS                      DeviceAddress;\r
+  LIST_ENTRY                                HandleList;\r
 } MAP_INFO;\r
 #define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)\r
 \r
 LIST_ENTRY                        gMaps = INITIALIZE_LIST_HEAD_VARIABLE(gMaps);\r
 \r
+/**\r
+  This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,\r
+  based upon the DeviceAddress.\r
+\r
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.\r
+  @param[in]  DeviceAddress     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
+**/\r
+VOID\r
+SyncDeviceHandleToMapInfo (\r
+  IN EFI_HANDLE            DeviceHandle,\r
+  IN EFI_PHYSICAL_ADDRESS  DeviceAddress,\r
+  IN UINT64                Length,\r
+  IN UINT64                IoMmuAccess\r
+  )\r
+{\r
+  MAP_INFO                 *MapInfo;\r
+  MAP_HANDLE_INFO          *MapHandleInfo;\r
+  LIST_ENTRY               *Link;\r
+  EFI_TPL                  OriginalTpl;\r
+\r
+  //\r
+  // Find MapInfo according to DeviceAddress\r
+  //\r
+  OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);\r
+  MapInfo = NULL;\r
+  for (Link = GetFirstNode (&gMaps)\r
+       ; !IsNull (&gMaps, Link)\r
+       ; Link = GetNextNode (&gMaps, Link)\r
+       ) {\r
+    MapInfo = MAP_INFO_FROM_LINK (Link);\r
+    if (MapInfo->DeviceAddress == DeviceAddress) {\r
+      break;\r
+    }\r
+  }\r
+  if ((MapInfo == NULL) || (MapInfo->DeviceAddress != DeviceAddress)) {\r
+    DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: DeviceAddress(0x%lx) - not found\n", DeviceAddress));\r
+    gBS->RestoreTPL (OriginalTpl);\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Find MapHandleInfo according to DeviceHandle\r
+  //\r
+  MapHandleInfo = NULL;\r
+  for (Link = GetFirstNode (&MapInfo->HandleList)\r
+       ; !IsNull (&MapInfo->HandleList, Link)\r
+       ; Link = GetNextNode (&MapInfo->HandleList, Link)\r
+       ) {\r
+    MapHandleInfo = MAP_HANDLE_INFO_FROM_LINK (Link);\r
+    if (MapHandleInfo->DeviceHandle == DeviceHandle) {\r
+      break;\r
+    }\r
+  }\r
+  if ((MapHandleInfo != NULL) && (MapHandleInfo->DeviceHandle == DeviceHandle)) {\r
+    MapHandleInfo->IoMmuAccess       = IoMmuAccess;\r
+    gBS->RestoreTPL (OriginalTpl);\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // No DeviceHandle\r
+  // Initialize and insert the MAP_HANDLE_INFO structure\r
+  //\r
+  MapHandleInfo = AllocatePool (sizeof (MAP_HANDLE_INFO));\r
+  if (MapHandleInfo == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: %r\n", EFI_OUT_OF_RESOURCES));\r
+    gBS->RestoreTPL (OriginalTpl);\r
+    return ;\r
+  }\r
+\r
+  MapHandleInfo->Signature         = MAP_HANDLE_INFO_SIGNATURE;\r
+  MapHandleInfo->DeviceHandle      = DeviceHandle;\r
+  MapHandleInfo->IoMmuAccess       = IoMmuAccess;\r
+\r
+  InsertTailList (&MapInfo->HandleList, &MapHandleInfo->Link);\r
+  gBS->RestoreTPL (OriginalTpl);\r
+\r
+  return ;\r
+}\r
+\r
 /**\r
   Provides the controller-specific addresses required to access system memory from a\r
   DMA bus master.\r
@@ -156,6 +249,7 @@ IoMmuMap (
   MapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
   MapInfo->HostAddress       = PhysicalAddress;\r
   MapInfo->DeviceAddress     = DmaMemoryTop;\r
+  InitializeListHead(&MapInfo->HandleList);\r
 \r
   //\r
   // Allocate a buffer below 4GB to map the transfer to.\r
@@ -227,6 +321,7 @@ IoMmuUnmap (
   )\r
 {\r
   MAP_INFO                 *MapInfo;\r
+  MAP_HANDLE_INFO          *MapHandleInfo;\r
   LIST_ENTRY               *Link;\r
   EFI_TPL                  OriginalTpl;\r
 \r
@@ -259,6 +354,15 @@ IoMmuUnmap (
   RemoveEntryList (&MapInfo->Link);\r
   gBS->RestoreTPL (OriginalTpl);\r
 \r
+  //\r
+  // remove all nodes in MapInfo->HandleList\r
+  //\r
+  while (!IsListEmpty (&MapInfo->HandleList)) {\r
+    MapHandleInfo = MAP_HANDLE_INFO_FROM_LINK (MapInfo->HandleList.ForwardLink);\r
+    RemoveEntryList (&MapHandleInfo->Link);\r
+    FreePool (MapHandleInfo);\r
+  }\r
+\r
   if (MapInfo->DeviceAddress != MapInfo->HostAddress) {\r
     //\r
     // If this is a write operation from the Bus Master's point of view,\r
index 841a5a9..25d7c80 100644 (file)
@@ -113,6 +113,24 @@ IoMmuFreeBuffer (
   IN  VOID                                     *HostAddress\r
   );\r
 \r
+/**\r
+  This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,\r
+  based upon the DeviceAddress.\r
+\r
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.\r
+  @param[in]  DeviceAddress     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
+**/\r
+VOID\r
+SyncDeviceHandleToMapInfo (\r
+  IN EFI_HANDLE            DeviceHandle,\r
+  IN EFI_PHYSICAL_ADDRESS  DeviceAddress,\r
+  IN UINT64                Length,\r
+  IN UINT64                IoMmuAccess\r
+  );\r
+\r
 /**\r
   Convert the DeviceHandle to SourceId and Segment.\r
 \r
@@ -236,21 +254,30 @@ VTdSetAttribute (
     // Record the entry to driver global variable.\r
     // As such once VTd is activated, the setting can be adopted.\r
     //\r
-    return RequestAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);\r
+    Status = RequestAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);\r
+  } else {\r
+    PERF_CODE (\r
+      AsciiSPrint (PerfToken, sizeof(PerfToken), "S%04xB%02xD%02xF%01x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function);\r
+      Identifier = (Segment << 16) | SourceId.Uint16;\r
+      PERF_START_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);\r
+    );\r
+\r
+    Status = SetAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);\r
+\r
+    PERF_CODE (\r
+      Identifier = (Segment << 16) | SourceId.Uint16;\r
+      PERF_END_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);\r
+    );\r
   }\r
 \r
-  PERF_CODE (\r
-    AsciiSPrint (PerfToken, sizeof(PerfToken), "S%04xB%02xD%02xF%01x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function);\r
-    Identifier = (Segment << 16) | SourceId.Uint16;\r
-    PERF_START_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);\r
-  );\r
-\r
-  Status = SetAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);\r
-\r
-  PERF_CODE (\r
-    Identifier = (Segment << 16) | SourceId.Uint16;\r
-    PERF_END_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);\r
-  );\r
+  if (!EFI_ERROR(Status)) {\r
+    SyncDeviceHandleToMapInfo (\r
+      DeviceHandle,\r
+      DeviceAddress,\r
+      Length,\r
+      IoMmuAccess\r
+      );\r
+  }\r
 \r
   return Status;\r
 }\r