Bridged PCI Config space

Hi guys, I?m having trouble caused by a new motherboard that no longer supports the legacy PCI configuration. Everything is now PCIe so manufacturers like Intel are dropping legacy PCI support from their BIOS. This is causing a problem with my driver because the device is connected to a PCI Express-to-PCI Bridge card. The problem is the BIOS is not setting certain PCI config values (like CacheLineSize and LatencyTimer). Now I can fix the PCI config values from my driver by getting the bus interface (see below). The problem is that the PCI config on the bridge is also not correct. How would I get the bus interface of the bridge I?m connected to?

Thanks,
Rob

BUS_INTERFACE_STANDARD busInterface;
UCHAR tmpU8;

status = GetBusInterface(deviceExtension->pDeviceObject, &busInterface);
if (NT_SUCCESS(status))
{
/* Get the Cache Line Size. */
busInterface.GetBusData(busInterface.Context, PCI_WHICHSPACE_CONFIG, &tmpU8,
FIELD_OFFSET(PCI_COMMON_HEADER, CacheLineSize), sizeof(tmpU8));
}

NTSTATUS GetBusInterface(IN PDEVICE_OBJECT pDeviceObject, OUT PBUS_INTERFACE_STANDARD pBusInterface)
{
NTSTATUS status;
PIRP pIrp = NULL;
KEVENT event;
PDEVICE_OBJECT pTargetObject = NULL;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION stack = NULL;

KeInitializeEvent(&event, NotificationEvent, FALSE);

pTargetObject = IoGetAttachedDeviceReference(pDeviceObject);

pIrp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP,
pTargetObject,
NULL,
0,
NULL,
&event,
&ioStatus
);
if (pIrp == NULL)
{
ObDereferenceObject(pTargetObject);
return STATUS_INSUFFICIENT_RESOURCES;
}

stack = IoGetNextIrpStackLocation(pIrp);
stack->MajorFunction = IRP_MJ_PNP;
stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
stack->Parameters.QueryInterface.InterfaceType = &GUID_BUS_INTERFACE_STANDARD;
stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
stack->Parameters.QueryInterface.Version = PCI_BUS_INTERFACE_STANDARD_VERSION;
stack->Parameters.QueryInterface.Interface = (PINTERFACE)pBusInterface;
stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;

status = IoCallDriver(pTargetObject, pIrp);

if (status == STATUS_PENDING)
{
status = KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE,
NULL
);

status = ioStatus.Status;
}

ObDereferenceObject(pTargetObject);
return status;
}

Can you identify the bridge chip? It may have a special device to self-configure, when the BIOS does not (or there’s no BIOS at all). Some CMD bridges, for example, can load their configuration from a serial eeprom.

– pa

lspci identifies the bridge as follows:

22:00.0 PCI bridge [0604]: Texas Instruments XIO2001 PCI Express-to-PCI Bridge [104c:8240]
23:01.0 Co-processor [0b40]: Xilinx Corporation Device [10ee:cae1]
23:02.0 Co-processor [0b40]: Xilinx Corporation Device [10ee:cae1]

Obviously those are my devices connected to the bridge.

These devices belong to the PCI.SYS driver.

You can write a lower filter for the bridge device and perform what you think you should do when the device is enumerated.

This device belongs to the System class so your filter driver may need a special signature.

Sent from my phone

De : xxxxx@cae.com
Envoyé le :jeudi 13 avril 2017 00:20
À : Windows System Software Devs Interest List
Objet :RE:[ntdev] Bridged PCI Config space

lspci identifies the bridge as follows:

22:00.0 PCI bridge [0604]: Texas Instruments XIO2001 PCI Express-to-PCI Bridge [104c:8240]
23:01.0 Co-processor [0b40]: Xilinx Corporation Device [10ee:cae1]
23:02.0 Co-processor [0b40]: Xilinx Corporation Device [10ee:cae1]

Obviously those are my devices connected to the bridge.


NTDEV is sponsored by OSR

Visit the list online at: http:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

> Texas Instruments XIO2001 PCI Express-to-PCI Bridge

It does support a EEPROM. Please see http://www.ti.com/lit/an/scpa045d/scpa045d.pdf , ch. 7.1

Regards,
– pa

Thanks for the suggestions guys. Good catch on the bridge EEPROM. I didn?t even think about that. I came across the filter driver idea D.T. suggested but I thought there must be an easier way… something like a GetParentDevice function but the closest thing I could find was IoGetDeviceObjectPointer(). Would that blow up if the device belongs to a System class?

Another solution would be to use the lspci and setpci tools from Linux. These tools work under Windows but they are limited to the primary bus from 0x00 to 0x1F. Under Linux I can easily fix the problem with the commands:

setpci -d 104c:8240 CACHE_LINE_SIZE=08
setpci -d 10ee:cae1 LATENCY_TIMER=20

The limitation comes from the driver used by these tools (DirectIO32.sys). It does direct access to I/O ports which can blue screens some PCs. I have the code for this abomination if anyone is interested in making it non-malware.

Rob

Could IRP_MN_READ_READ_CONFIG/IRP_MN_WRITE_CONFIG help ?

https://msdn.microsoft.com/en-us/library/windows/hardware/ff551769(v=vs.85).aspx

Sent from my phone

De : xxxxx@cae.com
Envoyé le :jeudi 13 avril 2017 19:58
À : Windows System Software Devs Interest List
Objet :RE:[ntdev] Bridged PCI Config space

Thanks for the suggestions guys. Good catch on the bridge EEPROM. I didn?t even think about that. I came across the filter driver idea D.T. suggested but I thought there must be an easier way… something like a GetParentDevice function but the closest thing I could find was IoGetDeviceObjectPointer(). Would that blow up if the device belongs to a System class?

Another solution would be to use the lspci and setpci tools from Linux. These tools work under Windows but they are limited to the primary bus from 0x00 to 0x1F. Under Linux I can easily fix the problem with the commands:

setpci -d 104c:8240 CACHE_LINE_SIZE=08
setpci -d 10ee:cae1 LATENCY_TIMER=20

The limitation comes from the driver used by these tools (DirectIO32.sys). It does direct access to I/O ports which can blue screens some PCs. I have the code for this abomination if anyone is interested in making it non-malware.

Rob


NTDEV is sponsored by OSR

Visit the list online at: http:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

That’s pretty much what I am already doing if you look at the code in my first post. Go to the link you posted and scroll to the bottom, “To get a bus interface, a driver sends an IRP_MN_QUERY_INTERFACE request to its parent bus driver.”

That part works… I’m trying to get the bus interface of the bridge my device is connected to.

>The limitation comes from the driver used by these tools (DirectIO32.sys). It does direct access to I/O ports which can blue screens some PCs.

That is why the lower filter solution should be given a try. In user mode, you can obtain a list a devices from the System Class (SetupDiGetClassDevs with GUID_DEVCLASS_SYSTEM), then you walk the device list and get the HardwareId for each device until you get the HardwareId of your bridge device.

Once you have the bridge device, open it’s registry key and add your filter driver to the LowerFilters device’s REG_MULTI_SZ registry value. The filter driver should not be very busy. It should only filter IRP_MN_READ_CONFIG/IRP_MN_WRITE_CONFIG PNP IRPs.

Here you have an example of a PCI root bus lower filter installed by AMD.

http://www.amd-drivers.com/inffile-415.html

You can also use a kernel mode service (a driver that is not a filter driver and that has no associated device). This driver would create a control device and receive commands (IOCTL) This driver would receive the PDO name of the bridge from user mode, use IoGetDeviceObjectPointer to open the device object and send the IRP_MN_WRITE_CONFIG_IRP. The driver could get the HardwareId of the device before sending the IRP, so this is pretty safe. You may not need a special signature in that case.