/** @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
\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
\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
\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
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
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