--- /dev/null
+/** @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
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/PerformanceLib.h>\r
+#include <Library/PrintLib.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 VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32))\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 DATA number.\r
+// The number may be enlarged later.\r
+//\r
+#define MAX_VTD_PCI_DATA_NUMBER 0x100\r
+\r
+typedef struct {\r
+ UINT8 DeviceType;\r
+ VTD_SOURCE_ID PciSourceId;\r
+ EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId;\r
+ // for statistic analysis\r
+ UINTN AccessCount;\r
+} PCI_DEVICE_DATA;\r
+\r
+typedef struct {\r
+ BOOLEAN IncludeAllFlag;\r
+ UINTN PciDeviceDataNumber;\r
+ UINTN PciDeviceDataMaxNumber;\r
+ PCI_DEVICE_DATA *PciDeviceData;\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 HasDirtyContext;\r
+ BOOLEAN HasDirtyPages;\r
+ PCI_DEVICE_INFORMATION PciDeviceInfo;\r
+} VTD_UNIT_INFORMATION;\r
+\r
+/**\r
+ The scan bus callback function.\r
+\r
+ It is called in PCI bus scan for each PCI device under the bus.\r
+\r
+ @param[in] Context The context of the callback.\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] Bus The bus of the source.\r
+ @param[in] Device The device of the source.\r
+ @param[in] Function The function of the source.\r
+\r
+ @retval EFI_SUCCESS The specific PCI device is processed in the callback.\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *SCAN_BUS_FUNC_CALLBACK_FUNC) (\r
+ IN VOID *Context,\r
+ IN UINT16 Segment,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Function\r
+ );\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 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.\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] DeviceType The DMAR device scope type.\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 UINT8 DeviceType,\r
+ IN BOOLEAN CheckExist\r
+ );\r
+\r
+/**\r
+ The scan bus callback function to always enable page attribute.\r
+\r
+ @param[in] Context The context of the callback.\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] Bus The bus of the source.\r
+ @param[in] Device The device of the source.\r
+ @param[in] Function The function of the source.\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
+EFIAPI\r
+ScanBusCallbackRegisterPciDevice (\r
+ IN VOID *Context,\r
+ IN UINT16 Segment,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Function\r
+ );\r
+\r
+/**\r
+ Scan PCI bus and invoke callback function for each PCI devices under the bus.\r
+\r
+ @param[in] Context The context of the callback function.\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] Bus The bus of the source.\r
+ @param[in] Callback The callback function in PCI scan.\r
+\r
+ @retval EFI_SUCCESS The PCI devices under the bus are scaned.\r
+**/\r
+EFI_STATUS\r
+ScanPciBus (\r
+ IN VOID *Context,\r
+ IN UINT16 Segment,\r
+ IN UINT8 Bus,\r
+ IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback\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 VTd engine.\r
+ @retval (UINTN)-1 The VTd engine 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] DomainIdentifier The domain ID of the source.\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 UINT16 DomainIdentifier,\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 data.\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 data.\r
+ @retval (UINTN)-1 The PCI data is not found.\r
+**/\r
+UINTN\r
+GetPciDataIndex (\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
+/**\r
+ Flush VTD page table and context table memory.\r
+\r
+ This action is to make sure the IOMMU engine can get final data in memory.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+ @param[in] Base The base address of memory to be flushed.\r
+ @param[in] Size The size of memory in bytes to be flushed.\r
+**/\r
+VOID\r
+FlushPageTableMemory (\r
+ IN UINTN VtdIndex,\r
+ IN UINTN Base,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Get PCI device information from DMAR DevScopeEntry.\r
+\r
+ @param[in] Segment The segment number.\r
+ @param[in] DmarDevScopeEntry DMAR DevScopeEntry\r
+ @param[out] Bus The bus number.\r
+ @param[out] Device The device number.\r
+ @param[out] Function The function number.\r
+\r
+ @retval EFI_SUCCESS The PCI device information is returned.\r
+**/\r
+EFI_STATUS\r
+GetPciBusDeviceFunction (\r
+ IN UINT16 Segment,\r
+ IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,\r
+ OUT UINT8 *Bus,\r
+ OUT UINT8 *Device,\r
+ OUT UINT8 *Function\r
+ );\r
+\r
+#endif\r