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