]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
BaseTools:Add import in FvImageSection
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / DmaProtection.c
index 6052a0aebe45197d9fd81c8280bed467893b6a71..956ebb2d3d3d5c77be22e631c288b1a73b1daaee 100644 (file)
@@ -1,13 +1,7 @@
 /** @file\r
 \r
-  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php.\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -18,6 +12,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 +509,14 @@ SetupVtd (
 \r
   ParseDmarAcpiTableRmrr ();\r
 \r
+  if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) == 0) {\r
+    //\r
+    // Support IOMMU access attribute request recording before DMAR table is installed.\r
+    // Here is to process the requests.\r
+    //\r
+    ProcessRequestedAccessAttribute ();\r
+  }\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
@@ -412,6 +559,9 @@ AcpiNotificationFunc (
 \r
   Status = GetDmarAcpiTable ();\r
   if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_ALREADY_STARTED) {\r
+      gBS->CloseEvent (Event);\r
+    }\r
     return;\r
   }\r
   SetupVtd ();\r
@@ -431,9 +581,20 @@ OnExitBootServices (
   IN VOID                                    *Context\r
   )\r
 {\r
+  UINTN   VtdIndex;\r
+\r
   DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));\r
   DumpVtdRegsAll ();\r
 \r
+  DEBUG ((DEBUG_INFO, "Invalidate all\n"));\r
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
+    FlushWriteBuffer (VtdIndex);\r
+\r
+    InvalidateContextCache (VtdIndex);\r
+\r
+    InvalidateIOTLB (VtdIndex);\r
+  }\r
+\r
   if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
     DisableDmar ();\r
     DumpVtdRegsAll ();\r
@@ -470,28 +631,36 @@ InitializeDmaProtection (
   EFI_STATUS  Status;\r
   EFI_EVENT   ExitBootServicesEvent;\r
   EFI_EVENT   LegacyBootEvent;\r
-  EFI_EVENT   Event;\r
-  \r
+  EFI_EVENT   EventAcpi10;\r
+  EFI_EVENT   EventAcpi20;\r
+\r
   Status = gBS->CreateEventEx (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
+                  VTD_TPL_LEVEL,\r
                   AcpiNotificationFunc,\r
                   NULL,\r
                   &gEfiAcpi10TableGuid,\r
-                  &Event\r
+                  &EventAcpi10\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   Status = gBS->CreateEventEx (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
+                  VTD_TPL_LEVEL,\r
                   AcpiNotificationFunc,\r
                   NULL,\r
                   &gEfiAcpi20TableGuid,\r
-                  &Event\r
+                  &EventAcpi20\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
+  //\r
+  // Signal the events initially for the case\r
+  // that DMAR table has been installed.\r
+  //\r
+  gBS->SignalEvent (EventAcpi20);\r
+  gBS->SignalEvent (EventAcpi10);\r
+\r
   Status = gBS->CreateEventEx (\r
                   EVT_NOTIFY_SIGNAL,\r
                   TPL_CALLBACK,\r