Skip to content

Commit 1c129ea

Browse files
committed
pci: move doc to readme
1 parent 92c7bb6 commit 1c129ea

File tree

5 files changed

+213
-158
lines changed

5 files changed

+213
-158
lines changed

README.adoc

Lines changed: 211 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -523,13 +523,13 @@ This likely comes from the ifdef split at `init/main.c`:
523523
524524
/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
525525
#define pr_debug(fmt, ...) \
526-
dynamic_pr_debug(fmt, ##__VA_ARGS__)
526+
dynamic_pr_debug(fmt, ##__VA_ARGS__)
527527
#elif defined(DEBUG)
528528
#define pr_debug(fmt, ...) \
529-
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
529+
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
530530
#else
531531
#define pr_debug(fmt, ...) \
532-
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
532+
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
533533
#endif
534534
....
535535

@@ -2837,13 +2837,13 @@ dummy-irq: interrupt occurred on IRQ 1
28372837
However, this module is intended to fire only once as can be seen from its source:
28382838

28392839
....
2840-
static int count = 0;
2840+
static int count = 0;
28412841
2842-
if (count == 0) {
2843-
printk(KERN_INFO "dummy-irq: interrupt occurred on IRQ %d\n",
2844-
irq);
2845-
count++;
2846-
}
2842+
if (count == 0) {
2843+
printk(KERN_INFO "dummy-irq: interrupt occurred on IRQ %d\n",
2844+
irq);
2845+
count++;
2846+
}
28472847
....
28482848

28492849
and furthermore interrupt `1` and `12` happen immediately TODO why, were they somehow pending?
@@ -3494,7 +3494,7 @@ it makes the terminal go crazy, as if multiple processes are randomly eating up
34943494
* `/dev/ttyN` for the other graphic TTYs. Note that there are only 63 available ones, from `/dev/tty1` to `/dev/tty63` (`/dev/tty0` is the current one): link:https://superuser.com/questions/449781/why-is-there-so-many-linux-dev-tty[]. I think this is determined by:
34953495
+
34963496
....
3497-
#define MAX_NR_CONSOLES 63
3497+
#define MAX_NR_CONSOLES 63
34983498
....
34993499
+
35003500
in `linux/include/uapi/linux/vt.h`.
@@ -3745,11 +3745,200 @@ Studying them can teach you:
37453745

37463746
To get started, have a look at the "Hardware device drivers" section under link:kernel_module/README.adoc[], and try to run those modules, and then grep the QEMU source code.
37473747

3748-
==== Mainline hardware models
3748+
The hardware models can be either:
37493749

3750-
This section documents hardware models present in the QEMU upstream.
3750+
* present in the QEMU upstream
3751+
* added in on link:https://github.com/cirosantilli/qemu[our fork of QEMU].
3752+
+
3753+
These have been explicitly designed to be educational rather than model real existing hardware.
3754+
+
3755+
But note that upstream [[edu]] device is also purely educational.
3756+
3757+
==== PCI
3758+
3759+
Only tested in x86.
3760+
3761+
===== pci_min
3762+
3763+
PCI driver for our minimal `pci_min.c` QEMU fork device:
3764+
3765+
....
3766+
insmod /pci_min.ko
3767+
....
3768+
3769+
Source:
3770+
3771+
* Kernel module: link:kernel_module/pci_min.c[].
3772+
* QEMU device: https://github.com/cirosantilli/qemu/blob/lkmc/hw/misc/lkmc_pci_min.c
3773+
3774+
Works because we add to our default QEMU CLI:
3775+
3776+
....
3777+
-device lkmc_pci_min
3778+
....
3779+
3780+
Probe already does a MMIO write, which generates an IRQ and tests everything.
3781+
3782+
[[edu]]
3783+
===== QEMU edu PCI device
3784+
3785+
Small upstream educational PCI device:
3786+
3787+
....
3788+
/pci.sh
3789+
....
3790+
3791+
Source:
3792+
3793+
* kernel module: link:kernel_module/pci.c[]
3794+
* QEMU device:
3795+
** source: https://github.com/qemu/qemu/blob/v2.12.0/hw/misc/edu.c
3796+
** documentation: https://github.com/qemu/qemu/blob/v2.12.0/docs/specs/edu.txt
3797+
* test script: link:rootfs_overlay/pci.sh[]
3798+
3799+
Works because we add to our default QEMU CLI:
3800+
3801+
....
3802+
-device edu
3803+
....
3804+
3805+
This example uses:
3806+
3807+
* the QEMU `edu` educational device, which is a minimal educational in-tree PCI example
3808+
* out `/pci.ko` kernel module, which exercises the `edu` hardware.
3809+
+
3810+
I've contacted the awesome original author author of `edu` link:https://github.com/jirislaby[Jiri Slaby], and he told there is no official kernel module example because this was created for a kernel module university course that he gives, and he didn't want to give away answers. link:https://github.com/cirosantilli/how-to-teach-efficiently[I don't agree with that philosophy], so students, cheat away with this repo and go make startups instead.
3811+
3812+
TODO exercise DMA on the kernel module. The `edu` hardware model has that feature:
3813+
3814+
* https://stackoverflow.com/questions/32592734/are-there-any-dma-driver-example-pcie-and-fpga/44716747#44716747
3815+
* https://stackoverflow.com/questions/17913679/how-to-instantiate-and-use-a-dma-driver-linux-module
3816+
3817+
===== setpci
3818+
3819+
There are two versions of `setpci` and `lspci`:
3820+
3821+
* a simple one from BusyBox
3822+
* 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.
3823+
3824+
`setpci` can read and write to PCI configuration registers.
3825+
3826+
Read is possible from Linux with:
3827+
3828+
....
3829+
hexdump /sys/bus/pci/devices/0000:00:05.0/config
3830+
....
3831+
3832+
and `/dev/mem` can of course do both reads and writes, but `setpci` provides nice human readable register names, e.g.:
3833+
3834+
....
3835+
setpci --dumpregs
3836+
....
3837+
3838+
then and then get the values with either bus or device id:
3839+
3840+
....
3841+
setpci -s 0000:00:05.0 BASE_ADDRESS_0
3842+
setpci -d 1234:11e9 BASE_ADDRESS_0
3843+
....
3844+
3845+
Note however that `BASE_ADDRESS_0` also appears when you do:
3846+
3847+
....
3848+
lspci -v
3849+
....
3850+
3851+
Then you can try messing with that address with:
3852+
3853+
....
3854+
devmem 0xfeb52000 w 0x12345678
3855+
....
3856+
3857+
which for our <<pci_min>> device fires interrupts.
3858+
3859+
===== Introduction to PCI
3860+
3861+
The PCI standard is non-free, obviously like everything in low level: https://pcisig.com/specifications but Google gives several illegal PDF hits :-)
3862+
3863+
And of course, the best documentation available is: http://wiki.osdev.org/PCI
3864+
3865+
Like every other hardware, we could interact with PCI on x86 using only IO instructions and memory operations.
3866+
3867+
But PCI is a complex communication protocol that the Linux kernel implements beautifully for us, so let's use the kernel API.
3868+
3869+
Bibliography:
3870+
3871+
* edu device source and spec in QEMU tree:
3872+
** https://github.com/qemu/qemu/blob/v2.7.0/hw/misc/edu.c
3873+
** https://github.com/qemu/qemu/blob/v2.7.0/docs/specs/edu.txt
3874+
* http://www.zarb.org/~trem/kernel/pci/pci-driver.c inb outb runnable example (no device)
3875+
* LDD3 PCI chapter
3876+
* another QEMU device + module, but using a custom QEMU device:
3877+
** https://github.com/levex/kernel-qemu-pci/blob/31fc9355161b87cea8946b49857447ddd34c7aa6/module/levpci.c
3878+
** https://github.com/levex/kernel-qemu-pci/blob/31fc9355161b87cea8946b49857447ddd34c7aa6/qemu/hw/char/lev-pci.c
3879+
* https://is.muni.cz/el/1433/podzim2016/PB173/um/65218991/ course given by the creator of the edu device. In Czech, and only describes API
3880+
* http://nairobi-embedded.org/linux_pci_device_driver.html
3881+
3882+
===== PCI BFD
3883+
3884+
`lspci -k` shows something like:
3885+
3886+
....
3887+
00:04.0 Class 00ff: 1234:11e8 lkmc_pci
3888+
....
3889+
3890+
Meaning of the first numbers:
3891+
3892+
....
3893+
<8:bus>:<5:device>.<3:function>
3894+
....
3895+
3896+
Often abbreviated to BDF.
3897+
3898+
* bus: groups PCI slots
3899+
* device: maps to one slot
3900+
* function: https://stackoverflow.com/questions/19223394/what-is-the-function-number-in-pci/44735372#44735372
3901+
3902+
Sometimes a fourth number is also added, e.g.:
37513903

3752-
===== GPIO
3904+
....
3905+
0000:00:04.0
3906+
....
3907+
3908+
TODO is that the domain?
3909+
3910+
Class: pure magic: https://www-s.acm.illinois.edu/sigops/2007/roll_your_own/7.c.1.html TODO: does it have any side effects? Set in the edu device at:
3911+
3912+
....
3913+
k->class_id = PCI_CLASS_OTHERS
3914+
....
3915+
3916+
===== PCI BAR
3917+
3918+
https://stackoverflow.com/questions/30190050/what-is-base-address-register-bar-in-pcie/44716618#44716618
3919+
3920+
Each PCI device has 6 BAR IOs (base address register) as per the PCI spec.
3921+
3922+
Each BAR corresponds to an address range that can be used to communicate with the PCI.
3923+
3924+
Each BAR is of one of the two types:
3925+
3926+
* `IORESOURCE_IO`: must be accessed with `inX` and `outX`
3927+
* `IORESOURCE_MEM`: must be accessed with `ioreadX` and `iowriteX`. This is the saner method apparently, and what the edu device uses.
3928+
3929+
The length of each region is defined by the hardware, and communicated to software via the configuration registers.
3930+
3931+
The Linux kernel automatically parses the 64 bytes of standardized configuration registers for us.
3932+
3933+
QEMU devices register those regions with:
3934+
3935+
....
3936+
memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu,
3937+
"edu-mmio", 1 << 20);
3938+
pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);
3939+
....
3940+
3941+
==== GPIO
37533942

37543943
TODO: broken. Was working before we moved `arm` from `-M versatilepb` to `-M virt` around af210a76711b7fa4554dcc2abd0ddacfc810dfd4. Either make it work on `-M virt` if that is possible, or document precisely how to make it work with `versatilepb`, or hopefully `vexpress` which is newer.
37553944

@@ -3775,11 +3964,13 @@ then test it out with:
37753964
/gpio.sh
37763965
....
37773966

3967+
Source: link:rootfs_overlay/gpio.sh[].
3968+
37783969
Buildroot's Linux tools package provides some GPIO CLI tools: `lsgpio`, `gpio-event-mon`, `gpio-hammer`, TODO document them here.
37793970

37803971
Those broke MIPS build in 2017-02: https://bugs.busybox.net/show_bug.cgi?id=10276 and so we force disable them in our MIPS build currently.
37813972

3782-
===== LEDs
3973+
==== LEDs
37833974

37843975
TODO: broken when `arm` moved to `-M virt`, same as <<gpio>>.
37853976

@@ -3823,15 +4014,9 @@ Relevant kernel files:
38234014
* `drivers/leds/led-class.c`
38244015
* `drivers/leds/leds-sysctl.c`
38254016

3826-
==== Fork hardware models
3827-
3828-
This section documents hardware models added on link:https://github.com/cirosantilli/qemu[our fork of QEMU].
3829-
3830-
These have been explicitly designed to be educational rather than model real existing hardware.
3831-
3832-
===== platform_device
4017+
==== platform_device
38334018

3834-
This is an example of hardware coded into an ARM `-M versatilepb` SoC.
4019+
Minimal platform device example coded into the `-M versatilepb` SoC of our QEMU fork.
38354020

38364021
Using this device now requires checking out to the branch:
38374022

@@ -3859,7 +4044,7 @@ Expected outcome after insmod:
38594044
* QEMU reports MMIO with printfs
38604045
* IRQs are generated and handled by this module, which logs to dmesg
38614046

3862-
Also without insmodding this module, try:
4047+
Also without insmoding this module, try:
38634048

38644049
....
38654050
devmem 0x101e9000 w 0x12345678
@@ -6247,7 +6432,9 @@ Runnable stuff:
62476432

62486433
Theory:
62496434

6250-
* http://nairobi-embedded.org you will fall here a lot when the hard Google queries start popping. They have covered everything we do here basically, but with a more manual approach, while this repo automates everything.
6435+
* http://nairobi-embedded.org you will fall here a lot when you start popping the hard QEMU Google queries. They have covered everything we do here basically, but with a more manual approach, while this repo automates everything.
6436+
+
6437+
I couldn't find the markup source code for the tutorials, and as a result when the domain went down in May 2018, you have to use http://web.archive.org/ to see the pages...
62516438
* https://balau82.wordpress.com awesome low level resource
62526439
* https://rwmj.wordpress.com/ awesome red hatter
62536440
* https://lwn.net

br2

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ BR2_TARGET_ROOTFS_EXT2_SIZE="512M"
1414
# remove the init.d file for now.
1515
#BR2_PACKAGE_IFUPDOWN_SCRIPTS=n
1616

17+
# Misc
1718
BR2_CCACHE=y
1819
# Otherwise our precious debug would break!
1920
BR2_CCACHE_USE_BASEDIR=n
@@ -25,6 +26,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES="../busybox_config_fragment"
2526
BR2_PACKAGE_DHRYSTONE=y
2627
BR2_PACKAGE_FILE=y
2728
BR2_PACKAGE_OVERRIDE_FILE="../buildroot_override"
29+
BR2_PACKAGE_PCIUTILS=y
2830
# For qemu-ga on guest. TODO: do something with it, and document it.
2931
BR2_PACKAGE_QEMU=y
3032
BR2_PACKAGE_STRACE=y
@@ -66,33 +68,3 @@ BR2_PACKAGE_TRACE_CMD=y
6668
BR2_PACKAGE_DTC=y
6769
BR2_PACKAGE_DTC_PROGRAMS=y
6870
BR2_PACKAGE_HOST_DTC=y
69-
70-
# Provides setpci and a lspci more advanced than Busybox's
71-
#
72-
# setpci can read and write to PCI configuration registers.
73-
#
74-
# Read is possible from Linux with:
75-
#
76-
# hexdump /sys/bus/pci/devices/0000:00:05.0/config
77-
#
78-
# and /dev/mem can of course do both reads and writes,
79-
# but setpci provies nice human readable register names, e.g.:
80-
#
81-
# setpci --dumpregs
82-
#
83-
# then and then get the values with either bus or device id:
84-
#
85-
# setpci -s 0000:00:05.0 BASE_ADDRESS_0
86-
# setpci -d 1234:11e9 BASE_ADDRESS_0
87-
#
88-
# Note however that BASE_ADDRESS_0 also appears when you do:
89-
#
90-
# lspci -v
91-
#
92-
# Then you can try messing with that address with:
93-
#
94-
# devmem2 0xfeb52000 w 0x12345678
95-
#
96-
# which for our pci_min device fires interrupts.
97-
#
98-
BR2_PACKAGE_PCIUTILS=y

kernel_module/README.adoc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,3 @@
5252
. Arch
5353
.. x86
5454
... link:ring0.c[]
55-
.. ARM
56-
... link:pmccntr.c[]
57-
. Hardware device drivers
58-
.. link:pci_min.c[]
59-
.. link:pci.c[]

0 commit comments

Comments
 (0)