--- /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 descriptor.\r
+\r
+ @param[in] VtdIndex The index used to identify a VTd engine.\r
+ @param[in] Segment The Segment used to identify a VTd engine.\r
+ @param[in] SourceId The SourceId used to identify a VTd engine and table entry.\r
+\r
+ @return The index of the PCI descriptor.\r
+ @retval (UINTN)-1 The PCI descriptor is not found.\r
+**/\r
+UINTN\r
+GetPciDescriptor (\r
+ IN UINTN VtdIndex,\r
+ IN UINT16 Segment,\r
+ IN VTD_SOURCE_ID SourceId\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
+ return (UINTN)-1;\r
+ }\r
+\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
+ if ((mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus == SourceId.Bits.Bus) &&\r
+ (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device == SourceId.Bits.Device) &&\r
+ (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].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 as PCI descriptor.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] SourceId The SourceId of the source.\r
+ @param[in] IsRealPciDevice TRUE: It is a real PCI device.\r
+ FALSE: It is not a real PCI device.\r
+ @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.\r
+ FALSE: SUCCESS will be returned if the PCI device is registered.\r
+\r
+ @retval EFI_SUCCESS The PCI device is registered.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
+ @retval EFI_ALREADY_STARTED The device is already registered.\r
+**/\r
+EFI_STATUS\r
+RegisterPciDevice (\r
+ IN UINTN VtdIndex,\r
+ IN UINT16 Segment,\r
+ IN VTD_SOURCE_ID SourceId,\r
+ IN BOOLEAN IsRealPciDevice,\r
+ IN BOOLEAN CheckExist\r
+ )\r
+{\r
+ PCI_DEVICE_INFORMATION *PciDeviceInfo;\r
+ VTD_SOURCE_ID *PciDescriptor;\r
+ UINTN PciDescriptorIndex;\r
+ UINTN Index;\r
+ BOOLEAN *NewIsRealPciDevice;\r
+ VTD_SOURCE_ID *NewPciDescriptors;\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
+ PciDescriptorIndex = GetPciDescriptor (Index, Segment, SourceId);\r
+ if (PciDescriptorIndex != (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
+ PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
+ if (PciDescriptorIndex == (UINTN)-1) {\r
+ //\r
+ // Register new\r
+ //\r
+\r
+ if (PciDeviceInfo->PciDescriptorNumber >= PciDeviceInfo->PciDescriptorMaxNumber) {\r
+ //\r
+ // Reallocate\r
+ //\r
+ NewIsRealPciDevice = AllocateZeroPool (sizeof(*NewIsRealPciDevice) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
+ if (NewIsRealPciDevice == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ NewPciDescriptors = AllocateZeroPool (sizeof(*NewPciDescriptors) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
+ if (NewPciDescriptors == NULL) {\r
+ FreePool (NewIsRealPciDevice);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ PciDeviceInfo->PciDescriptorMaxNumber += MAX_PCI_DESCRIPTORS;\r
+ if (PciDeviceInfo->IsRealPciDevice != NULL) {\r
+ CopyMem (NewIsRealPciDevice, PciDeviceInfo->IsRealPciDevice, sizeof(*NewIsRealPciDevice) * PciDeviceInfo->PciDescriptorNumber);\r
+ FreePool (PciDeviceInfo->IsRealPciDevice);\r
+ }\r
+ PciDeviceInfo->IsRealPciDevice = NewIsRealPciDevice;\r
+ if (PciDeviceInfo->PciDescriptors != NULL) {\r
+ CopyMem (NewPciDescriptors, PciDeviceInfo->PciDescriptors, sizeof(*NewPciDescriptors) * PciDeviceInfo->PciDescriptorNumber);\r
+ FreePool (PciDeviceInfo->PciDescriptors);\r
+ }\r
+ PciDeviceInfo->PciDescriptors = NewPciDescriptors;\r
+ }\r
+\r
+ ASSERT (PciDeviceInfo->PciDescriptorNumber < PciDeviceInfo->PciDescriptorMaxNumber);\r
+\r
+ PciDescriptor = &PciDeviceInfo->PciDescriptors[PciDeviceInfo->PciDescriptorNumber];\r
+ PciDescriptor->Bits.Bus = SourceId.Bits.Bus;\r
+ PciDescriptor->Bits.Device = SourceId.Bits.Device;\r
+ PciDescriptor->Bits.Function = SourceId.Bits.Function;\r
+ PciDeviceInfo->IsRealPciDevice[PciDeviceInfo->PciDescriptorNumber] = IsRealPciDevice;\r
+\r
+ PciDeviceInfo->PciDescriptorNumber++;\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
+ if (!IsRealPciDevice) {\r
+ DEBUG ((DEBUG_INFO, " (*)"));\r
+ }\r
+ DEBUG ((DEBUG_INFO, "\n"));\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
+ Scan PCI bus and register PCI devices under the bus.\r
+\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] Segment The segment of the source.\r
+ @param[in] Bus The bus of the source.\r
+\r
+ @retval EFI_SUCCESS The PCI devices under the bus are registered.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
+**/\r
+EFI_STATUS\r
+ScanPciBus (\r
+ IN UINTN VtdIndex,\r
+ IN UINT16 Segment,\r
+ IN UINT8 Bus\r
+ )\r
+{\r
+ 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
+ VTD_SOURCE_ID SourceId;\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
+ SourceId.Bits.Bus = Bus;\r
+ SourceId.Bits.Device = Device;\r
+ SourceId.Bits.Function = Function;\r
+ Status = RegisterPciDevice (VtdIndex, Segment, SourceId, TRUE, FALSE);\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 (VtdIndex, Segment, SecondaryBusNumber);\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.PciDescriptorNumber,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag\r
+ ));\r
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
+ DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",\r
+ mVtdUnitInformation[VtdIndex].Segment,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device,\r
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].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 PCI descriptor.\r
+ @retval (UINTN)-1 The PCI descriptor is not found.\r
+**/\r
+UINTN\r
+FindVtdIndexByPciDevice (\r
+ IN UINT16 Segment,\r
+ IN VTD_SOURCE_ID SourceId,\r
+ OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,\r
+ OUT VTD_CONTEXT_ENTRY **ContextEntry\r
+ )\r
+{\r
+ 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 PciDescriptorIndex;\r
+\r
+ for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
+ if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
+ continue;\r
+ }\r
+\r
+ PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
+ if (PciDescriptorIndex == (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)LShiftU64 (ExtRootEntry->Bits.LowerContextTablePointer, 12) ;\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)LShiftU64 (RootEntry->Bits.ContextTablePointer, 12) ;\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