mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
pci: review setpci and devmem manipulations
Make if you do this then this happens relations clearer.
This commit is contained in:
105
README.adoc
105
README.adoc
@@ -2760,7 +2760,7 @@ Now try the following:
|
||||
* press a mouse key, and release it after a few seconds
|
||||
* move the mouse around
|
||||
|
||||
Outcome: dmesg shows which IRQ was fired for each action throug messages of type:
|
||||
Outcome: dmesg shows which IRQ was fired for each action through messages of type:
|
||||
|
||||
....
|
||||
handler irq = 1 dev = 250
|
||||
@@ -2769,7 +2769,7 @@ handler irq = 1 dev = 250
|
||||
`dev` is the character device for the module and never changes, as can be confirmed by:
|
||||
|
||||
....
|
||||
cat /proc/devices | grep lkmc_irq
|
||||
grep lkmc_irq /proc/devices
|
||||
....
|
||||
|
||||
The IRQs that we observe are:
|
||||
@@ -3776,6 +3776,25 @@ PCI driver for our minimal `pci_min.c` QEMU fork device:
|
||||
insmod /pci_min.ko
|
||||
....
|
||||
|
||||
Outcome:
|
||||
|
||||
....
|
||||
<4>[ 10.608241] pci_min: loading out-of-tree module taints kernel.
|
||||
<6>[ 10.609935] probe
|
||||
<6>[ 10.651881] dev->irq = 11
|
||||
lkmc_pci_min mmio_write addr = 0 val = 12345678 size = 4
|
||||
<6>[ 10.668515] irq_handler irq = 11 dev = 251
|
||||
lkmc_pci_min mmio_write addr = 4 val = 0 size = 4
|
||||
....
|
||||
|
||||
What happened:
|
||||
|
||||
* right at probe time, we write to a register
|
||||
* our hardware model is coded such that it generates an interrupt when written to
|
||||
* the Linux kernel interrupt handler write to another register, which tells the hardware to stop sending interrupts
|
||||
|
||||
Kernel messages and printks from inside QEMU are shown all together, to see that more clearly, run in <<graphic-mode>> instead.
|
||||
|
||||
Source:
|
||||
|
||||
* Kernel module: link:kernel_module/pci_min.c[].
|
||||
@@ -3798,12 +3817,12 @@ Small upstream educational PCI device:
|
||||
/pci.sh
|
||||
....
|
||||
|
||||
Source:
|
||||
This tests a lot of features of the edu device, to understand the results, compare the inputs with the documentation of the hardware: https://github.com/qemu/qemu/blob/v2.12.0/docs/specs/edu.txt
|
||||
|
||||
Sources:
|
||||
|
||||
* kernel module: link:kernel_module/pci.c[]
|
||||
* QEMU device:
|
||||
** source: https://github.com/qemu/qemu/blob/v2.12.0/hw/misc/edu.c
|
||||
** documentation: https://github.com/qemu/qemu/blob/v2.12.0/docs/specs/edu.txt
|
||||
* QEMU device: https://github.com/qemu/qemu/blob/v2.12.0/hw/misc/edu.c
|
||||
* test script: link:rootfs_overlay/pci.sh[]
|
||||
|
||||
Works because we add to our default QEMU CLI:
|
||||
@@ -3824,31 +3843,41 @@ TODO exercise DMA on the kernel module. The `edu` hardware model has that featur
|
||||
* https://stackoverflow.com/questions/32592734/are-there-any-dma-driver-example-pcie-and-fpga/44716747#44716747
|
||||
* https://stackoverflow.com/questions/17913679/how-to-instantiate-and-use-a-dma-driver-linux-module
|
||||
|
||||
===== setpci
|
||||
===== Manipulate PCI registers directly
|
||||
|
||||
There are two versions of `setpci` and `lspci`:
|
||||
In this section we will try to interact with PCI devices directly from userland without kernel modules.
|
||||
|
||||
* a simple one from BusyBox
|
||||
* a more complete one from link:https://github.com/pciutils/pciutils[pciutils] which Buildroot has a package for. This is the one we enable by default.
|
||||
|
||||
`setpci` can read and write to PCI configuration registers.
|
||||
|
||||
Read is possible from Linux with:
|
||||
First identify the PCI device with:
|
||||
|
||||
....
|
||||
hexdump /sys/bus/pci/devices/0000:00:05.0/config
|
||||
lspci
|
||||
....
|
||||
|
||||
and `/dev/mem` can of course do both reads and writes, but `setpci` provides nice human readable register names, e.g.:
|
||||
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 `edu` and `pci_min` respectively by the magic numbers: `1234:11e?`
|
||||
|
||||
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
|
||||
....
|
||||
|
||||
then and then get the values with either bus or device id:
|
||||
Get the values of a given config register from its human readable name, either with either bus or device id:
|
||||
|
||||
....
|
||||
setpci -s 0000:00:05.0 BASE_ADDRESS_0
|
||||
setpci -s 0000:00:06.0 BASE_ADDRESS_0
|
||||
setpci -d 1234:11e9 BASE_ADDRESS_0
|
||||
....
|
||||
|
||||
@@ -3858,13 +3887,49 @@ 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:
|
||||
|
||||
....
|
||||
devmem 0xfeb52000 w 0x12345678
|
||||
devmem 0xfeb54000 w 0x12345678
|
||||
....
|
||||
|
||||
which for our <<pci_min>> device fires interrupts.
|
||||
which writes to the first register of our <<pci_min>> device.
|
||||
|
||||
The device then fires an interrupt at irq 11, which is unhandled, which leads the kernel to say you are a bad boy:
|
||||
|
||||
....
|
||||
lkmc_pci_min mmio_write addr = 0 val = 12345678 size = 4
|
||||
<5>[ 1064.042435] random: crng init done
|
||||
<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 <<pci_min>> kernel module, and so it keeps firing, which leads to infinitely many messages being printed:
|
||||
|
||||
....
|
||||
handler irq = 11 dev = 251
|
||||
....
|
||||
|
||||
===== pciutils
|
||||
|
||||
There are two versions of `setpci` and `lspci`:
|
||||
|
||||
* a simple one from BusyBox
|
||||
* a more complete one from link:https://github.com/pciutils/pciutils[pciutils] which Buildroot has a package for, and is the default on Ubuntu 18.04 host. This is the one we enable by default.
|
||||
|
||||
===== Introduction to PCI
|
||||
|
||||
|
||||
Reference in New Issue
Block a user