none
PCI Express Status Register at User Space

    Question

  • Hi Everyone

    I'm new with driver develoment so maybe some of my questions may be easy to answer.

    My first question is:

    I'm developing an application and I need to show the user the PCI Status Register so the user can see if the slots are ok. The question is. Is there any way to get the PCI status register at a application without need to develop a driver ?

    Second and last question.

    Where to start studing to develop drivers ? Is there any actual book with samples of code ? All books I've seen have too much theory an no code.

    Thanks a lot

    Rafael Machado


    rafael machado

    Thursday, March 29, 2012 1:40 PM

Answers

  • Before going the driver route, take a look at the SetupAPI's and whether they will provide enough data for your needs.  The WDK has the DevCon sample which shows how to work many of these API's.  Even if you determine you need a driver, you will probably need a helper application and the SetupAPI's will be needed there.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, March 29, 2012 2:25 PM
  • You NEVER access PCI address space from your driver, unless your driver is pci.sys, which I doubt. You cannot access it from your driver because you do not, and cannot, access the spinlock defined by the driver controlling the PCI address space hence you can never sync access to that IO space and endup being nothing more than a system panic and crash looking for an excuse to happen. From your driver you attach to the PCI/PCIe driver, create an IRP_MJ_READ/WRITE_CONFIG and send that to the lower driver you attached. Doing it any other is simply piss poor programming.

    Gary G. Little NanoTelesis Systems, LLC


    Thursday, March 29, 2012 9:10 PM
  • yes i said windbg provides you a lot of information about pci

    when you are using the !pci extension command

    may be you can check it out 

    to see if the information you require is provided by windbg 

    Friday, March 30, 2012 8:46 PM

All replies

  • On developing drivers, no there is not a book with full samples, but there are two good books out there from Microsoft Press.  First get "Developing Drivers with the Windows Driver Foundation"  this is the book for programming in KMDF and UMDF the new frameworks for driver development.  Many sections use pieces of the samples from the Windows Driver Kit (WDK).  The Windows Driver Kit is the source for many excellent samples of drivers.   The second book is "Programming the Windows Driver Model", this describes the older model of driver programming, which is still useful in many cases and which the new framework is layered over.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, March 29, 2012 1:46 PM
  • Hi Donald / Everyone

    Thanks for the answer. I'll take a look at this books.

    What about the first question. Is it possible to access the Status Register of a PCIe at a user  mode application ?

    Thanks

    Rafael Machado


    rafael machado

    Thursday, March 29, 2012 1:53 PM
  • Your first source of knowledge is the WDK, which you get from Microsoft. Secondary reading would be Walter Oney's book on driver development. It's dated, does not include KMDF since only WDM was available but does provide a valuable resource. Check with OsrOnline.com for a seminar to attend or Azius.com. A class or two is worth more than months of individual reading or study.

    Have explored Powershell for the PCIe information you desire? It may be contained in a database you can access using WQL via Powershell or a .NET application using C# or C++.


    Gary G. Little NanoTelesis Systems, LLC


    Thursday, March 29, 2012 1:54 PM
  • I have not tried to access it even from kernel mode.  I believe the register is owned by the OS, so to access it you would have to find the correct physical device object (PDO) instantiated by the pci.sys driver and then do a query to get the PCI_EXPRESS_CAPABILITY structure.  In a quick check I did not find even how to get this data.

    Lets back up, and ask why do you believe you need this?:  Windows does not want drivers probing for harfware instead plug and play delivers you the resources to access a device you INF file for a driver indentifies that the driver can support.  So unlike a lot of OS'es that expect you to walk the PCI busses and check slots for your firms device, Windows does that for you.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, March 29, 2012 2:05 PM
  • Hi all

    Gary.

    I'm chacking what you sad and maybe this can solve my problem. I'm still checking. Thanks a lot anyway

    Donald

    The scenario is that. I have an application that I nned to show the user the status of each PCI and PCIe slot. I was considering the possibility of writing a driver for that. And I going to the wrong way ? Thanks a lot too

    Rafael Machado


    rafael machado

    Thursday, March 29, 2012 2:17 PM
  • Before going the driver route, take a look at the SetupAPI's and whether they will provide enough data for your needs.  The WDK has the DevCon sample which shows how to work many of these API's.  Even if you determine you need a driver, you will probably need a helper application and the SetupAPI's will be needed there.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, March 29, 2012 2:25 PM
  • Hi Donald

    I'll check what you and Gary told me.

    Thanks Guys


    rafael machado

    Thursday, March 29, 2012 2:27 PM
  • Rafael,

    If all you need is to get the status of slots - then by all means search a usermode interface: WMI or SetupApi, or even hack in the registry or ask the system/mobo vendor for a tool.

    If you can, do this work in Linux, where this is much easier.

    Avoid mucking with drivers and kernel mode. You (and we) likely will regret it.

    -- pa

    Thursday, March 29, 2012 2:33 PM
  • PCI config information used to be obtained by creating and sending an read config request in the current driver to the bus driver controlling the PCI controller. I don;t remember the precise n ame of the IRP that was created but it did have CONFIG and READ in the name. It's been a while since I used it. Whether that still applies to PCIe I do not know.

    Gary G. Little NanoTelesis Systems, LLC

    Thursday, March 29, 2012 3:02 PM
  • is this information is what you are looking for ? google tells me pci status register is at 0x6 in this link

    http://tldp.org/LDP/tlk/dd/pci.html

    some arbitrary datasheet from google 82559ER Fast Ethernet PCI Controller
    Networking Silicon
    Datasheet

    also says

    6.1.3 PCI Status Register
    The 82559ER Status register is used to record status information for PCI bus related events. The
    format of this register is shown in the figure below.
    Note that bits 21, 22, 26, and 27 are set to 0b and bits 20, 23, and 25 are set to 1b. The PCI Status
    register bits are described in the table below.
    Figure 19.  PCI Status Register
    0
    Detected Parity Error
    Signaled System Error
    Received Master Abort
    Received Target Abort
    Signaled Target Abort
    Devsel Timing
    Parity Error Detected
    Fast Back To Back (target)
    Capabilities List
    Reserved 0 1 1 0 0 0 1 0
    31 30 29 28 27 26 25 24 23 22 21 20 19 16
    Table 5.  PCI Status Register Bits

    windbg tells me it is at 6

    lkd> dt nt!_PCI_COMMON_CONFIG status
       +0x006 Status : Uint2B

    lkd> !pci 100  2 1 1

    PCI Configuration Space (Segment:0000 Bus:02 Device:01 Function:01)
    Common Header:
        00: VendorID       10ec Realtek Semiconductor
        02: DeviceID       8139
        04: Command        0005 IOSpaceEn BusInitiate
        06: Status         0290 CapList FB2BCapable DEVSELTiming:1
        08: RevisionID     10
        09: ProgIF         00
        0a: SubClass       00 Ethernet Controller
        0b: BaseClass      02 Network Controller
        0c: CacheLineSize  0000
        0d: LatencyTimer   00
        0e: HeaderType     00
        0f: BIST           00
        10: BAR0           00001001
        14: BAR1           51200000
        18: BAR2           00000000
        1c: BAR3           00000000
        20: BAR4           00000000
        24: BAR5           00000000
        28: CBCISPtr       00000000
        2c: SubSysVenID    103c
        2e: SubSysID       30d9
        30: ROMBAR         00000000
        34: CapPtr         50
        3c: IntLine        10
        3d: IntPin         01
        3e: MinGnt         20
        3f: MaxLat         40
    Device Private:
        40: 00000000 00000000 00000000 00000000
        50: f7c20001 00000100 00000000 00000000
        60: 00000000 00000000 00000000 00000000
        70: 00000000 00000000 00000000 00000000
        80: 00000000 00000000 00000000 00000000
        90: 00000000 00000000 00000000 00000000
        a0: 00000000 00000000 00000000 00000000
        b0: 00000000 00000000 00000000 00000000
        c0: 00000000 00000000 00000000 00000000
        d0: 00000000 00000000 00000000 00000000
        e0: 00000000 00000000 00000000 00000000
        f0: 00000000 00000000 00000000 00000000
    Capabilities:
        50: CapID          01 PwrMgmt Capability
        51: NextPtr        00
        52: PwrMgmtCap     f7c2 D1Support D2Support PMED1 PMED2 PMED3Hot PMED3Cold Version=2
        54: PwrMgmtCtrl    0100 PMEEnable DataScale:0 DataSel:0 D0

    if yes then you can check windbg

    Thursday, March 29, 2012 8:34 PM
  • You NEVER access PCI address space from your driver, unless your driver is pci.sys, which I doubt. You cannot access it from your driver because you do not, and cannot, access the spinlock defined by the driver controlling the PCI address space hence you can never sync access to that IO space and endup being nothing more than a system panic and crash looking for an excuse to happen. From your driver you attach to the PCI/PCIe driver, create an IRP_MJ_READ/WRITE_CONFIG and send that to the lower driver you attached. Doing it any other is simply piss poor programming.

    Gary G. Little NanoTelesis Systems, LLC


    Thursday, March 29, 2012 9:10 PM
  • Hi everyone

    First of all thanks a lot for the answer. You are really helping me.

    As I told before, I was checking the possiblity of accessing what I need with WMI, but unfortunetly I cannot do that because WMI doesn't implement the CIM_PCIController. So WMI is out of my list for this case. With WMI I'm not able to get to Capabilities Structure level

    Now I'll check the setup API and proposed by Pavel.

    I've read in some places about what you sad Gary (IRP_MJ_READ/WRITE_CONFIG). I'll take a look at this too.

    blufferisme, sorry but I didn't understand what you told. You mean I should try to get the information at WinDebug ?

    Thanks guys


    rafael machado

    Friday, March 30, 2012 12:36 PM
  • yes i said windbg provides you a lot of information about pci

    when you are using the !pci extension command

    may be you can check it out 

    to see if the information you require is provided by windbg 

    Friday, March 30, 2012 8:46 PM
  • Hi everyone

    I've checked something about SetupAPI but didn't find the relation between this API and what I need. Doen any of you could explain me how can I get the PCI information using SetupAPI ?

    blufferisme, I'm checking WinDBG now. If the information I need is returned by WinDBG does this mean I don't need a driver to access the information or WinDBG uses drivers to get data ?

    Gary, I'm taking a look at how to attach drivers and send IRP_MJ_READ/WRITE_CONFIG.

    Thanks everyone for the help.

    The fight will continue :)

    Rafael R. Machado


    rafael machado

    Monday, April 02, 2012 1:35 PM
  • Windbg uses a module running in one machine enabled by boot settings on the system.  Windbg then runs on another system to get the data. 


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Monday, April 02, 2012 1:46 PM
  • Hi Donald. By module you mean driver ?

    Thanks

    Rafael


    rafael machado

    Monday, April 02, 2012 2:15 PM
  • No I mean a kernel installed module, not something that will appear in the driver list.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Monday, April 02, 2012 2:27 PM
  • Hi everyone.

    Windbg is really cool!!

    There I have everything I need. (thanks blufferisme for the tip)

    Does any of you could explain a little bit more about what Gary says some posts ago?

    "From your driver you attach to the PCI/PCIe driver, create an IRP_MJ_READ/WRITE_CONFIG and send that to the lower driver you attached. Doing it any other is simply piss poor programming. "

    I think this is the way I need to go. With this Gary means that I need to create a driver that is attached to another driver right ? Is there any documentation related to this process ?

    Thanks guys

    Rafael


    rafael machado

    Monday, April 02, 2012 2:54 PM
  • Goto http://www.hollistech.com/ under resources look at Replacing HalGetBusData In windows 2000 this tells you how to do what Gary is talking about.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Monday, April 02, 2012 3:11 PM
  • windbg in local kernel debugging mode will return the pci specs using dbgeng interfaces to read those data

    the flow is something like

    !kext !pci -> pcidump->pcidumpbus->readpci ->ReadIoSpace64 -> Ioctl using ZwDebugSystemControl

    upto xp if windbg is installed in clients computer getting those info on a client computer even if not booted with /debug 

    is as simple as issuing a cmd like this

    C:\>kd -kl -c "!pci 0x100 0 1c;q"

    with vista and above the same info with the same cmdline is possible only if the client computer is booted with /debug  as the os doesnot allow local kernel debugging unless booted with /debug

    a sample output for a pci Express capability with CapId @ 0x40 as follows


    C:\>kd -kl -c "!pci 0x100 0 1c;q"

    Microsoft (R) Windows Debugger Version 6.12.0002.633 X86

    lkd> kd: Reading initial command '!pci 0x100 0 1c;q'

    PCI Configuration Space (Segment:0000 Bus:00 Device:1c Function:00)
    Common Header:
        00: VendorID       8086 Intel Corporation
        02: DeviceID       283f
        04: Command        0007 IOSpaceEn MemSpaceEn BusInitiate
        06: Status         0010 CapList
        08: RevisionID     03
        09: ProgIF         00
        0a: SubClass       04 PCI-PCI Bridge
        0b: BaseClass      06 Bridge Device
        0c: CacheLineSize  0000
        0d: LatencyTimer   00
        0e: HeaderType     81
        0f: BIST           00
        10: BAR0           00000000
        14: BAR1           00000000
        18: PriBusNum      00
        19: SecBusNum      01
        1a: SubBusNum      01
        1b: SecLatencyTmr  00
        1c: IOBase         20
        1d: IOLimit        20
        1e: SecStatus      0000
        20: MemBase        5130
        22: MemLimit       5230
        24: PrefMemBase    5001
        26: PrefMemLimit   50f1
        28: PrefBaseHi     00000000
        2c: PrefLimitHi    00000000
        30: IOBaseHi       0000
        32: IOLimitHi      0000
        34: CapPtr         40
        38: ROMBAR         00000000
        3c: IntLine        12
        3d: IntPin         01
        3e: BridgeCtrl     0000
    Device Private:
        40: 01418010 00008fc0 00100000 01114c11
        50: 30110000 0000a0e0 00400009 00000000
        60: 00000000 00000000 00000000 00000000
        70: 00000000 00000000 00000000 00000000
        80: 00009005 00000000 00000000 00000000
        90: 0000a00d 30d9103c 00000000 00000000
        a0: c8020001 00000000 00000000 00000000
        b0: 00000000 00000000 00000000 00000000
        c0: 00000000 00000000 00000000 00000000
        d0: 00000000 00000000 48110000 00000000
        e0: 00c70000 00080706 00000030 00000000
        f0: 00000000 00000000 00050f86 00000000
    Capabilities:
        40: CapID          10 PCI Express Capability
        41: NextPtr        80
        42: Express Caps   0141 Type:Root port
        44: Device Caps    00008fc0
        48: Device Control 0000 MRR:128 ns ap pf et MP:128 ro ur fe nf ce
        4a: Device Status  0010 tp AP ur fe nf ce
        4c: Link Caps      01114c11
        50: Link Control   0000 es cc rl ld RCB:64 ASPM:None
        52: Link Status    3011 SCC lt lte NLW:x1 LS:2.5
        54: Slot Caps      0000a0e0
        58: Slot Control   0009 pcc PI:?? AI:?? hpi cc PDE mrls pfd AB
        5a: Slot Status    0040 PDS hpi cc pdc ms pfd ab
        5c: Root Control   0000 pmei fs nfs cs
        5e: Reserved       0000
        60: Root Status    00000000 pmep pmes ID:0

        80: CapID          05 MSI Capability
        81: NextPtr        90
        82: MsgCtrl        MultipleMsgEnable:0 (0x1) MultipleMsgCapable:0 (0x1)
        84: MsgAddr        0
        88: MsData         0

        90: CapID          0d Subsystem ID Capability
        91: NextPtr        a0
        94: SubVendorID    103c
        96: SubSystemID    30d9

        a0: CapID          01 PwrMgmt Capability
        a1: NextPtr        00
        a2: PwrMgmtCap     c802 PMED0 PMED3Hot PMED3Cold Version=2
        a4: PwrMgmtCtrl    0000 DataScale:0 DataSel:0 D0


    quit:

    C:\>






    Monday, April 02, 2012 6:25 PM
  • You really, really don't want to write a driver for this.

    -- pa

    Monday, April 02, 2012 7:22 PM
  • I think I don't have other choice. But what Donald told at the last post gave me a light.
    I'm checking Donald's post

    Your post was a warning or a opinion ? :)


    rafael machado

    Monday, April 02, 2012 7:28 PM
  • Your post was a warning or a opinion ? :)

    Both.

    ** UPDATE**

    Look at this while waiting for more useful responces.

    --pa



    • Edited by Pavel A Tuesday, April 03, 2012 12:39 PM
    Tuesday, April 03, 2012 2:12 AM
  • Hi all

    Well, as I told before I'm new with this.

    Does any of you see another way to get the capabilities structure and Status regiter of the PCI bus, without writing a driver ?

    Thanks for the advice Pavel


    rafael machado

    Tuesday, April 03, 2012 12:20 PM
  • this is not really exposed without a driver because outside of a driver the information is not very useful

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Tuesday, April 03, 2012 4:44 PM
    Owner
  • So the only way seems to be with a driver right ?

    By the way, thanks Donald for the link to  http://www.hollistech.com/. This seems to be what I need if the only way is work with drivers.

    Rafael


    rafael machado

    Tuesday, April 03, 2012 6:18 PM
  • You Haven't Mentioned your os if you are targeting newer os > winxp your only choice is to work with a driver either an existing one or new one 

    if you were targeting xp you had an undocumented unsupportable non production way code that can whet only your curiosity using ZwSystemDebugControl() API  (so no driver ) (this api itself is undocumented and its internal workings parameters locks and whatever are on the deep end of some pointless hole.

    here is an output of such an exe

    you can verify that the output will match byte by byte to one of a post i made earlier in this thread the one with pciE CapId

    zwdbgsys:\>dir /b
    zwdbgsys.cpp

    zwdbgsys:\>cl /nologo zwdbgsys.cpp
    zwdbgsys.cpp

    zwdbgsys:\>dir /b
    zwdbgsys.cpp
    zwdbgsys.exe
    zwdbgsys.obj

    zwdbgsys:\>zwdbgsys.exe
    ZwSysDbg is locaated at 7C90DE4E
    bytes Returned is 4 and content is  283f8086  ----> intel  & device id
    bytes Returned is 4 and content is  100007  ---> caplist
    bytes Returned is 4 and content is  6040003
    bytes Returned is 4 and content is  810000
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  10100
    bytes Returned is 4 and content is  2020
    bytes Returned is 4 and content is  52305130
    bytes Returned is 4 and content is  50f15001
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  40
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  112
    bytes Returned is 4 and content is  1418010
    bytes Returned is 4 and content is  8fc0
    bytes Returned is 4 and content is  100000
    bytes Returned is 4 and content is  1114c11
    bytes Returned is 4 and content is  30110000
    bytes Returned is 4 and content is  a0e0
    bytes Returned is 4 and content is  400009
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  9005
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  a00d
    bytes Returned is 4 and content is  30d9103c
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  c8020001
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  48110000
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  c70000
    bytes Returned is 4 and content is  80706
    bytes Returned is 4 and content is  30
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  0
    bytes Returned is 4 and content is  50f86
    bytes Returned is 4 and content is  0

    zwdbgsys:\>

    conceptually the code would belike

    LoadLib -> GetProc -> ZwSystemDebugControl -> OpenProcess->AdjustTokenPrivileges ->WriteIoSpace -> ReadIoSpace

    Tuesday, April 03, 2012 11:53 PM
  • Hi everyone

    blufferisme

    Really nice this API!.. unfortunetly the system must work in windows xp, 7, server 2008... so I think this option is kind of risk.

    I'll follow the way mentioned by Gary and Donald. Seems to be the best  choice, but thanks a lot anyway. I'm reading something about ZwSystemDebugControl() and this is giving me some tips about drivers and how the OS works.

    Thanks a lot everyone. I'll try some tests now with drivers and as soon as I have what I need I'll tell you.

    Thanks Guys


    rafael machado

    Wednesday, April 04, 2012 2:36 PM
  • Hi everyone. Long time that we don't talk.

    I've being researching about this topic (Get PCI Express information), and I found the following article:

    http://support.microsoft.com/kb/253232

    There, at the first code sample, there is a code used to get the PCI express area. But after the fisrt code sample we have this text:

    Because you can only send the PnP I/O Request Packets (IRPs) at PASSIVE_LEVEL, you cannot use the above function to get the configuration information at DISPATCH_LEVEL.

    May be my english is worst than I imagine. But doesn't this text means that the previous code sample is for a PASSIVE_LEVEL application ?

    Just to close any doubt I may have:

    Dispatch level = drivers

    Passivel Level = normal applications

    Thanks everyone


    rafael machado

    Thursday, April 26, 2012 1:46 PM
  • No PASSIVE_LEVEL and DISPATCH_LEVEL are both run in drivers.  PASSIVE_LEVEL is what all user space code runs in, but this is not anything that indicates whether it is the kernel or the user.  These levels represent preemtable versus non-preemtable code. 


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, April 26, 2012 3:54 PM
  • Thanks for the answer Donald.

    So the code I found at http://support.microsoft.com/kb/253232 (the first sample code), seems to work in a "normal" application instead of need to write a driver for this right ?


    rafael machado

    Friday, April 27, 2012 12:31 PM
  • So the code I found at http://support.microsoft.com/kb/253232 (the first sample code), seems to work in a "normal" application instead of need to write a driver for this right ?

    Unfortunately, wrong. The code in that KB article is intended to run in driver context. Not in normal application. More to this: " The driver should be part of the device's driver stack". We are back on square one.

    Since you do have some kernel driver for your device anyway, research how you can use that driver.

    -- pa

    



    • Edited by Pavel A Friday, April 27, 2012 2:25 PM
    Friday, April 27, 2012 2:23 PM
  • Thanks a lot for the answer Pavel.

    I'll research about this.


    rafael machado

    Friday, April 27, 2012 2:28 PM
  • Here I'am again after some research.

    The current scenario is that, I have a driver project that is compiling and running with no errors, but unfortunately I'am not able to get the result of my IRP_MN_READ_CONFIG.

    The code is basically the same as the one on the link http://support.microsoft.com/kb/253232 

    NTSTATUS
    ReadWriteConfigSpace(
        IN PDEVICE_OBJECT  DeviceObject,
        IN ULONG  ReadOrWrite,  // 0 for read, 1 for write
        IN PVOID  Buffer,
        IN ULONG  Offset,
        IN ULONG  Length
        )
    {
        KEVENT event;
        NTSTATUS status;
        PIRP irp;
        IO_STATUS_BLOCK ioStatusBlock;
        PIO_STACK_LOCATION irpStack;
        PDEVICE_OBJECT targetObject;
        PAGED_CODE();
        KeInitializeEvent(&event, NotificationEvent, FALSE);
        
    	//targetObject = IoGetAttachedDeviceReference(DeviceObject);
    	targetObject = DeviceObject;
        
    	irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
                                           targetObject,
                                           NULL,
                                           0,
                                           NULL,
                                           &event,
                                           &ioStatusBlock);
        if (irp == NULL) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto End;
        }
        irpStack = IoGetNextIrpStackLocation(irp);
        if (ReadOrWrite == 0) {
            irpStack->MinorFunction = IRP_MN_READ_CONFIG;
        } else {
            irpStack->MinorFunction = IRP_MN_WRITE_CONFIG;
        }
        irpStack->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
        irpStack->Parameters.ReadWriteConfig.Buffer = Buffer;
        irpStack->Parameters.ReadWriteConfig.Offset = Offset;
        irpStack->Parameters.ReadWriteConfig.Length = Length;
        // Initialize the status to error in case the bus driver does not 
        // set it correctly.
        irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
        status = IoCallDriver(targetObject, irp);
        if (status == STATUS_PENDING) {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = ioStatusBlock.Status;
        }
    End:
        // Done with reference
        ObDereferenceObject(targetObject);
        return status;
    }

    I have two doubts now.

    First: At the following code:

    line 1: //targetObject = IoGetAttachedDeviceReference(DeviceObject);
    line 2: targetObject = DeviceObject;

    The line 1 is the line we hae on the original code, but while I'm debugging the code I see that targetObject is referencing the same driver that I'm developping. So when I call:

    status = IoCallDriver(targetObject, irp);

    I'm calling the same driver I'm developping, and not the next driver on the driver stack. At line 2 I changed the target to be the PNPManager.

    Is this correct ? Should I call the PNPManager at this line ?

    Second:

    After calling:

    IoCallDriver(targetObject, irp);

    The resul should be placed at the buffer right ? :

    irpStack->Parameters.ReadWriteConfig.Buffer = Buffer;

    I'm calling this function this way:

    NTSTATUS DriverTestDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
    	
    	
    	PDriverTest_DEVICE_EXTENSION deviceExtension = NULL;
    	
    	IoSkipCurrentIrpStackLocation(Irp);
    	deviceExtension = (PDriverTest_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
    	
    	ULONG * buff = NULL;
    	ReadWriteConfigSpace(deviceExtension->TargetDeviceObject,0,buff,0,10);
    	return STATUS_SUCCESS;
    }
    Am I doing some stupid mistake or misunderstanding something ?

    Thanks everyone

    Friday, May 04, 2012 5:19 PM
  • rafael machado wrote:
    >
    >I have two doubts now.
    >
    >First: At the following code:
    >
    >line 1: //targetObject = IoGetAttachedDeviceReference(DeviceObject);
    >line 2: targetObject = DeviceObject;
    >
    >The line 1 is the line we hae on the original code, but while I'm debugging
    >the code I see that targetObject is referencing the same driver that I'm
    >developping. So when I call:
    >
    >status = IoCallDriver(targetObject, irp);
    >
    >I'm calling the same driver I'm developping, and not the next driver on the
    >driver stack. At line 2 I changed the target to be the PNPManager.
    >
    >Is this correct ?
     
    I don't know what you mean by PNPManager here.  Yes, your line 2 is sending
    the IRP to yourself.  However, your driver's PnP handler is supposed to
    pass any PnP IRPs that it doesn't handle down to the next driver anyway, so
    the net effect will be the same.
     
    However, you aren't passing YOUR device object, you are passing
    TargetDeviceObject from your extension.  What does that contain?  Is it
    already the next device down?
     
    Also, if you aren't grabbing an extra reference (by calling
    IoGetAttachedDeviceReference), then you certainly do not want to call
    ObDereferenceObject at the end!! 
     
    >Second:
    >
    >After calling:
    >
    >IoCallDriver(targetObject, irp);
    >
    >The resul should be placed at the buffer right ? :
    >
    >irpStack->Parameters.ReadWriteConfig.Buffer = Buffer;
     
    Yes, assuming you are doing a "read".
     
    >I'm calling this function this way:
    >NTSTATUS DriverTestDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    >{
    >    PDriverTest_DEVICE_EXTENSION deviceExtension = NULL;
    >    IoSkipCurrentIrpStackLocation(Irp);
    >    deviceExtension = (PDriverTest_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
    >    ULONG * buff = NULL;
    >    ReadWriteConfigSpace(deviceExtension->TargetDeviceObject,0,buff,0,10);
    >
    >Am I doing some stupid mistake or misunderstanding something ?
     
    You are making some stupid mistakes.  Where do you think the call is going
    to put the information you are requesting?  You haven't given it a buffer!
    You are passing a NULL.  That will cause a blue screen.
     
    What do you think you are going to read here?  Why 10 bytes?  PCI
    configuration space comes in units of dwords.  If you just want the vendor
    ID and device ID, you'd do:
     
        ULONG buff;
        ReadWriteConfigSpace( ..., 0, &buff, 0, sizeof(buff) );
     
    Note that "buff" is not a pointer, and I am passing the ADDRESS of buff
    here, and I'm only requesting as much space as "buff" will hold.
    --
    Tim Roberts, timr@probo.com
    Providenza & Boekelheide, Inc.
     

    Tim Roberts, VC++ MVP Providenza & Boekelheide, Inc.
    Saturday, May 05, 2012 11:33 PM
  • I have two doubts now.

    First: At the following code:

    line 1: //targetObject = IoGetAttachedDeviceReference(DeviceObject);
    line 2: targetObject = DeviceObject;

    The line 1 is the line we hae on the original code, but while I'm debugging the code I see that targetObject is referencing the same driver that I'm developping. So when I call:

    status = IoCallDriver(targetObject, irp);

    I'm calling the same driver I'm developping, and not the next driver on the driver stack. At line 2 I changed the target to be the PNPManager.

    Changed the target to PNPManager?? It is not a device in your stack, you cannot call it. The IRP_MN_QUERY_INTERFACE or IRP_MN_READ_CONFIG requests should go to the driver below you. You get this object as the 2nd arg in your AddDevice. See for example [WDK 7.1 0]\src\general\pcidrv\wdm\PCIDRV.C function PciDrvAddDevice.   Using IoGetAttachedDeviceReference, as in the KB example, should work as well.

    Am I doing some stupid mistake or misunderstanding something ?

    May be. It is not especially simple and intuitive, even in comparison to Linux.

    -- pa

    Saturday, May 05, 2012 11:37 PM
  • you don't want to send the QI directly to the PDO. pnp rules state that the QI should flow down through the top of the stack (ie your device object if you are the top) all the way to the PDO if needed.  At the very least, send the QI to the device you are attached to (ie the result of IoAttachDeviceToDeviceStack) and not the PDO (although the attached device could very well be the PDO directly)

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Saturday, May 05, 2012 11:43 PM
    Owner
  • HI everyone.

    Now I understood the device stack.

    I think I did what I need. I'm doing some tests.

    Thanks a lot Tim, Pavel and Doron.


    rafael machado

    Tuesday, May 08, 2012 6:30 PM
  • Hi everyone

    I'm doing some tests now and I'm having on error while compiling this line of code:

    PBUS_INTERFACE_STANDARD busInterface;
    .
    .
    .
    busInterface = new('IBFG', NonPagedPool) BUS_INTERFACE_STANDARD;

    The error is this:

    error C2660: 'operator new' : function does not take 3 arguments

    This code was taken from the second example ( The Driver Interface (IRP_MN_QUERY_INTERFACE) method)) of the document "Replacing GetBusData in Windows 2000" from the site: http://www.hollistech.com/

    Siggested by Donald 20 posts ago

    Does eny of you know what it the problem ? Do I need to change something on the compiler ?

    I've tried to find the constructor of the Bus_Interface_Standard unsuccescully.

    Google didn't answer me too. I'm Using Visual DDK project and Visual Studio 2008

    Sorry if it's a stupid mistake. I'm kind of new with C++ and C

    Thanks a lot everyone. Your help is saving me and I'm learning a lot


    rafael machado

    Thursday, May 10, 2012 11:51 AM
  • You've just stepped on the path of pain and frustration :-(  Unfortunately it is not going to be easy. If you can find a consultant/contractor to do this piece of code for you - by all means do so.

    Regards,

    -- pa

    Thursday, May 10, 2012 3:13 PM
  • The sample I pointed you to uses the C++ framework from the same site.  I would strip out the C++ stuff from the code and use straight C, since there are a lot of tricky things about use C++ in the kernel.  I don't remember if this was asked before, are you doing this for one device, or do you need a general purpose capability for all PCI devices.  I ask this since if it is the later you need a PCI bus driver, and in that case I concur with Pavel, get a consultant.  If it is for a single device this is something that can be done in a fairly simple driver, and depending on your willingness to slog through things it should be doable.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, May 10, 2012 3:21 PM
  • Hi Donald.

    This is just for PCIExpress devices. Just need to get some information related to the slot status, capabilities structures and this kind of things.

    I think I'm on the right way. The tips everybody here gives me are really working.

    I'm using just C on the sample as you told Donald. But I have a question.

    When I create the BUS_INTERFACE_STANDARD structure, it's not "creating"

    function GetBusData, as on the picture below:

    Does anybody have any idea about what am I missing ?

    Thanks everyone


    rafael machado


    Thursday, May 10, 2012 6:39 PM
  • Have you noticed that InterfaceReference pointer also looks wrong? Looks like something is wrong with your tools or settings.

    -- pa

    Thursday, May 10, 2012 9:49 PM
  • Yes. The only functions that are "working" are SetBusData and InterfaceDereference.

    I'll update virtualBox and try again.


    rafael machado

    Friday, May 11, 2012 1:34 PM
  • Hi Everyone.

    I did the code work now using IRP_MN_READ_CONFIG.

    The strange thing now is that when I execute:

    ReadWriteConfigSpace(DeviceObject, 0, &pPciConfig,0,sizeof(PCI_COMMON_HEADER));

    the pPciConfig structure is not populated.

    Here is the code used to read the data:

    NTSTATUS
    ReadWriteConfigSpace(
        IN PDEVICE_OBJECT DeviceObject,
        IN ULONG	      ReadOrWrite, // 0 for read 1 for write
        IN PVOID	      Buffer,
        IN ULONG	      Offset,
        IN ULONG	      Length
        )
    {
        KEVENT event;
        NTSTATUS status;
        PIRP irp;
        IO_STATUS_BLOCK ioStatusBlock;
        PIO_STACK_LOCATION irpStack;
        PDEVICE_OBJECT targetObject;
        PAGED_CODE();
        KeInitializeEvent( &event, NotificationEvent, FALSE );
        targetObject = IoGetAttachedDeviceReference( DeviceObject );
        irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
                                            targetObject,
                                            NULL,
                                            0,
                                            NULL,
                                            &event,
                                            &ioStatusBlock );
        if (irp == NULL) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto End;
        }
        irpStack = IoGetNextIrpStackLocation( irp );
        if (ReadOrWrite == 0) {
            irpStack->MinorFunction = IRP_MN_READ_CONFIG;
        }else {
            irpStack->MinorFunction = IRP_MN_WRITE_CONFIG;
        }
        irpStack->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
        irpStack->Parameters.ReadWriteConfig.Buffer = Buffer;
        irpStack->Parameters.ReadWriteConfig.Offset = Offset;
        irpStack->Parameters.ReadWriteConfig.Length = Length;
        // 
        // Initialize the status to error in case the bus driver does not 
        // set it correctly.
        // 
        irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
        status = IoCallDriver( targetObject, irp );
        if (status == STATUS_PENDING) {
            KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
            status = ioStatusBlock.Status;
        }
    End:
        // 
        // Done with reference
        // 
        ObDereferenceObject( targetObject );
        return status;
    }

    Any idea about the problem ?

    Thanks and Regards


    rafael machado

    Friday, May 11, 2012 8:12 PM
  • Hi all

    I did some tests using vbox and UEFI to check if my code is returning the data correctly. At UEFI environment whe have the command PCI.

    With this command we return all PCI information we have as on the image bellow:

    

    With the command: pci 00 00 00 -i I have the Space used by the PCI device () in this case the first device

    Infortunetly, when I run my filter driver, I don't get the vendor ID: 8086

    My question is. What can I do to have all PCI devices on the same way I have at UEFI environment so I can loop then and find the device I really want ?

    Thanks everyone


    rafael machado



    Monday, May 14, 2012 5:46 PM
  • This is what I have at windows driver:

    Seems to be just memory trash. I'm not sure if the PCI space is being accessed using this driver.


    Monday, May 14, 2012 5:50 PM
  • Hi everyone.

    Just to close this conversation.

    For those who are trying to understand WDM, the following link contains what I was searching.

    http://www.codeproject.com/Articles/35378/Access-Physical-Memory-Port-and-PCI-Configuration

    Thanks everyone for the help and sorry about some questions I did. Now I'm studing and understood several things I asked before.

    Thanks again


    rafael machado

    Thursday, May 24, 2012 6:52 PM
  • I hope you changed a lot of this sample.  It is not plug and play and has a huge number of flaws.  The last time a customer of mine use this one as a start, I was able to identify it as the cause of at least 20 unique crashes.  This is terrible code that does not reflect good practice 10 years ago, let alone today.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, May 24, 2012 7:09 PM
  • Hi Donald.

    Thanks again for the answer.

    So as I understood the correct way is to migrate this code to PNP right ?

    Could you please tell some of these flaws you told ? I saw just one because I'm still begining to study driver development. I'm doing a course at my country. For now the only thing I saw as incorrect it that this code use IoAttachDeviceToDeviceStack instead of IoAttachDeviceToDeviceStackSafe.

    Thanks


    rafael machado

    Friday, May 25, 2012 11:23 AM
  • Rafael, it seems that _your_ driver already is PnP (since it is the functon or filter driver of your PCI device). So it _should_ work. Why it doesn't? We could not tell from the information you've posted (thus I suspected some "beginner issue").

    -- pa


    • Edited by Pavel A Friday, May 25, 2012 1:21 PM
    Friday, May 25, 2012 1:20 PM
  • At a minimum you need to:

    1.  Change this to be built under the WDK with BUILD

    2.  Run PreFast (first turning off all filtering) and fix all the bugs shown for this code

    3.  Run Static Driver Verifier and again fix all the bugs for this code.

    4.  Put it on a test environment, with Driver verifier turned on and run PnpDtest against the device with this driver loaded.

    I suspect you will find this is a lot of work.  I would have started with a good filter sample in KMDF from the WDK unless you wanted a bus filter (which is possible from your description). 

    If it was a bus filter start with a good WDM filter sample from the WDK, and then expect a lot of challenges.  PCI Bus filters can be written (I've done one comercially) but they can be challenging to get right.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Friday, May 25, 2012 2:08 PM
  • Answering one at a time.

    Pavel.

    The driver is working correctly at a test environment. I'm just woried about what Donald say. I understand that this is a PNP driver too.

    Donald.

    I've already done the first item. Sorry for the question, but what do you mean with PreFast ?

    About the Static Driver Verifier, I'm checkng this tool and how to use it. Thanks for the tips.


    rafael machado

    Friday, May 25, 2012 4:03 PM
  • In you build command window, do the following:

    a. execute "prefast view", then choose the filter button at the top of the window and select "no defects"

    b.  edit the sources file for your driver adding "MSC_WARNING_LEVEL=/W4 /WX".  This is not a prefast thing, but it means you get all the compiler checks.  Note if MSC_WARNING_LEVEL is present already, edit it to this.

    c. build the driver by the command "prefast build -cefbw" so that it runs Prefast on your sources and rebuilds everything.  From then on use prefast with the build command to check you driver.  If prefast reports errors, "prefast view" will show them.  Note: if you have been getting OACR popups you will see some prefast errors, but since OACR applies filters it is worse than worthless IMHO.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Friday, May 25, 2012 4:25 PM
  • Thanks again for the help Donald.


    rafael machado

    Monday, May 28, 2012 1:36 PM