23.6.1.2. Manipulate PCI registers directly
In this section we will try to interact with PCI devices directly from userland without kernel modules.
First identify the PCI device with:
lspci
In our case for example, we see:
00:06.0 Unclassified device [00ff]: Device 1234:11e8 (rev 10) 00:07.0 Unclassified device [00ff]: Device 1234:11e9
which we identify as being QEMU edu PCI device by the magic number: 1234:11e8
.
Alternatively, we can also do use the QEMU monitor:
./qemu-monitor info qtree
which gives:
dev: edu, id "" addr = 06.0 romfile = "" rombar = 1 (0x1) multifunction = false command_serr_enable = true x-pcie-lnksta-dllla = true x-pcie-extcap-init = true class Class 00ff, addr 00:06.0, pci id 1234:11e8 (sub 1af4:1100) bar 0: mem at 0xfea00000 [0xfeafffff]
Read the configuration registers as binary:
hexdump /sys/bus/pci/devices/0000:00:06.0/config
Get nice human readable names and offsets of the registers and some enums:
setpci --dumpregs
Get the values of a given config register from its human readable name, either with either bus or device id:
setpci -s 0000:00:06.0 BASE_ADDRESS_0 setpci -d 1234:11e8 BASE_ADDRESS_0
Note however that BASE_ADDRESS_0
also appears when you do:
lspci -v
as:
Memory at feb54000
Then you can try messing with that address with /dev/mem:
devmem 0xfeb54000 w 0x12345678
which writes to the first register of the edu device.
The device then fires an interrupt at irq 11, which is unhandled, which leads the kernel to say you are a bad person:
<3>[ 1065.567742] irq 11: nobody cared (try booting with the "irqpoll" option)
followed by a trace.
Next, also try using our irq.ko IRQ monitoring module before triggering the interrupt:
insmod irq.ko devmem 0xfeb54000 w 0x12345678
Our kernel module handles the interrupt, but does not acknowledge it like our proper edu kernel module, and so it keeps firing, which leads to infinitely many messages being printed:
handler irq = 11 dev = 251