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 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; }
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; }
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; }