BUS_INTERFACE_STANDARD::GetBusData and location (bus, slot, function)

It seems I looked everywhere, but it still unclear to me:
How to read PCI Configuration Address Space of exact device, which I know only by location: bus, slot and function?

I’ve got old driver code, that has special IOCTL code to read Configuration Address Space. There are implemented 2 methods to do so:

  1. Using HalGetBusDataByOffset
    PCI_SLOT_NUMBER slot = { 0 };
    slot.u.bits.DeviceNumber = dwSlot;
    slot.u.bits.FunctionNumber = dwFunction;
    data_len_ret = HalGetBusDataByOffset( PCIConfiguration,
    dwBus, slot.u.AsULONG,
    ulData, dwOffset, sizeof(ulData) );

It turned out that this way is not working anymore https://msdn.microsoft.com/en-us/library/windows/hardware/ff546644(v=vs.85).aspx . Or may be it never worked at all.

  1. Using direct access to ports 0xCF8 and 0xCFC
    ULONG config_address = (1ul << 31) |
    (bus << 16) | (slot << 11) | (function << 8) | offset ;
    WRITE_PORT_ULONG( (PULONG )0xCF8, config_address );
    ulData = READ_PORT_ULONG( (PULONG )0xCFC );

This way works, but it is not recommended. Because there is no synchronization. And having WDF its probably bad idea to touch the meat.

The proper ways to access Configuration Address Space in WDF are 2 following:
(According to https://docs.microsoft.com/en-us/windows-hardware/drivers/pci/accessing-pci-device-configuration-space )

A. Send IRP_MN_READ_CONFIG package to exact device https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/irp-mn-read-config

B. Get BUS_INTERFACE_STANDARD struct and call method GetBusData from there.

I would like to use B method for many reasons. But here I completely lost concept.
Method BUS_INTERFACE_STANDARD::GetBusData has following signature:
ULONG GET_SET_DEVICE_DATA (
Inout_opt PVOID Context,
In ULONG DataType,
Inout_updates_bytes(Length) PVOID Buffer,
In ULONG Offset,
In_range(!=,0) ULONG Length
);

There is no way to specify Bus.Slot.Function.
So I assume, that information about bus location is stored in Context.
In this case, I had to request individual BUS_INTERFACE_STANDARD interface from the device instance located there.
But how I can do it? How can I get WDFDEVICE knowing only triplet Bus.Slot.Function ? I searched everywhere, but there is no API to do so.

Or maybe I should get this interface from the PCI Bus device itself. Its additional challenge, because the device has no strict name, and can be multiple. But moreover even if I get this interface somehow (maybe by developing/using yet another pci filter), how I can apply location triplet at GetBusData?

Also I hoped, that interface PCI_BUS_INTERFACE_STANDARD and method ReadConfig can save me. But it’s look like nobody provide it.
Like specified at http://www.hollistech.com/Resources/Misc%20articles/getbusdata.htm
“You might be tempted to use GUID_PCI_BUS_INTERFACE_STANDARD, but this will not work, even if you know for a fact that the pci bus driver is beneath you on the stack.”

Please, explain me how I can read Configuration Space by only Bus.Slot.Function using modern WDF.

Well first there is the question why do you want this? A driver really
doesn’t need this, because unlike the old days a driver doesn’t enumerate
the devices by HalGetBusDataByOffset instead the PnP manager does.

If you really need this it is going to have to be a bus filter driver for
the PCI bus so you see all the PDO’s and can then issue the
IRP_MN_READ_CONFIG … approach for each device.

Don Burn
Windows Driver Consulting
Website: http://www.windrvr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, January 19, 2018 2:58 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] BUS_INTERFACE_STANDARD::GetBusData and location (bus, slot,
function)

It seems I looked everywhere, but it still unclear to me:
How to read PCI Configuration Address Space of exact device, which I know
only by location: bus, slot and function?

I’ve got old driver code, that has special IOCTL code to read Configuration
Address Space. There are implemented 2 methods to do so:
1. Using HalGetBusDataByOffset
PCI_SLOT_NUMBER slot = { 0 };
slot.u.bits.DeviceNumber = dwSlot;
slot.u.bits.FunctionNumber = dwFunction;
data_len_ret = HalGetBusDataByOffset( PCIConfiguration,
dwBus, slot.u.AsULONG,
ulData, dwOffset, sizeof(ulData) );

It turned out that this way is not working anymore
https://msdn.microsoft.com/en-us/library/windows/hardware/ff546644(v=vs.85).
aspx . Or may be it never worked at all.

2. Using direct access to ports 0xCF8 and 0xCFC
ULONG config_address = (1ul << 31) |
(bus << 16) | (slot << 11) | (function << 8) | offset ;
WRITE_PORT_ULONG( (PULONG )0xCF8, config_address );
ulData = READ_PORT_ULONG( (PULONG )0xCFC );

This way works, but it is not recommended. Because there is no
synchronization. And having WDF its probably bad idea to touch the meat.

The proper ways to access Configuration Address Space in WDF are 2
following:
(According to
https://docs.microsoft.com/en-us/windows-hardware/drivers/pci/accessing-pci-
device-configuration-space )

A. Send IRP_MN_READ_CONFIG package to exact device
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/irp-mn-read
-config

B. Get BUS_INTERFACE_STANDARD struct and call method GetBusData from there.

I would like to use B method for many reasons. But here I completely lost
concept.
Method BUS_INTERFACE_STANDARD::GetBusData has following signature:
ULONG GET_SET_DEVICE_DATA (
Inout_opt PVOID Context,
In ULONG DataType,
Inout_updates_bytes(Length) PVOID Buffer,
In ULONG Offset,
In_range(!=,0) ULONG Length
);

There is no way to specify Bus.Slot.Function.
So I assume, that information about bus location is stored in Context.
In this case, I had to request individual BUS_INTERFACE_STANDARD interface
from the device instance located there.
But how I can do it? How can I get WDFDEVICE knowing only triplet
Bus.Slot.Function ? I searched everywhere, but there is no API to do so.

Or maybe I should get this interface from the PCI Bus device itself. Its
additional challenge, because the device has no strict name, and can be
multiple. But moreover even if I get this interface somehow (maybe by
developing/using yet another pci filter), how I can apply location triplet
at GetBusData?

Also I hoped, that interface PCI_BUS_INTERFACE_STANDARD and method
ReadConfig can save me. But it’s look like nobody provide it.
Like specified at
http://www.hollistech.com/Resources/Misc%20articles/getbusdata.htm
“You might be tempted to use GUID_PCI_BUS_INTERFACE_STANDARD, but this will
not work, even if you know for a fact that the pci bus driver is beneath you
on the stack.”

Please, explain me how I can read Configuration Space by only
Bus.Slot.Function using modern WDF.


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:>

Yeahh, I expected answer like “You do it wrong”.
But I only recently start to learn about Windows Driver and I try to just update old driver functionality (that is widely used from User-Mode) to modern WDF approach.

I can’t understand, why for simple access to device configuration space by location b.s.f I had to develop and deploy full new layer - filter - which can affect performance and which I still can’t understand how to actually setup into PCI device stack.

Ok. Even if I’ll write filter, I’ll stuck at the same problem - how to deal with BUS_INTERFACE_STANDARD interface. Am I really need to request and store these interfaces for each device to further call GetBusData, not to mention about dereferencing it properly?

Sorry, if I sound childish, but I can’t understand why things became so much overcomplicated without any apparent reason.

Thank you anyway, Don.

Best regards. Eugene Petrov.

|Well first there is the question why do you want this? A driver really
|doesn’t need this, because unlike the old days a driver doesn’t enumerate
|the devices by HalGetBusDataByOffset instead the PnP manager does.
|
|If you really need this it is going to have to be a bus filter driver for
|the PCI bus so you see all the PDO’s and can then issue the
|IRP_MN_READ_CONFIG … approach for each device.
|
|
|Don Burn
|Windows Driver Consulting
|Website: http://www.windrvr.com

Actually depending on how you look at it, things became much simpler. It
was a pain to walk the buses looking for your device so you could grab the
resources and program it.

As far as performance, the impact is very minimal, you really only need to
monitor IRP_MJ_PNP and that is not in the operational path, so does not
really impact the system. What can be a pain especially for a new driver
writer is writing a bus filter driver, they are not documented, and they
have to be WDM, since KMDF does not support bus filters.

Don Burn
Windows Driver Consulting
Website: http://www.windrvr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, January 19, 2018 5:58 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] BUS_INTERFACE_STANDARD::GetBusData and location (bus,
slot, function)

Yeahh, I expected answer like “You do it wrong”.
But I only recently start to learn about Windows Driver and I try to just
update old driver functionality (that is widely used from User-Mode) to
modern WDF approach.

I can’t understand, why for simple access to device configuration space by
location b.s.f I had to develop and deploy full new layer - filter - which
can affect performance and which I still can’t understand how to actually
setup into PCI device stack.

Ok. Even if I’ll write filter, I’ll stuck at the same problem - how to deal
with BUS_INTERFACE_STANDARD interface. Am I really need to request and store
these interfaces for each device to further call GetBusData, not to mention
about dereferencing it properly?

Sorry, if I sound childish, but I can’t understand why things became so much
overcomplicated without any apparent reason.

Thank you anyway, Don.
------------------------
Best regards. Eugene Petrov.

|Well first there is the question why do you want this? A driver really
|doesn’t need this, because unlike the old days a driver doesn’t
|enumerate the devices by HalGetBusDataByOffset instead the PnP manager
does.
|
|If you really need this it is going to have to be a bus filter driver
|for the PCI bus so you see all the PDO’s and can then issue the
|IRP_MN_READ_CONFIG … approach for each device.
|
|
|Don Burn
|Windows Driver Consulting
|Website: http://www.windrvr.com


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:>

How it can be so? WDF had function WdfFdoInitSetFilter
https://msdn.microsoft.com/en-us/library/windows/hardware/ff547273(v=vs.85).aspx

And here at OSR you can find perfect article http://www.osronline.com/article.cfm?article=446
KMDF Filter Driver: 30-Minutes – Installation: Ah…Somewhat Longer

Code part there is perfectly clear, and whole article is just pleasure to read. However, I still couldn’t figure out how to actually install filter driver, to make it work from Windows 7. And in sample code ‘install’ folder has nothing useful.
Looks like I need to fight it myself.
And backport all functionality of accessing device by location b.s.f to avoid redesign User-Level libraries.
Uhhh :frowning:

|As far as performance, the impact is very minimal, you really only need to
|monitor IRP_MJ_PNP and that is not in the operational path, so does not
|really impact the system. What can be a pain especially for a new driver
|writer is writing a bus filter driver, they are not documented, and they
|have to be WDM, since KMDF does not support bus filters.

A bus filter driver is different, it monitors the creation of PDO through
the IRP_MJ_PNP calls and has to create Filter Device Object for each PDO.
KMDF assumes that you are attaching to the PDO specified by the INF file,
and has no way to handle this case.

I’ve written several bus filter drivers, all of which were done after KMDF
came out.

Don Burn
Windows Driver Consulting
Website: http://www.windrvr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, January 19, 2018 7:25 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] BUS_INTERFACE_STANDARD::GetBusData and location (bus,
slot, function)

How it can be so? WDF had function WdfFdoInitSetFilter
https://msdn.microsoft.com/en-us/library/windows/hardware/ff547273(v=vs.85).
aspx

And here at OSR you can find perfect article
http://www.osronline.com/article.cfm?article=446
KMDF Filter Driver: 30-Minutes – Installation: Ah…Somewhat Longer

Code part there is perfectly clear, and whole article is just pleasure to
read. However, I still couldn’t figure out how to actually install filter
driver, to make it work from Windows 7. And in sample code ‘install’ folder
has nothing useful.
Looks like I need to fight it myself.
And backport all functionality of accessing device by location b.s.f to
avoid redesign User-Level libraries.
Uhhh :frowning:

|As far as performance, the impact is very minimal, you really only need
|to monitor IRP_MJ_PNP and that is not in the operational path, so does not
|really impact the system. What can be a pain especially for a new driver
|writer is writing a bus filter driver, they are not documented, and
|they have to be WDM, since KMDF does not support bus filters.


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:>

xxxxx@gmail.com wrote:

But I only recently start to learn about Windows Driver and I try to just update old driver functionality (that is widely used from User-Mode) to modern WDF approach.

It’s more than WDF.  You’re talking about practices from literally 20
years ago, before WDM, and before PnP.

 

I can’t understand, why for simple access to device configuration space by location b.s.f I had to develop and deploy full new layer - filter - which can affect performance and which I still can’t understand how to actually setup into PCI device stack.

Safety and reliability.  In the old NT 4 days, you had to go out looking
for your device.  That requires intimate knowledge of the bus type being
used (bus/slot/function?), it requires you to touch devices that don’t
belong to you, it encouraged bad practices (why should I search more
than 3 buses?), and it encourages poorly encapsulated drivers.  With
PnP, the I/O system deals with the bus, and hands you the resources for
your device.  Now, if the bus itself should somehow change, you don’t
have to know about it.  You aren’t required to troll through devices
that don’t belong to you, and it is more difficult for your driver to
interfere with another device.

 

Ok. Even if I’ll write filter, I’ll stuck at the same problem - how to deal with BUS_INTERFACE_STANDARD interface. Am I really need to request and store these interfaces for each device to further call GetBusData, not to mention about dereferencing it properly?

It’s rather similar to COM, which is why they call it an “interface”. 
You get a pointer to set of function pointers, and you call through
those function pointers to get the functionality you need.

Sorry, if I sound childish, but I can’t understand why things became so much overcomplicated without any apparent reason.

There are very, very good reasons for it.  The scheme you are using is
more complicated, and is tied very strongly to one type of bus.  You
just don’t see the complexity because you’re familiar with it.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.