--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2019, Linaro, Ltd. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ 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
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DmaLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Protocol/IoMmu.h>\r
+\r
+/**\r
+ Set IOMMU attribute for a system memory.\r
+\r
+ If the IOMMU protocol exists, the system memory cannot be used\r
+ for DMA by default.\r
+\r
+ When a device requests a DMA access for a system memory,\r
+ the device driver need use SetAttribute() to update the IOMMU\r
+ attribute to request DMA access (read and/or write).\r
+\r
+ The DeviceHandle is used to identify which device submits the request.\r
+ The IOMMU implementation need translate the device path to an IOMMU device\r
+ ID, and set IOMMU hardware register accordingly.\r
+ 1) DeviceHandle can be a standard PCI device.\r
+ The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.\r
+ The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.\r
+ The memory for BusMasterCommonBuffer need set\r
+ EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.\r
+ After the memory is used, the memory need set 0 to keep it being\r
+ protected.\r
+ 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).\r
+ The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or\r
+ EDKII_IOMMU_ACCESS_WRITE.\r
+\r
+ @param[in] This The protocol instance pointer.\r
+ @param[in] DeviceHandle The device who initiates the DMA access\r
+ request.\r
+ @param[in] Mapping The mapping value returned from Map().\r
+ @param[in] IoMmuAccess The IOMMU access.\r
+\r
+ @retval EFI_SUCCESS The IoMmuAccess is set for the memory range\r
+ specified by DeviceAddress and Length.\r
+ @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.\r
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by\r
+ Map().\r
+ @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination\r
+ of access.\r
+ @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.\r
+ @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported\r
+ by the IOMMU.\r
+ @retval EFI_UNSUPPORTED The IOMMU does not support the memory range\r
+ specified by Mapping.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
+ modify the IOMMU access.\r
+ @retval EFI_DEVICE_ERROR The IOMMU device reported an error while\r
+ attempting the operation.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentIoMmuSetAttribute (\r
+ IN EDKII_IOMMU_PROTOCOL *This,\r
+ IN EFI_HANDLE DeviceHandle,\r
+ IN VOID *Mapping,\r
+ IN UINT64 IoMmuAccess\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Provides the controller-specific addresses required to access system memory\r
+ from a DMA bus master. On SEV guest, the DMA operations must be performed on\r
+ shared buffer hence we allocate a bounce buffer to map the HostAddress to a\r
+ DeviceAddress. The Encryption attribute is removed from the DeviceAddress\r
+ buffer.\r
+\r
+ @param This The protocol instance pointer.\r
+ @param Operation Indicates if the bus master is going to read or\r
+ write to system memory.\r
+ @param HostAddress The system memory address to map to the PCI\r
+ controller.\r
+ @param NumberOfBytes On input the number of bytes to map. On output\r
+ the number of bytes that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master\r
+ PCI controller to use to access the hosts\r
+ HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The range was mapped for the returned\r
+ NumberOfBytes.\r
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common\r
+ buffer.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested\r
+ address.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentIoMmuMap (\r
+ IN EDKII_IOMMU_PROTOCOL *This,\r
+ IN EDKII_IOMMU_OPERATION Operation,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ DMA_MAP_OPERATION DmaOperation;\r
+\r
+ switch (Operation) {\r
+ case EdkiiIoMmuOperationBusMasterRead:\r
+ case EdkiiIoMmuOperationBusMasterRead64:\r
+ DmaOperation = MapOperationBusMasterRead;\r
+ break;\r
+\r
+ case EdkiiIoMmuOperationBusMasterWrite:\r
+ case EdkiiIoMmuOperationBusMasterWrite64:\r
+ DmaOperation = MapOperationBusMasterWrite;\r
+ break;\r
+\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
+ DmaOperation = MapOperationBusMasterCommonBuffer;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return DmaMap (DmaOperation, HostAddress, NumberOfBytes,\r
+ DeviceAddress, Mapping);\r
+}\r
+\r
+/**\r
+ Completes the Map() operation and releases any corresponding resources.\r
+\r
+ @param This The protocol instance pointer.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by\r
+ Map().\r
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system\r
+ memory.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentIoMmuUnmap (\r
+ IN EDKII_IOMMU_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ return DmaUnmap (Mapping);\r
+}\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\r
+ @param This The protocol instance pointer.\r
+ @param Type This parameter is not used and must be ignored.\r
+ @param MemoryType The type of memory to allocate,\r
+ EfiBootServicesData or EfiRuntimeServicesData.\r
+ @param Pages The number of pages to allocate.\r
+ @param HostAddress A pointer to store the base system memory\r
+ address of the allocated range.\r
+ @param Attributes The requested bit mask of attributes for the\r
+ allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal\r
+ attribute bits are MEMORY_WRITE_COMBINE and\r
+ MEMORY_CACHED.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentIoMmuAllocateBuffer (\r
+ IN EDKII_IOMMU_PROTOCOL *This,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Pages,\r
+ IN OUT VOID **HostAddress,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ return DmaAllocateBuffer (MemoryType, Pages, HostAddress);\r
+}\r
+\r
+/**\r
+ Frees memory that was allocated with AllocateBuffer().\r
+\r
+ @param This The protocol instance pointer.\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base system memory address of the allocated\r
+ range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and\r
+ Pages was not allocated with AllocateBuffer().\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentIoMmuFreeBuffer (\r
+ IN EDKII_IOMMU_PROTOCOL *This,\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress\r
+ )\r
+{\r
+ return DmaFreeBuffer (Pages, HostAddress);\r
+}\r
+\r
+STATIC EDKII_IOMMU_PROTOCOL mNonCoherentIoMmuOps = {\r
+ EDKII_IOMMU_PROTOCOL_REVISION,\r
+ NonCoherentIoMmuSetAttribute,\r
+ NonCoherentIoMmuMap,\r
+ NonCoherentIoMmuUnmap,\r
+ NonCoherentIoMmuAllocateBuffer,\r
+ NonCoherentIoMmuFreeBuffer,\r
+};\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentIoMmuDxeEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return gBS->InstallMultipleProtocolInterfaces (&ImageHandle,\r
+ &gEdkiiIoMmuProtocolGuid, &mNonCoherentIoMmuOps,\r
+ NULL);\r
+}\r