BOOLEAN NTAPI HalpValidPCISlot(IN PBUS_HANDLER BusHandler, IN PCI_SLOT_NUMBER Slot) { PCI_SLOT_NUMBER MultiSlot; PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; UCHAR HeaderType; //ULONG Device; /* Simple validation */ if (Slot.u.bits.Reserved) return FALSE; if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE; /* Function 0 doesn't need checking */ if (!Slot.u.bits.FunctionNumber) return TRUE; /* Functions 0+ need Multi-Function support, so check the slot */ //Device = Slot.u.bits.DeviceNumber; MultiSlot = Slot; MultiSlot.u.bits.FunctionNumber = 0; /* Send function 0 request to get the header back */ HalpReadPCIConfig(BusHandler, MultiSlot, &HeaderType, FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType), sizeof(UCHAR)); /* Now make sure the header is multi-function */ if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) return FALSE; return TRUE; }
INIT_FUNCTION BOOLEAN NTAPI HalpIsValidPCIDevice(IN PBUS_HANDLER BusHandler, IN PCI_SLOT_NUMBER Slot) { UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH]; PPCI_COMMON_CONFIG PciHeader = (PVOID)DataBuffer; ULONG i; ULONG_PTR Address; /* Read the PCI header */ HalpReadPCIConfig(BusHandler, Slot, PciHeader, 0, PCI_COMMON_HDR_LENGTH); /* Make sure it's a valid device */ if ((PciHeader->VendorID == PCI_INVALID_VENDORID) || (PCI_CONFIGURATION_TYPE(PciHeader) != PCI_DEVICE_TYPE)) { /* Bail out */ return FALSE; } /* Make sure interrupt numbers make sense */ if (((PciHeader->u.type0.InterruptPin) && (PciHeader->u.type0.InterruptPin > 4)) || (PciHeader->u.type0.InterruptLine & 0x70)) { /* Bail out */ return FALSE; } /* Now scan PCI BARs */ for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) { /* Check what kind of address it is */ Address = PciHeader->u.type0.BaseAddresses[i]; if (Address & PCI_ADDRESS_IO_SPACE) { /* Highest I/O port is 65535 */ if (Address > 0xFFFF) return FALSE; } else { /* MMIO should be higher than 0x80000 */ if ((Address > 0xF) && (Address < 0x80000)) return FALSE; } /* Is this a 64-bit address? */ if (!(Address & PCI_ADDRESS_IO_SPACE) && ((Address & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) { /* Check the next-next entry, since this one 64-bits wide */ i++; } } /* Header, interrupt and address data all make sense */ return TRUE; }
INIT_FUNCTION BOOLEAN NTAPI HalpGetPciBridgeConfig(IN ULONG PciType, IN PUCHAR BusCount) { PCI_SLOT_NUMBER PciSlot; ULONG i, j, k; UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH]; PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer; PBUS_HANDLER BusHandler; /* Loop PCI buses */ PciSlot.u.bits.Reserved = 0; for (i = 0; i < *BusCount; i++) { /* Get the bus handler */ BusHandler = HalHandlerForBus(PCIBus, i); /* Loop every device */ for (j = 0; j < PCI_MAX_DEVICES; j++) { /* Loop every function */ PciSlot.u.bits.DeviceNumber = j; for (k = 0; k < PCI_MAX_FUNCTION; k++) { /* Build the final slot structure */ PciSlot.u.bits.FunctionNumber = k; /* Read the configuration information */ HalpReadPCIConfig(BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); /* Skip if this is an invalid function */ if (PciData->VendorID == PCI_INVALID_VENDORID) continue; /* Make sure that this is a PCI bridge or a cardbus bridge */ if (!HalpIsBridgeDevice(PciData)) continue; /* Not supported */ if (!WarningsGiven[2]++) DPRINT1("Your machine has a PCI-to-PCI or CardBUS Bridge. PCI devices may fail!\n"); continue; } } } /* If we exited the loop, then there's no bridge to worry about */ return FALSE; }
ULONG NTAPI HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler, IN ULONG BusNumber, IN PCI_SLOT_NUMBER SlotNumber, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length) { BUS_HANDLER BusHandler; /* Setup fake PCI Bus handler */ RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); BusHandler.BusNumber = BusNumber; /* Read configuration data */ HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length); /* Return length */ return Length; }
BOOLEAN HalpGetPciBridgeConfig ( IN ULONG HwType, IN PUCHAR MaxPciBus ) /*++ Routine Description: Scan the devices on all known pci buses trying to locate any pci to pci bridges. Record the hierarchy for the buses, and which buses have what addressing limits. Arguments: HwType - Configuration type. MaxPciBus - # of PCI buses reported by the bios --*/ { PBUS_HANDLER ChildBus; PPCIPBUSDATA ChildBusData; ULONG d, f, i, j, BusNo; UCHAR Rescan; BOOLEAN FoundDisabledBridge; CONFIGBRIDGE CB; Rescan = 0; FoundDisabledBridge = FALSE; // // Find each bus on a bridge and initialize it's base and limit information // CB.PciData = (PPCI_COMMON_CONFIG) CB.Buffer; CB.SlotNumber.u.bits.Reserved = 0; for (BusNo=0; BusNo < *MaxPciBus; BusNo++) { CB.BusHandler = HalpHandlerForBus (PCIBus, BusNo); CB.BusData = (PPCIPBUSDATA) CB.BusHandler->BusData; for (d = 0; d < PCI_MAX_DEVICES; d++) { CB.SlotNumber.u.bits.DeviceNumber = d; for (f = 0; f < PCI_MAX_FUNCTION; f++) { CB.SlotNumber.u.bits.FunctionNumber = f; // // Read PCI configuration information // HalpReadPCIConfig ( CB.BusHandler, CB.SlotNumber, CB.PciData, 0, PCI_COMMON_HDR_LENGTH ); if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { // next device break; } if (!IsPciBridge (CB.PciData)) { // not a PCI-PCI bridge, next function continue; } if (!(CB.PciData->Command & PCI_ENABLE_BUS_MASTER)) { // this PCI bridge is not enabled - skip it for now FoundDisabledBridge = TRUE; continue; } if ((ULONG) CB.PciData->u.type1.PrimaryBus != CB.BusHandler->BusNumber) { DBGMSG ("HAL GetPciData: bad primarybus!!!\n"); // what to do? } // // Found a PCI-PCI brdige. Determine the PIRQ to bus number // mappings and store them in the HalpPCIBusToPirqTable[]. // for (i = CB.PciData->u.type1.SecondaryBus; i <= CB.PciData->u.type1.SubordinateBus; i++) { HalpPCIBusToPirqTable[i] = HalpPCIPinToLineTable[d]; } // // Found a PCI-PCI bridge. Determine it's parent child // relationships // ChildBus = HalpHandlerForBus (PCIBus, CB.PciData->u.type1.SecondaryBus); if (!ChildBus) { DBGMSG ("HAL GetPciData: found configured pci bridge\n"); // up the number of buses if (CB.PciData->u.type1.SecondaryBus > Rescan) { Rescan = CB.PciData->u.type1.SecondaryBus; } continue; } ChildBusData = (PPCIPBUSDATA) ChildBus->BusData; if (ChildBusData->BridgeConfigRead) { // this child buses releationships already processed continue; } // // Remember the limits which are programmed into this bridge // ChildBusData->BridgeConfigRead = TRUE; HalpSetBusHandlerParent (ChildBus, CB.BusHandler); ChildBusData->ParentBus = (UCHAR) CB.BusHandler->BusNumber; ChildBusData->CommonData.ParentSlot = CB.SlotNumber; ChildBus->BusAddresses->IO.Base = PciBridgeIO2Base( CB.PciData->u.type1.IOBase, CB.PciData->u.type1.IOBaseUpper16 ); ChildBus->BusAddresses->IO.Limit = PciBridgeIO2Limit( CB.PciData->u.type1.IOLimit, CB.PciData->u.type1.IOLimitUpper16 ); // // Special VGA address remapping occuring on this bridge? // if (CB.PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA && ChildBus->BusAddresses->IO.Base < ChildBus->BusAddresses->IO.Limit) { DBGMSG("HAL: VGA mode enable in bridge\n"); HalpSetPciBridgedVgaCronk ( ChildBus->BusNumber, (ULONG) ChildBus->BusAddresses->IO.Base, (ULONG) ChildBus->BusAddresses->IO.Limit ); } // // If supported I/O ranges on this bus are limitied to // 256bytes on every 1K aligned boundry within the // range, then redo supported IO BusAddresses to match // if (CB.PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_ISA && ChildBus->BusAddresses->IO.Base < ChildBus->BusAddresses->IO.Limit) { DBGMSG("HAL: ISA mode enable in bridge\n"); // assume Base is 1K aligned i = (ULONG) ChildBus->BusAddresses->IO.Base; j = (ULONG) ChildBus->BusAddresses->IO.Limit; // convert head entry ChildBus->BusAddresses->IO.Limit = i + 256; i += 1024; // add remaining ranges while (i < j) { HalpAddRange ( &ChildBus->BusAddresses->IO, 1, // address space 0, // system base i, // bus address i + 256 // bus limit ); // next range i += 1024; } } ChildBus->BusAddresses->Memory.Base = PciBridgeMemory2Base(CB.PciData->u.type1.MemoryBase); ChildBus->BusAddresses->Memory.Limit = PciBridgeMemory2Limit(CB.PciData->u.type1.MemoryLimit); // On x86 it's ok to clip Prefetch to 32 bits if (CB.PciData->u.type1.PrefetchBaseUpper32 == 0) { ChildBus->BusAddresses->PrefetchMemory.Base = PciBridgeMemory2Base(CB.PciData->u.type1.PrefetchBase); ChildBus->BusAddresses->PrefetchMemory.Limit = PciBridgeMemory2Limit(CB.PciData->u.type1.PrefetchLimit); if (CB.PciData->u.type1.PrefetchLimitUpper32) { ChildBus->BusAddresses->PrefetchMemory.Limit = (ULONGLONG)0xffffffff; } } // should call HalpAssignPCISlotResources to assign // baseaddresses, etc... } } } if (Rescan) { *MaxPciBus = Rescan; return TRUE; } if (!FoundDisabledBridge) { return FALSE; } DBGMSG ("HAL GetPciData: found disabled pci bridge\n"); return FALSE; }
VOID HalpGetPciBridgeNeeds ( IN ULONG HwType, IN PUCHAR MaxPciBus, IN PCONFIGBRIDGE Current ) { ACCESS_MASK DesiredAccess; UNICODE_STRING unicodeString; PUCHAR buffer; HANDLE handle; OBJECT_ATTRIBUTES objectAttributes; PCM_FULL_RESOURCE_DESCRIPTOR Descriptor; PCONFIGURATION_COMPONENT Component; CONFIGBRIDGE CB; ULONG mnum, d, f; NTSTATUS status; buffer = ExAllocatePool (PagedPool, 1024); // init CB.PciData = (PPCI_COMMON_CONFIG) CB.Buffer; CB.SlotNumber.u.bits.Reserved = 0; Current->IO = Current->Memory = Current->PFMemory = 0; // // Assign this bridge an ID, and turn on configuration space // Current->PciData->u.type1.PrimaryBus = (UCHAR) Current->BusNo; Current->PciData->u.type1.SecondaryBus = (UCHAR) *MaxPciBus; Current->PciData->u.type1.SubordinateBus = (UCHAR) 0xFF; Current->PciData->u.type1.SecondaryStatus = 0xffff; Current->PciData->Status = 0xffff; Current->PciData->Command = 0; Current->PciData->u.type1.BridgeControl = PCI_ASSERT_BRIDGE_RESET; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); KeStallExecutionProcessor (100); Current->PciData->u.type1.BridgeControl = 0; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); KeStallExecutionProcessor (100); // // Allocate new handler for bus // CB.BusHandler = HalpAllocateAndInitPciBusHandler (HwType, *MaxPciBus, FALSE); CB.BusData = (PPCIPBUSDATA) CB.BusHandler->BusData; CB.BusNo = *MaxPciBus; *MaxPciBus += 1; // // Add another PCI bus in the registry // mnum = 0; for (; ;) { // // Find next available MultiFunctionAdapter key // DesiredAccess = KEY_READ | KEY_WRITE; swprintf ((PWCHAR) buffer, L"%s\\%d", rgzMultiFunctionAdapter, mnum); RtlInitUnicodeString (&unicodeString, (PWCHAR) buffer); InitializeObjectAttributes( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL ); status = ZwOpenKey( &handle, DesiredAccess, &objectAttributes); if (!NT_SUCCESS(status)) { break; } // already exists, next ZwClose (handle); mnum += 1; } ZwCreateKey (&handle, DesiredAccess, &objectAttributes, 0, NULL, REG_OPTION_VOLATILE, &d ); // // Add needed registry values for this MultifucntionAdapter entry // RtlInitUnicodeString (&unicodeString, rgzIdentifier); ZwSetValueKey (handle, &unicodeString, 0L, REG_SZ, L"PCI", sizeof (L"PCI") ); RtlInitUnicodeString (&unicodeString, rgzConfigurationData); Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) buffer; Descriptor->InterfaceType = PCIBus; Descriptor->BusNumber = CB.BusNo; Descriptor->PartialResourceList.Version = 0; Descriptor->PartialResourceList.Revision = 0; Descriptor->PartialResourceList.Count = 0; ZwSetValueKey (handle, &unicodeString, 0L, REG_FULL_RESOURCE_DESCRIPTOR, Descriptor, sizeof (*Descriptor) ); RtlInitUnicodeString (&unicodeString, L"Component Information"); Component = (PCONFIGURATION_COMPONENT) buffer; RtlZeroMemory (Component, sizeof (*Component)); Component->AffinityMask = 0xffffffff; ZwSetValueKey (handle, &unicodeString, 0L, REG_BINARY, Component, FIELD_OFFSET (CONFIGURATION_COMPONENT, ConfigurationDataLength) ); ZwClose (handle); // // Since the firmware didn't configure this bridge we'll assume that // the PCI interrupts are bridged. // for (d = 0; d < PCI_MAX_DEVICES; d++) { CB.SlotNumber.u.bits.DeviceNumber = d; for (f = 0; f < PCI_MAX_FUNCTION; f++) { CB.SlotNumber.u.bits.FunctionNumber = f; HalpReadPCIConfig ( Current->BusHandler, CB.SlotNumber, CB.PciData, 0, PCI_COMMON_HDR_LENGTH ); if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { break; } if (CB.PciData->u.type0.InterruptPin && (PCI_CONFIG_TYPE (CB.PciData) == PCI_DEVICE_TYPE || PCI_CONFIG_TYPE (CB.PciData) == PCI_BRIDGE_TYPE)) { // // Get IRQ value from table since firmware // did not initialize the bridge. // Current->PciData->u.type1.InterruptPin = CB.PciData->u.type0.InterruptPin + (UCHAR)d % 4; Current->PciData->u.type1.InterruptLine = HalpPCIPinToLineTable[(CB.BusNo*8) + CB.SlotNumber.u.bits.DeviceNumber]; } } } // // Look at each device on the bus and determine it's resource needs // for (d = 0; d < PCI_MAX_DEVICES; d++) { CB.SlotNumber.u.bits.DeviceNumber = d; for (f = 0; f < PCI_MAX_FUNCTION; f++) { CB.SlotNumber.u.bits.FunctionNumber = f; HalpReadPCIConfig ( CB.BusHandler, CB.SlotNumber, CB.PciData, 0, PCI_COMMON_HDR_LENGTH ); if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { break; } if (IsPciBridge (CB.PciData)) { // oh look - another bridge ... HalpGetPciBridgeNeeds (HwType, MaxPciBus, &CB); continue; } if (PCI_CONFIG_TYPE (CB.PciData) != PCI_DEVICE_TYPE) { continue; } // found a device - figure out the resources it needs } } // // Found all sub-buses set SubordinateBus accordingly // Current->PciData->u.type1.SubordinateBus = (UCHAR) *MaxPciBus - 1; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); // // Set the bridges IO, Memory, and Prefetch Memory windows // // For now just pick some numbers & set everyone the same // IO 0x6000 - 0xFFFF // MEM 0x40000000 - 0x4FFFFFFF // PFMEM 0x50000000 - 0x5FFFFFFF Current->PciData->u.type1.IOBase = 0xD000 >> 12 << 4; Current->PciData->u.type1.IOLimit = 0xffff >> 12 << 4; Current->PciData->u.type1.MemoryBase = 0x0 >> 20 << 4; Current->PciData->u.type1.MemoryLimit = 0x0 >> 20 << 4; Current->PciData->u.type1.PrefetchBase = 0 >> 20 << 4; Current->PciData->u.type1.PrefetchLimit = 0 >> 20 << 4; Current->PciData->u.type1.PrefetchBaseUpper32 = 0; Current->PciData->u.type1.PrefetchLimitUpper32 = 0; Current->PciData->u.type1.IOBaseUpper16 = 0; Current->PciData->u.type1.IOLimitUpper16 = 0; Current->PciData->u.type1.BridgeControl = PCI_ENABLE_BRIDGE_ISA; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); HalpReadPCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); // enable memory & io decodes Current->PciData->Command = PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, &Current->PciData->Command, FIELD_OFFSET (PCI_COMMON_CONFIG, Command), sizeof (Current->PciData->Command) ); ExFreePool (buffer); }
NTSTATUS HalpAdjustPCIResourceList ( IN PBUS_HANDLER BusHandler, IN PBUS_HANDLER RootHandler, IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList ) /*++ Rewrite the callers requested resource list to fit within the supported ranges of this bus --*/ { NTSTATUS Status; PPCIPBUSDATA BusData; PCI_SLOT_NUMBER PciSlot; PSUPPORTED_RANGE Interrupt; PSUPPORTED_RANGE Range; PSUPPORTED_RANGES SupportedRanges; PPCI_COMMON_CONFIG PciData, PciOrigData; UCHAR buffer[PCI_COMMON_HDR_LENGTH]; UCHAR buffer2[PCI_COMMON_HDR_LENGTH]; BOOLEAN UseBusRanges; ULONG i, j, RomIndex, length, ebit; ULONG Base[PCI_TYPE0_ADDRESSES + 1]; PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; BusData = (PPCIPBUSDATA) BusHandler->BusData; PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber); // // Determine PCI device's interrupt restrictions // Status = BusData->GetIrqRange(BusHandler, RootHandler, PciSlot, &Interrupt); if (!NT_SUCCESS(Status)) { return Status; } SupportedRanges = NULL; UseBusRanges = TRUE; Status = STATUS_INSUFFICIENT_RESOURCES; if (HalpPciLockSettings) { PciData = (PPCI_COMMON_CONFIG) buffer; PciOrigData = (PPCI_COMMON_CONFIG) buffer2; HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); // // If this is a device, and it current has its decodes enabled, // then use the currently programmed ranges only // if (PCI_CONFIG_TYPE(PciData) == 0 && (PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE))) { // // Save current settings // RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH); for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { BaseAddress[j] = &PciData->u.type0.BaseAddresses[j]; } BaseAddress[j] = &PciData->u.type0.ROMBaseAddress; RomIndex = j; // // Write all one-bits to determine lengths for each address // for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) { Base[j] = *BaseAddress[j]; *BaseAddress[j] = 0xFFFFFFFF; } PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); *BaseAddress[RomIndex] &= ~PCI_ROMADDRESS_ENABLED; HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); // // restore original settings // HalpWritePCIConfig ( BusHandler, PciSlot, &PciOrigData->Status, FIELD_OFFSET (PCI_COMMON_CONFIG, Status), PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) ); HalpWritePCIConfig ( BusHandler, PciSlot, PciOrigData, 0, FIELD_OFFSET (PCI_COMMON_CONFIG, Status) ); // // Build a memory & io range list of just the ranges already // programmed into the device // UseBusRanges = FALSE; SupportedRanges = HalpAllocateNewRangeList(); if (!SupportedRanges) { goto CleanUp; } *BaseAddress[RomIndex] &= ~PCI_ADDRESS_IO_SPACE; for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) { i = *BaseAddress[j]; if (i & PCI_ADDRESS_IO_SPACE) { length = 1 << 2; Range = &SupportedRanges->IO; ebit = PCI_ENABLE_IO_SPACE; } else { length = 1 << 4; Range = &SupportedRanges->Memory; ebit = PCI_ENABLE_MEMORY_SPACE; if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) { Range = &SupportedRanges->PrefetchMemory; } } Base[j] &= ~(length-1); while (!(i & length) && length) { length <<= 1; } if (j == RomIndex && !(PciOrigData->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED)) { // range not enabled, don't use it length = 0; } if (length) { if (!(PciOrigData->Command & ebit)) { // range not enabled, don't use preprogrammed values UseBusRanges = TRUE; } if (Range->Limit >= Range->Base) { Range->Next = ExAllocatePool (PagedPool, sizeof (SUPPORTED_RANGE)); Range = Range->Next; if (!Range) { goto CleanUp; } Range->Next = NULL; } Range->Base = Base[j]; Range->Limit = Base[j] + length - 1; } if (Is64BitBaseAddress(i)) { // skip upper half of 64 bit address since this processor // only supports 32 bits of address space j++; } } } } // // Adjust resources // Status = HaliAdjustResourceListRange ( UseBusRanges ? BusHandler->BusAddresses : SupportedRanges, Interrupt, pResourceList ); CleanUp: if (SupportedRanges) { HalpFreeRangeList (SupportedRanges); } ExFreePool (Interrupt); return Status; }
BOOLEAN HalpGetPciBridgeConfig ( IN ULONG HwType, IN PUCHAR MaxPciBus ) /*++ Routine Description: Scan the devices on all known pci buses trying to locate any pci to pci bridges. Record the hierarchy for the buses, and which buses have what addressing limits. Arguments: HwType - Configuration type. MaxPciBus - # of PCI buses reported by the bios --*/ { PBUS_HANDLER ChildBus; PPCIPBUSDATA ChildBusData; ULONG d, f, i, j, BusNo; UCHAR Rescan; BOOLEAN FoundDisabledBridge; CONFIGBRIDGE CB; Rescan = 0; FoundDisabledBridge = FALSE; // // Find each bus on a bridge and initialize it's base and limit information // CB.PciData = (PPCI_COMMON_CONFIG) CB.Buffer; CB.SlotNumber.u.bits.Reserved = 0; for (BusNo=0; BusNo < *MaxPciBus; BusNo++) { CB.BusHandler = HalpHandlerForBus (PCIBus, BusNo); CB.BusData = (PPCIPBUSDATA) CB.BusHandler->BusData; for (d = 0; d < PCI_MAX_DEVICES; d++) { CB.SlotNumber.u.bits.DeviceNumber = d; for (f = 0; f < PCI_MAX_FUNCTION; f++) { CB.SlotNumber.u.bits.FunctionNumber = f; // // Read PCI configuration information // HalpReadPCIConfig ( CB.BusHandler, CB.SlotNumber, CB.PciData, 0, PCI_COMMON_HDR_LENGTH ); if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { // next device break; } if (!IsPciBridge (CB.PciData)) { // not a PCI-PCI bridge, next function continue; } if (!(CB.PciData->Command & PCI_ENABLE_BUS_MASTER)) { // this PCI bridge is not enabled - skip it for now FoundDisabledBridge = TRUE; continue; } if ((ULONG) CB.PciData->u.type1.PrimaryBus != CB.BusHandler->BusNumber) { DBGMSG ("HAL GetPciData: bad primarybus!!!\n"); // what to do? } // // Found a PCI-PCI bridge. Determine it's parent child // releationships // ChildBus = HalpHandlerForBus (PCIBus, CB.PciData->u.type1.SecondaryBus); if (!ChildBus) { DBGMSG ("HAL GetPciData: found configured pci bridge\n"); // up the number of buses if (CB.PciData->u.type1.SecondaryBus > Rescan) { //Rescan = CB.PciData->u.type1.SecondaryBus; JAKETEMP Rescan = CB.PciData->u.type1.SecondaryBus + 1; } continue; } ChildBusData = (PPCIPBUSDATA) ChildBus->BusData; if (ChildBusData->BridgeConfigRead) { // this child buses releationships already processed continue; } // // Remember the limits which are programmed into this bridge // ChildBusData->BridgeConfigRead = TRUE; HalpSetBusHandlerParent (ChildBus, CB.BusHandler); ChildBusData->ParentBus = (UCHAR) CB.BusHandler->BusNumber; ChildBusData->CommonData.ParentSlot = CB.SlotNumber; ChildBus->BusAddresses->IO.Base = PciBridgeIO2Base( CB.PciData->u.type1.IOBase, CB.PciData->u.type1.IOBaseUpper16 ); ChildBus->BusAddresses->IO.Limit = PciBridgeIO2Limit( CB.PciData->u.type1.IOLimit, CB.PciData->u.type1.IOLimitUpper16 ); // // Special VGA address remapping occuring on this bridge? // if (CB.PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA && ChildBus->BusAddresses->IO.Base < ChildBus->BusAddresses->IO.Limit) { HalpSetPciBridgedVgaCronk ( ChildBus->BusNumber, (ULONG) ChildBus->BusAddresses->IO.Base, (ULONG) ChildBus->BusAddresses->IO.Limit ); } // // If supported I/O ranges on this bus are limitied to // 256bytes on every 1K aligned boundry within the // range, then redo supported IO BusAddresses to match // if (CB.PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_ISA && ChildBus->BusAddresses->IO.Base < ChildBus->BusAddresses->IO.Limit) { // assume Base is 1K aligned i = (ULONG) ChildBus->BusAddresses->IO.Base; j = (ULONG) ChildBus->BusAddresses->IO.Limit; // convert head entry ChildBus->BusAddresses->IO.Limit = i + 256; i += 1024; // add remaining ranges while (i < j) { HalpAddRange ( &ChildBus->BusAddresses->IO, 1, // address space 0, // system base i, // bus address i + 256 // bus limit ); // next range i += 1024; } } ChildBus->BusAddresses->Memory.Base = PciBridgeMemory2Base(CB.PciData->u.type1.MemoryBase); ChildBus->BusAddresses->Memory.Limit = PciBridgeMemory2Limit(CB.PciData->u.type1.MemoryLimit); // On x86 it's ok to clip Prefetch to 32 bits // BUGBUG This is OK on existing PPCs too, but this may have to change // on later implementations. if (CB.PciData->u.type1.PrefetchBaseUpper32 == 0) { ChildBus->BusAddresses->PrefetchMemory.Base = PciBridgeMemory2Base(CB.PciData->u.type1.PrefetchBase); ChildBus->BusAddresses->PrefetchMemory.Limit = PciBridgeMemory2Limit(CB.PciData->u.type1.PrefetchLimit); if (CB.PciData->u.type1.PrefetchLimitUpper32) { ChildBus->BusAddresses->PrefetchMemory.Limit = 0xffffffff; } } // should call HalpAssignPCISlotResources to assign // baseaddresses, etc... } } } if (Rescan) { *MaxPciBus = Rescan; return TRUE; } if (!FoundDisabledBridge) { return FALSE; } DBGMSG ("HAL GetPciData: found disabled pci bridge\n"); #ifdef INIT_PCI_BRIDGE // // We've calculated all the parent's buses known bases & limits. // While doing this a pci-pci bus was found that the bios didn't // configure. This is not expected, and we'll make some guesses // at a configuration here and enable it. // // (this code is primarily for testing the above code since // currently no system bioses actually configure the child buses) // for (BusNo=0; BusNo < *MaxPciBus; BusNo++) { CB.BusHandler = HalpHandlerForBus (PCIBus, BusNo); CB.BusData = (PPCIPBUSDATA) CB.BusHandler->BusData; for (d = 0; d < PCI_MAX_DEVICES; d++) { CB.SlotNumber.u.bits.DeviceNumber = d; for (f = 0; f < PCI_MAX_FUNCTION; f++) { CB.SlotNumber.u.bits.FunctionNumber = f; HalpReadPCIConfig ( CB.BusHandler, CB.SlotNumber, CB.PciData, 0, PCI_COMMON_HDR_LENGTH ); if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { break; } if (!IsPciBridge (CB.PciData)) { // not a PCI-PCI bridge continue; } if ((CB.PciData->Command & PCI_ENABLE_BUS_MASTER)) { // this PCI bridge is enabled continue; } // // We have a disabled bus - assign it a number, then // determine all the requirements of all devices // on the other side of this bridge // CB.BusNo = BusNo; HalpGetPciBridgeNeeds (HwType, MaxPciBus, &CB); } } } // preform Rescan return TRUE; #else return FALSE; #endif }
NTSTATUS NTAPI HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler, IN PBUS_HANDLER RootHandler, IN PUNICODE_STRING RegistryPath, IN PUNICODE_STRING DriverClassName OPTIONAL, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN ULONG Slot, IN OUT PCM_RESOURCE_LIST *AllocatedResources) { PCI_COMMON_CONFIG PciConfig; SIZE_T Address; ULONG ResourceCount; ULONG Size[PCI_TYPE0_ADDRESSES]; NTSTATUS Status = STATUS_SUCCESS; UCHAR Offset; PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; PCI_SLOT_NUMBER SlotNumber; ULONG WriteBuffer; DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n"); /* FIXME: Should handle 64-bit addresses */ /* Read configuration data */ SlotNumber.u.AsULONG = Slot; HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH); /* Check if we read it correctly */ if (PciConfig.VendorID == PCI_INVALID_VENDORID) return STATUS_NO_SUCH_DEVICE; /* Read the PCI configuration space for the device and store base address and size information in temporary storage. Count the number of valid base addresses */ ResourceCount = 0; for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) { if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address]) PciConfig.u.type0.BaseAddresses[Address] = 0; /* Memory resource */ if (0 != PciConfig.u.type0.BaseAddresses[Address]) { ResourceCount++; Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]); /* Write 0xFFFFFFFF there */ WriteBuffer = 0xffffffff; HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG)); /* Read that figure back from the config space */ HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG)); /* Write back initial value */ HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG)); } } /* Interrupt resource */ if (0 != PciConfig.u.type0.InterruptPin && 0 != PciConfig.u.type0.InterruptLine && 0xFF != PciConfig.u.type0.InterruptLine) ResourceCount++; /* Allocate output buffer and initialize */ *AllocatedResources = ExAllocatePoolWithTag( PagedPool, sizeof(CM_RESOURCE_LIST) + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), TAG_HAL); if (NULL == *AllocatedResources) return STATUS_NO_MEMORY; (*AllocatedResources)->Count = 1; (*AllocatedResources)->List[0].InterfaceType = PCIBus; (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber; (*AllocatedResources)->List[0].PartialResourceList.Version = 1; (*AllocatedResources)->List[0].PartialResourceList.Revision = 1; (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount; Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors; /* Store configuration information */ for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) { if (0 != PciConfig.u.type0.BaseAddresses[Address]) { if (PCI_ADDRESS_MEMORY_SPACE == (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) { Descriptor->Type = CmResourceTypeMemory; Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; /* FIXME Just a guess */ Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK); Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK); } else if (PCI_ADDRESS_IO_SPACE == (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) { Descriptor->Type = CmResourceTypePort; Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ Descriptor->Flags = CM_RESOURCE_PORT_IO; /* FIXME Just a guess */ Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK; Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff); } else { ASSERT(FALSE); return STATUS_UNSUCCESSFUL; } Descriptor++; } } if (0 != PciConfig.u.type0.InterruptPin && 0 != PciConfig.u.type0.InterruptLine && 0xFF != PciConfig.u.type0.InterruptLine) { Descriptor->Type = CmResourceTypeInterrupt; Descriptor->ShareDisposition = CmResourceShareShared; /* FIXME Just a guess */ Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; /* FIXME Just a guess */ Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine; Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine; Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; Descriptor++; } ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount); /* FIXME: Should store the resources in the registry resource map */ return Status; }
ULONG NTAPI HalpSetPCIData(IN PBUS_HANDLER BusHandler, IN PBUS_HANDLER RootHandler, IN PCI_SLOT_NUMBER Slot, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length) { UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH]; PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer; ULONG Len = 0; #ifdef SARCH_XBOX /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely * hang the Xbox. Also, the device number doesn't seem to be decoded for the * video card, so it appears to be present on 1:0:0 - 1:31:0. * We hack around these problems by indicating "device not present" for devices * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */ if ((0 == BusHandler->BusNumber && 0 == Slot.u.bits.DeviceNumber && (1 == Slot.u.bits.FunctionNumber || 2 == Slot.u.bits.FunctionNumber)) || (1 == BusHandler->BusNumber && 0 != Slot.u.bits.DeviceNumber)) { DPRINT1("Trying to set data on blacklisted PCI slot\n"); return 0; } #endif /* Normalize the length */ if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG); /* Check if this is a vendor-specific read */ if (Offset >= PCI_COMMON_HDR_LENGTH) { /* Read the header */ HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG)); /* Make sure the vendor is valid */ if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; } else { /* Read the entire header and validate the vendor ID */ Len = PCI_COMMON_HDR_LENGTH; HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len); if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; /* Return what's after the offset and normalize */ Len -= Offset; if (Len > Length) Len = Length; /* Copy the specific caller data */ RtlMoveMemory(PciBuffer + Offset, Buffer, Len); /* Write the actual configuration data */ HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len); /* Update buffer and offset, decrement total length */ Offset += Len; Buffer = (PVOID)((ULONG_PTR)Buffer + Len); Length -= Len; } /* Now we still have something to copy */ if (Length) { /* Check if it's vendor-specific data */ if (Offset >= PCI_COMMON_HDR_LENGTH) { /* Read it now */ HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length); Len += Length; } } /* Update the total length read */ return Len; }
INIT_FUNCTION VOID NTAPI HalpInitializePciBus(VOID) { #ifndef _MINIHAL_ PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; UCHAR PciType; PCI_SLOT_NUMBER PciSlot; ULONG i, j, k; UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH]; PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer; PBUS_HANDLER BusHandler; ULONG HackFlags; BOOLEAN ExtendedAddressDecoding = FALSE; NTSTATUS Status; /* Query registry information */ PciRegistryInfo = HalpQueryPciRegistryInfo(); if (!PciRegistryInfo) return; /* Initialize the PCI configuration lock */ KeInitializeSpinLock(&HalpPCIConfigLock); /* Get the type and free the info structure */ PciType = PciRegistryInfo->HardwareMechanism & 0xF; /* Check if this is a type 2 PCI bus with at least one bus */ if ((PciRegistryInfo->NoBuses) && (PciType == 2)) { /* Setup the PCI slot */ PciSlot.u.bits.Reserved = 0; PciSlot.u.bits.FunctionNumber = 0; /* Loop all slots */ for (i = 0; i < 32; i++) { /* Try to setup a Type 2 PCI slot */ PciType = 2; BusHandler = HalpAllocateAndInitPciBusHandler(2, 0, TRUE); if (!BusHandler) break; /* Now check if it's valid */ if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break; /* Heh, the BIOS lied... try Type 1 */ PciType = 1; BusHandler = HalpAllocateAndInitPciBusHandler(1, 0, TRUE); if (!BusHandler) break; /* Now check if it's valid */ if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break; /* Keep trying */ PciType = 2; } /* Now allocate the correct kind of handler */ HalpAllocateAndInitPciBusHandler(PciType, 0, FALSE); } /* Okay, now loop all PCI bridges */ do { /* Loop all PCI buses */ for (i = 0; i < PciRegistryInfo->NoBuses; i++) { /* Check if we have a handler for it */ if (!HalHandlerForBus(PCIBus, i)) { /* Allocate it */ HalpAllocateAndInitPciBusHandler(PciType, i, FALSE); } } /* Go to the next bridge */ } while (HalpGetPciBridgeConfig(PciType, &PciRegistryInfo->NoBuses)); /* Now build correct address range informaiton */ HalpFixupPciSupportedRanges(PciRegistryInfo->NoBuses); /* Loop every bus */ DbgPrint("\n====== PCI BUS HARDWARE DETECTION =======\n\n"); PciSlot.u.bits.Reserved = 0; for (i = 0; i < PciRegistryInfo->NoBuses; i++) { /* Get the bus handler */ BusHandler = HalHandlerForBus(PCIBus, i); /* Loop every device */ for (j = 0; j < 32; j++) { /* Loop every function */ PciSlot.u.bits.DeviceNumber = j; for (k = 0; k < 8; k++) { /* Build the final slot structure */ PciSlot.u.bits.FunctionNumber = k; /* Read the configuration information */ HalpReadPCIConfig(BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); /* Skip if this is an invalid function */ if (PciData->VendorID == PCI_INVALID_VENDORID) continue; /* Print out the entry */ HalpDebugPciDumpBus(i, j, k, PciData); /* Check if this is a Cardbus bridge */ if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) { /* Not supported */ DbgPrint("\tDevice is a PCI Cardbus Bridge. It will not work!\n"); continue; } /* Check if this is a PCI device */ if (PCI_CONFIGURATION_TYPE(PciData) != PCI_BRIDGE_TYPE) { /* Check if it has an interrupt pin and line registered */ if ((PciData->u.type1.InterruptPin) && (PciData->u.type1.InterruptLine)) { /* Check if this interrupt line is connected to the bus */ if (PciData->u.type1.InterruptLine < 16) { /* Is this an IDE device? */ if (!HalpIsIdeDevice(PciData)) { /* We'll mask out this interrupt then */ DbgPrint("\tDevice is using IRQ %d! ISA Cards using that IRQ may fail!\n", PciData->u.type1.InterruptLine); HalpPciIrqMask |= (1 << PciData->u.type1.InterruptLine); } } } } /* Check for broken Intel chips */ if (PciData->VendorID == 0x8086) { /* Check for broken 82830 PCI controller */ if ((PciData->DeviceID == 0x04A3) && (PciData->RevisionID < 0x11)) { /* Skip */ DbgPrint("\tDevice is a broken Intel 82430 PCI Controller. It will not work!\n\n"); continue; } /* Check for broken 82378 PCI-to-ISA Bridge */ if ((PciData->DeviceID == 0x0484) && (PciData->RevisionID <= 3)) { /* Skip */ DbgPrint("\tDevice is a broken Intel 82378 PCI-to-ISA Bridge. It will not work!\n\n"); continue; } /* Check for broken 82450 PCI Bridge */ if ((PciData->DeviceID == 0x84C4) && (PciData->RevisionID <= 4)) { DbgPrint("\tDevice is a Intel Orion 82450 PCI Bridge. It will not work!\n\n"); continue; } } /* Do we know this card? */ if (!ExtendedAddressDecoding) { /* Check for it */ if (HalpIsRecognizedCard(PciRegistryInfo, PciData, HALP_CARD_FEATURE_FULL_DECODE)) { /* We'll do chipset checks later */ DbgPrint("\tDevice has Extended Address Decoding. It may fail to work on older BIOSes!\n"); ExtendedAddressDecoding = TRUE; } } /* Now check the registry for chipset hacks */ Status = HalpGetChipHacks(PciData->VendorID, PciData->DeviceID, PciData->RevisionID, &HackFlags); if (NT_SUCCESS(Status)) { /* Check for broken ACPI routing */ if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_ACPI_IRQ_ROUTING) { DbgPrint("This chipset has broken ACPI IRQ Routing! Be aware!\n\n"); continue; } /* Check for broken ACPI timer */ if (HackFlags & HAL_PCI_CHIP_HACK_BROKEN_ACPI_TIMER) { DbgPrint("This chipset has a broken ACPI timer! Be aware!\n\n"); continue; } /* Check for hibernate-disable */ if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_HIBERNATE) { DbgPrint("This chipset has a broken PCI device which is incompatible with hibernation. Be aware!\n\n"); continue; } /* Check for USB controllers that generate SMIs */ if (HackFlags & HAL_PCI_CHIP_HACK_USB_SMI_DISABLE) { DbgPrint("This chipset has a USB controller which generates SMIs. ReactOS will likely fail to boot!\n\n"); continue; } } /* Terminate the entry */ DbgPrint("\n"); } } } /* Initialize NMI Crash Flag */ HalpGetNMICrashFlag(); /* Free the registry data */ ExFreePoolWithTag(PciRegistryInfo, TAG_HAL); /* Tell PnP if this hard supports correct decoding */ HalpMarkChipsetDecode(ExtendedAddressDecoding); DbgPrint("====== PCI BUS DETECTION COMPLETE =======\n\n"); #endif }