PCItree displays all components of the PCIbus as a tree structure. The Config Space of devices can be read and edited. If a device features io or memory space it can be read and edited as well (but be carefull! it can hang or even damage your hardware!).
pcitree scans the PCIbus of the host PC and displays the found components as a tree. components are found if a read of DID and VID doesn't return 0xffffffff.
last PCI bus number: The value of the highes PCIbus number is displayed right above the tree pane
b.d.f : Each PCI component has an integer number for bus, device and function.
direct select: in case you think not all components in the PCIbus system are found:
any b.d.f can be choosen directly by the three spin controls in the direct select box. A config read is done for this b.d.f and the result is displayed in the Config Space Dump.
If for a choosen b.d.f a PCI component exists it is highlightet in the tree pane.
++ expands all levels of the tree
-- collapses all levels of the tree
refresh tree rescans the whole PCIbus
save tree writes the tree structure to a file
reset bridge resets the secondary PCIbus of a PPB. After the reset the config space of all devices behind the bridge is restored.
Nr of ConfRegs:
16 : config space from adress 0 to 0x3f is read (default)
64 : config space from adress 0 to 0xff is read
refresh dump: rereads the config space of the device and displays it
If a component is selected in the tree the register contents of its configuration space (16 or 64 dwords) are displayed in the lower right window.
If a BAR is used (value != 0) it is indicated wether its memory or io space.
You can double click on a BAR to view/edit the memory/io space
You should know what happens if you read memory/io space !!
The following information is extracted and decoded from the config space:
VendorID: value & decoded
Subsys VID: value & decoded
Subsys ID : value
Base/Sub Class code: value & decoded
Interrupt Pin/Line: decoded
revision number: value
you can click and double click on a Config Space Register in the list box
if you click on a Config register in the list box its DWORD contents is displayed
in the edit box. You can modify this value (the 1st character must be an x). The
string will be scanned by sscanf(str, "x%X", &data).
Write ConfReg writes the DWORD value of the edit box to the Config register.
The sscaned value is displayed below the edit box (for feedback).
refr after wr. refreshes the dump after the Write Confreg
A component with a INT pin is displayed as "X(b.d.f)DDDD.VVVV" where X is one of
the INT pins INTA to INTD. b.d.f is bus.device.function number. DDDD is DeviceID
and VVVV is VendorID.
Note: the range of the BAR space is not derieved because it needs a READ-WRITE-READ-
WRITE sequence to the BAR which can cause malfunctions of the PCI system !!
(see "BAR space" below)
Only 32 bit adress space is supported.
BAR space detection:
If you click YES in the message box the following happens:
the BAR in the ConfigSpace is read and stored
the BAR is written with 0xffffffff (!!)
the BAR is read. With the read value the size of the memory/io space is determined
the BAR is written with the stored BAR value
a linear adress of 1Kbyte is mapped to the physical adress (the contents of the BAR)
a new Dialog window with a list box is opened
(In some cases the described BAR detection can cause malfunctions of the PCI system because the BAR is temporarily changed !!)
If you click NO then the described procedure is not done. Instead a size of 1 MByte is assumed.
128 Bytes: only the first 128 Bytes of the selected 1Kbyte range are displayed
and refreshed (faster cont. cycles & shorter cycles to
view with a logic analyzer)
1024 Bytes: the whole 1K range is displayed in the list box (default)
If the size of the memory/io space is smaller only this space is displayed.
select view range:
If the size of the memory/io space is bigger than 1Kbyte then you can select another
1Kbyte block to be displayed in the list box. Just move the scrollbars for KB range
and MB range.
list box contents:
1st col: DWORD contents (MSbyte:LSbyte)
2nd col: address offset in the memory/io space
3rd col: ASCII character of the 4 bytes (LSbyte:MSbyte)
refr. view : rereads the selected 1Kbyte (or 128 Byte) block and displays it in the list box
select one DWORD in the list box or select a range of DWORDs in the list box
the first DWORD of the selected range is displayed in the edit box. Physical address and number of selected DWORDs are displayed at the right of the edit box.
You can modify the value in the edit box (the 1st character must be an x). The string will be scanned by sscanf(str, "x%X", &data) when the write button is pushed. The sscaned value is displayed below the edit box (for feedback).
Write Memory writes the DWORD value of the edit box to the selected range with the following options:
loop on/off. continously loops accesing the selected range
stops if button is being unchecked
toggle. toggles (inverts) every second DWORD to be written
count. increments each WORD of the DWORD for the next write access
verify. after the selected range is written it is read and compared to the
written values. If an error occurs (the cont. loop is stoped and) the
false values are highlighted in the list box
refresh view after write. refreshes the whole list box after the selected
range is written (and verified)
the function memcpy( p_dest, p_src, b_range ) is used to read max. 1Kbytes from the selected memory/io space to a buffer and then write it to the selected destination.
-select a range in the list box that should be copied to another location
-select the first location where the source block should be copied to
-push mem copy
possible problems to get the BAR space:
> To: Mailing List Recipients <firstname.lastname@example.org
> Subject: Re: Unruly BIOSes and the Intel i960RP
> I had a problem with a Base Address Register in the Intel i960RP. The
> BIOS writes FFFF FFFF to this register and then reads what comes back to
> determine the size required by the device. The i960 returns a value
> based on the limit register once and once only, and subsequent reads
> from the BAR return the current programmed value of BAR. The PCI
> specification, as I read it, does not preclude this behaviour.
> It would seem to be more complicated to implement this behaviour as it
> requires a register to keep state information, and a side effect of
> reading in configuration space is to alter this state. Still, that is
> what happens, so I have to live with it.
> Some BIOSes, it seems, read the BAR twice when determining the address
> limit. Such BIOSes are confused by what they see come back, and so write
> 8000 8000 to the BAR. This seems to me equally bizarre. Surely 0000 0000
> would be a more sensible thing to write to a difficult BAR: this would
> effectively disable the allocation requested by that BAR ?
> I am considering writing a PCI configuration helper which runs after the
> BIOS but before Windows gets started, and straightens out anomolies such
> as the one above.