Move IntelVTdDxe to Feature/VTd/IntelVTdDxe.
Suggested-by: Star Zeng <star.zeng@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
--- /dev/null
+/** @file\r
+ BmDma related function\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
+#include <PiDxe.h>\r
+\r
+#include <Protocol/IoMmu.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+// TBD: May make it a policy\r
+#define DMA_MEMORY_TOP MAX_UINTN\r
+//#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL\r
+\r
+#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
+typedef struct {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+ EDKII_IOMMU_OPERATION Operation;\r
+ UINTN NumberOfBytes;\r
+ UINTN NumberOfPages;\r
+ EFI_PHYSICAL_ADDRESS HostAddress;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress;\r
+} MAP_INFO;\r
+#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)\r
+\r
+LIST_ENTRY gMaps = INITIALIZE_LIST_HEAD_VARIABLE(gMaps);\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
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+ MAP_INFO *MapInfo;\r
+ EFI_PHYSICAL_ADDRESS DmaMemoryTop;\r
+ BOOLEAN NeedRemap;\r
+\r
+ if (NumberOfBytes == NULL || DeviceAddress == NULL ||\r
+ Mapping == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "IoMmuMap: ==> 0x%08x - 0x%08x (%x)\n", HostAddress, *NumberOfBytes, Operation));\r
+\r
+ //\r
+ // Make sure that Operation is valid\r
+ //\r
+ if ((UINT32) Operation >= EdkiiIoMmuOperationMaximum) {\r
+ DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ NeedRemap = FALSE;\r
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
+\r
+ DmaMemoryTop = DMA_MEMORY_TOP;\r
+\r
+ //\r
+ // Alignment check\r
+ //\r
+ if ((*NumberOfBytes != ALIGN_VALUE(*NumberOfBytes, SIZE_4KB)) ||\r
+ (PhysicalAddress != ALIGN_VALUE(PhysicalAddress, SIZE_4KB))) {\r
+ if ((Operation == EdkiiIoMmuOperationBusMasterCommonBuffer) ||\r
+ (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64)) {\r
+ //\r
+ // The input buffer might be a subset from IoMmuAllocateBuffer.\r
+ // Skip the check.\r
+ //\r
+ } else {\r
+ NeedRemap = TRUE;\r
+ }\r
+ }\r
+\r
+ if ((PhysicalAddress + *NumberOfBytes) >= DMA_MEMORY_TOP) {\r
+ NeedRemap = TRUE;\r
+ }\r
+\r
+ if (((Operation != EdkiiIoMmuOperationBusMasterRead64 &&\r
+ Operation != EdkiiIoMmuOperationBusMasterWrite64 &&\r
+ Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&\r
+ ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
+ //\r
+ // If the root bridge or the device cannot handle performing DMA above\r
+ // 4GB but any part of the DMA transfer being mapped is above 4GB, then\r
+ // map the DMA transfer to a buffer below 4GB.\r
+ //\r
+ NeedRemap = TRUE;\r
+ DmaMemoryTop = MIN (DmaMemoryTop, SIZE_4GB - 1);\r
+ }\r
+\r
+ if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
+ Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
+ if (NeedRemap) {\r
+ //\r
+ // Common Buffer operations can not be remapped. If the common buffer\r
+ // is above 4GB, then it is not possible to generate a mapping, so return\r
+ // an error.\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_UNSUPPORTED));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Allocate a MAP_INFO structure to remember the mapping when Unmap() is\r
+ // called later.\r
+ //\r
+ MapInfo = AllocatePool (sizeof (MAP_INFO));\r
+ if (MapInfo == NULL) {\r
+ *NumberOfBytes = 0;\r
+ DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Initialize the MAP_INFO structure\r
+ //\r
+ MapInfo->Signature = MAP_INFO_SIGNATURE;\r
+ MapInfo->Operation = Operation;\r
+ MapInfo->NumberOfBytes = *NumberOfBytes;\r
+ MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
+ MapInfo->HostAddress = PhysicalAddress;\r
+ MapInfo->DeviceAddress = DmaMemoryTop;\r
+\r
+ //\r
+ // Allocate a buffer below 4GB to map the transfer to.\r
+ //\r
+ if (NeedRemap) {\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiBootServicesData,\r
+ MapInfo->NumberOfPages,\r
+ &MapInfo->DeviceAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (MapInfo);\r
+ *NumberOfBytes = 0;\r
+ DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // If this is a read operation from the Bus Master's point of view,\r
+ // then copy the contents of the real buffer into the mapped buffer\r
+ // so the Bus Master can read the contents of the real buffer.\r
+ //\r
+ if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
+ Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
+ CopyMem (\r
+ (VOID *) (UINTN) MapInfo->DeviceAddress,\r
+ (VOID *) (UINTN) MapInfo->HostAddress,\r
+ MapInfo->NumberOfBytes\r
+ );\r
+ }\r
+ } else {\r
+ MapInfo->DeviceAddress = MapInfo->HostAddress;\r
+ }\r
+\r
+ InsertTailList (&gMaps, &MapInfo->Link);\r
+\r
+ //\r
+ // The DeviceAddress is the address of the maped buffer below 4GB\r
+ //\r
+ *DeviceAddress = MapInfo->DeviceAddress;\r
+ //\r
+ // Return a pointer to the MAP_INFO structure in Mapping\r
+ //\r
+ *Mapping = MapInfo;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "IoMmuMap: 0x%08x - 0x%08x <==\n", *DeviceAddress, *Mapping));\r
+\r
+ return EFI_SUCCESS;\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
+ MAP_INFO *MapInfo;\r
+ LIST_ENTRY *Link;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "IoMmuUnmap: 0x%08x\n", Mapping));\r
+\r
+ if (Mapping == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MapInfo = NULL;\r
+ for (Link = GetFirstNode (&gMaps)\r
+ ; !IsNull (&gMaps, Link)\r
+ ; Link = GetNextNode (&gMaps, Link)\r
+ ) {\r
+ MapInfo = MAP_INFO_FROM_LINK (Link);\r
+ if (MapInfo == Mapping) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Mapping is not a valid value returned by Map()\r
+ //\r
+ if (MapInfo != Mapping) {\r
+ DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ RemoveEntryList (&MapInfo->Link);\r
+\r
+ if (MapInfo->DeviceAddress != MapInfo->HostAddress) {\r
+ //\r
+ // If this is a write operation from the Bus Master's point of view,\r
+ // then copy the contents of the mapped buffer into the real buffer\r
+ // so the processor can read the contents of the real buffer.\r
+ //\r
+ if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
+ MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
+ CopyMem (\r
+ (VOID *) (UINTN) MapInfo->HostAddress,\r
+ (VOID *) (UINTN) MapInfo->DeviceAddress,\r
+ MapInfo->NumberOfBytes\r
+ );\r
+ }\r
+\r
+ //\r
+ // Free the mapped buffer and the MAP_INFO structure.\r
+ //\r
+ gBS->FreePages (MapInfo->DeviceAddress, MapInfo->NumberOfPages);\r
+ }\r
+\r
+ FreePool (Mapping);\r
+ return EFI_SUCCESS;\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 and 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
+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
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: ==> 0x%08x\n", Pages));\r
+\r
+ //\r
+ // Validate Attributes\r
+ //\r
+ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {\r
+ DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Check for invalid inputs\r
+ //\r
+ if (HostAddress == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The only valid memory types are EfiBootServicesData and\r
+ // EfiRuntimeServicesData\r
+ //\r
+ if (MemoryType != EfiBootServicesData &&\r
+ MemoryType != EfiRuntimeServicesData) {\r
+ DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PhysicalAddress = DMA_MEMORY_TOP;\r
+ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
+ //\r
+ // Limit allocations to memory below 4GB\r
+ //\r
+ PhysicalAddress = MIN (PhysicalAddress, SIZE_4GB - 1);\r
+ }\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ MemoryType,\r
+ Pages,\r
+ &PhysicalAddress\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: 0x%08x <==\n", *HostAddress));\r
+\r
+ return Status;\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
+ DEBUG ((DEBUG_VERBOSE, "IoMmuFreeBuffer: 0x%\n", Pages));\r
+ return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);\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
+ MAP_INFO *MapInfo;\r
+ LIST_ENTRY *Link;\r
+\r
+ if (Mapping == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MapInfo = NULL;\r
+ for (Link = GetFirstNode (&gMaps)\r
+ ; !IsNull (&gMaps, Link)\r
+ ; Link = GetNextNode (&gMaps, Link)\r
+ ) {\r
+ MapInfo = MAP_INFO_FROM_LINK (Link);\r
+ if (MapInfo == Mapping) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Mapping is not a valid value returned by Map()\r
+ //\r
+ if (MapInfo != Mapping) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *DeviceAddress = MapInfo->DeviceAddress;\r
+ *NumberOfPages = MapInfo->NumberOfPages;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /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
+#include "DmaProtection.h"\r
+\r
+EFI_ACPI_SDT_PROTOCOL *mAcpiSdt;\r
+UINT64 mBelow4GMemoryLimit;\r
+UINT64 mAbove4GMemoryLimit;\r
+\r
+EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;\r
+\r
+/**\r
+ return the UEFI memory information.\r
+\r
+ @param[out] Below4GMemoryLimit The below 4GiB memory limit\r
+ @param[out] Above4GMemoryLimit The above 4GiB memory limit\r
+**/\r
+VOID\r
+ReturnUefiMemoryMap (\r
+ OUT UINT64 *Below4GMemoryLimit,\r
+ OUT UINT64 *Above4GMemoryLimit\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;\r
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;\r
+ EFI_MEMORY_DESCRIPTOR *EfiEntry;\r
+ EFI_MEMORY_DESCRIPTOR *NextEfiEntry;\r
+ EFI_MEMORY_DESCRIPTOR TempEfiEntry;\r
+ UINTN EfiMemoryMapSize;\r
+ UINTN EfiMapKey;\r
+ UINTN EfiDescriptorSize;\r
+ UINT32 EfiDescriptorVersion;\r
+ UINT64 MemoryBlockLength;\r
+\r
+ *Below4GMemoryLimit = 0;\r
+ *Above4GMemoryLimit = 0;\r
+\r
+ //\r
+ // Get the EFI memory map.\r
+ //\r
+ EfiMemoryMapSize = 0;\r
+ EfiMemoryMap = NULL;\r
+ Status = gBS->GetMemoryMap (\r
+ &EfiMemoryMapSize,\r
+ EfiMemoryMap,\r
+ &EfiMapKey,\r
+ &EfiDescriptorSize,\r
+ &EfiDescriptorVersion\r
+ );\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ do {\r
+ //\r
+ // Use size returned back plus 1 descriptor for the AllocatePool.\r
+ // We don't just multiply by 2 since the "for" loop below terminates on\r
+ // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize\r
+ // we process bogus entries and create bogus E820 entries.\r
+ //\r
+ EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);\r
+ ASSERT (EfiMemoryMap != NULL);\r
+ Status = gBS->GetMemoryMap (\r
+ &EfiMemoryMapSize,\r
+ EfiMemoryMap,\r
+ &EfiMapKey,\r
+ &EfiDescriptorSize,\r
+ &EfiDescriptorVersion\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (EfiMemoryMap);\r
+ }\r
+ } while (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Sort memory map from low to high\r
+ //\r
+ EfiEntry = EfiMemoryMap;\r
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
+ while (EfiEntry < EfiMemoryMapEnd) {\r
+ while (NextEfiEntry < EfiMemoryMapEnd) {\r
+ if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {\r
+ CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
+ CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
+ CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
+ }\r
+\r
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);\r
+ }\r
+\r
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+ }\r
+\r
+ //\r
+ //\r
+ //\r
+ DEBUG ((DEBUG_INFO, "MemoryMap:\n"));\r
+ EfiEntry = EfiMemoryMap;\r
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
+ while (EfiEntry < EfiMemoryMapEnd) {\r
+ MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));\r
+ DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));\r
+ switch (EfiEntry->Type) {\r
+ case EfiLoaderCode:\r
+ case EfiLoaderData:\r
+ case EfiBootServicesCode:\r
+ case EfiBootServicesData:\r
+ case EfiConventionalMemory:\r
+ case EfiRuntimeServicesCode:\r
+ case EfiRuntimeServicesData:\r
+ case EfiACPIReclaimMemory:\r
+ case EfiACPIMemoryNVS:\r
+ case EfiReservedMemoryType:\r
+ if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {\r
+ //\r
+ // Skip the memory block is under 1MB\r
+ //\r
+ } else if (EfiEntry->PhysicalStart >= BASE_4GB) {\r
+ if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
+ *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
+ }\r
+ } else {\r
+ if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
+ *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+ }\r
+\r
+ FreePool (EfiMemoryMap);\r
+\r
+ DEBUG ((DEBUG_INFO, "Result:\n"));\r
+ DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit));\r
+ DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit));\r
+\r
+ return ;\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
+ScanBusCallbackAlwaysEnablePageAttribute (\r
+ IN VOID *Context,\r
+ IN UINT16 Segment,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Function\r
+ )\r
+{\r
+ VTD_SOURCE_ID SourceId;\r
+ EFI_STATUS Status;\r
+\r
+ SourceId.Bits.Bus = Bus;\r
+ SourceId.Bits.Device = Device;\r
+ SourceId.Bits.Function = Function;\r
+ Status = AlwaysEnablePageAttribute (Segment, SourceId);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Always enable the VTd page attribute for the device in the DeviceScope.\r
+\r
+ @param[in] DeviceScope the input device scope data structure\r
+\r
+ @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.\r
+**/\r
+EFI_STATUS\r
+AlwaysEnablePageAttributeDeviceScope (\r
+ IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope\r
+ )\r
+{\r
+ UINT8 Bus;\r
+ UINT8 Device;\r
+ UINT8 Function;\r
+ VTD_SOURCE_ID SourceId;\r
+ UINT8 SecondaryBusNumber;\r
+ EFI_STATUS Status;\r
+\r
+ Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);\r
+\r
+ if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {\r
+ //\r
+ // Need scan the bridge and add all devices.\r
+ //\r
+ SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
+ Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);\r
+ return Status;\r
+ } else {\r
+ SourceId.Bits.Bus = Bus;\r
+ SourceId.Bits.Device = Device;\r
+ SourceId.Bits.Function = Function;\r
+ Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);\r
+ return Status;\r
+ }\r
+}\r
+\r
+/**\r
+ Always enable the VTd page attribute for the device matching DeviceId.\r
+\r
+ @param[in] PciDeviceId the input PCI device ID\r
+\r
+ @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.\r
+**/\r
+EFI_STATUS\r
+AlwaysEnablePageAttributePciDeviceId (\r
+ IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId\r
+ )\r
+{\r
+ UINTN VtdIndex;\r
+ UINTN PciIndex;\r
+ PCI_DEVICE_DATA *PciDeviceData;\r
+ EFI_STATUS Status;\r
+\r
+ for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
+ for (PciIndex = 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; PciIndex++) {\r
+ PciDeviceData = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciIndex];\r
+\r
+ if (((PciDeviceId->VendorId == 0xFFFF) || (PciDeviceId->VendorId == PciDeviceData->PciDeviceId.VendorId)) &&\r
+ ((PciDeviceId->DeviceId == 0xFFFF) || (PciDeviceId->DeviceId == PciDeviceData->PciDeviceId.DeviceId)) &&\r
+ ((PciDeviceId->RevisionId == 0xFF) || (PciDeviceId->RevisionId == PciDeviceData->PciDeviceId.RevisionId)) &&\r
+ ((PciDeviceId->SubsystemVendorId == 0xFFFF) || (PciDeviceId->SubsystemVendorId == PciDeviceData->PciDeviceId.SubsystemVendorId)) &&\r
+ ((PciDeviceId->SubsystemDeviceId == 0xFFFF) || (PciDeviceId->SubsystemDeviceId == PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) {\r
+ Status = AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex].Segment, PciDeviceData->PciSourceId);\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Always enable the VTd page attribute for the device.\r
+\r
+ @param[in] DeviceInfo the exception device information\r
+\r
+ @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.\r
+**/\r
+EFI_STATUS\r
+AlwaysEnablePageAttributeExceptionDeviceInfo (\r
+ IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *DeviceInfo\r
+ )\r
+{\r
+ switch (DeviceInfo->Type) {\r
+ case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:\r
+ return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1));\r
+ case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:\r
+ return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1));\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize platform VTd policy.\r
+**/\r
+VOID\r
+InitializePlatformVTdPolicy (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN DeviceInfoCount;\r
+ VOID *DeviceInfo;\r
+ EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;\r
+ UINTN Index;\r
+\r
+ //\r
+ // It is optional.\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEdkiiPlatformVTdPolicyProtocolGuid,\r
+ NULL,\r
+ (VOID **)&mPlatformVTdPolicy\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));\r
+ Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);\r
+ if (!EFI_ERROR(Status)) {\r
+ ThisDeviceInfo = DeviceInfo;\r
+ for (Index = 0; Index < DeviceInfoCount; Index++) {\r
+ if (ThisDeviceInfo->Type == EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END) {\r
+ break;\r
+ }\r
+ AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);\r
+ ThisDeviceInfo = (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo->Length);\r
+ }\r
+ FreePool (DeviceInfo);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Setup VTd engine.\r
+**/\r
+VOID\r
+SetupVtd (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *PciEnumerationComplete;\r
+ UINTN Index;\r
+ UINT64 Below4GMemoryLimit;\r
+ UINT64 Above4GMemoryLimit;\r
+\r
+ //\r
+ // PCI Enumeration must be done\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiPciEnumerationCompleteProtocolGuid,\r
+ NULL,\r
+ &PciEnumerationComplete\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);\r
+ Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);\r
+ DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));\r
+\r
+ mBelow4GMemoryLimit = Below4GMemoryLimit;\r
+ mAbove4GMemoryLimit = Above4GMemoryLimit;\r
+\r
+ //\r
+ // 1. setup\r
+ //\r
+ DEBUG ((DEBUG_INFO, "GetDmarAcpiTable\n"));\r
+ Status = GetDmarAcpiTable ();\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));\r
+ Status = ParseDmarAcpiTableDrhd ();\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));\r
+ PrepareVtdConfig ();\r
+\r
+ //\r
+ // 2. initialization\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));\r
+ Status = SetupTranslationTable ();\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ InitializePlatformVTdPolicy ();\r
+\r
+ ParseDmarAcpiTableRmrr ();\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
+ DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);\r
+ }\r
+ if (mVtdUnitInformation[Index].RootEntryTable != NULL) {\r
+ DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);\r
+ }\r
+ }\r
+\r
+ //\r
+ // 3. enable\r
+ //\r
+ DEBUG ((DEBUG_INFO, "EnableDmar\n"));\r
+ Status = EnableDmar ();\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));\r
+ DumpVtdRegsAll ();\r
+}\r
+\r
+/**\r
+ ACPI notification function.\r
+\r
+ @param[in] Table A pointer to the ACPI table header.\r
+ @param[in] Version The ACPI table's version.\r
+ @param[in] TableKey The table key for this ACPI table.\r
+\r
+ @retval EFI_SUCCESS The notification function is executed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiNotificationFunc (\r
+ IN EFI_ACPI_SDT_HEADER *Table,\r
+ IN EFI_ACPI_TABLE_VERSION Version,\r
+ IN UINTN TableKey\r
+ )\r
+{\r
+ if (Table->Signature == EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE) {\r
+ DEBUG((DEBUG_INFO, "Vtd AcpiNotificationFunc\n"));\r
+ SetupVtd ();\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Exit boot service callback function.\r
+\r
+ @param[in] Event The event handle.\r
+ @param[in] Context The event content.\r
+**/\r
+VOID\r
+EFIAPI\r
+OnExitBootServices (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));\r
+ DumpVtdRegsAll ();\r
+\r
+ if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
+ DisableDmar ();\r
+ DumpVtdRegsAll ();\r
+ }\r
+}\r
+\r
+/**\r
+ Legacy boot callback function.\r
+\r
+ @param[in] Event The event handle.\r
+ @param[in] Context The event content.\r
+**/\r
+VOID\r
+EFIAPI\r
+OnLegacyBoot (\r
+ EFI_EVENT Event,\r
+ VOID *Context\r
+ )\r
+{\r
+ DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));\r
+ DumpVtdRegsAll ();\r
+ DisableDmar ();\r
+ DumpVtdRegsAll ();\r
+}\r
+\r
+/**\r
+ Initialize DMA protection.\r
+**/\r
+VOID\r
+InitializeDmaProtection (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT ExitBootServicesEvent;\r
+ EFI_EVENT LegacyBootEvent;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **) &mAcpiSdt);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = mAcpiSdt->RegisterNotify (TRUE, AcpiNotificationFunc);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ OnExitBootServices,\r
+ NULL,\r
+ &gEfiEventExitBootServicesGuid,\r
+ &ExitBootServicesEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = EfiCreateEventLegacyBootEx (\r
+ TPL_NOTIFY,\r
+ OnLegacyBoot,\r
+ NULL,\r
+ &LegacyBootEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return ;\r
+}\r
--- /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
--- /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
+#include "DmaProtection.h"\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ EFI_ACPI_DESCRIPTION_HEADER Header;\r
+ UINT32 Entry;\r
+} RSDT_TABLE;\r
+\r
+typedef struct {\r
+ EFI_ACPI_DESCRIPTION_HEADER Header;\r
+ UINT64 Entry;\r
+} XSDT_TABLE;\r
+\r
+#pragma pack()\r
+\r
+EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;\r
+\r
+/**\r
+ Dump DMAR DeviceScopeEntry.\r
+\r
+ @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry\r
+**/\r
+VOID\r
+DumpDmarDeviceScopeEntry (\r
+ IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry\r
+ )\r
+{\r
+ UINTN PciPathNumber;\r
+ UINTN PciPathIndex;\r
+ EFI_ACPI_DMAR_PCI_PATH *PciPath;\r
+\r
+ if (DmarDeviceScopeEntry == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " *************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " * DMA-Remapping Device Scope Entry Structure *\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " *************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ (sizeof(UINTN) == sizeof(UINT64)) ?\r
+ " DMAR Device Scope Entry address ...................... 0x%016lx\n" :\r
+ " DMAR Device Scope Entry address ...................... 0x%08x\n",\r
+ DmarDeviceScopeEntry\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Device Scope Entry Type ............................ 0x%02x\n",\r
+ DmarDeviceScopeEntry->Type\r
+ ));\r
+ switch (DmarDeviceScopeEntry->Type) {\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
+ DEBUG ((DEBUG_INFO,\r
+ " PCI Endpoint Device\n"\r
+ ));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
+ DEBUG ((DEBUG_INFO,\r
+ " PCI Sub-hierachy\n"\r
+ ));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:\r
+ DEBUG ((DEBUG_INFO,\r
+ " IOAPIC\n"\r
+ ));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:\r
+ DEBUG ((DEBUG_INFO,\r
+ " MSI Capable HPET\n"\r
+ ));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:\r
+ DEBUG ((DEBUG_INFO,\r
+ " ACPI Namespace Device\n"\r
+ ));\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ DEBUG ((DEBUG_INFO,\r
+ " Length ............................................. 0x%02x\n",\r
+ DmarDeviceScopeEntry->Length\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Enumeration ID ..................................... 0x%02x\n",\r
+ DmarDeviceScopeEntry->EnumerationId\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Starting Bus Number ................................ 0x%02x\n",\r
+ DmarDeviceScopeEntry->StartBusNumber\r
+ ));\r
+\r
+ PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);\r
+ PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);\r
+ for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {\r
+ DEBUG ((DEBUG_INFO,\r
+ " Device ............................................. 0x%02x\n",\r
+ PciPath[PciPathIndex].Device\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Function ........................................... 0x%02x\n",\r
+ PciPath[PciPathIndex].Function\r
+ ));\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " *************************************************************************\n\n"\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Dump DMAR ANDD table.\r
+\r
+ @param[in] Andd DMAR ANDD table\r
+**/\r
+VOID\r
+DumpDmarAndd (\r
+ IN EFI_ACPI_DMAR_ANDD_HEADER *Andd\r
+ )\r
+{\r
+ if (Andd == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " * ACPI Name-space Device Declaration Structure *\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ (sizeof(UINTN) == sizeof(UINT64)) ?\r
+ " ANDD address ........................................... 0x%016lx\n" :\r
+ " ANDD address ........................................... 0x%08x\n",\r
+ Andd\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Type ................................................. 0x%04x\n",\r
+ Andd->Header.Type\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Length ............................................... 0x%04x\n",\r
+ Andd->Header.Length\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ACPI Device Number ................................... 0x%02x\n",\r
+ Andd->AcpiDeviceNumber\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ACPI Object Name ..................................... '%a'\n",\r
+ (Andd + 1)\r
+ ));\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n\n"\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Dump DMAR RHSA table.\r
+\r
+ @param[in] Rhsa DMAR RHSA table\r
+**/\r
+VOID\r
+DumpDmarRhsa (\r
+ IN EFI_ACPI_DMAR_RHSA_HEADER *Rhsa\r
+ )\r
+{\r
+ if (Rhsa == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " * Remapping Hardware Status Affinity Structure *\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ (sizeof(UINTN) == sizeof(UINT64)) ?\r
+ " RHSA address ........................................... 0x%016lx\n" :\r
+ " RHSA address ........................................... 0x%08x\n",\r
+ Rhsa\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Type ................................................. 0x%04x\n",\r
+ Rhsa->Header.Type\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Length ............................................... 0x%04x\n",\r
+ Rhsa->Header.Length\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Register Base Address ................................ 0x%016lx\n",\r
+ Rhsa->RegisterBaseAddress\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Proximity Domain ..................................... 0x%08x\n",\r
+ Rhsa->ProximityDomain\r
+ ));\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n\n"\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Dump DMAR ATSR table.\r
+\r
+ @param[in] Atsr DMAR ATSR table\r
+**/\r
+VOID\r
+DumpDmarAtsr (\r
+ IN EFI_ACPI_DMAR_ATSR_HEADER *Atsr\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
+ INTN AtsrLen;\r
+\r
+ if (Atsr == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " * Root Port ATS Capability Reporting Structure *\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ (sizeof(UINTN) == sizeof(UINT64)) ?\r
+ " ATSR address ........................................... 0x%016lx\n" :\r
+ " ATSR address ........................................... 0x%08x\n",\r
+ Atsr\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Type ................................................. 0x%04x\n",\r
+ Atsr->Header.Type\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Length ............................................... 0x%04x\n",\r
+ Atsr->Header.Length\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Flags ................................................ 0x%02x\n",\r
+ Atsr->Flags\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ALL_PORTS .......................................... 0x%02x\n",\r
+ Atsr->Flags & EFI_ACPI_DMAR_ATSR_FLAGS_ALL_PORTS\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Segment Number ....................................... 0x%04x\n",\r
+ Atsr->SegmentNumber\r
+ ));\r
+\r
+ AtsrLen = Atsr->Header.Length - sizeof(EFI_ACPI_DMAR_ATSR_HEADER);\r
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Atsr + 1);\r
+ while (AtsrLen > 0) {\r
+ DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
+ AtsrLen -= DmarDeviceScopeEntry->Length;\r
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n\n"\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Dump DMAR RMRR table.\r
+\r
+ @param[in] Rmrr DMAR RMRR table\r
+**/\r
+VOID\r
+DumpDmarRmrr (\r
+ IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
+ INTN RmrrLen;\r
+\r
+ if (Rmrr == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " * Reserved Memory Region Reporting Structure *\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ (sizeof(UINTN) == sizeof(UINT64)) ?\r
+ " RMRR address ........................................... 0x%016lx\n" :\r
+ " RMRR address ........................................... 0x%08x\n",\r
+ Rmrr\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Type ................................................. 0x%04x\n",\r
+ Rmrr->Header.Type\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Length ............................................... 0x%04x\n",\r
+ Rmrr->Header.Length\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Segment Number ....................................... 0x%04x\n",\r
+ Rmrr->SegmentNumber\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Reserved Memory Region Base Address .................. 0x%016lx\n",\r
+ Rmrr->ReservedMemoryRegionBaseAddress\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Reserved Memory Region Limit Address ................. 0x%016lx\n",\r
+ Rmrr->ReservedMemoryRegionLimitAddress\r
+ ));\r
+\r
+ RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);\r
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);\r
+ while (RmrrLen > 0) {\r
+ DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
+ RmrrLen -= DmarDeviceScopeEntry->Length;\r
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n\n"\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Dump DMAR DRHD table.\r
+\r
+ @param[in] Drhd DMAR DRHD table\r
+**/\r
+VOID\r
+DumpDmarDrhd (\r
+ IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
+ INTN DrhdLen;\r
+\r
+ if (Drhd == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " * DMA-Remapping Hardware Definition Structure *\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ (sizeof(UINTN) == sizeof(UINT64)) ?\r
+ " DRHD address ........................................... 0x%016lx\n" :\r
+ " DRHD address ........................................... 0x%08x\n",\r
+ Drhd\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Type ................................................. 0x%04x\n",\r
+ Drhd->Header.Type\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Length ............................................... 0x%04x\n",\r
+ Drhd->Header.Length\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Flags ................................................ 0x%02x\n",\r
+ Drhd->Flags\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " INCLUDE_PCI_ALL .................................... 0x%02x\n",\r
+ Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Segment Number ....................................... 0x%04x\n",\r
+ Drhd->SegmentNumber\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Register Base Address ................................ 0x%016lx\n",\r
+ Drhd->RegisterBaseAddress\r
+ ));\r
+\r
+ DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);\r
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);\r
+ while (DrhdLen > 0) {\r
+ DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
+ DrhdLen -= DmarDeviceScopeEntry->Length;\r
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " ***************************************************************************\n\n"\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Dump DMAR ACPI table.\r
+\r
+ @param[in] Dmar DMAR ACPI table\r
+**/\r
+VOID\r
+DumpAcpiDMAR (\r
+ IN EFI_ACPI_DMAR_HEADER *Dmar\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+ INTN DmarLen;\r
+\r
+ if (Dmar == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Dump Dmar table\r
+ //\r
+ DEBUG ((DEBUG_INFO,\r
+ "*****************************************************************************\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ "* DMAR Table *\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ "*****************************************************************************\n"\r
+ ));\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ (sizeof(UINTN) == sizeof(UINT64)) ?\r
+ "DMAR address ............................................. 0x%016lx\n" :\r
+ "DMAR address ............................................. 0x%08x\n",\r
+ Dmar\r
+ ));\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ " Table Contents:\n"\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Host Address Width ................................... 0x%02x\n",\r
+ Dmar->HostAddressWidth\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " Flags ................................................ 0x%02x\n",\r
+ Dmar->Flags\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " INTR_REMAP ......................................... 0x%02x\n",\r
+ Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP\r
+ ));\r
+ DEBUG ((DEBUG_INFO,\r
+ " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",\r
+ Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT\r
+ ));\r
+\r
+ DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);\r
+ while (DmarLen > 0) {\r
+ switch (DmarHeader->Type) {\r
+ case EFI_ACPI_DMAR_TYPE_DRHD:\r
+ DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
+ break;\r
+ case EFI_ACPI_DMAR_TYPE_RMRR:\r
+ DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
+ break;\r
+ case EFI_ACPI_DMAR_TYPE_ATSR:\r
+ DumpDmarAtsr ((EFI_ACPI_DMAR_ATSR_HEADER *)DmarHeader);\r
+ break;\r
+ case EFI_ACPI_DMAR_TYPE_RHSA:\r
+ DumpDmarRhsa ((EFI_ACPI_DMAR_RHSA_HEADER *)DmarHeader);\r
+ break;\r
+ case EFI_ACPI_DMAR_TYPE_ANDD:\r
+ DumpDmarAndd ((EFI_ACPI_DMAR_ANDD_HEADER *)DmarHeader);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ DmarLen -= DmarHeader->Length;\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ "*****************************************************************************\n\n"\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Dump DMAR ACPI table.\r
+**/\r
+VOID\r
+VtdDumpDmarTable (\r
+ VOID\r
+ )\r
+{\r
+ DumpAcpiDMAR ((EFI_ACPI_DMAR_HEADER *)(UINTN)mAcpiDmarTable);\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
+ EFI_ACPI_DMAR_PCI_PATH *DmarPciPath;\r
+ UINT8 MyBus;\r
+ UINT8 MyDevice;\r
+ UINT8 MyFunction;\r
+\r
+ DmarPciPath = (EFI_ACPI_DMAR_PCI_PATH *)((UINTN)(DmarDevScopeEntry + 1));\r
+ MyBus = DmarDevScopeEntry->StartBusNumber;\r
+ MyDevice = DmarPciPath->Device;\r
+ MyFunction = DmarPciPath->Function;\r
+\r
+ switch (DmarDevScopeEntry->Type) {\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
+ while ((UINTN)DmarPciPath + sizeof(EFI_ACPI_DMAR_PCI_PATH) < (UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length) {\r
+ MyBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, MyBus, MyDevice, MyFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
+ DmarPciPath ++;\r
+ MyDevice = DmarPciPath->Device;\r
+ MyFunction = DmarPciPath->Function;\r
+ }\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:\r
+ break;\r
+ }\r
+\r
+ *Bus = MyBus;\r
+ *Device = MyDevice;\r
+ *Function = MyFunction;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Process DMAR DHRD table.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] DmarDrhd The DRHD table.\r
+\r
+ @retval EFI_SUCCESS The DRHD table is processed.\r
+**/\r
+EFI_STATUS\r
+ProcessDhrd (\r
+ IN UINTN VtdIndex,\r
+ IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;\r
+ UINT8 Bus;\r
+ UINT8 Device;\r
+ UINT8 Function;\r
+ UINT8 SecondaryBusNumber;\r
+ EFI_STATUS Status;\r
+ VTD_SOURCE_ID SourceId;\r
+\r
+ mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress = (UINTN)DmarDrhd->RegisterBaseAddress;\r
+ DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));\r
+\r
+ mVtdUnitInformation[VtdIndex].Segment = DmarDrhd->SegmentNumber;\r
+\r
+ if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0) {\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = TRUE;\r
+ DEBUG ((DEBUG_INFO," ProcessDhrd: with INCLUDE ALL\n"));\r
+\r
+ Status = ScanPciBus((VOID *)VtdIndex, DmarDrhd->SegmentNumber, 0, ScanBusCallbackRegisterPciDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = FALSE;\r
+ DEBUG ((DEBUG_INFO," ProcessDhrd: without INCLUDE ALL\n"));\r
+ }\r
+\r
+ DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));\r
+ while ((UINTN)DmarDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {\r
+\r
+ Status = GetPciBusDeviceFunction (DmarDrhd->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO," ProcessDhrd: "));\r
+ switch (DmarDevScopeEntry->Type) {\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
+ DEBUG ((DEBUG_INFO,"PCI Endpoint"));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
+ DEBUG ((DEBUG_INFO,"PCI-PCI bridge"));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:\r
+ DEBUG ((DEBUG_INFO,"IOAPIC"));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:\r
+ DEBUG ((DEBUG_INFO,"MSI Capable HPET"));\r
+ break;\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:\r
+ DEBUG ((DEBUG_INFO,"ACPI Namespace Device"));\r
+ break;\r
+ }\r
+ DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", DmarDrhd->SegmentNumber, Bus, Device, Function));\r
+\r
+ SourceId.Bits.Bus = Bus;\r
+ SourceId.Bits.Device = Device;\r
+ SourceId.Bits.Function = Function;\r
+\r
+ Status = RegisterPciDevice (VtdIndex, DmarDrhd->SegmentNumber, SourceId, DmarDevScopeEntry->Type, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // There might be duplication for special device other than standard PCI device.\r
+ //\r
+ switch (DmarDevScopeEntry->Type) {\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ switch (DmarDevScopeEntry->Type) {\r
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
+ SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DmarDrhd->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
+ Status = ScanPciBus ((VOID *)VtdIndex, DmarDrhd->SegmentNumber, SecondaryBusNumber, ScanBusCallbackRegisterPciDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Process DMAR RMRR table.\r
+\r
+ @param[in] DmarRmrr The RMRR table.\r
+\r
+ @retval EFI_SUCCESS The RMRR table is processed.\r
+**/\r
+EFI_STATUS\r
+ProcessRmrr (\r
+ IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;\r
+ UINT8 Bus;\r
+ UINT8 Device;\r
+ UINT8 Function;\r
+ EFI_STATUS Status;\r
+ VTD_SOURCE_ID SourceId;\r
+\r
+ DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));\r
+\r
+ DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));\r
+ while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {\r
+ if (DmarDevScopeEntry->Type != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {\r
+ DEBUG ((DEBUG_INFO,"RMRR DevScopeEntryType is not endpoint, type[0x%x] \n", DmarDevScopeEntry->Type));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,"RMRR S%04x B%02x D%02x F%02x\n", DmarRmrr->SegmentNumber, Bus, Device, Function));\r
+\r
+ SourceId.Bits.Bus = Bus;\r
+ SourceId.Bits.Device = Device;\r
+ SourceId.Bits.Function = Function;\r
+ Status = SetAccessAttribute (\r
+ DmarRmrr->SegmentNumber,\r
+ SourceId,\r
+ DmarRmrr->ReservedMemoryRegionBaseAddress,\r
+ DmarRmrr->ReservedMemoryRegionLimitAddress + 1 - DmarRmrr->ReservedMemoryRegionBaseAddress,\r
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get VTd engine number.\r
+**/\r
+UINTN\r
+GetVtdEngineNumber (\r
+ VOID\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+ UINTN VtdIndex;\r
+\r
+ VtdIndex = 0;\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
+ while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
+ switch (DmarHeader->Type) {\r
+ case EFI_ACPI_DMAR_TYPE_DRHD:\r
+ VtdIndex++;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+ }\r
+ return VtdIndex ;\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
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+ EFI_STATUS Status;\r
+ UINTN VtdIndex;\r
+\r
+ mVtdUnitNumber = GetVtdEngineNumber ();\r
+ DEBUG ((DEBUG_INFO," VtdUnitNumber - %d\n", mVtdUnitNumber));\r
+ ASSERT (mVtdUnitNumber > 0);\r
+ if (mVtdUnitNumber == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ mVtdUnitInformation = AllocateZeroPool (sizeof(*mVtdUnitInformation) * mVtdUnitNumber);\r
+ ASSERT (mVtdUnitInformation != NULL);\r
+ if (mVtdUnitInformation == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ mVtdHostAddressWidthMask = LShiftU64 (1ull, mAcpiDmarTable->HostAddressWidth) - 1;\r
+\r
+ VtdIndex = 0;\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
+ while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
+ switch (DmarHeader->Type) {\r
+ case EFI_ACPI_DMAR_TYPE_DRHD:\r
+ ASSERT (VtdIndex < mVtdUnitNumber);\r
+ Status = ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ VtdIndex++;\r
+\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+ }\r
+ ASSERT (VtdIndex == mVtdUnitNumber);\r
+\r
+ for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
+ DumpPciDeviceInfo (VtdIndex);\r
+ }\r
+ return EFI_SUCCESS ;\r
+}\r
+\r
+/**\r
+ Parse DMAR DRHD table.\r
+\r
+ @return EFI_SUCCESS The DMAR DRHD table is parsed.\r
+**/\r
+EFI_STATUS\r
+ParseDmarAcpiTableRmrr (\r
+ VOID\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+ EFI_STATUS Status;\r
+\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
+ while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
+ switch (DmarHeader->Type) {\r
+ case EFI_ACPI_DMAR_TYPE_RMRR:\r
+ Status = ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+ }\r
+ return EFI_SUCCESS ;\r
+}\r
+\r
+/**\r
+ This function scan ACPI table in RSDT.\r
+\r
+ @param[in] Rsdt ACPI RSDT\r
+ @param[in] Signature ACPI table signature\r
+\r
+ @return ACPI table\r
+**/\r
+VOID *\r
+ScanTableInRSDT (\r
+ IN RSDT_TABLE *Rsdt,\r
+ IN UINT32 Signature\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 EntryCount;\r
+ UINT32 *EntryPtr;\r
+ EFI_ACPI_DESCRIPTION_HEADER *Table;\r
+\r
+ EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);\r
+\r
+ EntryPtr = &Rsdt->Entry;\r
+ for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {\r
+ Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));\r
+ if (Table->Signature == Signature) {\r
+ return Table;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ This function scan ACPI table in XSDT.\r
+\r
+ @param[in] Xsdt ACPI XSDT\r
+ @param[in] Signature ACPI table signature\r
+\r
+ @return ACPI table\r
+**/\r
+VOID *\r
+ScanTableInXSDT (\r
+ IN XSDT_TABLE *Xsdt,\r
+ IN UINT32 Signature\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 EntryCount;\r
+ UINT64 EntryPtr;\r
+ UINTN BasePtr;\r
+ EFI_ACPI_DESCRIPTION_HEADER *Table;\r
+\r
+ EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);\r
+\r
+ BasePtr = (UINTN)(&(Xsdt->Entry));\r
+ for (Index = 0; Index < EntryCount; Index ++) {\r
+ CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));\r
+ Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr));\r
+ if (Table->Signature == Signature) {\r
+ return Table;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ This function scan ACPI table in RSDP.\r
+\r
+ @param[in] Rsdp ACPI RSDP\r
+ @param[in] Signature ACPI table signature\r
+\r
+ @return ACPI table\r
+**/\r
+VOID *\r
+FindAcpiPtr (\r
+ IN EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp,\r
+ IN UINT32 Signature\r
+ )\r
+{\r
+ EFI_ACPI_DESCRIPTION_HEADER *AcpiTable;\r
+ RSDT_TABLE *Rsdt;\r
+ XSDT_TABLE *Xsdt;\r
+\r
+ AcpiTable = NULL;\r
+\r
+ //\r
+ // Check ACPI2.0 table\r
+ //\r
+ Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;\r
+ Xsdt = NULL;\r
+ if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {\r
+ Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress;\r
+ }\r
+ //\r
+ // Check Xsdt\r
+ //\r
+ if (Xsdt != NULL) {\r
+ AcpiTable = ScanTableInXSDT (Xsdt, Signature);\r
+ }\r
+ //\r
+ // Check Rsdt\r
+ //\r
+ if ((AcpiTable == NULL) && (Rsdt != NULL)) {\r
+ AcpiTable = ScanTableInRSDT (Rsdt, Signature);\r
+ }\r
+\r
+ return AcpiTable;\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
+ VOID *AcpiTable;\r
+ EFI_STATUS Status;\r
+\r
+ AcpiTable = NULL;\r
+ Status = EfiGetSystemConfigurationTable (\r
+ &gEfiAcpi20TableGuid,\r
+ &AcpiTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EfiGetSystemConfigurationTable (\r
+ &gEfiAcpiTableGuid,\r
+ &AcpiTable\r
+ );\r
+ }\r
+ ASSERT (AcpiTable != NULL);\r
+\r
+ mAcpiDmarTable = FindAcpiPtr (\r
+ (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable,\r
+ EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE\r
+ );\r
+ DEBUG ((DEBUG_INFO,"DMAR Table - 0x%08x\n", mAcpiDmarTable));\r
+ if (mAcpiDmarTable == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ VtdDumpDmarTable();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Intel VTd driver.\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
+#include <PiDxe.h>\r
+\r
+#include <Protocol/IoMmu.h>\r
+#include <Protocol/PciIo.h>\r
+\r
+#include <Library/IoLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\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 and 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
+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
+ 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
+ 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
+ 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
+\r
+ Status = GetDeviceInfoFromMapping (Mapping, &DeviceAddress, &NumberOfPages);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ Status = VTdSetAttribute (\r
+ This,\r
+ DeviceHandle,\r
+ DeviceAddress,\r
+ EFI_PAGES_TO_SIZE(NumberOfPages),\r
+ IoMmuAccess\r
+ );\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
--- /dev/null
+## @file\r
+# Intel VTd DXE Driver.\r
+#\r
+# This driver initializes VTd engine based upon DMAR ACPI tables\r
+# and provide DMA protection to PCI or ACPI device.\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
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = IntelVTdDxe\r
+ MODULE_UNI_FILE = IntelVTdDxe.uni\r
+ FILE_GUID = 987555D6-595D-4CFA-B895-59B89368BD4D\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = IntelVTdInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+#\r
+\r
+[Sources]\r
+ IntelVTdDxe.c\r
+ BmDma.c\r
+ DmaProtection.c\r
+ DmaProtection.h\r
+ DmarAcpiTable.c\r
+ PciInfo.c\r
+ TranslationTable.c\r
+ TranslationTableEx.c\r
+ VtdReg.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ IntelSiliconPkg/IntelSiliconPkg.dec\r
+\r
+[LibraryClasses]\r
+ DebugLib\r
+ UefiDriverEntryPoint\r
+ UefiBootServicesTableLib\r
+ BaseLib\r
+ IoLib\r
+ PciSegmentLib\r
+ BaseMemoryLib\r
+ MemoryAllocationLib\r
+ UefiLib\r
+ CacheMaintenanceLib\r
+ PerformanceLib\r
+ PrintLib\r
+\r
+[Guids]\r
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event\r
+ gEfiAcpi20TableGuid ## CONSUMES ## SystemTable\r
+ gEfiAcpiTableGuid ## CONSUMES ## SystemTable\r
+\r
+[Protocols]\r
+ gEdkiiIoMmuProtocolGuid ## PRODUCES\r
+ gEfiAcpiSdtProtocolGuid ## CONSUMES\r
+ gEfiPciIoProtocolGuid ## CONSUMES\r
+ gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES\r
+ gEdkiiPlatformVTdPolicyProtocolGuid ## SOMETIMES_CONSUMES\r
+\r
+[Pcd]\r
+ gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES\r
+\r
+[Depex]\r
+ gEfiPciRootBridgeIoProtocolGuid AND\r
+ gEfiAcpiSdtProtocolGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ IntelVTdDxeExtra.uni\r
+\r
--- /dev/null
+// /** @file\r
+// IntelVTdDxe Module Localized Abstract and Description Content\r
+//\r
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are\r
+// 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
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Intel VTd DXE Driver."\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "This driver initializes VTd engine based upon DMAR ACPI tables and provide DMA protection to PCI or ACPI device."\r
+\r
--- /dev/null
+// /** @file\r
+// IntelVTdDxe Localized Strings and Content\r
+//\r
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are\r
+// 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
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"Intel VTd DXE Driver"\r
+\r
+\r
--- /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
+#include "DmaProtection.h"\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
+ UINTN Index;\r
+ VTD_SOURCE_ID *PciSourceId;\r
+\r
+ if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
+ return (UINTN)-1;\r
+ }\r
+\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {\r
+ PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;\r
+ if ((PciSourceId->Bits.Bus == SourceId.Bits.Bus) &&\r
+ (PciSourceId->Bits.Device == SourceId.Bits.Device) &&\r
+ (PciSourceId->Bits.Function == SourceId.Bits.Function) ) {\r
+ return Index;\r
+ }\r
+ }\r
+\r
+ return (UINTN)-1;\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
+ PCI_DEVICE_INFORMATION *PciDeviceInfo;\r
+ VTD_SOURCE_ID *PciSourceId;\r
+ UINTN PciDataIndex;\r
+ UINTN Index;\r
+ PCI_DEVICE_DATA *NewPciDeviceData;\r
+ EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId;\r
+\r
+ PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;\r
+\r
+ if (PciDeviceInfo->IncludeAllFlag) {\r
+ //\r
+ // Do not register device in other VTD Unit\r
+ //\r
+ for (Index = 0; Index < VtdIndex; Index++) {\r
+ PciDataIndex = GetPciDataIndex (Index, Segment, SourceId);\r
+ if (PciDataIndex != (UINTN)-1) {\r
+ DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered by Other Vtd(%d)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, Index));\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);\r
+ if (PciDataIndex == (UINTN)-1) {\r
+ //\r
+ // Register new\r
+ //\r
+\r
+ if (PciDeviceInfo->PciDeviceDataNumber >= PciDeviceInfo->PciDeviceDataMaxNumber) {\r
+ //\r
+ // Reallocate\r
+ //\r
+ NewPciDeviceData = AllocateZeroPool (sizeof(*NewPciDeviceData) * (PciDeviceInfo->PciDeviceDataMaxNumber + MAX_VTD_PCI_DATA_NUMBER));\r
+ if (NewPciDeviceData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER;\r
+ if (PciDeviceInfo->PciDeviceData != NULL) {\r
+ CopyMem (NewPciDeviceData, PciDeviceInfo->PciDeviceData, sizeof(*NewPciDeviceData) * PciDeviceInfo->PciDeviceDataNumber);\r
+ FreePool (PciDeviceInfo->PciDeviceData);\r
+ }\r
+ PciDeviceInfo->PciDeviceData = NewPciDeviceData;\r
+ }\r
+\r
+ ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceDataMaxNumber);\r
+\r
+ PciSourceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciSourceId;\r
+ PciSourceId->Bits.Bus = SourceId.Bits.Bus;\r
+ PciSourceId->Bits.Device = SourceId.Bits.Device;\r
+ PciSourceId->Bits.Function = SourceId.Bits.Function;\r
+\r
+ DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+\r
+ PciDeviceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciDeviceId;\r
+ if ((DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) ||\r
+ (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {\r
+ PciDeviceId->VendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_VENDOR_ID_OFFSET));\r
+ PciDeviceId->DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_DEVICE_ID_OFFSET));\r
+ PciDeviceId->RevisionId = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_REVISION_ID_OFFSET));\r
+\r
+ DEBUG ((DEBUG_INFO, " (%04x:%04x:%02x", PciDeviceId->VendorId, PciDeviceId->DeviceId, PciDeviceId->RevisionId));\r
+\r
+ if (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {\r
+ PciDeviceId->SubsystemVendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_VENDOR_ID_OFFSET));\r
+ PciDeviceId->SubsystemDeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_ID_OFFSET));\r
+ DEBUG ((DEBUG_INFO, ":%04x:%04x", PciDeviceId->SubsystemVendorId, PciDeviceId->SubsystemDeviceId));\r
+ }\r
+ DEBUG ((DEBUG_INFO, ")"));\r
+ }\r
+\r
+ PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].DeviceType = DeviceType;\r
+\r
+ if ((DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) &&\r
+ (DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {\r
+ DEBUG ((DEBUG_INFO, " (*)"));\r
+ }\r
+ DEBUG ((DEBUG_INFO, "\n"));\r
+\r
+ PciDeviceInfo->PciDeviceDataNumber++;\r
+ } else {\r
+ if (CheckExist) {\r
+ DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The scan bus callback function to register PCI device.\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 PCI device is registered.\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
+ VTD_SOURCE_ID SourceId;\r
+ UINTN VtdIndex;\r
+ UINT8 BaseClass;\r
+ UINT8 SubClass;\r
+ UINT8 DeviceType;\r
+ EFI_STATUS Status;\r
+\r
+ VtdIndex = (UINTN)Context;\r
+ SourceId.Bits.Bus = Bus;\r
+ SourceId.Bits.Device = Device;\r
+ SourceId.Bits.Function = Function;\r
+\r
+ DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT;\r
+ BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));\r
+ if (BaseClass == PCI_CLASS_BRIDGE) {\r
+ SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));\r
+ if (SubClass == PCI_CLASS_BRIDGE_P2P) {\r
+ DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE;\r
+ }\r
+ }\r
+\r
+ Status = RegisterPciDevice (VtdIndex, Segment, SourceId, DeviceType, FALSE);\r
+ return Status;\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
+ UINT8 Device;\r
+ UINT8 Function;\r
+ UINT8 SecondaryBusNumber;\r
+ UINT8 HeaderType;\r
+ UINT8 BaseClass;\r
+ UINT8 SubClass;\r
+ UINT32 MaxFunction;\r
+ UINT16 VendorID;\r
+ UINT16 DeviceID;\r
+ EFI_STATUS Status;\r
+\r
+ // Scan the PCI bus for devices\r
+ for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {\r
+ HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));\r
+ MaxFunction = PCI_MAX_FUNC + 1;\r
+ if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {\r
+ MaxFunction = 1;\r
+ }\r
+ for (Function = 0; Function < MaxFunction; Function++) {\r
+ VendorID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));\r
+ DeviceID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));\r
+ if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {\r
+ continue;\r
+ }\r
+\r
+ Status = Callback (Context, Segment, Bus, Device, Function);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));\r
+ if (BaseClass == PCI_CLASS_BRIDGE) {\r
+ SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));\r
+ if (SubClass == PCI_CLASS_BRIDGE_P2P) {\r
+ SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
+ DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));\r
+ if (SecondaryBusNumber != 0) {\r
+ Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\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
+ UINTN Index;\r
+\r
+ DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag\r
+ ));\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {\r
+ DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",\r
+ mVtdUnitInformation[VtdIndex].Segment,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function\r
+ ));\r
+ }\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
+ UINTN VtdIndex;\r
+ VTD_ROOT_ENTRY *RootEntry;\r
+ VTD_CONTEXT_ENTRY *ContextEntryTable;\r
+ VTD_CONTEXT_ENTRY *ThisContextEntry;\r
+ VTD_EXT_ROOT_ENTRY *ExtRootEntry;\r
+ VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;\r
+ VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;\r
+ UINTN PciDataIndex;\r
+\r
+ for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
+ if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
+ continue;\r
+ }\r
+\r
+ PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);\r
+ if (PciDataIndex == (UINTN)-1) {\r
+ continue;\r
+ }\r
+\r
+// DEBUG ((DEBUG_INFO,"FindVtdIndex(0x%x) for S%04x B%02x D%02x F%02x\n", VtdIndex, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+\r
+ if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {\r
+ ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];\r
+ ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;\r
+ ThisExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];\r
+ if (ThisExtContextEntry->Bits.AddressWidth == 0) {\r
+ continue;\r
+ }\r
+ *ExtContextEntry = ThisExtContextEntry;\r
+ *ContextEntry = NULL;\r
+ } else {\r
+ RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];\r
+ ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;\r
+ ThisContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];\r
+ if (ThisContextEntry->Bits.AddressWidth == 0) {\r
+ continue;\r
+ }\r
+ *ExtContextEntry = NULL;\r
+ *ContextEntry = ThisContextEntry;\r
+ }\r
+\r
+ return VtdIndex;\r
+ }\r
+\r
+ return (UINTN)-1;\r
+}\r
+\r
--- /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
+#include "DmaProtection.h"\r
+\r
+/**\r
+ Create extended context entry.\r
+\r
+ @param[in] VtdIndex The index of the VTd engine.\r
+\r
+ @retval EFI_SUCCESS The extended context entry is created.\r
+ @retval EFI_OUT_OF_RESOURCE No enough resource to create extended context entry.\r
+**/\r
+EFI_STATUS\r
+CreateExtContextEntry (\r
+ IN UINTN VtdIndex\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
+ VOID *Addr;\r
+\r
+ Addr = AllocatePages (Pages);\r
+ if (Addr == NULL) {\r
+ return NULL;\r
+ }\r
+ ZeroMem (Addr, EFI_PAGES_TO_SIZE(Pages));\r
+ return Addr;\r
+}\r
+\r
+/**\r
+ Set second level paging entry attribute based upon IoMmuAccess.\r
+\r
+ @param[in] PtEntry The paging entry.\r
+ @param[in] IoMmuAccess The IOMMU access.\r
+**/\r
+VOID\r
+SetSecondLevelPagingEntryAttribute (\r
+ IN VTD_SECOND_LEVEL_PAGING_ENTRY *PtEntry,\r
+ IN UINT64 IoMmuAccess\r
+ )\r
+{\r
+ PtEntry->Bits.Read = ((IoMmuAccess & EDKII_IOMMU_ACCESS_READ) != 0);\r
+ PtEntry->Bits.Write = ((IoMmuAccess & EDKII_IOMMU_ACCESS_WRITE) != 0);\r
+}\r
+\r
+/**\r
+ Create context entry.\r
+\r
+ @param[in] VtdIndex The index of the VTd engine.\r
+\r
+ @retval EFI_SUCCESS The context entry is created.\r
+ @retval EFI_OUT_OF_RESOURCE No enough resource to create context entry.\r
+**/\r
+EFI_STATUS\r
+CreateContextEntry (\r
+ IN UINTN VtdIndex\r
+ )\r
+{\r
+ UINTN Index;\r
+ VOID *Buffer;\r
+ UINTN RootPages;\r
+ UINTN ContextPages;\r
+ VTD_ROOT_ENTRY *RootEntry;\r
+ VTD_CONTEXT_ENTRY *ContextEntryTable;\r
+ VTD_CONTEXT_ENTRY *ContextEntry;\r
+ VTD_SOURCE_ID *PciSourceId;\r
+ VTD_SOURCE_ID SourceId;\r
+ UINTN MaxBusNumber;\r
+ UINTN EntryTablePages;\r
+\r
+ MaxBusNumber = 0;\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {\r
+ PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;\r
+ if (PciSourceId->Bits.Bus > MaxBusNumber) {\r
+ MaxBusNumber = PciSourceId->Bits.Bus;\r
+ }\r
+ }\r
+ DEBUG ((DEBUG_INFO," MaxBusNumber - 0x%x\n", MaxBusNumber));\r
+\r
+ RootPages = EFI_SIZE_TO_PAGES (sizeof (VTD_ROOT_ENTRY) * VTD_ROOT_ENTRY_NUMBER);\r
+ ContextPages = EFI_SIZE_TO_PAGES (sizeof (VTD_CONTEXT_ENTRY) * VTD_CONTEXT_ENTRY_NUMBER);\r
+ EntryTablePages = RootPages + ContextPages * (MaxBusNumber + 1);\r
+ Buffer = AllocateZeroPages (EntryTablePages);\r
+ if (Buffer == NULL) {\r
+ DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ mVtdUnitInformation[VtdIndex].RootEntryTable = (VTD_ROOT_ENTRY *)Buffer;\r
+ Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);\r
+\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {\r
+ PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;\r
+\r
+ SourceId.Bits.Bus = PciSourceId->Bits.Bus;\r
+ SourceId.Bits.Device = PciSourceId->Bits.Device;\r
+ SourceId.Bits.Function = PciSourceId->Bits.Function;\r
+\r
+ RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];\r
+ if (RootEntry->Bits.Present == 0) {\r
+ RootEntry->Bits.ContextTablePointerLo = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 12);\r
+ RootEntry->Bits.ContextTablePointerHi = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 32);\r
+ RootEntry->Bits.Present = 1;\r
+ Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);\r
+ FlushPageTableMemory (VtdIndex, (UINTN)RootEntry, sizeof(*RootEntry));\r
+ }\r
+\r
+ ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;\r
+ ContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];\r
+ ContextEntry->Bits.TranslationType = 0;\r
+ ContextEntry->Bits.FaultProcessingDisable = 0;\r
+ ContextEntry->Bits.Present = 0;\r
+\r
+ DEBUG ((DEBUG_INFO,"Source: S%04x B%02x D%02x F%02x\n", mVtdUnitInformation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+\r
+ switch (mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW) {\r
+ case BIT1:\r
+ ContextEntry->Bits.AddressWidth = 0x1;\r
+ break;\r
+ case BIT2:\r
+ ContextEntry->Bits.AddressWidth = 0x2;\r
+ break;\r
+ }\r
+ FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create second level paging entry table.\r
+\r
+ @param[in] VtdIndex The index of the VTd engine.\r
+ @param[in] SecondLevelPagingEntry The second level paging entry.\r
+ @param[in] MemoryBase The base of the memory.\r
+ @param[in] MemoryLimit The limit of the memory.\r
+ @param[in] IoMmuAccess The IOMMU access.\r
+\r
+ @return The second level paging entry.\r
+**/\r
+VTD_SECOND_LEVEL_PAGING_ENTRY *\r
+CreateSecondLevelPagingEntryTable (\r
+ IN UINTN VtdIndex,\r
+ IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
+ IN UINT64 MemoryBase,\r
+ IN UINT64 MemoryLimit,\r
+ IN UINT64 IoMmuAccess\r
+ )\r
+{\r
+ UINTN Index4;\r
+ UINTN Index3;\r
+ UINTN Index2;\r
+ UINTN Lvl4Start;\r
+ UINTN Lvl4End;\r
+ UINTN Lvl3Start;\r
+ UINTN Lvl3End;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;\r
+ UINT64 BaseAddress;\r
+ UINT64 EndAddress;\r
+\r
+ if (MemoryLimit == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BaseAddress = ALIGN_VALUE_LOW(MemoryBase, SIZE_2MB);\r
+ EndAddress = ALIGN_VALUE_UP(MemoryLimit, SIZE_2MB);\r
+ DEBUG ((DEBUG_INFO,"CreateSecondLevelPagingEntryTable: BaseAddress - 0x%016lx, EndAddress - 0x%016lx\n", BaseAddress, EndAddress));\r
+\r
+ if (SecondLevelPagingEntry == NULL) {\r
+ SecondLevelPagingEntry = AllocateZeroPages (1);\r
+ if (SecondLevelPagingEntry == NULL) {\r
+ DEBUG ((DEBUG_ERROR,"Could not Alloc LVL4 PT. \n"));\r
+ return NULL;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If no access is needed, just create not present entry.\r
+ //\r
+ if (IoMmuAccess == 0) {\r
+ return SecondLevelPagingEntry;\r
+ }\r
+\r
+ Lvl4Start = RShiftU64 (BaseAddress, 39) & 0x1FF;\r
+ Lvl4End = RShiftU64 (EndAddress - 1, 39) & 0x1FF;\r
+\r
+ DEBUG ((DEBUG_INFO," Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start, Lvl4End));\r
+\r
+ Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;\r
+ for (Index4 = Lvl4Start; Index4 <= Lvl4End; Index4++) {\r
+ if (Lvl4PtEntry[Index4].Uint64 == 0) {\r
+ Lvl4PtEntry[Index4].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);\r
+ if (Lvl4PtEntry[Index4].Uint64 == 0) {\r
+ DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));\r
+ ASSERT(FALSE);\r
+ return NULL;\r
+ }\r
+ SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+ }\r
+\r
+ Lvl3Start = RShiftU64 (BaseAddress, 30) & 0x1FF;\r
+ if (ALIGN_VALUE_LOW(BaseAddress + SIZE_1GB, SIZE_1GB) <= EndAddress) {\r
+ Lvl3End = SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY);\r
+ } else {\r
+ Lvl3End = RShiftU64 (EndAddress - 1, 30) & 0x1FF;\r
+ }\r
+ DEBUG ((DEBUG_INFO," Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\n", Index4, Lvl3Start, Lvl3End));\r
+\r
+ Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.AddressHi);\r
+ for (Index3 = Lvl3Start; Index3 <= Lvl3End; Index3++) {\r
+ if (Lvl3PtEntry[Index3].Uint64 == 0) {\r
+ Lvl3PtEntry[Index3].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);\r
+ if (Lvl3PtEntry[Index3].Uint64 == 0) {\r
+ DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));\r
+ ASSERT(FALSE);\r
+ return NULL;\r
+ }\r
+ SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+ }\r
+\r
+ Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.AddressHi);\r
+ for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {\r
+ Lvl2PtEntry[Index2].Uint64 = BaseAddress;\r
+ SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry[Index2], IoMmuAccess);\r
+ Lvl2PtEntry[Index2].Bits.PageSize = 1;\r
+ BaseAddress += SIZE_2MB;\r
+ if (BaseAddress >= MemoryLimit) {\r
+ goto Done;\r
+ }\r
+ }\r
+ FlushPageTableMemory (VtdIndex, (UINTN)Lvl2PtEntry, SIZE_4KB);\r
+ }\r
+ FlushPageTableMemory (VtdIndex, (UINTN)&Lvl3PtEntry[Lvl3Start], (UINTN)&Lvl3PtEntry[Lvl3End + 1] - (UINTN)&Lvl3PtEntry[Lvl3Start]);\r
+ }\r
+ FlushPageTableMemory (VtdIndex, (UINTN)&Lvl4PtEntry[Lvl4Start], (UINTN)&Lvl4PtEntry[Lvl4End + 1] - (UINTN)&Lvl4PtEntry[Lvl4Start]);\r
+\r
+Done:\r
+ return SecondLevelPagingEntry;\r
+}\r
+\r
+/**\r
+ Create second level paging entry.\r
+\r
+ @param[in] VtdIndex The index of the VTd engine.\r
+ @param[in] IoMmuAccess The IOMMU access.\r
+\r
+ @return The second level paging entry.\r
+**/\r
+VTD_SECOND_LEVEL_PAGING_ENTRY *\r
+CreateSecondLevelPagingEntry (\r
+ IN UINTN VtdIndex,\r
+ IN UINT64 IoMmuAccess\r
+ )\r
+{\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;\r
+\r
+ SecondLevelPagingEntry = NULL;\r
+ SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, 0, mBelow4GMemoryLimit, IoMmuAccess);\r
+ if (SecondLevelPagingEntry == NULL) {\r
+ return NULL;\r
+ }\r
+ SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, SIZE_4GB, mAbove4GMemoryLimit, IoMmuAccess);\r
+ if (SecondLevelPagingEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ return SecondLevelPagingEntry;\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
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
+ DEBUG((DEBUG_INFO, "CreateContextEntry - %d\n", Index));\r
+ if (mVtdUnitInformation[Index].ECapReg.Bits.ECS) {\r
+ Status = CreateExtContextEntry (Index);\r
+ } else {\r
+ Status = CreateContextEntry (Index);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\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
+ UINTN Index;\r
+ UINTN Index2;\r
+ VTD_CONTEXT_ENTRY *ContextEntry;\r
+\r
+ DEBUG ((DEBUG_INFO,"=========================\n"));\r
+ DEBUG ((DEBUG_INFO,"DMAR Context Entry Table:\n"));\r
+\r
+ DEBUG ((DEBUG_INFO,"RootEntry Address - 0x%x\n", RootEntry));\r
+\r
+ for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {\r
+ if ((RootEntry[Index].Uint128.Uint64Lo != 0) || (RootEntry[Index].Uint128.Uint64Hi != 0)) {\r
+ DEBUG ((DEBUG_INFO," RootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",\r
+ Index, Index, RootEntry[Index].Uint128.Uint64Hi, RootEntry[Index].Uint128.Uint64Lo));\r
+ }\r
+ if (RootEntry[Index].Bits.Present == 0) {\r
+ continue;\r
+ }\r
+ ContextEntry = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry[Index].Bits.ContextTablePointerLo, RootEntry[Index].Bits.ContextTablePointerHi);\r
+ for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER; Index2++) {\r
+ if ((ContextEntry[Index2].Uint128.Uint64Lo != 0) || (ContextEntry[Index2].Uint128.Uint64Hi != 0)) {\r
+ DEBUG ((DEBUG_INFO," ContextEntry(0x%02x) D%02xF%02x - 0x%016lx %016lx\n",\r
+ Index2, Index2 >> 3, Index2 & 0x7, ContextEntry[Index2].Uint128.Uint64Hi, ContextEntry[Index2].Uint128.Uint64Lo));\r
+ }\r
+ if (ContextEntry[Index2].Bits.Present == 0) {\r
+ continue;\r
+ }\r
+ DumpSecondLevelPagingEntry ((VOID *)(UINTN)VTD_64BITS_ADDRESS(ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerLo, ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerHi));\r
+ }\r
+ }\r
+ DEBUG ((DEBUG_INFO,"=========================\n"));\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
+ UINTN Index4;\r
+ UINTN Index3;\r
+ UINTN Index2;\r
+ UINTN Index1;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl1PtEntry;\r
+\r
+ DEBUG ((DEBUG_VERBOSE,"================\n"));\r
+ DEBUG ((DEBUG_VERBOSE,"DMAR Second Level Page Table:\n"));\r
+\r
+ DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));\r
+ Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;\r
+ for (Index4 = 0; Index4 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index4++) {\r
+ if (Lvl4PtEntry[Index4].Uint64 != 0) {\r
+ DEBUG ((DEBUG_VERBOSE," Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index4, Lvl4PtEntry[Index4].Uint64));\r
+ }\r
+ if (Lvl4PtEntry[Index4].Uint64 == 0) {\r
+ continue;\r
+ }\r
+ Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.AddressHi);\r
+ for (Index3 = 0; Index3 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index3++) {\r
+ if (Lvl3PtEntry[Index3].Uint64 != 0) {\r
+ DEBUG ((DEBUG_VERBOSE," Lvl3Pt Entry(0x%03x) - 0x%016lx\n", Index3, Lvl3PtEntry[Index3].Uint64));\r
+ }\r
+ if (Lvl3PtEntry[Index3].Uint64 == 0) {\r
+ continue;\r
+ }\r
+\r
+ Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.AddressHi);\r
+ for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {\r
+ if (Lvl2PtEntry[Index2].Uint64 != 0) {\r
+ DEBUG ((DEBUG_VERBOSE," Lvl2Pt Entry(0x%03x) - 0x%016lx\n", Index2, Lvl2PtEntry[Index2].Uint64));\r
+ }\r
+ if (Lvl2PtEntry[Index2].Uint64 == 0) {\r
+ continue;\r
+ }\r
+ if (Lvl2PtEntry[Index2].Bits.PageSize == 0) {\r
+ Lvl1PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl2PtEntry[Index2].Bits.AddressLo, Lvl2PtEntry[Index2].Bits.AddressHi);\r
+ for (Index1 = 0; Index1 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index1++) {\r
+ if (Lvl1PtEntry[Index1].Uint64 != 0) {\r
+ DEBUG ((DEBUG_VERBOSE," Lvl1Pt Entry(0x%03x) - 0x%016lx\n", Index1, Lvl1PtEntry[Index1].Uint64));\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ DEBUG ((DEBUG_VERBOSE,"================\n"));\r
+}\r
+\r
+/**\r
+ Invalid page entry.\r
+\r
+ @param VtdIndex The VTd engine index.\r
+**/\r
+VOID\r
+InvalidatePageEntry (\r
+ IN UINTN VtdIndex\r
+ )\r
+{\r
+ if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation[VtdIndex].HasDirtyPages) {\r
+ InvalidateVtdIOTLBGlobal (VtdIndex);\r
+ }\r
+ mVtdUnitInformation[VtdIndex].HasDirtyContext = FALSE;\r
+ mVtdUnitInformation[VtdIndex].HasDirtyPages = FALSE;\r
+}\r
+\r
+#define VTD_PG_R BIT0\r
+#define VTD_PG_W BIT1\r
+#define VTD_PG_X BIT2\r
+#define VTD_PG_EMT (BIT3 | BIT4 | BIT5)\r
+#define VTD_PG_TM (BIT62)\r
+\r
+#define VTD_PG_PS BIT7\r
+\r
+#define PAGE_PROGATE_BITS (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VTD_PG_R)\r
+\r
+#define PAGING_4K_MASK 0xFFF\r
+#define PAGING_2M_MASK 0x1FFFFF\r
+#define PAGING_1G_MASK 0x3FFFFFFF\r
+\r
+#define PAGING_VTD_INDEX_MASK 0x1FF\r
+\r
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull\r
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull\r
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull\r
+\r
+typedef enum {\r
+ PageNone,\r
+ Page4K,\r
+ Page2M,\r
+ Page1G,\r
+} PAGE_ATTRIBUTE;\r
+\r
+typedef struct {\r
+ PAGE_ATTRIBUTE Attribute;\r
+ UINT64 Length;\r
+ UINT64 AddressMask;\r
+} PAGE_ATTRIBUTE_TABLE;\r
+\r
+PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {\r
+ {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},\r
+ {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},\r
+ {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},\r
+};\r
+\r
+/**\r
+ Return length according to page attributes.\r
+\r
+ @param[in] PageAttributes The page attribute of the page entry.\r
+\r
+ @return The length of page entry.\r
+**/\r
+UINTN\r
+PageAttributeToLength (\r
+ IN PAGE_ATTRIBUTE PageAttribute\r
+ )\r
+{\r
+ UINTN Index;\r
+ for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {\r
+ if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
+ return (UINTN)mPageAttributeTable[Index].Length;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Return page table entry to match the address.\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] Address The address to be checked.\r
+ @param[out] PageAttributes The page attribute of the page entry.\r
+\r
+ @return The page entry.\r
+**/\r
+VOID *\r
+GetSecondLevelPageTableEntry (\r
+ IN UINTN VtdIndex,\r
+ IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
+ IN PHYSICAL_ADDRESS Address,\r
+ OUT PAGE_ATTRIBUTE *PageAttribute\r
+ )\r
+{\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ UINTN Index3;\r
+ UINTN Index4;\r
+ UINT64 *L1PageTable;\r
+ UINT64 *L2PageTable;\r
+ UINT64 *L3PageTable;\r
+ UINT64 *L4PageTable;\r
+\r
+ Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_VTD_INDEX_MASK;\r
+ Index3 = ((UINTN)Address >> 30) & PAGING_VTD_INDEX_MASK;\r
+ Index2 = ((UINTN)Address >> 21) & PAGING_VTD_INDEX_MASK;\r
+ Index1 = ((UINTN)Address >> 12) & PAGING_VTD_INDEX_MASK;\r
+\r
+ L4PageTable = (UINT64 *)SecondLevelPagingEntry;\r
+ if (L4PageTable[Index4] == 0) {\r
+ L4PageTable[Index4] = (UINT64)(UINTN)AllocateZeroPages (1);\r
+ if (L4PageTable[Index4] == 0) {\r
+ DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));\r
+ ASSERT(FALSE);\r
+ *PageAttribute = PageNone;\r
+ return NULL;\r
+ }\r
+ SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L4PageTable[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+ FlushPageTableMemory (VtdIndex, (UINTN)&L4PageTable[Index4], sizeof(L4PageTable[Index4]));\r
+ }\r
+\r
+ L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);\r
+ if (L3PageTable[Index3] == 0) {\r
+ L3PageTable[Index3] = (UINT64)(UINTN)AllocateZeroPages (1);\r
+ if (L3PageTable[Index3] == 0) {\r
+ DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));\r
+ ASSERT(FALSE);\r
+ *PageAttribute = PageNone;\r
+ return NULL;\r
+ }\r
+ SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L3PageTable[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+ FlushPageTableMemory (VtdIndex, (UINTN)&L3PageTable[Index3], sizeof(L3PageTable[Index3]));\r
+ }\r
+ if ((L3PageTable[Index3] & VTD_PG_PS) != 0) {\r
+ // 1G\r
+ *PageAttribute = Page1G;\r
+ return &L3PageTable[Index3];\r
+ }\r
+\r
+ L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);\r
+ if (L2PageTable[Index2] == 0) {\r
+ L2PageTable[Index2] = Address & PAGING_2M_ADDRESS_MASK_64;\r
+ SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L2PageTable[Index2], 0);\r
+ L2PageTable[Index2] |= VTD_PG_PS;\r
+ FlushPageTableMemory (VtdIndex, (UINTN)&L2PageTable[Index2], sizeof(L2PageTable[Index2]));\r
+ }\r
+ if ((L2PageTable[Index2] & VTD_PG_PS) != 0) {\r
+ // 2M\r
+ *PageAttribute = Page2M;\r
+ return &L2PageTable[Index2];\r
+ }\r
+\r
+ // 4k\r
+ L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);\r
+ if ((L1PageTable[Index1] == 0) && (Address != 0)) {\r
+ *PageAttribute = PageNone;\r
+ return NULL;\r
+ }\r
+ *PageAttribute = Page4K;\r
+ return &L1PageTable[Index1];\r
+}\r
+\r
+/**\r
+ Modify memory attributes of page entry.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+ @param[in] PageEntry The page entry.\r
+ @param[in] IoMmuAccess The IOMMU access.\r
+ @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.\r
+**/\r
+VOID\r
+ConvertSecondLevelPageEntryAttribute (\r
+ IN UINTN VtdIndex,\r
+ IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,\r
+ IN UINT64 IoMmuAccess,\r
+ OUT BOOLEAN *IsModified\r
+ )\r
+{\r
+ UINT64 CurrentPageEntry;\r
+ UINT64 NewPageEntry;\r
+\r
+ CurrentPageEntry = PageEntry->Uint64;\r
+ SetSecondLevelPagingEntryAttribute (PageEntry, IoMmuAccess);\r
+ FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));\r
+ NewPageEntry = PageEntry->Uint64;\r
+ if (CurrentPageEntry != NewPageEntry) {\r
+ *IsModified = TRUE;\r
+ DEBUG ((DEBUG_VERBOSE, "ConvertSecondLevelPageEntryAttribute 0x%lx", CurrentPageEntry));\r
+ DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));\r
+ } else {\r
+ *IsModified = FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ This function returns if there is need to split page entry.\r
+\r
+ @param[in] BaseAddress The base address to be checked.\r
+ @param[in] Length The length to be checked.\r
+ @param[in] PageAttribute The page attribute of the page entry.\r
+\r
+ @retval SplitAttributes on if there is need to split page entry.\r
+**/\r
+PAGE_ATTRIBUTE\r
+NeedSplitPage (\r
+ IN PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN PAGE_ATTRIBUTE PageAttribute\r
+ )\r
+{\r
+ UINT64 PageEntryLength;\r
+\r
+ PageEntryLength = PageAttributeToLength (PageAttribute);\r
+\r
+ if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {\r
+ return PageNone;\r
+ }\r
+\r
+ if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {\r
+ return Page4K;\r
+ }\r
+\r
+ return Page2M;\r
+}\r
+\r
+/**\r
+ This function splits one page entry to small page entries.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+ @param[in] PageEntry The page entry to be splitted.\r
+ @param[in] PageAttribute The page attribute of the page entry.\r
+ @param[in] SplitAttribute How to split the page entry.\r
+\r
+ @retval RETURN_SUCCESS The page entry is splitted.\r
+ @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.\r
+ @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.\r
+**/\r
+RETURN_STATUS\r
+SplitSecondLevelPage (\r
+ IN UINTN VtdIndex,\r
+ IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,\r
+ IN PAGE_ATTRIBUTE PageAttribute,\r
+ IN PAGE_ATTRIBUTE SplitAttribute\r
+ )\r
+{\r
+ UINT64 BaseAddress;\r
+ UINT64 *NewPageEntry;\r
+ UINTN Index;\r
+\r
+ ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);\r
+\r
+ if (PageAttribute == Page2M) {\r
+ //\r
+ // Split 2M to 4K\r
+ //\r
+ ASSERT (SplitAttribute == Page4K);\r
+ if (SplitAttribute == Page4K) {\r
+ NewPageEntry = AllocateZeroPages (1);\r
+ DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
+ if (NewPageEntry == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+ BaseAddress = PageEntry->Uint64 & PAGING_2M_ADDRESS_MASK_64;\r
+ for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
+ NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | (PageEntry->Uint64 & PAGE_PROGATE_BITS);\r
+ }\r
+ FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);\r
+\r
+ PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;\r
+ SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+ FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));\r
+ return RETURN_SUCCESS;\r
+ } else {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ } else if (PageAttribute == Page1G) {\r
+ //\r
+ // Split 1G to 2M\r
+ // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.\r
+ //\r
+ ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);\r
+ if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {\r
+ NewPageEntry = AllocateZeroPages (1);\r
+ DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
+ if (NewPageEntry == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+ BaseAddress = PageEntry->Uint64 & PAGING_1G_ADDRESS_MASK_64;\r
+ for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
+ NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | VTD_PG_PS | (PageEntry->Uint64 & PAGE_PROGATE_BITS);\r
+ }\r
+ FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);\r
+\r
+ PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;\r
+ SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+ FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));\r
+ return RETURN_SUCCESS;\r
+ } else {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ } else {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+}\r
+\r
+/**\r
+ Set VTd attribute for a system memory on second level page entry\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
+SetSecondLevelPagingAttribute (\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
+ VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry;\r
+ PAGE_ATTRIBUTE PageAttribute;\r
+ UINTN PageEntryLength;\r
+ PAGE_ATTRIBUTE SplitAttribute;\r
+ EFI_STATUS Status;\r
+ BOOLEAN IsEntryModified;\r
+\r
+ DEBUG ((DEBUG_VERBOSE,"SetSecondLevelPagingAttribute (%d) (0x%016lx - 0x%016lx : %x) \n", VtdIndex, BaseAddress, Length, IoMmuAccess));\r
+ DEBUG ((DEBUG_VERBOSE," SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));\r
+\r
+ if (BaseAddress != ALIGN_VALUE(BaseAddress, SIZE_4KB)) {\r
+ DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ if (Length != ALIGN_VALUE(Length, SIZE_4KB)) {\r
+ DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ while (Length != 0) {\r
+ PageEntry = GetSecondLevelPageTableEntry (VtdIndex, SecondLevelPagingEntry, BaseAddress, &PageAttribute);\r
+ if (PageEntry == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PageEntry - NULL\n"));\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ PageEntryLength = PageAttributeToLength (PageAttribute);\r
+ SplitAttribute = NeedSplitPage (BaseAddress, Length, PageAttribute);\r
+ if (SplitAttribute == PageNone) {\r
+ ConvertSecondLevelPageEntryAttribute (VtdIndex, PageEntry, IoMmuAccess, &IsEntryModified);\r
+ if (IsEntryModified) {\r
+ mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;\r
+ }\r
+ //\r
+ // Convert success, move to next\r
+ //\r
+ BaseAddress += PageEntryLength;\r
+ Length -= PageEntryLength;\r
+ } else {\r
+ Status = SplitSecondLevelPage (VtdIndex, PageEntry, PageAttribute, SplitAttribute);\r
+ if (RETURN_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "SplitSecondLevelPage - %r\n", Status));\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;\r
+ //\r
+ // Just split current page\r
+ // Convert success in next around\r
+ //\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\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
+ EFI_STATUS Status;\r
+ Status = EFI_NOT_FOUND;\r
+ if (SecondLevelPagingEntry != NULL) {\r
+ Status = SetSecondLevelPagingAttribute (VtdIndex, DomainIdentifier, SecondLevelPagingEntry, BaseAddress, Length, IoMmuAccess);\r
+ }\r
+ return Status;\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
+ UINTN VtdIndex;\r
+ EFI_STATUS Status;\r
+ VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;\r
+ VTD_CONTEXT_ENTRY *ContextEntry;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;\r
+ UINT64 Pt;\r
+ UINTN PciDataIndex;\r
+ UINT16 DomainIdentifier;\r
+\r
+ SecondLevelPagingEntry = NULL;\r
+\r
+ DEBUG ((DEBUG_VERBOSE,"SetAccessAttribute (S%04x B%02x D%02x F%02x) (0x%016lx - 0x%08x, %x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, BaseAddress, (UINTN)Length, IoMmuAccess));\r
+\r
+ VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);\r
+ if (VtdIndex == (UINTN)-1) {\r
+ DEBUG ((DEBUG_ERROR,"SetAccessAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciDataIndex].AccessCount++;\r
+ //\r
+ // DomainId should not be 0.\r
+ //\r
+ DomainIdentifier = (UINT16)(PciDataIndex + 1);\r
+\r
+ if (ExtContextEntry != NULL) {\r
+ if (ExtContextEntry->Bits.Present == 0) {\r
+ SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);\r
+ DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);\r
+\r
+ ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
+ ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
+ ExtContextEntry->Bits.DomainIdentifier = DomainIdentifier;\r
+ ExtContextEntry->Bits.Present = 1;\r
+ FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtContextEntry));\r
+ DumpDmarExtContextEntryTable (mVtdUnitInformation[VtdIndex].ExtRootEntryTable);\r
+ mVtdUnitInformation[VtdIndex].HasDirtyContext = TRUE;\r
+ } else {\r
+ SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo, ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi);\r
+ DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ }\r
+ } else if (ContextEntry != NULL) {\r
+ if (ContextEntry->Bits.Present == 0) {\r
+ SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);\r
+ DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);\r
+\r
+ ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
+ ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
+ ContextEntry->Bits.DomainIdentifier = DomainIdentifier;\r
+ ContextEntry->Bits.Present = 1;\r
+ FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));\r
+ DumpDmarContextEntryTable (mVtdUnitInformation[VtdIndex].RootEntryTable);\r
+ mVtdUnitInformation[VtdIndex].HasDirtyContext = TRUE;\r
+ } else {\r
+ SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ContextEntry->Bits.SecondLevelPageTranslationPointerLo, ContextEntry->Bits.SecondLevelPageTranslationPointerHi);\r
+ DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ }\r
+ }\r
+\r
+ //\r
+ // Do not update FixedSecondLevelPagingEntry\r
+ //\r
+ if (SecondLevelPagingEntry != mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry) {\r
+ Status = SetPageAttribute (\r
+ VtdIndex,\r
+ DomainIdentifier,\r
+ SecondLevelPagingEntry,\r
+ BaseAddress,\r
+ Length,\r
+ IoMmuAccess\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR,"SetPageAttribute - %r\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ InvalidatePageEntry (VtdIndex);\r
+\r
+ return EFI_SUCCESS;\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
+ UINTN VtdIndex;\r
+ VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;\r
+ VTD_CONTEXT_ENTRY *ContextEntry;\r
+ VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;\r
+ UINT64 Pt;\r
+\r
+ DEBUG ((DEBUG_INFO,"AlwaysEnablePageAttribute (S%04x B%02x D%02x F%02x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+\r
+ VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);\r
+ if (VtdIndex == (UINTN)-1) {\r
+ DEBUG ((DEBUG_ERROR,"AlwaysEnablePageAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry == 0) {\r
+ DEBUG((DEBUG_INFO, "CreateSecondLevelPagingEntry - %d\n", VtdIndex));\r
+ mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
+ }\r
+\r
+ SecondLevelPagingEntry = mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry;\r
+ Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);\r
+ if (ExtContextEntry != NULL) {\r
+ ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
+ ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
+ ExtContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);\r
+ ExtContextEntry->Bits.Present = 1;\r
+ FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtContextEntry));\r
+ } else if (ContextEntry != NULL) {\r
+ ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
+ ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
+ ContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);\r
+ ContextEntry->Bits.Present = 1;\r
+ FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /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
+#include "DmaProtection.h"\r
+\r
+/**\r
+ Create extended context entry.\r
+\r
+ @param[in] VtdIndex The index of the VTd engine.\r
+\r
+ @retval EFI_SUCCESS The extended context entry is created.\r
+ @retval EFI_OUT_OF_RESOURCE No enough resource to create extended context entry.\r
+**/\r
+EFI_STATUS\r
+CreateExtContextEntry (\r
+ IN UINTN VtdIndex\r
+ )\r
+{\r
+ UINTN Index;\r
+ VOID *Buffer;\r
+ UINTN RootPages;\r
+ UINTN ContextPages;\r
+ VTD_EXT_ROOT_ENTRY *ExtRootEntry;\r
+ VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;\r
+ VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;\r
+ VTD_SOURCE_ID *PciSourceId;\r
+ VTD_SOURCE_ID SourceId;\r
+ UINTN MaxBusNumber;\r
+ UINTN EntryTablePages;\r
+\r
+ MaxBusNumber = 0;\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {\r
+ PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;\r
+ if (PciSourceId->Bits.Bus > MaxBusNumber) {\r
+ MaxBusNumber = PciSourceId->Bits.Bus;\r
+ }\r
+ }\r
+ DEBUG ((DEBUG_INFO," MaxBusNumber - 0x%x\n", MaxBusNumber));\r
+\r
+ RootPages = EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_ROOT_ENTRY) * VTD_ROOT_ENTRY_NUMBER);\r
+ ContextPages = EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_CONTEXT_ENTRY) * VTD_CONTEXT_ENTRY_NUMBER);\r
+ EntryTablePages = RootPages + ContextPages * (MaxBusNumber + 1);\r
+ Buffer = AllocateZeroPages (EntryTablePages);\r
+ if (Buffer == NULL) {\r
+ DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ mVtdUnitInformation[VtdIndex].ExtRootEntryTable = (VTD_EXT_ROOT_ENTRY *)Buffer;\r
+ Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);\r
+\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {\r
+ PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;\r
+\r
+ SourceId.Bits.Bus = PciSourceId->Bits.Bus;\r
+ SourceId.Bits.Device = PciSourceId->Bits.Device;\r
+ SourceId.Bits.Function = PciSourceId->Bits.Function;\r
+\r
+ ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];\r
+ if (ExtRootEntry->Bits.LowerPresent == 0) {\r
+ ExtRootEntry->Bits.LowerContextTablePointerLo = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 12);\r
+ ExtRootEntry->Bits.LowerContextTablePointerHi = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 32);\r
+ ExtRootEntry->Bits.LowerPresent = 1;\r
+ ExtRootEntry->Bits.UpperContextTablePointerLo = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 12) + 1;\r
+ ExtRootEntry->Bits.UpperContextTablePointerHi = (UINT32) RShiftU64 (RShiftU64 ((UINT64)(UINTN)Buffer, 12) + 1, 20);\r
+ ExtRootEntry->Bits.UpperPresent = 1;\r
+ FlushPageTableMemory (VtdIndex, (UINTN)ExtRootEntry, sizeof(*ExtRootEntry));\r
+ Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);\r
+ }\r
+\r
+ ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;\r
+ ExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];\r
+ ExtContextEntry->Bits.TranslationType = 0;\r
+ ExtContextEntry->Bits.FaultProcessingDisable = 0;\r
+ ExtContextEntry->Bits.Present = 0;\r
+\r
+ DEBUG ((DEBUG_INFO,"DOMAIN: S%04x, B%02x D%02x F%02x\n", mVtdUnitInformation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+\r
+ switch (mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW) {\r
+ case BIT1:\r
+ ExtContextEntry->Bits.AddressWidth = 0x1;\r
+ break;\r
+ case BIT2:\r
+ ExtContextEntry->Bits.AddressWidth = 0x2;\r
+ break;\r
+ }\r
+ FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtContextEntry));\r
+ }\r
+\r
+ return EFI_SUCCESS;\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
+ UINTN Index;\r
+ UINTN Index2;\r
+ VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;\r
+\r
+ DEBUG ((DEBUG_INFO,"=========================\n"));\r
+ DEBUG ((DEBUG_INFO,"DMAR ExtContext Entry Table:\n"));\r
+\r
+ DEBUG ((DEBUG_INFO,"ExtRootEntry Address - 0x%x\n", ExtRootEntry));\r
+\r
+ for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {\r
+ if ((ExtRootEntry[Index].Uint128.Uint64Lo != 0) || (ExtRootEntry[Index].Uint128.Uint64Hi != 0)) {\r
+ DEBUG ((DEBUG_INFO," ExtRootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",\r
+ Index, Index, ExtRootEntry[Index].Uint128.Uint64Hi, ExtRootEntry[Index].Uint128.Uint64Lo));\r
+ }\r
+ if (ExtRootEntry[Index].Bits.LowerPresent == 0) {\r
+ continue;\r
+ }\r
+ ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry[Index].Bits.LowerContextTablePointerLo, ExtRootEntry[Index].Bits.LowerContextTablePointerHi);\r
+ for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {\r
+ if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) ||\r
+ (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) {\r
+ DEBUG ((DEBUG_INFO," ExtContextEntryLower(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n",\r
+ Index2, Index2 >> 3, Index2 & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1));\r
+ }\r
+ if (ExtContextEntry[Index2].Bits.Present == 0) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (ExtRootEntry[Index].Bits.UpperPresent == 0) {\r
+ continue;\r
+ }\r
+ ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry[Index].Bits.UpperContextTablePointerLo, ExtRootEntry[Index].Bits.UpperContextTablePointerHi);\r
+ for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {\r
+ if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) ||\r
+ (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) {\r
+ DEBUG ((DEBUG_INFO," ExtContextEntryUpper(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n",\r
+ Index2, (Index2 + 128) >> 3, (Index2 + 128) & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1));\r
+ }\r
+ if (ExtContextEntry[Index2].Bits.Present == 0) {\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ DEBUG ((DEBUG_INFO,"=========================\n"));\r
+}\r
--- /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
+#include "DmaProtection.h"\r
+\r
+UINT64 mVtdHostAddressWidthMask;\r
+UINTN mVtdUnitNumber;\r
+VTD_UNIT_INFORMATION *mVtdUnitInformation;\r
+\r
+BOOLEAN mVtdEnabled;\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
+ if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.C == 0) {\r
+ WriteBackDataCacheRange ((VOID *)Base, Size);\r
+ }\r
+}\r
+\r
+/**\r
+ Flush VTd engine write buffer.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+**/\r
+VOID\r
+FlushWriteBuffer (\r
+ IN UINTN VtdIndex\r
+ )\r
+{\r
+ UINT32 Reg32;\r
+\r
+ if (mVtdUnitInformation[VtdIndex].CapReg.Bits.RWBF != 0) {\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);\r
+ MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);\r
+ do {\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while ((Reg32 & B_GSTS_REG_WBF) != 0);\r
+ }\r
+}\r
+\r
+/**\r
+ Invalidate VTd context cache.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+**/\r
+EFI_STATUS\r
+InvalidateContextCache (\r
+ IN UINTN VtdIndex\r
+ )\r
+{\r
+ UINT64 Reg64;\r
+\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);\r
+ if ((Reg64 & B_CCMD_REG_ICC) != 0) {\r
+ DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%d)\n",VtdIndex));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));\r
+ Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);\r
+ MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG, Reg64);\r
+\r
+ do {\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);\r
+ } while ((Reg64 & B_CCMD_REG_ICC) != 0);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Invalidate VTd IOTLB.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+**/\r
+EFI_STATUS\r
+InvalidateIOTLB (\r
+ IN UINTN VtdIndex\r
+ )\r
+{\r
+ UINT64 Reg64;\r
+\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);\r
+ if ((Reg64 & B_IOTLB_REG_IVT) != 0) {\r
+ DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));\r
+ Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);\r
+ MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);\r
+\r
+ do {\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);\r
+ } while ((Reg64 & B_IOTLB_REG_IVT) != 0);\r
+\r
+ return EFI_SUCCESS;\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
+ if (!mVtdEnabled) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ DEBUG((DEBUG_VERBOSE, "InvalidateVtdIOTLBGlobal(%d)\n", VtdIndex));\r
+\r
+ //\r
+ // Write Buffer Flush before invalidation\r
+ //\r
+ FlushWriteBuffer (VtdIndex);\r
+\r
+ //\r
+ // Invalidate the context cache\r
+ //\r
+ if (mVtdUnitInformation[VtdIndex].HasDirtyContext) {\r
+ InvalidateContextCache (VtdIndex);\r
+ }\r
+\r
+ //\r
+ // Invalidate the IOTLB cache\r
+ //\r
+ if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation[VtdIndex].HasDirtyPages) {\r
+ InvalidateIOTLB (VtdIndex);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Prepare VTD configuration.\r
+**/\r
+VOID\r
+PrepareVtdConfig (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN DomainNumber;\r
+\r
+ for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
+ DEBUG ((DEBUG_INFO, "Dump VTd Capability (%d)\n", Index));\r
+ mVtdUnitInformation[Index].CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);\r
+ DumpVtdCapRegs (&mVtdUnitInformation[Index].CapReg);\r
+ mVtdUnitInformation[Index].ECapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_ECAP_REG);\r
+ DumpVtdECapRegs (&mVtdUnitInformation[Index].ECapReg);\r
+\r
+ if ((mVtdUnitInformation[Index].CapReg.Bits.SLLPS & BIT0) == 0) {\r
+ DEBUG((DEBUG_WARN, "!!!! 2MB super page is not supported on VTD %d !!!!\n", Index));\r
+ }\r
+ if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & BIT2) == 0) {\r
+ DEBUG((DEBUG_ERROR, "!!!! 4-level page-table is not supported on VTD %d !!!!\n", Index));\r
+ return ;\r
+ }\r
+\r
+ DomainNumber = (UINTN)1 << (UINT8)((UINTN)mVtdUnitInformation[Index].CapReg.Bits.ND * 2 + 4);\r
+ if (mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber >= DomainNumber) {\r
+ DEBUG((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >= DomainNumber(0x%x) !!!!\n", mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber, DomainNumber));\r
+ return ;\r
+ }\r
+ }\r
+ return ;\r
+}\r
+\r
+/**\r
+ Disable PMR in all VTd engine.\r
+**/\r
+VOID\r
+DisablePmr (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Reg32;\r
+ VTD_CAP_REG CapReg;\r
+ UINTN Index;\r
+\r
+ DEBUG ((DEBUG_INFO,"DisablePmr\n"));\r
+ for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
+ CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);\r
+ if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
+ continue ;\r
+ }\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+ if ((Reg32 & BIT0) != 0) {\r
+ MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);\r
+ do {\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+ } while((Reg32 & BIT0) != 0);\r
+ DEBUG ((DEBUG_INFO,"Pmr(%d) disabled\n", Index));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO,"Pmr(%d) not enabled\n", Index));\r
+ }\r
+ }\r
+ return ;\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
+ UINTN Index;\r
+ UINT32 Reg32;\r
+\r
+ for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
+ DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%d] \n", Index));\r
+\r
+ if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {\r
+ DEBUG((DEBUG_INFO, "ExtRootEntryTable 0x%x \n", mVtdUnitInformation[Index].ExtRootEntryTable));\r
+ MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].ExtRootEntryTable | BIT11);\r
+ } else {\r
+ DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", mVtdUnitInformation[Index].RootEntryTable));\r
+ MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].RootEntryTable);\r
+ }\r
+\r
+ MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);\r
+\r
+ DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));\r
+ do {\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while((Reg32 & B_GSTS_REG_RTPS) == 0);\r
+\r
+ //\r
+ // Init DMAr Fault Event and Data registers\r
+ //\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_FEDATA_REG);\r
+\r
+ //\r
+ // Write Buffer Flush before invalidation\r
+ //\r
+ FlushWriteBuffer (Index);\r
+\r
+ //\r
+ // Invalidate the context cache\r
+ //\r
+ InvalidateContextCache (Index);\r
+\r
+ //\r
+ // Invalidate the IOTLB cache\r
+ //\r
+ InvalidateIOTLB (Index);\r
+\r
+ //\r
+ // Enable VTd\r
+ //\r
+ MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);\r
+ DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));\r
+ do {\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while ((Reg32 & B_GSTS_REG_TE) == 0);\r
+\r
+ DEBUG ((DEBUG_INFO,"VTD (%d) enabled!<<<<<<\n",Index));\r
+ }\r
+\r
+ //\r
+ // Need disable PMR, since we already setup translation table.\r
+ //\r
+ DisablePmr ();\r
+\r
+ mVtdEnabled = TRUE;\r
+\r
+ return EFI_SUCCESS;\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
+ UINTN Index;\r
+ UINTN SubIndex;\r
+ UINT32 Reg32;\r
+\r
+ for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
+ DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%d] \n", Index));\r
+\r
+ //\r
+ // Write Buffer Flush before invalidation\r
+ //\r
+ FlushWriteBuffer (Index);\r
+\r
+ //\r
+ // Disable VTd\r
+ //\r
+ MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);\r
+ do {\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while((Reg32 & B_GSTS_REG_RTPS) == 0);\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);\r
+ DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));\r
+\r
+ DEBUG ((DEBUG_INFO,"VTD (%d) Disabled!<<<<<<\n",Index));\r
+ }\r
+\r
+ mVtdEnabled = FALSE;\r
+\r
+ for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
+ DEBUG((DEBUG_INFO, "engine [%d] access\n", Index));\r
+ for (SubIndex = 0; SubIndex < mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber; SubIndex++) {\r
+ DEBUG ((DEBUG_INFO, " PCI S%04X B%02x D%02x F%02x - %d\n",\r
+ mVtdUnitInformation[Index].Segment,\r
+ mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,\r
+ mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,\r
+ mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function,\r
+ mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].AccessCount\r
+ ));\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\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
+ DEBUG((DEBUG_INFO, " CapReg:\n", CapReg->Uint64));\r
+ DEBUG((DEBUG_INFO, " ND - 0x%x\n", CapReg->Bits.ND));\r
+ DEBUG((DEBUG_INFO, " AFL - 0x%x\n", CapReg->Bits.AFL));\r
+ DEBUG((DEBUG_INFO, " RWBF - 0x%x\n", CapReg->Bits.RWBF));\r
+ DEBUG((DEBUG_INFO, " PLMR - 0x%x\n", CapReg->Bits.PLMR));\r
+ DEBUG((DEBUG_INFO, " PHMR - 0x%x\n", CapReg->Bits.PHMR));\r
+ DEBUG((DEBUG_INFO, " CM - 0x%x\n", CapReg->Bits.CM));\r
+ DEBUG((DEBUG_INFO, " SAGAW - 0x%x\n", CapReg->Bits.SAGAW));\r
+ DEBUG((DEBUG_INFO, " MGAW - 0x%x\n", CapReg->Bits.MGAW));\r
+ DEBUG((DEBUG_INFO, " ZLR - 0x%x\n", CapReg->Bits.ZLR));\r
+ DEBUG((DEBUG_INFO, " FRO - 0x%x\n", CapReg->Bits.FRO));\r
+ DEBUG((DEBUG_INFO, " SLLPS - 0x%x\n", CapReg->Bits.SLLPS));\r
+ DEBUG((DEBUG_INFO, " PSI - 0x%x\n", CapReg->Bits.PSI));\r
+ DEBUG((DEBUG_INFO, " NFR - 0x%x\n", CapReg->Bits.NFR));\r
+ DEBUG((DEBUG_INFO, " MAMV - 0x%x\n", CapReg->Bits.MAMV));\r
+ DEBUG((DEBUG_INFO, " DWD - 0x%x\n", CapReg->Bits.DWD));\r
+ DEBUG((DEBUG_INFO, " DRD - 0x%x\n", CapReg->Bits.DRD));\r
+ DEBUG((DEBUG_INFO, " FL1GP - 0x%x\n", CapReg->Bits.FL1GP));\r
+ DEBUG((DEBUG_INFO, " PI - 0x%x\n", CapReg->Bits.PI));\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
+ DEBUG((DEBUG_INFO, " ECapReg:\n", ECapReg->Uint64));\r
+ DEBUG((DEBUG_INFO, " C - 0x%x\n", ECapReg->Bits.C));\r
+ DEBUG((DEBUG_INFO, " QI - 0x%x\n", ECapReg->Bits.QI));\r
+ DEBUG((DEBUG_INFO, " DT - 0x%x\n", ECapReg->Bits.DT));\r
+ DEBUG((DEBUG_INFO, " IR - 0x%x\n", ECapReg->Bits.IR));\r
+ DEBUG((DEBUG_INFO, " EIM - 0x%x\n", ECapReg->Bits.EIM));\r
+ DEBUG((DEBUG_INFO, " PT - 0x%x\n", ECapReg->Bits.PT));\r
+ DEBUG((DEBUG_INFO, " SC - 0x%x\n", ECapReg->Bits.SC));\r
+ DEBUG((DEBUG_INFO, " IRO - 0x%x\n", ECapReg->Bits.IRO));\r
+ DEBUG((DEBUG_INFO, " MHMV - 0x%x\n", ECapReg->Bits.MHMV));\r
+ DEBUG((DEBUG_INFO, " ECS - 0x%x\n", ECapReg->Bits.ECS));\r
+ DEBUG((DEBUG_INFO, " MTS - 0x%x\n", ECapReg->Bits.MTS));\r
+ DEBUG((DEBUG_INFO, " NEST - 0x%x\n", ECapReg->Bits.NEST));\r
+ DEBUG((DEBUG_INFO, " DIS - 0x%x\n", ECapReg->Bits.DIS));\r
+ DEBUG((DEBUG_INFO, " PASID - 0x%x\n", ECapReg->Bits.PASID));\r
+ DEBUG((DEBUG_INFO, " PRS - 0x%x\n", ECapReg->Bits.PRS));\r
+ DEBUG((DEBUG_INFO, " ERS - 0x%x\n", ECapReg->Bits.ERS));\r
+ DEBUG((DEBUG_INFO, " SRS - 0x%x\n", ECapReg->Bits.SRS));\r
+ DEBUG((DEBUG_INFO, " NWFS - 0x%x\n", ECapReg->Bits.NWFS));\r
+ DEBUG((DEBUG_INFO, " EAFS - 0x%x\n", ECapReg->Bits.EAFS));\r
+ DEBUG((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS));\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
+ UINTN Index;\r
+ UINT64 Reg64;\r
+ VTD_FRCD_REG FrcdReg;\r
+ VTD_CAP_REG CapReg;\r
+ UINT32 Reg32;\r
+ VTD_SOURCE_ID SourceId;\r
+\r
+ DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) Begin ####\n", VtdIndex));\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_VER_REG);\r
+ DEBUG((DEBUG_INFO, " VER_REG - 0x%08x\n", Reg32));\r
+\r
+ CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CAP_REG);\r
+ DEBUG((DEBUG_INFO, " CAP_REG - 0x%016lx\n", CapReg.Uint64));\r
+\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_ECAP_REG);\r
+ DEBUG((DEBUG_INFO, " ECAP_REG - 0x%016lx\n", Reg64));\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);\r
+ DEBUG((DEBUG_INFO, " GSTS_REG - 0x%08x \n", Reg32));\r
+\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_RTADDR_REG);\r
+ DEBUG((DEBUG_INFO, " RTADDR_REG - 0x%016lx\n", Reg64));\r
+\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);\r
+ DEBUG((DEBUG_INFO, " CCMD_REG - 0x%016lx\n", Reg64));\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);\r
+ DEBUG((DEBUG_INFO, " FSTS_REG - 0x%08x\n", Reg32));\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FECTL_REG);\r
+ DEBUG((DEBUG_INFO, " FECTL_REG - 0x%08x\n", Reg32));\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEDATA_REG);\r
+ DEBUG((DEBUG_INFO, " FEDATA_REG - 0x%08x\n", Reg32));\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEADDR_REG);\r
+ DEBUG((DEBUG_INFO, " FEADDR_REG - 0x%08x\n",Reg32));\r
+\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEUADDR_REG);\r
+ DEBUG((DEBUG_INFO, " FEUADDR_REG - 0x%08x\n",Reg32));\r
+\r
+ for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {\r
+ FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));\r
+ FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));\r
+ DEBUG((DEBUG_INFO, " FRCD_REG[%d] - 0x%016lx %016lx\n", Index, FrcdReg.Uint64[1], FrcdReg.Uint64[0]));\r
+ if (FrcdReg.Uint64[1] != 0 || FrcdReg.Uint64[0] != 0) {\r
+ DEBUG((DEBUG_INFO, " Fault Info - 0x%016lx\n", VTD_64BITS_ADDRESS(FrcdReg.Bits.FILo, FrcdReg.Bits.FIHi)));\r
+ SourceId.Uint16 = (UINT16)FrcdReg.Bits.SID;\r
+ DEBUG((DEBUG_INFO, " Source - B%02x D%02x F%02x\n", SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+ DEBUG((DEBUG_INFO, " Type - %x (%a)\n", FrcdReg.Bits.T, FrcdReg.Bits.T ? "read" : "write"));\r
+ DEBUG((DEBUG_INFO, " Reason - %x\n", FrcdReg.Bits.FR));\r
+ }\r
+ }\r
+\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IVA_REG);\r
+ DEBUG((DEBUG_INFO, " IVA_REG - 0x%016lx\n",Reg64));\r
+\r
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);\r
+ DEBUG((DEBUG_INFO, " IOTLB_REG - 0x%016lx\n",Reg64));\r
+\r
+ DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) End ####\n", VtdIndex));\r
+}\r
+\r
+/**\r
+ Dump VTd registers for all VTd engine.\r
+**/\r
+VOID\r
+DumpVtdRegsAll (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Num;\r
+\r
+ for (Num = 0; Num < mVtdUnitNumber; Num++) {\r
+ DumpVtdRegs (Num);\r
+ }\r
+}\r
+\r
+/**\r
+ Dump VTd registers if there is error.\r
+**/\r
+VOID\r
+DumpVtdIfError (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Num;\r
+ UINTN Index;\r
+ VTD_FRCD_REG FrcdReg;\r
+ VTD_CAP_REG CapReg;\r
+ UINT32 Reg32;\r
+ BOOLEAN HasError;\r
+\r
+ for (Num = 0; Num < mVtdUnitNumber; Num++) {\r
+ HasError = FALSE;\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG);\r
+ if (Reg32 != 0) {\r
+ HasError = TRUE;\r
+ }\r
+ Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FECTL_REG);\r
+ if ((Reg32 & BIT30) != 0) {\r
+ HasError = TRUE;\r
+ }\r
+\r
+ CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_CAP_REG);\r
+ for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {\r
+ FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));\r
+ FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));\r
+ if (FrcdReg.Bits.F != 0) {\r
+ HasError = TRUE;\r
+ }\r
+ }\r
+\r
+ if (HasError) {\r
+ DEBUG((DEBUG_INFO, "\n#### ERROR ####\n"));\r
+ DumpVtdRegs (Num);\r
+ DEBUG((DEBUG_INFO, "#### ERROR ####\n\n"));\r
+ //\r
+ // Clear\r
+ //\r
+ for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {\r
+ FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));\r
+ if (FrcdReg.Bits.F != 0) {\r
+ FrcdReg.Bits.F = 0;\r
+ MmioWrite64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)), FrcdReg.Uint64[1]);\r
+ }\r
+ MmioWrite32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG, MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG));\r
+ }\r
+ }\r
+ }\r
+}\r
\r
[Components]\r
IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf\r
- IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf\r
+ IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.inf\r
IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.inf\r
IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf\r
IntelSiliconPkg/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.inf\r
+++ /dev/null
-/** @file\r
- BmDma related function\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
-#include <PiDxe.h>\r
-\r
-#include <Protocol/IoMmu.h>\r
-\r
-#include <Library/BaseLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-\r
-// TBD: May make it a policy\r
-#define DMA_MEMORY_TOP MAX_UINTN\r
-//#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL\r
-\r
-#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
-typedef struct {\r
- UINT32 Signature;\r
- LIST_ENTRY Link;\r
- EDKII_IOMMU_OPERATION Operation;\r
- UINTN NumberOfBytes;\r
- UINTN NumberOfPages;\r
- EFI_PHYSICAL_ADDRESS HostAddress;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
-} MAP_INFO;\r
-#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)\r
-\r
-LIST_ENTRY gMaps = INITIALIZE_LIST_HEAD_VARIABLE(gMaps);\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
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
- MAP_INFO *MapInfo;\r
- EFI_PHYSICAL_ADDRESS DmaMemoryTop;\r
- BOOLEAN NeedRemap;\r
-\r
- if (NumberOfBytes == NULL || DeviceAddress == NULL ||\r
- Mapping == NULL) {\r
- DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- DEBUG ((DEBUG_VERBOSE, "IoMmuMap: ==> 0x%08x - 0x%08x (%x)\n", HostAddress, *NumberOfBytes, Operation));\r
-\r
- //\r
- // Make sure that Operation is valid\r
- //\r
- if ((UINT32) Operation >= EdkiiIoMmuOperationMaximum) {\r
- DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- NeedRemap = FALSE;\r
- PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
-\r
- DmaMemoryTop = DMA_MEMORY_TOP;\r
-\r
- //\r
- // Alignment check\r
- //\r
- if ((*NumberOfBytes != ALIGN_VALUE(*NumberOfBytes, SIZE_4KB)) ||\r
- (PhysicalAddress != ALIGN_VALUE(PhysicalAddress, SIZE_4KB))) {\r
- if ((Operation == EdkiiIoMmuOperationBusMasterCommonBuffer) ||\r
- (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64)) {\r
- //\r
- // The input buffer might be a subset from IoMmuAllocateBuffer.\r
- // Skip the check.\r
- //\r
- } else {\r
- NeedRemap = TRUE;\r
- }\r
- }\r
-\r
- if ((PhysicalAddress + *NumberOfBytes) >= DMA_MEMORY_TOP) {\r
- NeedRemap = TRUE;\r
- }\r
-\r
- if (((Operation != EdkiiIoMmuOperationBusMasterRead64 &&\r
- Operation != EdkiiIoMmuOperationBusMasterWrite64 &&\r
- Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&\r
- ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
- //\r
- // If the root bridge or the device cannot handle performing DMA above\r
- // 4GB but any part of the DMA transfer being mapped is above 4GB, then\r
- // map the DMA transfer to a buffer below 4GB.\r
- //\r
- NeedRemap = TRUE;\r
- DmaMemoryTop = MIN (DmaMemoryTop, SIZE_4GB - 1);\r
- }\r
-\r
- if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
- Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
- if (NeedRemap) {\r
- //\r
- // Common Buffer operations can not be remapped. If the common buffer\r
- // is above 4GB, then it is not possible to generate a mapping, so return\r
- // an error.\r
- //\r
- DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_UNSUPPORTED));\r
- return EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- //\r
- // Allocate a MAP_INFO structure to remember the mapping when Unmap() is\r
- // called later.\r
- //\r
- MapInfo = AllocatePool (sizeof (MAP_INFO));\r
- if (MapInfo == NULL) {\r
- *NumberOfBytes = 0;\r
- DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES));\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // Initialize the MAP_INFO structure\r
- //\r
- MapInfo->Signature = MAP_INFO_SIGNATURE;\r
- MapInfo->Operation = Operation;\r
- MapInfo->NumberOfBytes = *NumberOfBytes;\r
- MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
- MapInfo->HostAddress = PhysicalAddress;\r
- MapInfo->DeviceAddress = DmaMemoryTop;\r
-\r
- //\r
- // Allocate a buffer below 4GB to map the transfer to.\r
- //\r
- if (NeedRemap) {\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiBootServicesData,\r
- MapInfo->NumberOfPages,\r
- &MapInfo->DeviceAddress\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (MapInfo);\r
- *NumberOfBytes = 0;\r
- DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", Status));\r
- return Status;\r
- }\r
-\r
- //\r
- // If this is a read operation from the Bus Master's point of view,\r
- // then copy the contents of the real buffer into the mapped buffer\r
- // so the Bus Master can read the contents of the real buffer.\r
- //\r
- if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
- Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
- CopyMem (\r
- (VOID *) (UINTN) MapInfo->DeviceAddress,\r
- (VOID *) (UINTN) MapInfo->HostAddress,\r
- MapInfo->NumberOfBytes\r
- );\r
- }\r
- } else {\r
- MapInfo->DeviceAddress = MapInfo->HostAddress;\r
- }\r
-\r
- InsertTailList (&gMaps, &MapInfo->Link);\r
-\r
- //\r
- // The DeviceAddress is the address of the maped buffer below 4GB\r
- //\r
- *DeviceAddress = MapInfo->DeviceAddress;\r
- //\r
- // Return a pointer to the MAP_INFO structure in Mapping\r
- //\r
- *Mapping = MapInfo;\r
-\r
- DEBUG ((DEBUG_VERBOSE, "IoMmuMap: 0x%08x - 0x%08x <==\n", *DeviceAddress, *Mapping));\r
-\r
- return EFI_SUCCESS;\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
- MAP_INFO *MapInfo;\r
- LIST_ENTRY *Link;\r
-\r
- DEBUG ((DEBUG_VERBOSE, "IoMmuUnmap: 0x%08x\n", Mapping));\r
-\r
- if (Mapping == NULL) {\r
- DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- MapInfo = NULL;\r
- for (Link = GetFirstNode (&gMaps)\r
- ; !IsNull (&gMaps, Link)\r
- ; Link = GetNextNode (&gMaps, Link)\r
- ) {\r
- MapInfo = MAP_INFO_FROM_LINK (Link);\r
- if (MapInfo == Mapping) {\r
- break;\r
- }\r
- }\r
- //\r
- // Mapping is not a valid value returned by Map()\r
- //\r
- if (MapInfo != Mapping) {\r
- DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- RemoveEntryList (&MapInfo->Link);\r
-\r
- if (MapInfo->DeviceAddress != MapInfo->HostAddress) {\r
- //\r
- // If this is a write operation from the Bus Master's point of view,\r
- // then copy the contents of the mapped buffer into the real buffer\r
- // so the processor can read the contents of the real buffer.\r
- //\r
- if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
- MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
- CopyMem (\r
- (VOID *) (UINTN) MapInfo->HostAddress,\r
- (VOID *) (UINTN) MapInfo->DeviceAddress,\r
- MapInfo->NumberOfBytes\r
- );\r
- }\r
-\r
- //\r
- // Free the mapped buffer and the MAP_INFO structure.\r
- //\r
- gBS->FreePages (MapInfo->DeviceAddress, MapInfo->NumberOfPages);\r
- }\r
-\r
- FreePool (Mapping);\r
- return EFI_SUCCESS;\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 and 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
-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
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
-\r
- DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: ==> 0x%08x\n", Pages));\r
-\r
- //\r
- // Validate Attributes\r
- //\r
- if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {\r
- DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED));\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- //\r
- // Check for invalid inputs\r
- //\r
- if (HostAddress == NULL) {\r
- DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // The only valid memory types are EfiBootServicesData and\r
- // EfiRuntimeServicesData\r
- //\r
- if (MemoryType != EfiBootServicesData &&\r
- MemoryType != EfiRuntimeServicesData) {\r
- DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- PhysicalAddress = DMA_MEMORY_TOP;\r
- if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
- //\r
- // Limit allocations to memory below 4GB\r
- //\r
- PhysicalAddress = MIN (PhysicalAddress, SIZE_4GB - 1);\r
- }\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- MemoryType,\r
- Pages,\r
- &PhysicalAddress\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
- }\r
-\r
- DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: 0x%08x <==\n", *HostAddress));\r
-\r
- return Status;\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
- DEBUG ((DEBUG_VERBOSE, "IoMmuFreeBuffer: 0x%\n", Pages));\r
- return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);\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
- MAP_INFO *MapInfo;\r
- LIST_ENTRY *Link;\r
-\r
- if (Mapping == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- MapInfo = NULL;\r
- for (Link = GetFirstNode (&gMaps)\r
- ; !IsNull (&gMaps, Link)\r
- ; Link = GetNextNode (&gMaps, Link)\r
- ) {\r
- MapInfo = MAP_INFO_FROM_LINK (Link);\r
- if (MapInfo == Mapping) {\r
- break;\r
- }\r
- }\r
- //\r
- // Mapping is not a valid value returned by Map()\r
- //\r
- if (MapInfo != Mapping) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- *DeviceAddress = MapInfo->DeviceAddress;\r
- *NumberOfPages = MapInfo->NumberOfPages;\r
- return EFI_SUCCESS;\r
-}\r
-\r
+++ /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
-#include "DmaProtection.h"\r
-\r
-EFI_ACPI_SDT_PROTOCOL *mAcpiSdt;\r
-UINT64 mBelow4GMemoryLimit;\r
-UINT64 mAbove4GMemoryLimit;\r
-\r
-EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;\r
-\r
-/**\r
- return the UEFI memory information.\r
-\r
- @param[out] Below4GMemoryLimit The below 4GiB memory limit\r
- @param[out] Above4GMemoryLimit The above 4GiB memory limit\r
-**/\r
-VOID\r
-ReturnUefiMemoryMap (\r
- OUT UINT64 *Below4GMemoryLimit,\r
- OUT UINT64 *Above4GMemoryLimit\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;\r
- EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;\r
- EFI_MEMORY_DESCRIPTOR *EfiEntry;\r
- EFI_MEMORY_DESCRIPTOR *NextEfiEntry;\r
- EFI_MEMORY_DESCRIPTOR TempEfiEntry;\r
- UINTN EfiMemoryMapSize;\r
- UINTN EfiMapKey;\r
- UINTN EfiDescriptorSize;\r
- UINT32 EfiDescriptorVersion;\r
- UINT64 MemoryBlockLength;\r
-\r
- *Below4GMemoryLimit = 0;\r
- *Above4GMemoryLimit = 0;\r
-\r
- //\r
- // Get the EFI memory map.\r
- //\r
- EfiMemoryMapSize = 0;\r
- EfiMemoryMap = NULL;\r
- Status = gBS->GetMemoryMap (\r
- &EfiMemoryMapSize,\r
- EfiMemoryMap,\r
- &EfiMapKey,\r
- &EfiDescriptorSize,\r
- &EfiDescriptorVersion\r
- );\r
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
-\r
- do {\r
- //\r
- // Use size returned back plus 1 descriptor for the AllocatePool.\r
- // We don't just multiply by 2 since the "for" loop below terminates on\r
- // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize\r
- // we process bogus entries and create bogus E820 entries.\r
- //\r
- EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);\r
- ASSERT (EfiMemoryMap != NULL);\r
- Status = gBS->GetMemoryMap (\r
- &EfiMemoryMapSize,\r
- EfiMemoryMap,\r
- &EfiMapKey,\r
- &EfiDescriptorSize,\r
- &EfiDescriptorVersion\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (EfiMemoryMap);\r
- }\r
- } while (Status == EFI_BUFFER_TOO_SMALL);\r
-\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Sort memory map from low to high\r
- //\r
- EfiEntry = EfiMemoryMap;\r
- NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
- while (EfiEntry < EfiMemoryMapEnd) {\r
- while (NextEfiEntry < EfiMemoryMapEnd) {\r
- if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {\r
- CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
- CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
- CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
- }\r
-\r
- NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);\r
- }\r
-\r
- EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- }\r
-\r
- //\r
- //\r
- //\r
- DEBUG ((DEBUG_INFO, "MemoryMap:\n"));\r
- EfiEntry = EfiMemoryMap;\r
- EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
- while (EfiEntry < EfiMemoryMapEnd) {\r
- MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));\r
- DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));\r
- switch (EfiEntry->Type) {\r
- case EfiLoaderCode:\r
- case EfiLoaderData:\r
- case EfiBootServicesCode:\r
- case EfiBootServicesData:\r
- case EfiConventionalMemory:\r
- case EfiRuntimeServicesCode:\r
- case EfiRuntimeServicesData:\r
- case EfiACPIReclaimMemory:\r
- case EfiACPIMemoryNVS:\r
- case EfiReservedMemoryType:\r
- if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {\r
- //\r
- // Skip the memory block is under 1MB\r
- //\r
- } else if (EfiEntry->PhysicalStart >= BASE_4GB) {\r
- if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
- *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
- }\r
- } else {\r
- if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
- *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
- }\r
- }\r
- break;\r
- }\r
- EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- }\r
-\r
- FreePool (EfiMemoryMap);\r
-\r
- DEBUG ((DEBUG_INFO, "Result:\n"));\r
- DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit));\r
- DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit));\r
-\r
- return ;\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
-ScanBusCallbackAlwaysEnablePageAttribute (\r
- IN VOID *Context,\r
- IN UINT16 Segment,\r
- IN UINT8 Bus,\r
- IN UINT8 Device,\r
- IN UINT8 Function\r
- )\r
-{\r
- VTD_SOURCE_ID SourceId;\r
- EFI_STATUS Status;\r
-\r
- SourceId.Bits.Bus = Bus;\r
- SourceId.Bits.Device = Device;\r
- SourceId.Bits.Function = Function;\r
- Status = AlwaysEnablePageAttribute (Segment, SourceId);\r
- return Status;\r
-}\r
-\r
-/**\r
- Always enable the VTd page attribute for the device in the DeviceScope.\r
-\r
- @param[in] DeviceScope the input device scope data structure\r
-\r
- @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.\r
-**/\r
-EFI_STATUS\r
-AlwaysEnablePageAttributeDeviceScope (\r
- IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope\r
- )\r
-{\r
- UINT8 Bus;\r
- UINT8 Device;\r
- UINT8 Function;\r
- VTD_SOURCE_ID SourceId;\r
- UINT8 SecondaryBusNumber;\r
- EFI_STATUS Status;\r
-\r
- Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);\r
-\r
- if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {\r
- //\r
- // Need scan the bridge and add all devices.\r
- //\r
- SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
- Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);\r
- return Status;\r
- } else {\r
- SourceId.Bits.Bus = Bus;\r
- SourceId.Bits.Device = Device;\r
- SourceId.Bits.Function = Function;\r
- Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);\r
- return Status;\r
- }\r
-}\r
-\r
-/**\r
- Always enable the VTd page attribute for the device matching DeviceId.\r
-\r
- @param[in] PciDeviceId the input PCI device ID\r
-\r
- @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.\r
-**/\r
-EFI_STATUS\r
-AlwaysEnablePageAttributePciDeviceId (\r
- IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId\r
- )\r
-{\r
- UINTN VtdIndex;\r
- UINTN PciIndex;\r
- PCI_DEVICE_DATA *PciDeviceData;\r
- EFI_STATUS Status;\r
-\r
- for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
- for (PciIndex = 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; PciIndex++) {\r
- PciDeviceData = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciIndex];\r
-\r
- if (((PciDeviceId->VendorId == 0xFFFF) || (PciDeviceId->VendorId == PciDeviceData->PciDeviceId.VendorId)) &&\r
- ((PciDeviceId->DeviceId == 0xFFFF) || (PciDeviceId->DeviceId == PciDeviceData->PciDeviceId.DeviceId)) &&\r
- ((PciDeviceId->RevisionId == 0xFF) || (PciDeviceId->RevisionId == PciDeviceData->PciDeviceId.RevisionId)) &&\r
- ((PciDeviceId->SubsystemVendorId == 0xFFFF) || (PciDeviceId->SubsystemVendorId == PciDeviceData->PciDeviceId.SubsystemVendorId)) &&\r
- ((PciDeviceId->SubsystemDeviceId == 0xFFFF) || (PciDeviceId->SubsystemDeviceId == PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) {\r
- Status = AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex].Segment, PciDeviceData->PciSourceId);\r
- if (EFI_ERROR(Status)) {\r
- continue;\r
- }\r
- }\r
- }\r
- }\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Always enable the VTd page attribute for the device.\r
-\r
- @param[in] DeviceInfo the exception device information\r
-\r
- @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.\r
-**/\r
-EFI_STATUS\r
-AlwaysEnablePageAttributeExceptionDeviceInfo (\r
- IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *DeviceInfo\r
- )\r
-{\r
- switch (DeviceInfo->Type) {\r
- case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:\r
- return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1));\r
- case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:\r
- return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1));\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-}\r
-\r
-/**\r
- Initialize platform VTd policy.\r
-**/\r
-VOID\r
-InitializePlatformVTdPolicy (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN DeviceInfoCount;\r
- VOID *DeviceInfo;\r
- EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;\r
- UINTN Index;\r
-\r
- //\r
- // It is optional.\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEdkiiPlatformVTdPolicyProtocolGuid,\r
- NULL,\r
- (VOID **)&mPlatformVTdPolicy\r
- );\r
- if (!EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));\r
- Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);\r
- if (!EFI_ERROR(Status)) {\r
- ThisDeviceInfo = DeviceInfo;\r
- for (Index = 0; Index < DeviceInfoCount; Index++) {\r
- if (ThisDeviceInfo->Type == EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END) {\r
- break;\r
- }\r
- AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);\r
- ThisDeviceInfo = (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo->Length);\r
- }\r
- FreePool (DeviceInfo);\r
- }\r
- }\r
-}\r
-\r
-/**\r
- Setup VTd engine.\r
-**/\r
-VOID\r
-SetupVtd (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VOID *PciEnumerationComplete;\r
- UINTN Index;\r
- UINT64 Below4GMemoryLimit;\r
- UINT64 Above4GMemoryLimit;\r
-\r
- //\r
- // PCI Enumeration must be done\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiPciEnumerationCompleteProtocolGuid,\r
- NULL,\r
- &PciEnumerationComplete\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);\r
- Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);\r
- DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));\r
-\r
- mBelow4GMemoryLimit = Below4GMemoryLimit;\r
- mAbove4GMemoryLimit = Above4GMemoryLimit;\r
-\r
- //\r
- // 1. setup\r
- //\r
- DEBUG ((DEBUG_INFO, "GetDmarAcpiTable\n"));\r
- Status = GetDmarAcpiTable ();\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
- DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));\r
- Status = ParseDmarAcpiTableDrhd ();\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
- DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));\r
- PrepareVtdConfig ();\r
-\r
- //\r
- // 2. initialization\r
- //\r
- DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));\r
- Status = SetupTranslationTable ();\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
-\r
- InitializePlatformVTdPolicy ();\r
-\r
- ParseDmarAcpiTableRmrr ();\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
- DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);\r
- }\r
- if (mVtdUnitInformation[Index].RootEntryTable != NULL) {\r
- DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);\r
- }\r
- }\r
-\r
- //\r
- // 3. enable\r
- //\r
- DEBUG ((DEBUG_INFO, "EnableDmar\n"));\r
- Status = EnableDmar ();\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
- DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));\r
- DumpVtdRegsAll ();\r
-}\r
-\r
-/**\r
- ACPI notification function.\r
-\r
- @param[in] Table A pointer to the ACPI table header.\r
- @param[in] Version The ACPI table's version.\r
- @param[in] TableKey The table key for this ACPI table.\r
-\r
- @retval EFI_SUCCESS The notification function is executed.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AcpiNotificationFunc (\r
- IN EFI_ACPI_SDT_HEADER *Table,\r
- IN EFI_ACPI_TABLE_VERSION Version,\r
- IN UINTN TableKey\r
- )\r
-{\r
- if (Table->Signature == EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE) {\r
- DEBUG((DEBUG_INFO, "Vtd AcpiNotificationFunc\n"));\r
- SetupVtd ();\r
- }\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Exit boot service callback function.\r
-\r
- @param[in] Event The event handle.\r
- @param[in] Context The event content.\r
-**/\r
-VOID\r
-EFIAPI\r
-OnExitBootServices (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));\r
- DumpVtdRegsAll ();\r
-\r
- if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
- DisableDmar ();\r
- DumpVtdRegsAll ();\r
- }\r
-}\r
-\r
-/**\r
- Legacy boot callback function.\r
-\r
- @param[in] Event The event handle.\r
- @param[in] Context The event content.\r
-**/\r
-VOID\r
-EFIAPI\r
-OnLegacyBoot (\r
- EFI_EVENT Event,\r
- VOID *Context\r
- )\r
-{\r
- DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));\r
- DumpVtdRegsAll ();\r
- DisableDmar ();\r
- DumpVtdRegsAll ();\r
-}\r
-\r
-/**\r
- Initialize DMA protection.\r
-**/\r
-VOID\r
-InitializeDmaProtection (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_EVENT ExitBootServicesEvent;\r
- EFI_EVENT LegacyBootEvent;\r
-\r
- Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **) &mAcpiSdt);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = mAcpiSdt->RegisterNotify (TRUE, AcpiNotificationFunc);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_NOTIFY,\r
- OnExitBootServices,\r
- NULL,\r
- &gEfiEventExitBootServicesGuid,\r
- &ExitBootServicesEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = EfiCreateEventLegacyBootEx (\r
- TPL_NOTIFY,\r
- OnLegacyBoot,\r
- NULL,\r
- &LegacyBootEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return ;\r
-}\r
+++ /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
+++ /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
-#include "DmaProtection.h"\r
-\r
-#pragma pack(1)\r
-\r
-typedef struct {\r
- EFI_ACPI_DESCRIPTION_HEADER Header;\r
- UINT32 Entry;\r
-} RSDT_TABLE;\r
-\r
-typedef struct {\r
- EFI_ACPI_DESCRIPTION_HEADER Header;\r
- UINT64 Entry;\r
-} XSDT_TABLE;\r
-\r
-#pragma pack()\r
-\r
-EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;\r
-\r
-/**\r
- Dump DMAR DeviceScopeEntry.\r
-\r
- @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry\r
-**/\r
-VOID\r
-DumpDmarDeviceScopeEntry (\r
- IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry\r
- )\r
-{\r
- UINTN PciPathNumber;\r
- UINTN PciPathIndex;\r
- EFI_ACPI_DMAR_PCI_PATH *PciPath;\r
-\r
- if (DmarDeviceScopeEntry == NULL) {\r
- return;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " *************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " * DMA-Remapping Device Scope Entry Structure *\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " *************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- (sizeof(UINTN) == sizeof(UINT64)) ?\r
- " DMAR Device Scope Entry address ...................... 0x%016lx\n" :\r
- " DMAR Device Scope Entry address ...................... 0x%08x\n",\r
- DmarDeviceScopeEntry\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Device Scope Entry Type ............................ 0x%02x\n",\r
- DmarDeviceScopeEntry->Type\r
- ));\r
- switch (DmarDeviceScopeEntry->Type) {\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
- DEBUG ((DEBUG_INFO,\r
- " PCI Endpoint Device\n"\r
- ));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
- DEBUG ((DEBUG_INFO,\r
- " PCI Sub-hierachy\n"\r
- ));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:\r
- DEBUG ((DEBUG_INFO,\r
- " IOAPIC\n"\r
- ));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:\r
- DEBUG ((DEBUG_INFO,\r
- " MSI Capable HPET\n"\r
- ));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:\r
- DEBUG ((DEBUG_INFO,\r
- " ACPI Namespace Device\n"\r
- ));\r
- break;\r
- default:\r
- break;\r
- }\r
- DEBUG ((DEBUG_INFO,\r
- " Length ............................................. 0x%02x\n",\r
- DmarDeviceScopeEntry->Length\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Enumeration ID ..................................... 0x%02x\n",\r
- DmarDeviceScopeEntry->EnumerationId\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Starting Bus Number ................................ 0x%02x\n",\r
- DmarDeviceScopeEntry->StartBusNumber\r
- ));\r
-\r
- PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);\r
- PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);\r
- for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {\r
- DEBUG ((DEBUG_INFO,\r
- " Device ............................................. 0x%02x\n",\r
- PciPath[PciPathIndex].Device\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Function ........................................... 0x%02x\n",\r
- PciPath[PciPathIndex].Function\r
- ));\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " *************************************************************************\n\n"\r
- ));\r
-\r
- return;\r
-}\r
-\r
-/**\r
- Dump DMAR ANDD table.\r
-\r
- @param[in] Andd DMAR ANDD table\r
-**/\r
-VOID\r
-DumpDmarAndd (\r
- IN EFI_ACPI_DMAR_ANDD_HEADER *Andd\r
- )\r
-{\r
- if (Andd == NULL) {\r
- return;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " * ACPI Name-space Device Declaration Structure *\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- (sizeof(UINTN) == sizeof(UINT64)) ?\r
- " ANDD address ........................................... 0x%016lx\n" :\r
- " ANDD address ........................................... 0x%08x\n",\r
- Andd\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Type ................................................. 0x%04x\n",\r
- Andd->Header.Type\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Length ............................................... 0x%04x\n",\r
- Andd->Header.Length\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ACPI Device Number ................................... 0x%02x\n",\r
- Andd->AcpiDeviceNumber\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ACPI Object Name ..................................... '%a'\n",\r
- (Andd + 1)\r
- ));\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n\n"\r
- ));\r
-\r
- return;\r
-}\r
-\r
-/**\r
- Dump DMAR RHSA table.\r
-\r
- @param[in] Rhsa DMAR RHSA table\r
-**/\r
-VOID\r
-DumpDmarRhsa (\r
- IN EFI_ACPI_DMAR_RHSA_HEADER *Rhsa\r
- )\r
-{\r
- if (Rhsa == NULL) {\r
- return;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " * Remapping Hardware Status Affinity Structure *\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- (sizeof(UINTN) == sizeof(UINT64)) ?\r
- " RHSA address ........................................... 0x%016lx\n" :\r
- " RHSA address ........................................... 0x%08x\n",\r
- Rhsa\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Type ................................................. 0x%04x\n",\r
- Rhsa->Header.Type\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Length ............................................... 0x%04x\n",\r
- Rhsa->Header.Length\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Register Base Address ................................ 0x%016lx\n",\r
- Rhsa->RegisterBaseAddress\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Proximity Domain ..................................... 0x%08x\n",\r
- Rhsa->ProximityDomain\r
- ));\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n\n"\r
- ));\r
-\r
- return;\r
-}\r
-\r
-/**\r
- Dump DMAR ATSR table.\r
-\r
- @param[in] Atsr DMAR ATSR table\r
-**/\r
-VOID\r
-DumpDmarAtsr (\r
- IN EFI_ACPI_DMAR_ATSR_HEADER *Atsr\r
- )\r
-{\r
- EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
- INTN AtsrLen;\r
-\r
- if (Atsr == NULL) {\r
- return;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " * Root Port ATS Capability Reporting Structure *\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- (sizeof(UINTN) == sizeof(UINT64)) ?\r
- " ATSR address ........................................... 0x%016lx\n" :\r
- " ATSR address ........................................... 0x%08x\n",\r
- Atsr\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Type ................................................. 0x%04x\n",\r
- Atsr->Header.Type\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Length ............................................... 0x%04x\n",\r
- Atsr->Header.Length\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Flags ................................................ 0x%02x\n",\r
- Atsr->Flags\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ALL_PORTS .......................................... 0x%02x\n",\r
- Atsr->Flags & EFI_ACPI_DMAR_ATSR_FLAGS_ALL_PORTS\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Segment Number ....................................... 0x%04x\n",\r
- Atsr->SegmentNumber\r
- ));\r
-\r
- AtsrLen = Atsr->Header.Length - sizeof(EFI_ACPI_DMAR_ATSR_HEADER);\r
- DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Atsr + 1);\r
- while (AtsrLen > 0) {\r
- DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
- AtsrLen -= DmarDeviceScopeEntry->Length;\r
- DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n\n"\r
- ));\r
-\r
- return;\r
-}\r
-\r
-/**\r
- Dump DMAR RMRR table.\r
-\r
- @param[in] Rmrr DMAR RMRR table\r
-**/\r
-VOID\r
-DumpDmarRmrr (\r
- IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr\r
- )\r
-{\r
- EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
- INTN RmrrLen;\r
-\r
- if (Rmrr == NULL) {\r
- return;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " * Reserved Memory Region Reporting Structure *\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- (sizeof(UINTN) == sizeof(UINT64)) ?\r
- " RMRR address ........................................... 0x%016lx\n" :\r
- " RMRR address ........................................... 0x%08x\n",\r
- Rmrr\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Type ................................................. 0x%04x\n",\r
- Rmrr->Header.Type\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Length ............................................... 0x%04x\n",\r
- Rmrr->Header.Length\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Segment Number ....................................... 0x%04x\n",\r
- Rmrr->SegmentNumber\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Reserved Memory Region Base Address .................. 0x%016lx\n",\r
- Rmrr->ReservedMemoryRegionBaseAddress\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Reserved Memory Region Limit Address ................. 0x%016lx\n",\r
- Rmrr->ReservedMemoryRegionLimitAddress\r
- ));\r
-\r
- RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);\r
- DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);\r
- while (RmrrLen > 0) {\r
- DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
- RmrrLen -= DmarDeviceScopeEntry->Length;\r
- DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n\n"\r
- ));\r
-\r
- return;\r
-}\r
-\r
-/**\r
- Dump DMAR DRHD table.\r
-\r
- @param[in] Drhd DMAR DRHD table\r
-**/\r
-VOID\r
-DumpDmarDrhd (\r
- IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd\r
- )\r
-{\r
- EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
- INTN DrhdLen;\r
-\r
- if (Drhd == NULL) {\r
- return;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " * DMA-Remapping Hardware Definition Structure *\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- (sizeof(UINTN) == sizeof(UINT64)) ?\r
- " DRHD address ........................................... 0x%016lx\n" :\r
- " DRHD address ........................................... 0x%08x\n",\r
- Drhd\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Type ................................................. 0x%04x\n",\r
- Drhd->Header.Type\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Length ............................................... 0x%04x\n",\r
- Drhd->Header.Length\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Flags ................................................ 0x%02x\n",\r
- Drhd->Flags\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " INCLUDE_PCI_ALL .................................... 0x%02x\n",\r
- Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Segment Number ....................................... 0x%04x\n",\r
- Drhd->SegmentNumber\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Register Base Address ................................ 0x%016lx\n",\r
- Drhd->RegisterBaseAddress\r
- ));\r
-\r
- DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);\r
- DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);\r
- while (DrhdLen > 0) {\r
- DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
- DrhdLen -= DmarDeviceScopeEntry->Length;\r
- DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n\n"\r
- ));\r
-\r
- return;\r
-}\r
-\r
-/**\r
- Dump DMAR ACPI table.\r
-\r
- @param[in] Dmar DMAR ACPI table\r
-**/\r
-VOID\r
-DumpAcpiDMAR (\r
- IN EFI_ACPI_DMAR_HEADER *Dmar\r
- )\r
-{\r
- EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
- INTN DmarLen;\r
-\r
- if (Dmar == NULL) {\r
- return;\r
- }\r
-\r
- //\r
- // Dump Dmar table\r
- //\r
- DEBUG ((DEBUG_INFO,\r
- "*****************************************************************************\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- "* DMAR Table *\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- "*****************************************************************************\n"\r
- ));\r
-\r
- DEBUG ((DEBUG_INFO,\r
- (sizeof(UINTN) == sizeof(UINT64)) ?\r
- "DMAR address ............................................. 0x%016lx\n" :\r
- "DMAR address ............................................. 0x%08x\n",\r
- Dmar\r
- ));\r
-\r
- DEBUG ((DEBUG_INFO,\r
- " Table Contents:\n"\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Host Address Width ................................... 0x%02x\n",\r
- Dmar->HostAddressWidth\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " Flags ................................................ 0x%02x\n",\r
- Dmar->Flags\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " INTR_REMAP ......................................... 0x%02x\n",\r
- Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP\r
- ));\r
- DEBUG ((DEBUG_INFO,\r
- " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",\r
- Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT\r
- ));\r
-\r
- DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);\r
- while (DmarLen > 0) {\r
- switch (DmarHeader->Type) {\r
- case EFI_ACPI_DMAR_TYPE_DRHD:\r
- DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
- break;\r
- case EFI_ACPI_DMAR_TYPE_RMRR:\r
- DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
- break;\r
- case EFI_ACPI_DMAR_TYPE_ATSR:\r
- DumpDmarAtsr ((EFI_ACPI_DMAR_ATSR_HEADER *)DmarHeader);\r
- break;\r
- case EFI_ACPI_DMAR_TYPE_RHSA:\r
- DumpDmarRhsa ((EFI_ACPI_DMAR_RHSA_HEADER *)DmarHeader);\r
- break;\r
- case EFI_ACPI_DMAR_TYPE_ANDD:\r
- DumpDmarAndd ((EFI_ACPI_DMAR_ANDD_HEADER *)DmarHeader);\r
- break;\r
- default:\r
- break;\r
- }\r
- DmarLen -= DmarHeader->Length;\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,\r
- "*****************************************************************************\n\n"\r
- ));\r
-\r
- return;\r
-}\r
-\r
-/**\r
- Dump DMAR ACPI table.\r
-**/\r
-VOID\r
-VtdDumpDmarTable (\r
- VOID\r
- )\r
-{\r
- DumpAcpiDMAR ((EFI_ACPI_DMAR_HEADER *)(UINTN)mAcpiDmarTable);\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
- EFI_ACPI_DMAR_PCI_PATH *DmarPciPath;\r
- UINT8 MyBus;\r
- UINT8 MyDevice;\r
- UINT8 MyFunction;\r
-\r
- DmarPciPath = (EFI_ACPI_DMAR_PCI_PATH *)((UINTN)(DmarDevScopeEntry + 1));\r
- MyBus = DmarDevScopeEntry->StartBusNumber;\r
- MyDevice = DmarPciPath->Device;\r
- MyFunction = DmarPciPath->Function;\r
-\r
- switch (DmarDevScopeEntry->Type) {\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
- while ((UINTN)DmarPciPath + sizeof(EFI_ACPI_DMAR_PCI_PATH) < (UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length) {\r
- MyBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, MyBus, MyDevice, MyFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
- DmarPciPath ++;\r
- MyDevice = DmarPciPath->Device;\r
- MyFunction = DmarPciPath->Function;\r
- }\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:\r
- break;\r
- }\r
-\r
- *Bus = MyBus;\r
- *Device = MyDevice;\r
- *Function = MyFunction;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Process DMAR DHRD table.\r
-\r
- @param[in] VtdIndex The index of VTd engine.\r
- @param[in] DmarDrhd The DRHD table.\r
-\r
- @retval EFI_SUCCESS The DRHD table is processed.\r
-**/\r
-EFI_STATUS\r
-ProcessDhrd (\r
- IN UINTN VtdIndex,\r
- IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd\r
- )\r
-{\r
- EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;\r
- UINT8 Bus;\r
- UINT8 Device;\r
- UINT8 Function;\r
- UINT8 SecondaryBusNumber;\r
- EFI_STATUS Status;\r
- VTD_SOURCE_ID SourceId;\r
-\r
- mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress = (UINTN)DmarDrhd->RegisterBaseAddress;\r
- DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));\r
-\r
- mVtdUnitInformation[VtdIndex].Segment = DmarDrhd->SegmentNumber;\r
-\r
- if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0) {\r
- mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = TRUE;\r
- DEBUG ((DEBUG_INFO," ProcessDhrd: with INCLUDE ALL\n"));\r
-\r
- Status = ScanPciBus((VOID *)VtdIndex, DmarDrhd->SegmentNumber, 0, ScanBusCallbackRegisterPciDevice);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } else {\r
- mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = FALSE;\r
- DEBUG ((DEBUG_INFO," ProcessDhrd: without INCLUDE ALL\n"));\r
- }\r
-\r
- DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));\r
- while ((UINTN)DmarDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {\r
-\r
- Status = GetPciBusDeviceFunction (DmarDrhd->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO," ProcessDhrd: "));\r
- switch (DmarDevScopeEntry->Type) {\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
- DEBUG ((DEBUG_INFO,"PCI Endpoint"));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
- DEBUG ((DEBUG_INFO,"PCI-PCI bridge"));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:\r
- DEBUG ((DEBUG_INFO,"IOAPIC"));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:\r
- DEBUG ((DEBUG_INFO,"MSI Capable HPET"));\r
- break;\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:\r
- DEBUG ((DEBUG_INFO,"ACPI Namespace Device"));\r
- break;\r
- }\r
- DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", DmarDrhd->SegmentNumber, Bus, Device, Function));\r
-\r
- SourceId.Bits.Bus = Bus;\r
- SourceId.Bits.Device = Device;\r
- SourceId.Bits.Function = Function;\r
-\r
- Status = RegisterPciDevice (VtdIndex, DmarDrhd->SegmentNumber, SourceId, DmarDevScopeEntry->Type, TRUE);\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // There might be duplication for special device other than standard PCI device.\r
- //\r
- switch (DmarDevScopeEntry->Type) {\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
- return Status;\r
- }\r
- }\r
-\r
- switch (DmarDevScopeEntry->Type) {\r
- case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
- SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DmarDrhd->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
- Status = ScanPciBus ((VOID *)VtdIndex, DmarDrhd->SegmentNumber, SecondaryBusNumber, ScanBusCallbackRegisterPciDevice);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Process DMAR RMRR table.\r
-\r
- @param[in] DmarRmrr The RMRR table.\r
-\r
- @retval EFI_SUCCESS The RMRR table is processed.\r
-**/\r
-EFI_STATUS\r
-ProcessRmrr (\r
- IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr\r
- )\r
-{\r
- EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;\r
- UINT8 Bus;\r
- UINT8 Device;\r
- UINT8 Function;\r
- EFI_STATUS Status;\r
- VTD_SOURCE_ID SourceId;\r
-\r
- DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));\r
-\r
- DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));\r
- while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {\r
- if (DmarDevScopeEntry->Type != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {\r
- DEBUG ((DEBUG_INFO,"RMRR DevScopeEntryType is not endpoint, type[0x%x] \n", DmarDevScopeEntry->Type));\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- Status = GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO,"RMRR S%04x B%02x D%02x F%02x\n", DmarRmrr->SegmentNumber, Bus, Device, Function));\r
-\r
- SourceId.Bits.Bus = Bus;\r
- SourceId.Bits.Device = Device;\r
- SourceId.Bits.Function = Function;\r
- Status = SetAccessAttribute (\r
- DmarRmrr->SegmentNumber,\r
- SourceId,\r
- DmarRmrr->ReservedMemoryRegionBaseAddress,\r
- DmarRmrr->ReservedMemoryRegionLimitAddress + 1 - DmarRmrr->ReservedMemoryRegionBaseAddress,\r
- EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Get VTd engine number.\r
-**/\r
-UINTN\r
-GetVtdEngineNumber (\r
- VOID\r
- )\r
-{\r
- EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
- UINTN VtdIndex;\r
-\r
- VtdIndex = 0;\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
- while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
- switch (DmarHeader->Type) {\r
- case EFI_ACPI_DMAR_TYPE_DRHD:\r
- VtdIndex++;\r
- break;\r
- default:\r
- break;\r
- }\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
- }\r
- return VtdIndex ;\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
- EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
- EFI_STATUS Status;\r
- UINTN VtdIndex;\r
-\r
- mVtdUnitNumber = GetVtdEngineNumber ();\r
- DEBUG ((DEBUG_INFO," VtdUnitNumber - %d\n", mVtdUnitNumber));\r
- ASSERT (mVtdUnitNumber > 0);\r
- if (mVtdUnitNumber == 0) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- mVtdUnitInformation = AllocateZeroPool (sizeof(*mVtdUnitInformation) * mVtdUnitNumber);\r
- ASSERT (mVtdUnitInformation != NULL);\r
- if (mVtdUnitInformation == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- mVtdHostAddressWidthMask = LShiftU64 (1ull, mAcpiDmarTable->HostAddressWidth) - 1;\r
-\r
- VtdIndex = 0;\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
- while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
- switch (DmarHeader->Type) {\r
- case EFI_ACPI_DMAR_TYPE_DRHD:\r
- ASSERT (VtdIndex < mVtdUnitNumber);\r
- Status = ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- VtdIndex++;\r
-\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
- }\r
- ASSERT (VtdIndex == mVtdUnitNumber);\r
-\r
- for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
- DumpPciDeviceInfo (VtdIndex);\r
- }\r
- return EFI_SUCCESS ;\r
-}\r
-\r
-/**\r
- Parse DMAR DRHD table.\r
-\r
- @return EFI_SUCCESS The DMAR DRHD table is parsed.\r
-**/\r
-EFI_STATUS\r
-ParseDmarAcpiTableRmrr (\r
- VOID\r
- )\r
-{\r
- EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
- EFI_STATUS Status;\r
-\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
- while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
- switch (DmarHeader->Type) {\r
- case EFI_ACPI_DMAR_TYPE_RMRR:\r
- Status = ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
- }\r
- return EFI_SUCCESS ;\r
-}\r
-\r
-/**\r
- This function scan ACPI table in RSDT.\r
-\r
- @param[in] Rsdt ACPI RSDT\r
- @param[in] Signature ACPI table signature\r
-\r
- @return ACPI table\r
-**/\r
-VOID *\r
-ScanTableInRSDT (\r
- IN RSDT_TABLE *Rsdt,\r
- IN UINT32 Signature\r
- )\r
-{\r
- UINTN Index;\r
- UINT32 EntryCount;\r
- UINT32 *EntryPtr;\r
- EFI_ACPI_DESCRIPTION_HEADER *Table;\r
-\r
- EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);\r
-\r
- EntryPtr = &Rsdt->Entry;\r
- for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {\r
- Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));\r
- if (Table->Signature == Signature) {\r
- return Table;\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- This function scan ACPI table in XSDT.\r
-\r
- @param[in] Xsdt ACPI XSDT\r
- @param[in] Signature ACPI table signature\r
-\r
- @return ACPI table\r
-**/\r
-VOID *\r
-ScanTableInXSDT (\r
- IN XSDT_TABLE *Xsdt,\r
- IN UINT32 Signature\r
- )\r
-{\r
- UINTN Index;\r
- UINT32 EntryCount;\r
- UINT64 EntryPtr;\r
- UINTN BasePtr;\r
- EFI_ACPI_DESCRIPTION_HEADER *Table;\r
-\r
- EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);\r
-\r
- BasePtr = (UINTN)(&(Xsdt->Entry));\r
- for (Index = 0; Index < EntryCount; Index ++) {\r
- CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));\r
- Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr));\r
- if (Table->Signature == Signature) {\r
- return Table;\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- This function scan ACPI table in RSDP.\r
-\r
- @param[in] Rsdp ACPI RSDP\r
- @param[in] Signature ACPI table signature\r
-\r
- @return ACPI table\r
-**/\r
-VOID *\r
-FindAcpiPtr (\r
- IN EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp,\r
- IN UINT32 Signature\r
- )\r
-{\r
- EFI_ACPI_DESCRIPTION_HEADER *AcpiTable;\r
- RSDT_TABLE *Rsdt;\r
- XSDT_TABLE *Xsdt;\r
-\r
- AcpiTable = NULL;\r
-\r
- //\r
- // Check ACPI2.0 table\r
- //\r
- Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;\r
- Xsdt = NULL;\r
- if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {\r
- Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress;\r
- }\r
- //\r
- // Check Xsdt\r
- //\r
- if (Xsdt != NULL) {\r
- AcpiTable = ScanTableInXSDT (Xsdt, Signature);\r
- }\r
- //\r
- // Check Rsdt\r
- //\r
- if ((AcpiTable == NULL) && (Rsdt != NULL)) {\r
- AcpiTable = ScanTableInRSDT (Rsdt, Signature);\r
- }\r
-\r
- return AcpiTable;\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
- VOID *AcpiTable;\r
- EFI_STATUS Status;\r
-\r
- AcpiTable = NULL;\r
- Status = EfiGetSystemConfigurationTable (\r
- &gEfiAcpi20TableGuid,\r
- &AcpiTable\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EfiGetSystemConfigurationTable (\r
- &gEfiAcpiTableGuid,\r
- &AcpiTable\r
- );\r
- }\r
- ASSERT (AcpiTable != NULL);\r
-\r
- mAcpiDmarTable = FindAcpiPtr (\r
- (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable,\r
- EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE\r
- );\r
- DEBUG ((DEBUG_INFO,"DMAR Table - 0x%08x\n", mAcpiDmarTable));\r
- if (mAcpiDmarTable == NULL) {\r
- return EFI_UNSUPPORTED;\r
- }\r
- VtdDumpDmarTable();\r
-\r
- return EFI_SUCCESS;\r
-}\r
+++ /dev/null
-/** @file\r
- Intel VTd driver.\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
-#include <PiDxe.h>\r
-\r
-#include <Protocol/IoMmu.h>\r
-#include <Protocol/PciIo.h>\r
-\r
-#include <Library/IoLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\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