Accessing PCI Config Space for another device.

Hey, I’m pretty new to windows driver development ( I’m writing my first
driver that does real I/O with hardware). As part of my device
initialization I need to access the PCI Configuration Registers of the LPC
Interface Bridge (an Intel PCI device).

I’ve read some posts and examples (pcidrv) of reading/writing pci
configuration space for the device belonging to the driver, but I can’t find
any examples of accessing other devices.

Can I still use BUS_INTERFACE_STANDARD interface? If so, what do I pass it
in WdfFdoQueryForInterface? Can I get a device pointer from the Hardware
Id?

Any help or clarification is greatly appreciated!

Brian

If you have a Device Object of the bridge it would be easy. The problem is getting this Device Object. You need a filter for the bridge. In this case you could get the Device Object. And after that you could have access to PCI Configuration of the bridge.

Igor Sharovar

Well you can’t legitimately access the pci config registers of another
device, which is why all the examples show one how to access the
config registers of a device that your driver is either the function
or filter driver for.

Mark Roddy

On Thu, Feb 11, 2010 at 5:27 PM, Brian Parma wrote:
> Hey, I’m pretty new to windows driver development ( I’m writing my first
> driver that does real I/O with hardware). ?As part of my device
> initialization I need to access the PCI Configuration Registers of the LPC
> Interface Bridge (an Intel PCI device).
> I’ve read some posts and examples (pcidrv) of reading/writing pci
> configuration space for the device belonging to the driver, but I can’t find
> any examples of accessing other devices.
> Can I still use BUS_INTERFACE_STANDARD interface? ?If so, what do I pass it
> in?WdfFdoQueryForInterface? ?Can I get a device pointer from the Hardware
> Id?
>
> Any help or?clarification?is greatly appreciated!
> Brian
> — NTDEV is sponsored by OSR For our schedule of WDF, WDM, debugging and
> other seminars visit: http://www.osr.com/seminars To unsubscribe, visit the
> List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

On Thu, 2010-02-11 at 19:05 -0500, xxxxx@hotmail.com wrote:

If you have a Device Object of the bridge it would be easy. The
problem is getting this Device Object. You need a filter for the
bridge. In this case you could get the Device Object. And after that
you could have access to PCI Configuration of the bridge.

One way to obtain PCI device objects without a filter is as follows:

First, get the driver object of Windows’ PCI driver:

UNICODE_STRING uszName;
PDRIVER_OBJECT pci_do;

RtlInitUnicodeString(&uszName, L"\Driver\PCI");
ObReferenceObjectByName(&uszName,
OBJ_CASE_INSENSITIVE,
NULL,
0,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID *) &pci_do);

Use it to enumerate the device objects of all the PCI devices in the
system by calling IoEnumerateDeviceObjectList().

Then call IoGetDeviceProperty() on those device objects to locate the
devices of interest. Given a device object, you can obtain a reference
to its BUS_INTERFACE_STANDARD, which you could use to access the
device’s config space.

Don’t forget to clean up- you must dereference each
BUS_INTERFACE_STANDARD interface when you’re done with it, plus call
ObDereferenceObject() on each device object referenced by
IoEnumerateDeviceObjectList() AND on the PCI driver object you obtained
using ObReferenceObjectByName(). Finish your business and dereference
all of these items as quickly as possible.

It’s seriously asking for trouble to mess with another device’s config
space from your driver. Apart from that usage, this PCI device
enumeration technique could be useful in certain situations and seems to
be not well-known.

Mark Fontana

I know it’s not standard practice, but It can be done (some applications
like pciscope and rw utility). Unfortunately for my application I need to.

On Thu, Feb 11, 2010 at 5:09 PM, Mark Roddy wrote:

> Well you can’t legitimately access the pci config registers of another
> device, which is why all the examples show one how to access the
> config registers of a device that your driver is either the function
> or filter driver for.
>
> Mark Roddy
>
>
>
> On Thu, Feb 11, 2010 at 5:27 PM, Brian Parma wrote:
> > Hey, I’m pretty new to windows driver development ( I’m writing my first
> > driver that does real I/O with hardware). As part of my device
> > initialization I need to access the PCI Configuration Registers of the
> LPC
> > Interface Bridge (an Intel PCI device).
> > I’ve read some posts and examples (pcidrv) of reading/writing pci
> > configuration space for the device belonging to the driver, but I can’t
> find
> > any examples of accessing other devices.
> > Can I still use BUS_INTERFACE_STANDARD interface? If so, what do I pass
> it
> > in WdfFdoQueryForInterface? Can I get a device pointer from the Hardware
> > Id?
> >
> > Any help or clarification is greatly appreciated!
> > Brian
> > — NTDEV is sponsored by OSR For our schedule of WDF, WDM, debugging and
> > other seminars visit: http://www.osr.com/seminars To unsubscribe, visit
> the
> > List Server section of OSR Online at
> > http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

I thought about that, but it seems like a lot of work to have to write a
whole separate filter driver just to get this data, does an application like
pscope (i think its called) have a filter driver over every bus/device?

On Thu, Feb 11, 2010 at 5:05 PM, wrote:

> If you have a Device Object of the bridge it would be easy. The problem is
> getting this Device Object. You need a filter for the bridge. In this case
> you could get the Device Object. And after that you could have access to PCI
> Configuration of the bridge.
>
> Igor Sharovar
>
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

That sounds like something to try.

Interestingly enough I remembered this open source library/driver combo that
can read/write to pci configuration space:
http://openlibsys.org/

http:</http:>Looking through the code they similarly iterate
through possible PCI slots checking for a match, but
using HalGetBusDataByOffset, which MSDN says is obsolete.

On Thu, Feb 11, 2010 at 7:13 PM, Mark Fontana wrote:

>
> On Thu, 2010-02-11 at 19:05 -0500, xxxxx@hotmail.com wrote:
>
> > If you have a Device Object of the bridge it would be easy. The
> > problem is getting this Device Object. You need a filter for the
> > bridge. In this case you could get the Device Object. And after that
> > you could have access to PCI Configuration of the bridge.
>
> One way to obtain PCI device objects without a filter is as follows:
>
> First, get the driver object of Windows’ PCI driver:
>
> UNICODE_STRING uszName;
> PDRIVER_OBJECT pci_do;
>
> RtlInitUnicodeString(&uszName, L"\Driver\PCI");
> ObReferenceObjectByName(&uszName,
> OBJ_CASE_INSENSITIVE,
> NULL,
> 0,
> *IoDriverObjectType,
> KernelMode,
> NULL,
> (PVOID *) &pci_do);
>
> Use it to enumerate the device objects of all the PCI devices in the
> system by calling IoEnumerateDeviceObjectList().
>
> Then call IoGetDeviceProperty() on those device objects to locate the
> devices of interest. Given a device object, you can obtain a reference
> to its BUS_INTERFACE_STANDARD, which you could use to access the
> device’s config space.
>
> Don’t forget to clean up- you must dereference each
> BUS_INTERFACE_STANDARD interface when you’re done with it, plus call
> ObDereferenceObject() on each device object referenced by
> IoEnumerateDeviceObjectList() AND on the PCI driver object you obtained
> using ObReferenceObjectByName(). Finish your business and dereference
> all of these items as quickly as possible.
>
> It’s seriously asking for trouble to mess with another device’s config
> space from your driver. Apart from that usage, this PCI device
> enumeration technique could be useful in certain situations and seems to
> be not well-known.
>
> Mark Fontana
>
>
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

These are utilities that are using deprecated APIs or pounding on the hw directly. Might be OK for a utility, but not OK for a product you would sell to a customer

d

From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Brian Parma
Sent: Thursday, February 11, 2010 6:16 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Accessing PCI Config Space for another device.

I thought about that, but it seems like a lot of work to have to write a whole separate filter driver just to get this data, does an application like pscope (i think its called) have a filter driver over every bus/device?
On Thu, Feb 11, 2010 at 5:05 PM, > wrote:
If you have a Device Object of the bridge it would be easy. The problem is getting this Device Object. You need a filter for the bridge. In this case you could get the Device Object. And after that you could have access to PCI Configuration of the bridge.

Igor Sharovar


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

— NTDEV is sponsored by OSR For our schedule of WDF, WDM, debugging and other seminars visit: http://www.osr.com/seminars To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

IoGetDeviceProperty requires a PDO, not all devices returned by IoEnumerateDeviceObjectList will be a PDO. Passing a non PDO to IoGetDeviceProperty can cause a bugcheck (esp with DV or a chk kernel) or undefined behavior. For each device passed in that list, you need to send a IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS(TargetDeviceRelations) to get the PDO first. Also, mind you that just b/c you have the list of devices does not meant the state of those devices will remain the same. God knows how pci would handle you sending query device relations or a QI to a PDO it just deleted.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Mark Fontana
Sent: Thursday, February 11, 2010 6:14 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Accessing PCI Config Space for another device.

On Thu, 2010-02-11 at 19:05 -0500, xxxxx@hotmail.com wrote:

If you have a Device Object of the bridge it would be easy. The
problem is getting this Device Object. You need a filter for the
bridge. In this case you could get the Device Object. And after that
you could have access to PCI Configuration of the bridge.

One way to obtain PCI device objects without a filter is as follows:

First, get the driver object of Windows’ PCI driver:

UNICODE_STRING uszName;
PDRIVER_OBJECT pci_do;

RtlInitUnicodeString(&uszName, L"\Driver\PCI");
ObReferenceObjectByName(&uszName,
OBJ_CASE_INSENSITIVE,
NULL,
0,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID *) &pci_do);

Use it to enumerate the device objects of all the PCI devices in the
system by calling IoEnumerateDeviceObjectList().

Then call IoGetDeviceProperty() on those device objects to locate the
devices of interest. Given a device object, you can obtain a reference
to its BUS_INTERFACE_STANDARD, which you could use to access the
device’s config space.

Don’t forget to clean up- you must dereference each
BUS_INTERFACE_STANDARD interface when you’re done with it, plus call
ObDereferenceObject() on each device object referenced by
IoEnumerateDeviceObjectList() AND on the PCI driver object you obtained
using ObReferenceObjectByName(). Finish your business and dereference
all of these items as quickly as possible.

It’s seriously asking for trouble to mess with another device’s config
space from your driver. Apart from that usage, this PCI device
enumeration technique could be useful in certain situations and seems to
be not well-known.

Mark Fontana


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Thanks Doron! On your last point, could PCI really delete PDOs even
while I hold a reference on them?

Also, is there a way to safely determine whether an item returned by
IoEnumerateDeviceObjectList is already a PDO?

Mark

On Fri, 2010-02-12 at 04:38 +0000, Doron Holan wrote:

IoGetDeviceProperty requires a PDO, not all devices returned by
IoEnumerateDeviceObjectList will be a PDO. Passing a non PDO to
IoGetDeviceProperty can cause a bugcheck (esp with DV or a chk kernel)
or undefined behavior. For each device passed in that list, you need
to send a
IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS(TargetDeviceRelations) to get
the PDO first. Also, mind you that just b/c you have the list of
devices does not meant the state of those devices will remain the
same. God knows how pci would handle you sending query device
relations or a QI to a PDO it just deleted.

d

An ObReference does not lock state in any way, so yes, PCI could really delete a PDO even you hold a ref. the PDO memory will still be valid b/c of your outstanding ref, but the underlying state could be blown away and when the QI or any other irp is processed with that blown away state, weird things can happen.

I already told you the whe way you safe determine if the item returned by IoEnumerateDeviceObjectList is a PDO or not, you send a QDR(TargetDeviceRelations) to it and then use the result in the relations as the PDO you pass to whatever API you so choose that requires a PDO

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Mark Fontana
Sent: Thursday, February 11, 2010 9:04 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Accessing PCI Config Space for another device.

Thanks Doron! On your last point, could PCI really delete PDOs even
while I hold a reference on them?

Also, is there a way to safely determine whether an item returned by
IoEnumerateDeviceObjectList is already a PDO?

Mark

On Fri, 2010-02-12 at 04:38 +0000, Doron Holan wrote:

IoGetDeviceProperty requires a PDO, not all devices returned by
IoEnumerateDeviceObjectList will be a PDO. Passing a non PDO to
IoGetDeviceProperty can cause a bugcheck (esp with DV or a chk kernel)
or undefined behavior. For each device passed in that list, you need
to send a
IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS(TargetDeviceRelations) to get
the PDO first. Also, mind you that just b/c you have the list of
devices does not meant the state of those devices will remain the
same. God knows how pci would handle you sending query device
relations or a QI to a PDO it just deleted.

d


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

>belonging to the driver, but I can’t find any examples of accessing other devices.

This is just plain not supported in Windows.

There are only hackery-based ways, like using cf8/cfc (can hang) or installing the lower filter driver to the devnode you’re interested in and do the usual BUS_INTERFACE_STANDARD-based work.

Can I still use BUS_INTERFACE_STANDARD interface?

Only if you’re a member of the device’s devnode (i.e. functional driver or filter).

Windows intentionally provides no ways for anybody but the device’s own driver to access the PCI config spaces. This is done to reduce the dependencies and increase the stability.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

>using HalGetBusDataByOffset, which MSDN says is obsolete.

There is a very high probability that the single call to this function will disable power management on the machine.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

CFC/CF8 is not generally a good idea, because it is a two-stage operation (write address, write data), and it’s possible for the OS to want to read/write config space while you’re doing it, and context switch you out while you’re doing the write. This might result in writing to the wrong address or the wrong value to the right address, resulting in sadness.

A safer method you can use on most machines that support PCIe is to use memory mapped configuration space. You can cobble together the necessary information to do this from the PCIe Specification, ver. 3.0 of the PCI Firmware spec, and the ACPI spec (look for the MCFG table). The best/safest option is definitely a filter driver though.

You really shouldn’t modify the config space of a device whose driver you don’t own, but the danger is really dependent on what you’re changing. Obviously, if you move the bar while some driver is mapped to it, you’re going to crash the system as soon as the driver does something. Before you do the write you need to fully understand the implications of what you’re changing and how the driver might react to it. Also know that in the case of some devices/registers (particularly pci bridges), the pci driver will restore the value to what it was previously when it notices you changed it.

Let me add to that. Platforms (which means chipsets) are allowed to support
only one write to the memory-mapped config region at a time. If you map it
yourself, and you happen to write to it while the OS is also writing to it,
you’ll cause undefined results. Sometimes those results happen to be what
you want. Sometimes not.


Jake Oshins
Hyper-V I/O Architect
Windows Kernel Group

This post implies no warranties and confers no rights.


<jonathan.hearn> wrote in message news:xxxxx@ntdev…
> CFC/CF8 is not generally a good idea, because it is a two-stage operation
> (write address, write data), and it’s possible for the OS to want to
> read/write config space while you’re doing it, and context switch you out
> while you’re doing the write. This might result in writing to the wrong
> address or the wrong value to the right address, resulting in sadness.
>
> A safer method you can use on most machines that support PCIe is to use
> memory mapped configuration space. You can cobble together the necessary
> information to do this from the PCIe Specification, ver. 3.0 of the PCI
> Firmware spec, and the ACPI spec (look for the MCFG table). The
> best/safest option is definitely a filter driver though.
>
> You really shouldn’t modify the config space of a device whose driver you
> don’t own, but the danger is really dependent on what you’re changing.
> Obviously, if you move the bar while some driver is mapped to it, you’re
> going to crash the system as soon as the driver does something. Before
> you do the write you need to fully understand the implications of what
> you’re changing and how the driver might react to it. Also know that in
> the case of some devices/registers (particularly pci bridges), the pci
> driver will restore the value to what it was previously when it notices
> you changed it.
></jonathan.hearn>