+/** @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
+\r
+**/\r
+\r
+#ifndef _DMAR_PROTECTION_H_\r
+#define _DMAR_PROTECTION_H_\r
+\r
+#include <Uefi.h>\r
+#include <PiDxe.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciSegmentLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/Acpi.h>\r
+\r
+#include <Protocol/DxeSmmReadyToLock.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/PciEnumerationComplete.h>\r
+#include <Protocol/AcpiSystemDescriptionTable.h>\r
+#include <Protocol/PlatformVtdPolicy.h>\r
+#include <Protocol/IoMmu.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include <IndustryStandard/DmaRemappingReportingTable.h>\r
+#include <IndustryStandard/Vtd.h>\r
+\r
+#define ALIGN_VALUE_UP(Value, Alignment) (((Value) + (Alignment) - 1) & (~((Alignment) - 1)))\r
+#define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))\r
+\r
+//\r
+// This is the initial max PCI descriptor.\r
+// The number may be enlarged later.\r
+//\r
+#define MAX_PCI_DESCRIPTORS 0x100\r
+\r
+typedef struct {\r
+ BOOLEAN IncludeAllFlag;\r
+ UINTN PciDescriptorNumber;\r
+ UINTN PciDescriptorMaxNumber;\r
+ BOOLEAN *IsRealPciDevice;\r
+ VTD_SOURCE_ID *PciDescriptors;\r
+} PCI_DEVICE_INFORMATION;\r
+\r
+typedef struct {\r
+ UINTN VtdUnitBaseAddress;\r
+ UINT16 Segment;\r
+ VTD_CAP_REG CapReg;\r
+ VTD_ECAP_REG ECapReg;\r
+ VTD_ROOT_ENTRY *RootEntryTable;\r
+ VTD_EXT_ROOT_ENTRY *ExtRootEntryTable;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *FixedSecondLevelPagingEntry;\r
+ BOOLEAN HasDirtyPages;\r
+ PCI_DEVICE_INFORMATION PciDeviceInfo;\r
+} VTD_UNIT_INFORMATION;\r
+\r
+extern EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;\r
+\r
+extern UINT64 mVtdHostAddressWidthMask;\r
+extern UINTN mVtdUnitNumber;\r
+extern VTD_UNIT_INFORMATION *mVtdUnitInformation;\r
+\r
+extern UINT64 mBelow4GMemoryLimit;\r
+extern UINT64 mAbove4GMemoryLimit;\r
+\r
+extern EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;\r
+\r
+/**\r
+ Prepare VTD configuration.\r
+**/\r
+VOID\r
+PrepareVtdConfig (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Setup VTd translation table.\r
+\r
+ @retval EFI_SUCCESS Setup translation table successfully.\r
+ @retval EFI_OUT_OF_RESOURCE Setup translation table fail.\r
+**/\r
+EFI_STATUS\r
+SetupTranslationTable (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Enable DMAR translation.\r
+\r
+ @retval EFI_SUCCESS DMAR translation is enabled.\r
+ @retval EFI_DEVICE_ERROR DMAR translation is not enabled.\r
+**/\r
+EFI_STATUS\r
+EnableDmar (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Disable DMAR translation.\r
+\r
+ @retval EFI_SUCCESS DMAR translation is disabled.\r
+ @retval EFI_DEVICE_ERROR DMAR translation is not disabled.\r
+**/\r
+EFI_STATUS\r
+DisableDmar (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Invalid VTd IOTLB page.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] Address The address of IOTLB page.\r
+ @param[in] AddressMode The address mode of IOTLB page.\r
+ @param[in] DomainIdentifier The domain ID of the source.\r
+\r
+ @retval EFI_SUCCESS VTd IOTLB page is invalidated.\r
+ @retval EFI_DEVICE_ERROR VTd IOTLB page is not invalidated.\r
+**/\r
+EFI_STATUS\r
+InvalidateVtdIOTLBPage (\r
+ IN UINTN VtdIndex,\r
+ IN UINT64 Address,\r
+ IN UINT8 AddressMode,\r
+ IN UINT16 DomainIdentifier\r
+ );\r
+\r
+/**\r
+ Invalid VTd IOTLB domain.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] DomainIdentifier The domain ID of the source.\r
+\r
+ @retval EFI_SUCCESS VTd IOTLB domain is invalidated.\r
+ @retval EFI_DEVICE_ERROR VTd IOTLB domain is not invalidated.\r
+**/\r
+EFI_STATUS\r
+InvalidateVtdIOTLBDomain (\r
+ IN UINTN VtdIndex,\r
+ IN UINT16 DomainIdentifier\r
+ );\r
+\r
+/**\r
+ Invalid VTd global IOTLB.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+\r
+ @retval EFI_SUCCESS VTd global IOTLB is invalidated.\r
+ @retval EFI_DEVICE_ERROR VTd global IOTLB is not invalidated.\r
+**/\r
+EFI_STATUS\r
+InvalidateVtdIOTLBGlobal (\r
+ IN UINTN VtdIndex\r
+ );\r
+\r
+/**\r
+ Dump VTd registers.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+**/\r
+VOID\r
+DumpVtdRegs (\r
+ IN UINTN VtdIndex\r
+ );\r
+\r
+/**\r
+ Dump VTd registers for all VTd engine.\r
+**/\r
+VOID\r
+DumpVtdRegsAll (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Dump VTd capability registers.\r
+\r
+ @param[in] CapReg The capability register.\r
+**/\r
+VOID\r
+DumpVtdCapRegs (\r
+ IN VTD_CAP_REG *CapReg\r
+ );\r
+\r
+/**\r
+ Dump VTd extended capability registers.\r
+\r
+ @param[in] ECapReg The extended capability register.\r
+**/\r
+VOID\r
+DumpVtdECapRegs (\r
+ IN VTD_ECAP_REG *ECapReg\r
+ );\r
+\r
+/**\r
+ Register PCI device to VTd engine as PCI descriptor.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] SourceId The SourceId of the source.\r
+ @param[in] IsRealPciDevice TRUE: It is a real PCI device.\r
+ FALSE: It is not a real PCI device.\r
+ @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.\r
+ FALSE: SUCCESS will be returned if the PCI device is registered.\r
+\r
+ @retval EFI_SUCCESS The PCI device is registered.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
+ @retval EFI_ALREADY_STARTED The device is already registered.\r
+**/\r
+EFI_STATUS\r
+RegisterPciDevice (\r
+ IN UINTN VtdIndex,\r
+ IN UINT16 Segment,\r
+ IN VTD_SOURCE_ID SourceId,\r
+ IN BOOLEAN IsRealPciDevice,\r
+ IN BOOLEAN CheckExist\r
+ );\r
+\r
+/**\r
+ Scan PCI bus and register PCI devices under the bus.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] Bus The bus of the source.\r
+\r
+ @retval EFI_SUCCESS The PCI devices under the bus are registered.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
+**/\r
+EFI_STATUS\r
+ScanPciBus (\r
+ IN UINTN VtdIndex,\r
+ IN UINT16 Segment,\r
+ IN UINT8 Bus\r
+ );\r
+\r
+/**\r
+ Dump the PCI device information managed by this VTd engine.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+**/\r
+VOID\r
+DumpPciDeviceInfo (\r
+ IN UINTN VtdIndex\r
+ );\r
+\r
+/**\r
+ Find the VTd index by the Segment and SourceId.\r
+\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] SourceId The SourceId of the source.\r
+ @param[out] ExtContextEntry The ExtContextEntry of the source.\r
+ @param[out] ContextEntry The ContextEntry of the source.\r
+\r
+ @return The index of the PCI descriptor.\r
+ @retval (UINTN)-1 The PCI descriptor is not found.\r
+**/\r
+UINTN\r
+FindVtdIndexByPciDevice (\r
+ IN UINT16 Segment,\r
+ IN VTD_SOURCE_ID SourceId,\r
+ OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,\r
+ OUT VTD_CONTEXT_ENTRY **ContextEntry\r
+ );\r
+\r
+/**\r
+ Get the DMAR ACPI table.\r
+\r
+ @retval EFI_SUCCESS The DMAR ACPI table is got.\r
+ @retval EFI_NOT_FOUND The DMAR ACPI table is not found.\r
+**/\r
+EFI_STATUS\r
+GetDmarAcpiTable (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Parse DMAR DRHD table.\r
+\r
+ @return EFI_SUCCESS The DMAR DRHD table is parsed.\r
+**/\r
+EFI_STATUS\r
+ParseDmarAcpiTableDrhd (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Parse DMAR RMRR table.\r
+\r
+ @return EFI_SUCCESS The DMAR RMRR table is parsed.\r
+**/\r
+EFI_STATUS\r
+ParseDmarAcpiTableRmrr (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Dump DMAR context entry table.\r
+\r
+ @param[in] RootEntry DMAR root entry.\r
+**/\r
+VOID\r
+DumpDmarContextEntryTable (\r
+ IN VTD_ROOT_ENTRY *RootEntry\r
+ );\r
+\r
+/**\r
+ Dump DMAR extended context entry table.\r
+\r
+ @param[in] ExtRootEntry DMAR extended root entry.\r
+**/\r
+VOID\r
+DumpDmarExtContextEntryTable (\r
+ IN VTD_EXT_ROOT_ENTRY *ExtRootEntry\r
+ );\r
+\r
+/**\r
+ Dump DMAR second level paging entry.\r
+\r
+ @param[in] SecondLevelPagingEntry The second level paging entry.\r
+**/\r
+VOID\r
+DumpSecondLevelPagingEntry (\r
+ IN VOID *SecondLevelPagingEntry\r
+ );\r
+\r
+/**\r
+ Set VTd attribute for a system memory.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+ @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.\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
+EFI_STATUS\r
+SetPageAttribute (\r
+ IN UINTN VtdIndex,\r
+ IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
+ IN UINT64 BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 IoMmuAccess\r
+ );\r
+\r
+/**\r
+ Set VTd attribute for a system memory.\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
+EFI_STATUS\r
+SetAccessAttribute (\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
+/**\r
+ Return the index of PCI descriptor.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\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
+\r
+ @return The index of the PCI descriptor.\r
+ @retval (UINTN)-1 The PCI descriptor is not found.\r
+**/\r
+UINTN\r
+GetPciDescriptor (\r
+ IN UINTN VtdIndex,\r
+ IN UINT16 Segment,\r
+ IN VTD_SOURCE_ID SourceId\r
+ );\r
+\r
+/**\r
+ Dump VTd registers if there is error.\r
+**/\r
+VOID\r
+DumpVtdIfError (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Initialize platform VTd policy.\r
+**/\r
+VOID\r
+InitializePlatformVTdPolicy (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Always enable the VTd page attribute for the device.\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
+\r
+ @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.\r
+**/\r
+EFI_STATUS\r
+AlwaysEnablePageAttribute (\r
+ IN UINT16 Segment,\r
+ IN VTD_SOURCE_ID SourceId\r
+ );\r
+\r
+/**\r
+ Convert the DeviceHandle to SourceId and Segment.\r
+\r
+ @param[in] DeviceHandle The device who initiates the DMA access request.\r
+ @param[out] Segment The Segment used to identify a VTd engine.\r
+ @param[out] SourceId The SourceId used to identify a VTd engine and table entry.\r
+\r
+ @retval EFI_SUCCESS The Segment and SourceId are returned.\r
+ @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.\r
+ @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.\r
+**/\r
+EFI_STATUS\r
+DeviceHandleToSourceId (\r
+ IN EFI_HANDLE DeviceHandle,\r
+ OUT UINT16 *Segment,\r
+ OUT VTD_SOURCE_ID *SourceId\r
+ );\r
+\r
+/**\r
+ Get device information from mapping.\r
+\r
+ @param[in] Mapping The mapping.\r
+ @param[out] DeviceAddress The device address of the mapping.\r
+ @param[out] NumberOfPages The number of pages of the mapping.\r
+\r
+ @retval EFI_SUCCESS The device information is returned.\r
+ @retval EFI_INVALID_PARAMETER The mapping is invalid.\r
+**/\r
+EFI_STATUS\r
+GetDeviceInfoFromMapping (\r
+ IN VOID *Mapping,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT UINTN *NumberOfPages\r
+ );\r
+\r
+/**\r
+ Initialize DMA protection.\r
+**/\r
+VOID\r
+InitializeDmaProtection (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Allocate zero pages.\r
+\r
+ @param[in] Pages the number of pages.\r
+\r
+ @return the page address.\r
+ @retval NULL No resource to allocate pages.\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateZeroPages (\r
+ IN UINTN Pages\r
+ );\r
+\r
+#endif\r