/** Always enable the VTd page attribute for the device in the DeviceScope. @param[in] DeviceScope the input device scope data structure @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope. **/ EFI_STATUS AlwaysEnablePageAttributeDeviceScope ( IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope ) { UINT8 Bus; UINT8 Device; UINT8 Function; VTD_SOURCE_ID SourceId; UINT8 SecondaryBusNumber; EFI_STATUS Status; Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function); if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) { // // Need scan the bridge and add all devices. // SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute); return Status; } else { SourceId.Bits.Bus = Bus; SourceId.Bits.Device = Device; SourceId.Bits.Function = Function; Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId); return Status; } }
/** Scan PCI bus and invoke callback function for each PCI devices under the bus. @param[in] Context The context of the callback function. @param[in] Segment The segment of the source. @param[in] Bus The bus of the source. @param[in] Callback The callback function in PCI scan. @retval EFI_SUCCESS The PCI devices under the bus are scaned. **/ EFI_STATUS ScanPciBus ( IN VOID *Context, IN UINT16 Segment, IN UINT8 Bus, IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback ) { UINT8 Device; UINT8 Function; UINT8 SecondaryBusNumber; UINT8 HeaderType; UINT8 BaseClass; UINT8 SubClass; UINT32 MaxFunction; UINT16 VendorID; UINT16 DeviceID; EFI_STATUS Status; // Scan the PCI bus for devices for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) { HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET)); MaxFunction = PCI_MAX_FUNC + 1; if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) { MaxFunction = 1; } for (Function = 0; Function < MaxFunction; Function++) { VendorID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET)); DeviceID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET)); if (VendorID == 0xFFFF && DeviceID == 0xFFFF) { continue; } Status = Callback (Context, Segment, Bus, Device, Function); if (EFI_ERROR (Status)) { return Status; } BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2)); if (BaseClass == PCI_CLASS_BRIDGE) { SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1)); if (SubClass == PCI_CLASS_BRIDGE_P2P) { SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber)); if (SecondaryBusNumber != 0) { Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback); if (EFI_ERROR (Status)) { return Status; } } } } } } return EFI_SUCCESS; }
/** This function scan PCI bus. @param VtdIndex VTd engine index @param Bus Pci bus @retval EFI_SUCCESS scan PCI bus successfully. **/ EFI_STATUS ScanPciBus ( IN UINTN VtdIndex, IN UINT8 Bus ) { UINT8 Device; UINT8 Function; UINT8 SecondaryBusNumber; UINT8 HeaderType; UINT8 BaseClass; UINT8 SubClass; UINT32 MaxFunction; UINT16 VendorID; UINT16 DeviceID; EFI_STATUS Status; // Scan the PCI bus for devices for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) { HeaderType = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, 0, PCI_HEADER_TYPE_OFFSET)); MaxFunction = PCI_MAX_FUNC + 1; if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) { MaxFunction = 1; } for (Function = 0; Function < MaxFunction; Function++) { VendorID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_VENDOR_ID_OFFSET)); DeviceID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_DEVICE_ID_OFFSET)); if (VendorID == 0xFFFF && DeviceID == 0xFFFF) { continue; } Status = RegisterPciDevice (VtdIndex, Bus, Device, Function, FALSE); if (EFI_ERROR (Status)) { return Status; } BaseClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2)); if (BaseClass == PCI_CLASS_BRIDGE) { SubClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1)); if (SubClass == PCI_CLASS_BRIDGE_P2P) { SecondaryBusNumber = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); DEBUG ((EFI_D_INFO," ScanPciBus: PCI bridge B%02x D%02x F%02x (SecondBus:%02x)\n", Bus, Device, Function, SecondaryBusNumber)); if (SecondaryBusNumber != 0) { ScanPciBus (VtdIndex, SecondaryBusNumber); } } } } } return EFI_SUCCESS; }
EFI_STATUS ScanPciRootBridgeForRoms( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev ) { EFI_STATUS Status; EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; UINT16 MinBus; UINT16 MaxBus; UINT64 RootWindowBase; UINT64 RootWindowLimit; PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context; if (mPciOptionRomTableInstalled == FALSE) { gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable); mPciOptionRomTableInstalled = TRUE; } Status = IoDev->Configuration(IoDev, (VOID **)&Descriptors); if (EFI_ERROR (Status) || Descriptors == NULL) { return EFI_NOT_FOUND; } MinBus = 0xffff; MaxBus = 0xffff; RootWindowBase = 0; RootWindowLimit = 0; while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { // // Find bus range // if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { MinBus = (UINT16)Descriptors->AddrRangeMin; MaxBus = (UINT16)Descriptors->AddrRangeMax; } // // Find memory descriptors that are not prefetchable // if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) { // // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices // if (Descriptors->AddrRangeMax < 0x100000000ULL) { // // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB // if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) { RootWindowBase = Descriptors->AddrRangeMin; RootWindowLimit = Descriptors->AddrRangeMax; } } } Descriptors ++; } // // Make sure a bus range was found // if (MinBus == 0xffff || MaxBus == 0xffff) { return EFI_NOT_FOUND; } // // Make sure a non-prefetchable memory region was found // if (RootWindowBase == 0 && RootWindowLimit == 0) { return EFI_NOT_FOUND; } // // Round the Base and Limit values to 1 MB boudaries // RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000; RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1; // // Make sure that the size of the rounded window is greater than zero // if (RootWindowLimit <= RootWindowBase) { return EFI_NOT_FOUND; } // // Allocate buffer to save the Command register from all the PCI devices // Context.CommandRegisterBuffer = NULL; Status = gBS->AllocatePool( EfiBootServicesData, sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1), (VOID **)&Context.CommandRegisterBuffer ); if (EFI_ERROR (Status)) { return Status; } Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000); // // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits // ScanPciBus( IoDev, MinBus, MaxBus, 0, PCI_MAX_DEVICE, 0, PCI_MAX_FUNC, SaveCommandRegister, &Context ); // // Recursively scan all the busses for PCI Option ROMs // ScanPciBus( IoDev, MinBus, MinBus, 0, PCI_MAX_DEVICE, 0, PCI_MAX_FUNC, CheckForRom, &Context ); // // Restore the Command register in all the PCI devices // ScanPciBus( IoDev, MinBus, MaxBus, 0, PCI_MAX_DEVICE, 0, PCI_MAX_FUNC, RestoreCommandRegister, &Context ); // // Free the buffer used to save all the Command register values // gBS->FreePool(Context.CommandRegisterBuffer); return EFI_SUCCESS; }
VOID CheckForRom ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, UINT16 MinBus, UINT16 MaxBus, UINT16 MinDevice, UINT16 MaxDevice, UINT16 MinFunc, UINT16 MaxFunc, UINT16 Bus, UINT16 Device, UINT16 Func, IN VOID *VoidContext ) { EFI_STATUS Status; PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; UINT64 Address; PCI_TYPE00 PciHeader; PCI_TYPE01 *PciBridgeHeader; UINT32 Register; UINT32 RomBar; UINT32 RomBarSize; EFI_PHYSICAL_ADDRESS RomBuffer; UINT32 MaxRomSize; EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader; PCI_DATA_STRUCTURE Pcir; EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors; BOOLEAN LastImage; Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); // // Save the contents of the PCI Configuration Header // IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); if (IS_PCI_BRIDGE(&PciHeader)) { PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader); // // See if the PCI-PCI Bridge has its secondary interface enabled. // if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) { // // Disable the Prefetchable Memory Window // Register = 0x00000000; IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register); IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register); Register = 0xffffffff; IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register); IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register); // // Program Memory Window to the PCI Root Bridge Memory Window // IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow); // // Enable the Memory decode for the PCI-PCI Bridge // IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); Register |= 0x02; IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); // // Recurse on the Secondary Bus Number // ScanPciBus( IoDev, PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, 0, PCI_MAX_DEVICE, 0, PCI_MAX_FUNC, CheckForRom, Context ); } } else { // // Check if an Option ROM Register is present and save the Option ROM Window Register // RomBar = 0xffffffff; IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); RomBarSize = (~(RomBar & 0xfffff800)) + 1; // // Make sure the size of the ROM is between 0 and 16 MB // if (RomBarSize > 0 && RomBarSize <= 0x01000000) { // // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window // RomBar = (Context->PpbMemoryWindow & 0xffff) << 16; RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize; if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) { MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar; RomBar = RomBar + 1; IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); RomBar = RomBar - 1; // // Enable the Memory decode for the PCI Device // IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); Register |= 0x02; IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); // // Follow the chain of images to determine the size of the Option ROM present // Keep going until the last image is found by looking at the Indicator field // or the size of an image is 0, or the size of all the images is bigger than the // size of the window programmed into the PPB. // RomBarSize = 0; do { LastImage = TRUE; ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader)); IoDev->Mem.Read ( IoDev, EfiPciWidthUint8, RomBar + RomBarSize, sizeof(EfiRomHeader), &EfiRomHeader ); Pcir.ImageLength = 0; if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE && EfiRomHeader.PcirOffset != 0 && (EfiRomHeader.PcirOffset & 3) == 0 && RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) { ZeroMem (&Pcir, sizeof(Pcir)); IoDev->Mem.Read ( IoDev, EfiPciWidthUint8, RomBar + RomBarSize + EfiRomHeader.PcirOffset, sizeof(Pcir), &Pcir ); if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) { break; } if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) { break; } if ((Pcir.Indicator & 0x80) == 0x00) { LastImage = FALSE; } RomBarSize += Pcir.ImageLength * 512; } } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0); if (RomBarSize > 0) { // // Allocate a memory buffer for the Option ROM contents. // Status = gBS->AllocatePages( AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(RomBarSize), &RomBuffer ); if (!EFI_ERROR (Status)) { // // Copy the contents of the Option ROM to the memory buffer // IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer); Status = gBS->AllocatePool( EfiBootServicesData, ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR), (VOID*)&TempPciOptionRomDescriptors ); if (mPciOptionRomTable.PciOptionRomCount > 0) { CopyMem( TempPciOptionRomDescriptors, mPciOptionRomTable.PciOptionRomDescriptors, (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR) ); gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors); } mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]); TempPciOptionRomDescriptors->RomAddress = RomBuffer; TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData; TempPciOptionRomDescriptors->RomLength = RomBarSize; TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber; TempPciOptionRomDescriptors->Bus = (UINT8)Bus; TempPciOptionRomDescriptors->Dev = (UINT8)Device; TempPciOptionRomDescriptors->Func = (UINT8)Func; TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE; TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE; mPciOptionRomTable.PciOptionRomCount++; } } // // Disable the Memory decode for the PCI-PCI Bridge // IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); Register &= (~0x02); IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); } } } // // Restore the PCI Configuration Header // IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); }