+++ /dev/null
-/** @file\r
- Intel VTd driver.\r
-\r
- Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "DmaProtection.h"\r
-\r
-/**\r
- Provides the controller-specific addresses required to access system memory from a\r
- DMA bus master.\r
-\r
- @param This The protocol instance pointer.\r
- @param Operation Indicates if the bus master is going to read or write to system memory.\r
- @param HostAddress The system memory address to map to the PCI controller.\r
- @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
- that were mapped.\r
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
- access the hosts HostAddress.\r
- @param Mapping A resulting value to pass to Unmap().\r
-\r
- @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
- @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common 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 lack of resources.\r
- @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-IoMmuMap (\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
-/**\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 Map().\r
- @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-IoMmuUnmap (\r
- IN EDKII_IOMMU_PROTOCOL *This,\r
- IN VOID *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, EfiBootServicesData or\r
- EfiRuntimeServicesData.\r
- @param Pages The number of pages to allocate.\r
- @param HostAddress A pointer to store the base system memory address of the\r
- allocated range.\r
- @param Attributes The requested bit mask of attributes for the allocated range.\r
-\r
- @retval EFI_SUCCESS The requested memory pages were allocated.\r
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
- MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.\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
-EFI_STATUS\r
-EFIAPI\r
-IoMmuAllocateBuffer (\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
-/**\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 range.\r
-\r
- @retval EFI_SUCCESS The requested memory pages were freed.\r
- @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
- was not allocated with AllocateBuffer().\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-IoMmuFreeBuffer (\r
- IN EDKII_IOMMU_PROTOCOL *This,\r
- IN UINTN Pages,\r
- IN VOID *HostAddress\r
- );\r
-\r
-/**\r
- This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,\r
- based upon the DeviceAddress.\r
-\r
- @param[in] DeviceHandle The device who initiates the DMA access request.\r
- @param[in] DeviceAddress 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
-**/\r
-VOID\r
-SyncDeviceHandleToMapInfo (\r
- IN EFI_HANDLE DeviceHandle,\r
- IN EFI_PHYSICAL_ADDRESS DeviceAddress,\r
- IN UINT64 Length,\r
- IN UINT64 IoMmuAccess\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
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- UINTN Seg;\r
- UINTN Bus;\r
- UINTN Dev;\r
- UINTN Func;\r
- EFI_STATUS Status;\r
- EDKII_PLATFORM_VTD_DEVICE_INFO DeviceInfo;\r
-\r
- Status = EFI_NOT_FOUND;\r
- if (mPlatformVTdPolicy != NULL) {\r
- Status = mPlatformVTdPolicy->GetDeviceId (mPlatformVTdPolicy, DeviceHandle, &DeviceInfo);\r
- if (!EFI_ERROR(Status)) {\r
- *Segment = DeviceInfo.Segment;\r
- *SourceId = DeviceInfo.SourceId;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);\r
- if (EFI_ERROR(Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
- Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);\r
- if (EFI_ERROR(Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
- *Segment = (UINT16)Seg;\r
- SourceId->Bits.Bus = (UINT8)Bus;\r
- SourceId->Bits.Device = (UINT8)Dev;\r
- SourceId->Bits.Function = (UINT8)Func;\r
-\r
- return EFI_SUCCESS;\r
-}\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 ID,\r
- 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 EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.\r
- After the memory is used, the memory need set 0 to keep it being 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 EDKII_IOMMU_ACCESS_WRITE.\r
-\r
- @param[in] This The protocol instance pointer.\r
- @param[in] DeviceHandle The device who initiates the DMA access request.\r
- @param[in] DeviceAddress 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 DeviceAddress and Length.\r
- @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.\r
- @retval EFI_INVALID_PARAMETER DeviceAddress 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 DeviceHandle is unknown by the IOMMU.\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 DeviceAddress 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
-VTdSetAttribute (\r
- IN EDKII_IOMMU_PROTOCOL *This,\r
- IN EFI_HANDLE DeviceHandle,\r
- IN EFI_PHYSICAL_ADDRESS DeviceAddress,\r
- IN UINT64 Length,\r
- IN UINT64 IoMmuAccess\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT16 Segment;\r
- VTD_SOURCE_ID SourceId;\r
- CHAR8 PerfToken[sizeof("VTD(S0000.B00.D00.F00)")];\r
- UINT32 Identifier;\r
-\r
- DumpVtdIfError ();\r
-\r
- Status = DeviceHandleToSourceId (DeviceHandle, &Segment, &SourceId);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- DEBUG ((DEBUG_VERBOSE, "IoMmuSetAttribute: "));\r
- DEBUG ((DEBUG_VERBOSE, "PCI(S%x.B%x.D%x.F%x) ", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
- DEBUG ((DEBUG_VERBOSE, "(0x%lx~0x%lx) - %lx\n", DeviceAddress, Length, IoMmuAccess));\r
-\r
- if (mAcpiDmarTable == NULL) {\r
- //\r
- // Record the entry to driver global variable.\r
- // As such once VTd is activated, the setting can be adopted.\r
- //\r
- if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) != 0) {\r
- //\r
- // Force no IOMMU access attribute request recording before DMAR table is installed.\r
- //\r
- ASSERT_EFI_ERROR (EFI_NOT_READY);\r
- return EFI_NOT_READY;\r
- }\r
- Status = RequestAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);\r
- } else {\r
- PERF_CODE (\r
- AsciiSPrint (PerfToken, sizeof(PerfToken), "S%04xB%02xD%02xF%01x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function);\r
- Identifier = (Segment << 16) | SourceId.Uint16;\r
- PERF_START_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);\r
- );\r
-\r
- Status = SetAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);\r
-\r
- PERF_CODE (\r
- Identifier = (Segment << 16) | SourceId.Uint16;\r
- PERF_END_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);\r
- );\r
- }\r
-\r
- if (!EFI_ERROR(Status)) {\r
- SyncDeviceHandleToMapInfo (\r
- DeviceHandle,\r
- DeviceAddress,\r
- Length,\r
- IoMmuAccess\r
- );\r
- }\r
-\r
- return Status;\r
-}\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 ID,\r
- 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 EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.\r
- After the memory is used, the memory need set 0 to keep it being 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 EDKII_IOMMU_ACCESS_WRITE.\r
-\r
- @param[in] This The protocol instance pointer.\r
- @param[in] DeviceHandle The device who initiates the DMA access 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 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 Map().\r
- @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
- @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.\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 Mapping.\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
-EFIAPI\r
-IoMmuSetAttribute (\r
- IN EDKII_IOMMU_PROTOCOL *This,\r
- IN EFI_HANDLE DeviceHandle,\r
- IN VOID *Mapping,\r
- IN UINT64 IoMmuAccess\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
- UINTN NumberOfPages;\r
- EFI_TPL OriginalTpl;\r
-\r
- OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);\r
-\r
- Status = GetDeviceInfoFromMapping (Mapping, &DeviceAddress, &NumberOfPages);\r
- if (!EFI_ERROR(Status)) {\r
- Status = VTdSetAttribute (\r
- This,\r
- DeviceHandle,\r
- DeviceAddress,\r
- EFI_PAGES_TO_SIZE(NumberOfPages),\r
- IoMmuAccess\r
- );\r
- }\r
-\r
- gBS->RestoreTPL (OriginalTpl);\r
-\r
- return Status;\r
-}\r
-\r
-EDKII_IOMMU_PROTOCOL mIntelVTd = {\r
- EDKII_IOMMU_PROTOCOL_REVISION,\r
- IoMmuSetAttribute,\r
- IoMmuMap,\r
- IoMmuUnmap,\r
- IoMmuAllocateBuffer,\r
- IoMmuFreeBuffer,\r
-};\r
-\r
-/**\r
- Initialize the VTd driver.\r
-\r
- @param[in] ImageHandle ImageHandle of the loaded driver\r
- @param[in] SystemTable Pointer to the System Table\r
-\r
- @retval EFI_SUCCESS The Protocol is installed.\r
- @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.\r
- @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-IntelVTdInitialize (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_HANDLE Handle;\r
-\r
- if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- InitializeDmaProtection ();\r
-\r
- Handle = NULL;\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &Handle,\r
- &gEdkiiIoMmuProtocolGuid, &mIntelVTd,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r