2
votes

I am trying to write a program to dump option/expansion ROMs on linux. I already have the necessary PCI port IO to get an expansion ROM's base address out of the PCI configuration data at offset 0x30 and make it enabled, but when I try to access the base in memory I get a segfault. So I am trying to understand what is happening when you do the "echo 1 > rom" from a linux command line, since after that the rom seems plenty accessible (see here for a little more context: http://etherboot.org/wiki/romdumping)

E.g. let's say I do the following:

lspci

01:00.0 VGA compatible controller: ATI Technologies Inc RV370 5B60 [Radeon X300 (PCIE)]

cd /sys/bus/pci/devices/0000:01:00.0

lspci -x -v -s 01:00.0

01:00.0 VGA compatible controller: ATI Technologies Inc RV370 5B60 [Radeon X300 (PCIE)]
        Subsystem: ATI Technologies Inc Device 0402
        Flags: bus master, fast devsel, latency 0, IRQ 27
        Memory at d0000000 (32-bit, prefetchable) [size=128M]
        I/O ports at dc00 [size=256]
        Memory at dfde0000 (32-bit, non-prefetchable) [size=64K]
        Expansion ROM at dfe00000 [disabled] [size=128K]
        Capabilities: [50] Power Management version 2
        Capabilities: [58] Express Endpoint, MSI 00
        Capabilities: [80] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable+
        Capabilities: [100] Advanced Error Reporting <?>
        Kernel driver in use: radeon
        Kernel modules: radeonfb, radeon
00: 02 10 60 5b 07 04 10 00 00 00 00 03 10 00 80 00
10: 08 00 00 d0 01 dc 00 00 00 00 de df 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 02 10 02 04
30: 00 00 e0 df 50 00 00 00 00 00 00 00 0b 01 00 00

Note the line that says "Expansion ROM at dfe00000 [disabled] [size=128K]" Now per the PCI spec I can see that the bottom bit should be set to 1 to enable the expansion ROM, so I did a read and write back of 0xdfe00001, and then I get

01:00.0 VGA compatible controller: ATI Technologies Inc RV370 5B60 [Radeon X300 (PCIE)]
        Subsystem: ATI Technologies Inc Device 0402
        Flags: bus master, fast devsel, latency 0, IRQ 27
        Memory at d0000000 (32-bit, prefetchable) [size=128M]
        I/O ports at dc00 [size=256]
        Memory at dfde0000 (32-bit, non-prefetchable) [size=64K]
        Expansion ROM at dfe00000 [size=128K]
        Capabilities: [50] Power Management version 2
        Capabilities: [58] Express Endpoint, MSI 00
        Capabilities: [80] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable+
        Capabilities: [100] Advanced Error Reporting <?>
        Kernel driver in use: radeon
        Kernel modules: radeonfb, radeon
00: 02 10 60 5b 07 04 10 00 00 00 00 03 10 00 80 00
10: 08 00 00 d0 01 dc 00 00 00 00 de df 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 02 10 02 04
30: 01 00 e0 df 50 00 00 00 00 00 00 00 0b 01 00 00

(note the 0x01 at offset 0x30 and the line now saying "Expansion ROM at dfe00000 [size=128K]").

But I can't access 0xdfe00000. Meanwhile, when O do the "echo 1 > rom" in the command line, it does NOT change the line to remove the "disabled", and really it doesn't make any change at all to the output of lspci. So what is the "echo 1 > rom" doing that I'm not, which makes it subsequently possible to do the "dd if=rom of=/tmp/rom"?

Much appreciated

2

2 Answers

2
votes

rom is a special file usually read-protected unless '1' is written to it, from sysfs-pci.txt:

The 'rom' file is special in that it provides read-only access to the device's ROM file, if available. It's disabled by default, however, so applications should write the string "1" to the file to enable it before attempting a read call, and disable it following the access by writing "0" to the file. Note that the device must be enabled for a rom read to return data successfully. In the event a driver is not bound to the device, it can be enabled using the 'enable' file, documented above.

So it looks like 'echo 1 > rom' really only enables reading the rom through sysfs. Maybe you can't access the rom through its bar because it's not mapped to dfe00000 by default? Not sure, worth checking though.

0
votes

I've tried to get the exROM contents from an NVidia VGA board (NVS310) - from the Linux command line :-) This is what I did, approximately: From lspci -vvn, I found out that my board is at 0000:02:00.0 and its exROM is at 0xf7000000 size 512 kB (and its address decoder is disabled in the exROM BAR = via bit 0 in PCI config space reg #c0 == offset 0x30).

I then used setpci to toggle that "exROM BAR enable bit" in the PCI config space. Notice the notation value:mask in the "write" form of setpci:

setpci --dumpregs
setpci -s 0000:02:00.0 ROM_ADDRESS
setpci -s 0000:02:00.0 ROM_ADDRESS=00000001:00000001
setpci -s 0000:02:00.0 ROM_ADDRESS
lspci -vvn -s 0000:02:00.0
dd if=/dev/mem of=vgabios.bin bs=64k skip=63232 count=8

Which resulted in some semi-plausible looking binary data in a file 512 kB long.

Access via /sys/bus/pci/devices/0000:02:00.0/rom did not work, even after I wrote a "1" into that pseudo-file.