diff --git a/.gitignore b/.gitignore index 7968c2e..b79e7b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Extensions and prefixes. *.tmp +tmp.* *~ ?*.gitignore gitignore* diff --git a/README.adoc b/README.adoc index 318a39c..f2716dc 100644 --- a/README.adoc +++ b/README.adoc @@ -487,7 +487,7 @@ except that you don't need to know what is the maximum level. .... head kernel_module/modulename.c -grep 'modulename\.' README.adoc +grep 'insmod /modulename\.ko' README.adoc .... Many of the modules have userland test scripts / executables with the same name as the module, e.g. form inside the guest: @@ -730,7 +730,7 @@ ls /lib/modules/*/extra/ Kernel modules built from the Linux mainline tree with `CONFIG_SOME_MOD=m`, are automatically available with `modprobe`, e.g.: .... -modprobe dummy-irq +modprobe dummy-irq irq=1 .... ==== myinsmod @@ -2638,6 +2638,131 @@ insmod /warn_on.ko Can also be activated with the `panic_on_warn` boot parameter. +=== IRQ + +==== irq.ko + +Brute force monitor every shared interrupt that will accept us: + +.... +./run -F 'insmod /irq.ko' -x +.... + +Now try the following: + +* press a keyboard key and then release it after a few seconds +* 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: + +.... +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 +.... + +The IRQs that we observe are: + +* `1` for keyboard press and release. ++ +If you hold the key down for a while, it starts firing at a constant rate. So this happens at the hardware level! +* `12` mouse actions + +This only works if for IRQs for which the other handlers are registered as `IRQF_SHARED`. + +We can see which ones are those, either via dmesg messages of type: + +.... +genirq: Flags mismatch irq 0. 00000080 (myirqhandler0) vs. 00015a00 (timer) +request_irq irq = 0 ret = -16 +request_irq irq = 1 ret = 0 +.... + +which indicate that `0` is not, but `1` is, or with: + +.... +cat /proc/interrupts +.... + +which shows: + +.... + 0: 31 IO-APIC 2-edge timer + 1: 9 IO-APIC 1-edge i8042, myirqhandler0 +.... + +so only `1` has `myirqhandler0` attached but not `0`. + +TODO: properly understand how each IRQ maps to what number. + +==== dummy-irq + +The Linux kernel v4.16 mainline also has a `dummy-irq` module at `drivers/misc/dummy-irq.c` for monitoring a single IRQ. + +We build it by default with: + +.... +CONFIG_DUMMY_IRQ=m +.... + +And then you can do + +.... +./run -x +.... + +and in guest: + +.... +modprobe dummy-irq irq=1 +.... + +Outcome: when you click a key on the keyboard, dmesg shows: + +.... +dummy-irq: interrupt occurred on IRQ 1 +.... + +However, this module is intended to fire only once as can be seen from its source: + +.... + static int count = 0; + + if (count == 0) { + printk(KERN_INFO "dummy-irq: interrupt occurred on IRQ %d\n", + irq); + count++; + } +.... + +and furthermore interrupt `1` and `12` happen immediately TODO why, were they somehow pending? + +So so see something interesting, you need to monitor an interrupt that is more rare than the keyboard, e.g. <>. + +==== /proc/interrupts + +In the guest on <>: + +.... +watch -n 1 cat /proc/interrupts +.... + +Then see how clicking the mouse and keyboard affect the interrupt counts. + +This confirms that: + +* 1: keyboard +* 12: mouse click and drags + +The module also shows which handlers are registered for each IRQ, as we have observed at <> + +When in text mode, we can also observe interrupt line 4 with handler `ttyS0` increase continuously as IO goes through the UART. + === Linux kernel tracing Good overviews: @@ -3361,6 +3486,19 @@ devmem 0x101e9000 w 0x12345678 which touches the register from userland through `/dev/mem`. +We can also observe the interrupt with <>: + +.... +modprobe dummy-irq irq=34 +insmod /platform_device.ko +.... + +The IRQ number `34` was found by on the dmesg after: + +.... +insmod /platform_device.ko +.... + ==== gem5 educational hardware models TODO @@ -5684,6 +5822,7 @@ Theory: * https://rwmj.wordpress.com/ awesome red hatter * https://lwn.net * http://www.makelinux.net +* https://notes.shichao.io/lkd/ Awesome lists: diff --git a/kernel_config_fragment/default b/kernel_config_fragment/default index f68dfcd..491ebde 100644 --- a/kernel_config_fragment/default +++ b/kernel_config_fragment/default @@ -78,6 +78,7 @@ CONFIG_VIRTIO_NET=y # Misc CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_DUMMY_IRQ=m ## Networking @@ -177,21 +178,6 @@ CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_PL061=y -# In target: -# -# modprobe dummy-irq irq=34 -# insmod /platform_device.ko -# -# Outcome: -# -# lkmc_platform_device_write offset=0 value=12345678 size=4 -# dummy-irq: interrupt occurred on IRQ 34 -# -# When the device generates an IRQ, the dummy module also snoops it. -# -# The IRQ number 34 was found by via dmesg on a previous "insmod /platform_device.ko". -CONFIG_DUMMY_IRQ=m - # Like CONFIG_X86_PTDUMP for ARM. CONFIG_ARM64_PTDUMP=y diff --git a/kernel_module/irq.c b/kernel_module/irq.c index 654410f..fe6f2d7 100644 --- a/kernel_module/irq.c +++ b/kernel_module/irq.c @@ -1,42 +1,10 @@ -/* -Brute force monitor every shared interrupt that will accept us. - -I.e. only works if for IRQs for which the other handlers are registered as IRQF_SHARED. - -Usage: - -1. insmod and then use the keyboard and mouse. Those handlers are shared, - and the messages show up whenever you do something. - - Does not work in text mode of course. - -2. insmod some module that generates interrupts after insmod irq., - e.g. pci_min or platform_device. - - TODO: why does insmod in ARM lead to infinitely many interrupts handler irq = 45 dev = 252 - and blocks the board? Is the ARM timer shared, and x86 isn't? - -TODO: properly understand how each IRQ maps to what. - -The Linux kernel mainline also has dummy-irq for monitoring a single IRQ. - -Inside QEMU, also try: - - watch -n 1 cat /proc/interrupts - -Then see how clicking the mouse and keyboard affect the interrupts. This will point you to: - -- 1: keyboard -- 12: mouse click and drags -*/ - #include #include #include #include #include /* copy_from_user, copy_to_user */ -#define NAME "lkmc_character_device" +#define NAME "lkmc_irq" #define MAX_IRQS 256 static int irqs[MAX_IRQS];