mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-25 19:21:35 +01:00
migrate all
This commit is contained in:
227
README.adoc
227
README.adoc
@@ -440,11 +440,11 @@ OK, now time to hack GCC.
|
||||
|
||||
For convenience, let's use the <<user-mode-simulation>>.
|
||||
|
||||
If we run the program link:userland/gcc_hack.c[]:
|
||||
If we run the program link:userland/c/gcc_hack.c[]:
|
||||
|
||||
....
|
||||
./build-userland --static
|
||||
./run --static --userland gcc_hack
|
||||
./run --static --userland c/gcc_hack
|
||||
....
|
||||
|
||||
it produces the normal boring output:
|
||||
@@ -496,7 +496,7 @@ Now rebuild GCC, the program and re-run it:
|
||||
....
|
||||
./build-buildroot -- host-gcc-final-rebuild
|
||||
./build-userland --static
|
||||
./run --static --userland gcc_hack
|
||||
./run --static --userland c/gcc_hack
|
||||
....
|
||||
|
||||
and the new ouptut is now:
|
||||
@@ -1003,6 +1003,12 @@ Do a more clean out of tree build and run the program instead:
|
||||
"$(./getvar --userland-build-id host userland_build_dir)/hello.out"
|
||||
....
|
||||
|
||||
If you modify a dependency that is not currently considered such as a header file, force the rebuild with:
|
||||
|
||||
....
|
||||
./build --force-rebuild
|
||||
....
|
||||
|
||||
===== Userland setup getting started full system
|
||||
|
||||
First ensure that <<qemu-buildroot-setup>> is working.
|
||||
@@ -1551,7 +1557,7 @@ So once we find the address the first time, we can just reuse it afterwards, as
|
||||
Do a fresh boot and get the module:
|
||||
|
||||
....
|
||||
./run --eval-after './pr_debug.sh;insmod fops.ko;./poweroff.out'
|
||||
./run --eval-after './pr_debug.sh;insmod fops.ko;./linux/poweroff.out'
|
||||
....
|
||||
|
||||
The boot must be fresh, because the load address changes every time we insert, even after removing previous modules.
|
||||
@@ -1585,7 +1591,7 @@ so the offset address is `0x240` and we deduce that the function will be placed
|
||||
Now we can just do a fresh boot on shell 1:
|
||||
|
||||
....
|
||||
./run --eval 'insmod fops.ko;./poweroff.out' --wait-gdb
|
||||
./run --eval 'insmod fops.ko;./linux/poweroff.out' --wait-gdb
|
||||
....
|
||||
|
||||
and on shell 2:
|
||||
@@ -2653,13 +2659,13 @@ This method is not very flexible however, as it is hard to reliably pass multipl
|
||||
For this reason, we have created a more robust helper method with the `--eval` option:
|
||||
|
||||
....
|
||||
./run --eval 'echo "asdf qwer";insmod hello.ko;./poweroff.out'
|
||||
./run --eval 'echo "asdf qwer";insmod hello.ko;./linux/poweroff.out'
|
||||
....
|
||||
|
||||
It is basically a shortcut for:
|
||||
|
||||
....
|
||||
./run --kernel-cli 'init=/lkmc/eval_base64.sh - lkmc_eval="insmod hello.ko;./poweroff.out"'
|
||||
./run --kernel-cli 'init=/lkmc/eval_base64.sh - lkmc_eval="insmod hello.ko;./linux/poweroff.out"'
|
||||
....
|
||||
|
||||
Source: link:rootfs_overlay/lkmc/eval_base64.sh[].
|
||||
@@ -2689,7 +2695,7 @@ If the script is large, you can add it to a gitignored file and pass that to `--
|
||||
echo '
|
||||
cd /lkmc
|
||||
insmod hello.ko
|
||||
./poweroff.out
|
||||
./linux/poweroff.out
|
||||
' > data/gitignore.sh
|
||||
./run --eval "$(cat data/gitignore.sh)"
|
||||
....
|
||||
@@ -2700,7 +2706,7 @@ or add it to a file to the root filesystem guest and rebuild:
|
||||
echo '#!/bin/sh
|
||||
cd /lkmc
|
||||
insmod hello.ko
|
||||
./poweroff.out
|
||||
./linux/poweroff.out
|
||||
' > rootfs_overlay/lkmc/gitignore.sh
|
||||
chmod +x rootfs_overlay/lkmc/gitignore.sh
|
||||
./build-buildroot
|
||||
@@ -2724,19 +2730,19 @@ because BusyBox' `poweroff` tries to do some fancy stuff like killing init, like
|
||||
|
||||
But this fails when we are `init` itself!
|
||||
|
||||
`poweroff` works more brutally and effectively if you add `-f`:
|
||||
BusyBox' `poweroff` works more brutally and effectively if you add `-f`:
|
||||
|
||||
....
|
||||
./run --eval 'poweroff -f'
|
||||
....
|
||||
|
||||
but why not just use our minimal `./poweroff.out` and be done with it?
|
||||
but why not just use our minimal `./linux/poweroff.out` and be done with it?
|
||||
|
||||
....
|
||||
./run --eval './poweroff.out'
|
||||
./run --eval './linux/poweroff.out'
|
||||
....
|
||||
|
||||
Source: link:userland/poweroff.c[]
|
||||
Source: link:userland/linux/poweroff.c[]
|
||||
|
||||
This also illustrates how to shutdown the computer from C: https://stackoverflow.com/questions/28812514/how-to-shutdown-linux-using-c-or-qt-without-call-to-system
|
||||
|
||||
@@ -2745,28 +2751,30 @@ This also illustrates how to shutdown the computer from C: https://stackoverflow
|
||||
I dare you to guess what this does:
|
||||
|
||||
....
|
||||
./run --eval './sleep_forever.out'
|
||||
./run --eval './posix/sleep_forever.out'
|
||||
....
|
||||
|
||||
Source: link:userland/sleep_forever.c[]
|
||||
Source: link:userland/posix/sleep_forever.c[]
|
||||
|
||||
This executable is a convenient simple init that does not panic and sleeps instead.
|
||||
|
||||
==== time_boot.out
|
||||
|
||||
Get a reasonable answer to "how long does boot take?":
|
||||
Get a reasonable answer to "how long does boot take in guest time?":
|
||||
|
||||
....
|
||||
./run --eval-after './time_boot.out'
|
||||
./run --eval-after './linux/time_boot.c'
|
||||
....
|
||||
|
||||
Dmesg contains a message of type:
|
||||
Source: link:userland/linux/time_boot.out[]
|
||||
|
||||
That executable writes to `dmesg` directly through `/dev/kmsg` a message of type:
|
||||
|
||||
....
|
||||
[ 2.188242] time_boot.c
|
||||
[ 2.188242] /path/to/linux-kernel-module-cheat/userland/linux/time_boot.c
|
||||
....
|
||||
|
||||
which tells us that boot took `2.188242` seconds.
|
||||
which tells us that boot took `2.188242` seconds based on the dmesg timestamp.
|
||||
|
||||
Bibliography: https://stackoverflow.com/questions/12683169/measure-time-taken-for-linux-kernel-from-bootup-to-userpace/46517014#46517014
|
||||
|
||||
@@ -2784,7 +2792,7 @@ After the commands run, you are left on an interactive shell.
|
||||
The above command is basically equivalent to:
|
||||
|
||||
....
|
||||
./run --kernel-cli-after-dash 'lkmc_eval="insmod hello.ko;./poweroff.out;"'
|
||||
./run --kernel-cli-after-dash 'lkmc_eval="insmod hello.ko;./linux/poweroff.out;"'
|
||||
....
|
||||
|
||||
where the `lkmc_eval` option gets evaled by our default link:rootfs_overlay/etc/init.d/S98[] startup script.
|
||||
@@ -2850,7 +2858,7 @@ The annoying dash `-` gets passed as a parameter to `init`, which makes it impos
|
||||
Arguments with dots that come after `-` are still treated specially (of the form `subsystem.somevalue`) and disappear, from args, e.g.:
|
||||
|
||||
....
|
||||
./run --kernel-cli 'init=/lkmc/init_env_poweroff.out - /lkmc/poweroff.out'
|
||||
./run --kernel-cli 'init=/lkmc/init_env_poweroff.out - /lkmc/linux/poweroff.out'
|
||||
....
|
||||
|
||||
outputs:
|
||||
@@ -3399,6 +3407,33 @@ If you modify the userland programs, rebuild simply with:
|
||||
./build-userland
|
||||
....
|
||||
|
||||
==== User mode GDB step debug
|
||||
|
||||
The commands are analogous to full system <<gdb>>, e.g. without tmux:
|
||||
|
||||
....
|
||||
./run \
|
||||
--userland print_argv \
|
||||
--userland-args 'asdf "qw er"' \
|
||||
--wait-gdb \
|
||||
;
|
||||
./run-gdb \
|
||||
--userland print_argv \
|
||||
main
|
||||
;
|
||||
....
|
||||
|
||||
or with <<tmux>>:
|
||||
|
||||
....
|
||||
./run \
|
||||
--userland print_argv \
|
||||
--userland-args 'asdf "qw er"' \
|
||||
--tmux-args main \
|
||||
--wait-gdb \
|
||||
;
|
||||
....
|
||||
|
||||
==== User mode with host toolchain and QEMU
|
||||
|
||||
If you are lazy to built the Buildroot toolchain and QEMU, you can get away on Ubuntu 18.04 with just:
|
||||
@@ -3532,7 +3567,7 @@ So programs that rely on those libraries might not compile as GCC can't find the
|
||||
For example, if we try to build <<blas>> statically:
|
||||
|
||||
....
|
||||
./build-userland --has-package openblas --static -- openblas_hello
|
||||
./build-userland --has-package openblas --static -- libs/openblas_hello
|
||||
....
|
||||
|
||||
it fails with:
|
||||
@@ -3615,7 +3650,7 @@ So let's just play with some static ones:
|
||||
|
||||
TODO: how to escape spaces on the command line arguments?
|
||||
|
||||
Step debug also works:
|
||||
<<user-mode-gdb-step-debug,GDB step debug>> also works normally on gem5:
|
||||
|
||||
....
|
||||
./run \
|
||||
@@ -3708,7 +3743,7 @@ QEMU full system:
|
||||
time \
|
||||
./run \
|
||||
--arch arm \
|
||||
--eval-after 'time dhrystone 100000000;./poweroff.out' \
|
||||
--eval-after 'time dhrystone 100000000;./linux/poweroff.out' \
|
||||
;
|
||||
....
|
||||
|
||||
@@ -5128,11 +5163,11 @@ and so it is Read Only as shown by `ro`.
|
||||
Disable userland address space randomization. Test it out by running <<rand_check-out>> twice:
|
||||
|
||||
....
|
||||
./run --eval-after './rand_check.out;./poweroff.out'
|
||||
./run --eval-after './rand_check.out;./poweroff.out'
|
||||
./run --eval-after './linux/rand_check.out;./linux/poweroff.out'
|
||||
./run --eval-after './linux/rand_check.out;./linux/poweroff.out'
|
||||
....
|
||||
|
||||
If we remove it from our link:run[] script by hacking it up, the addresses shown by `rand_check.out` vary across boots.
|
||||
If we remove it from our link:run[] script by hacking it up, the addresses shown by `linux/rand_check.out` vary across boots.
|
||||
|
||||
Equivalent to:
|
||||
|
||||
@@ -7525,7 +7560,7 @@ TODO `--arch arm` and `--arch aarch64` does not count firmware instructions prop
|
||||
* We can also discount the instructions after `init` runs by using `readelf` to get the initial address of `init`. One easy way to do that now is to just run:
|
||||
+
|
||||
....
|
||||
./run-gdb-user "$(./getvar userland_build_dir)/poweroff.out" main
|
||||
./run-gdb-user "$(./getvar userland_build_dir)/linux/poweroff.out" main
|
||||
....
|
||||
+
|
||||
And get that from the traces, e.g. if the address is `4003a0`, then we search:
|
||||
@@ -7818,10 +7853,10 @@ echo 0 > /proc/sys/kernel/ctrl-alt-del
|
||||
Minimal example:
|
||||
|
||||
....
|
||||
./run --kernel-cli 'init=/lkmc/ctrl_alt_del.out' --graphic
|
||||
./run --kernel-cli 'init=/lkmc/linux/ctrl_alt_del.out' --graphic
|
||||
....
|
||||
|
||||
Source: link:userland/ctrl_alt_del.c[]
|
||||
Source: link:userland/linux/ctrl_alt_del.c[]
|
||||
|
||||
When you hit `Ctrl-Alt-Del` in the guest, our tiny init handles a `SIGINT` sent by the kernel and outputs to stdout:
|
||||
|
||||
@@ -8134,11 +8169,11 @@ DRM / DRI is the new interface that supersedes `fbdev`:
|
||||
|
||||
....
|
||||
./build-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
|
||||
./build-userland --has-package libdrm -- libdrm_modeset
|
||||
./run --eval-after './libdrm_modeset.out' --graphic
|
||||
./build-userland --has-package libdrm -- libs/libdrm_modeset
|
||||
./run --eval-after './libs/libdrm_modeset.out' --graphic
|
||||
....
|
||||
|
||||
Source: link:userland/libdrm_modeset.c[]
|
||||
Source: link:userland/libs/libdrm_modeset.c[]
|
||||
|
||||
Outcome: for a few seconds, the screen that contains the terminal gets taken over by changing colors of the rainbow.
|
||||
|
||||
@@ -8148,7 +8183,7 @@ TODO not working for `aarch64`, it takes over the screen for a few seconds and t
|
||||
./build-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
|
||||
./build-userland --has-package libdrm
|
||||
./build-buildroot
|
||||
./run --eval-after './libdrm_modeset.out' --graphic
|
||||
./run --eval-after './libs/libdrm_modeset.out' --graphic
|
||||
....
|
||||
|
||||
<<kmscube>> however worked, which means that it must be a bug with this demo?
|
||||
@@ -8173,7 +8208,7 @@ Try creating new displays:
|
||||
to see multiple `/dev/dri/cardN`, and then use a different display with:
|
||||
|
||||
....
|
||||
./run --eval-after './libdrm_modeset.out' --graphic
|
||||
./run --eval-after './libs/libdrm_modeset.out' --graphic
|
||||
....
|
||||
|
||||
Bibliography:
|
||||
@@ -9204,7 +9239,7 @@ QEMU also has a second trace mechanism in addition to `-trace`, find out the eve
|
||||
Let's pick the one that dumps executed instructions, `in_asm`:
|
||||
|
||||
....
|
||||
./run --eval './poweroff.out' -- -D out/trace.txt -d in_asm
|
||||
./run --eval './linux/poweroff.out' -- -D out/trace.txt -d in_asm
|
||||
less out/trace.txt
|
||||
....
|
||||
|
||||
@@ -9280,15 +9315,15 @@ This awesome feature allows you to examine a single run as many times as you wou
|
||||
|
||||
....
|
||||
# Record a run.
|
||||
./run --eval-after './rand_check.out;./poweroff.out;' --record
|
||||
./run --eval-after './linux/rand_check.out;./linux/poweroff.out;' --record
|
||||
# Replay the run.
|
||||
./run --eval-after './rand_check.out;./poweroff.out;' --replay
|
||||
./run --eval-after './linux/rand_check.out;./linux/poweroff.out;' --replay
|
||||
....
|
||||
|
||||
A convenient shortcut to do both at once to test the feature is:
|
||||
|
||||
....
|
||||
./qemu-rr --eval-after './rand_check.out;./poweroff.out;'
|
||||
./qemu-rr --eval-after './linux/rand_check.out;./linux/poweroff.out;'
|
||||
....
|
||||
|
||||
By comparing the terminal output of both runs, we can see that they are the exact same, including things which normally differ across runs:
|
||||
@@ -9315,7 +9350,7 @@ EXT4-fs (sda): re-mounted. Opts: block_validity,barrier,user_xattr
|
||||
TODO replay with network gets stuck:
|
||||
|
||||
....
|
||||
./qemu-rr --eval-after 'ifup -a;wget -S google.com;./poweroff.out;'
|
||||
./qemu-rr --eval-after 'ifup -a;wget -S google.com;./linux/poweroff.out;'
|
||||
....
|
||||
|
||||
after the message:
|
||||
@@ -9334,7 +9369,7 @@ Then, when I tried with <<initrd>> and no disk:
|
||||
|
||||
....
|
||||
./build-buildroot --arch aarch64 --initrd
|
||||
./qemu-rr --arch aarch64 --eval-after './rand_check.out;./poweroff.out;' --initrd
|
||||
./qemu-rr --arch aarch64 --eval-after './linux/rand_check.out;./linux/poweroff.out;' --initrd
|
||||
....
|
||||
|
||||
QEMU crashes with:
|
||||
@@ -9354,8 +9389,8 @@ TODO get working.
|
||||
QEMU replays support checkpointing, and this allows for a simplistic "reverse debugging" implementation proposed at https://lists.gnu.org/archive/html/qemu-devel/2018-06/msg00478.html on the unmerged link:https://github.com/ispras/qemu/tree/rr-180725[]:
|
||||
|
||||
....
|
||||
./run --eval-after './rand_check.out;./poweroff.out;' --record
|
||||
./run --eval-after './rand_check.out;./poweroff.out;' --replay --wait-gdb
|
||||
./run --eval-after './linux/rand_check.out;./linux/poweroff.out;' --record
|
||||
./run --eval-after './linux/rand_check.out;./linux/poweroff.out;' --replay --wait-gdb
|
||||
....
|
||||
|
||||
On another shell:
|
||||
@@ -9381,7 +9416,7 @@ and we are back at `start_kernel`
|
||||
TODO: is there any way to distinguish which instruction runs on each core? Doing:
|
||||
|
||||
....
|
||||
./run --arch x86_64 --cpus 2 --eval './poweroff.out' --trace exec_tb
|
||||
./run --arch x86_64 --cpus 2 --eval './linux/poweroff.out' --trace exec_tb
|
||||
./qemu-trace2txt
|
||||
....
|
||||
|
||||
@@ -9874,8 +9909,8 @@ Buildroot supports it, which makes everything just trivial:
|
||||
|
||||
....
|
||||
./build-buildroot --config 'BR2_PACKAGE_OPENBLAS=y'
|
||||
./build-userland --has-package openblas -- openblas_hello
|
||||
./run --eval-after './openblas_hello.out; echo $?'
|
||||
./build-userland --has-package openblas -- libs/openblas_hello
|
||||
./run --eval-after './libs/openblas_hello.out; echo $?'
|
||||
....
|
||||
|
||||
Outcome: the test passes:
|
||||
@@ -9884,7 +9919,7 @@ Outcome: the test passes:
|
||||
0
|
||||
....
|
||||
|
||||
Source: link:userland/openblas.c[]
|
||||
Source: link:userland/libs/openblas.c[]
|
||||
|
||||
The test performs a general matrix multiplication:
|
||||
|
||||
@@ -9914,13 +9949,13 @@ Header only linear algebra library with a mainline Buildroot package:
|
||||
|
||||
....
|
||||
./build-buildroot --config 'BR2_PACKAGE_EIGEN=y'
|
||||
./build-userland --has-package eigen -- eigen_hello
|
||||
./build-userland --has-package eigen -- libs/eigen_hello
|
||||
....
|
||||
|
||||
Just create an array and print it:
|
||||
|
||||
....
|
||||
./run --eval-after './eigen_hello.out'
|
||||
./run --eval-after './libs/eigen_hello.out'
|
||||
....
|
||||
|
||||
Output:
|
||||
@@ -9930,7 +9965,7 @@ Output:
|
||||
2.5 1.5
|
||||
....
|
||||
|
||||
Source: link:userland/eigen_hello.cpp[]
|
||||
Source: link:userland/libs/eigen_hello.cpp[]
|
||||
|
||||
This example just creates a matrix and prints it out.
|
||||
|
||||
@@ -10104,7 +10139,7 @@ You may also want to test if your patches are still functionally correct inside
|
||||
Analogous <<kernel-command-line-parameters,to QEMU>>:
|
||||
|
||||
....
|
||||
./run --arch arm --kernel-cli 'init=/lkmc/poweroff.out' --emulator gem5
|
||||
./run --arch arm --kernel-cli 'init=/lkmc/linux/poweroff.out' --emulator gem5
|
||||
....
|
||||
|
||||
Internals: when we give `--command-line=` to gem5, it overrides default command lines, including some mandatory ones which are required to boot properly.
|
||||
@@ -10738,39 +10773,7 @@ system.cpu.dtb.inst_misses
|
||||
system.cpu.dtb.inst_hits
|
||||
....
|
||||
|
||||
==== rdtsc
|
||||
|
||||
Let's have some fun and try to correlate the gem5 cycle count `system.cpu.numCycles` with the link:https://en.wikipedia.org/wiki/Time_Stamp_Counter[x86 `rdtsc` instruction] that is supposed to do the same thing:
|
||||
|
||||
....
|
||||
./build-userland -- rdtsc
|
||||
./run --eval './rdtsc.out;m5 exit;' --emulator gem5
|
||||
./gem5-stat
|
||||
....
|
||||
|
||||
Source: link:userland/rdtsc.c[]
|
||||
|
||||
`rdtsc` outputs a cycle count which we compare with gem5's `gem5-stat`:
|
||||
|
||||
* `3828578153`: `rdtsc`
|
||||
* `3830832635`: `gem5-stat`
|
||||
|
||||
which gives pretty close results, and serve as a nice sanity check that the cycle counter is coherent.
|
||||
|
||||
It is also nice to see that `rdtsc` is a bit smaller than the `stats.txt` value, since the latter also includes the exec syscall for `m5`.
|
||||
|
||||
Bibliography:
|
||||
|
||||
* https://en.wikipedia.org/wiki/Time_Stamp_Counter
|
||||
* https://stackoverflow.com/questions/9887839/clock-cycle-count-wth-gcc/9887979
|
||||
|
||||
===== pmccntr
|
||||
|
||||
TODO We didn't manage to find a working ARM analogue to <<rdtsc>>: link:kernel_modules/pmccntr.c[] is oopsing, and even it if weren't, it likely won't give the cycle count since boot since it needs to be activate before it starts counting anything:
|
||||
|
||||
* https://stackoverflow.com/questions/40454157/is-there-an-equivalent-instruction-to-rdtsc-in-arm
|
||||
* https://stackoverflow.com/questions/31620375/arm-cortex-a7-returning-pmccntr-0-in-kernel-mode-and-illegal-instruction-in-u/31649809#31649809
|
||||
* https://blog.regehr.org/archives/794
|
||||
For x86, it is interesting to try and correlate `numCycles` with:
|
||||
|
||||
==== config.ini
|
||||
|
||||
@@ -11575,6 +11578,42 @@ Getting started at: <<userland-assembly>>.
|
||||
|
||||
TODO
|
||||
|
||||
=== rdtsc
|
||||
|
||||
TODO: review this section, make a more controlled userland experiment with <<m5ops>> instrumentation.
|
||||
|
||||
Let's have some fun and try to correlate the gem5 <<stats-txt>> `system.cpu.numCycles` cycle count with the link:https://en.wikipedia.org/wiki/Time_Stamp_Counter[x86 `rdtsc` instruction] that is supposed to do the same thing:
|
||||
|
||||
....
|
||||
./build-userland --static arch/x86_64/c/rdtsc
|
||||
./run --eval './arch/x86_64/c/rdtsc.out;m5 exit;' --emulator gem5
|
||||
./gem5-stat
|
||||
....
|
||||
|
||||
Source: link:userland/rdtsc.c[]
|
||||
|
||||
`rdtsc` outputs a cycle count which we compare with gem5's `gem5-stat`:
|
||||
|
||||
* `3828578153`: `rdtsc`
|
||||
* `3830832635`: `gem5-stat`
|
||||
|
||||
which gives pretty close results, and serve as a nice sanity check that the cycle counter is coherent.
|
||||
|
||||
It is also nice to see that `rdtsc` is a bit smaller than the `stats.txt` value, since the latter also includes the exec syscall for `m5`.
|
||||
|
||||
Bibliography:
|
||||
|
||||
* https://en.wikipedia.org/wiki/Time_Stamp_Counter
|
||||
* https://stackoverflow.com/questions/9887839/clock-cycle-count-wth-gcc/9887979
|
||||
|
||||
==== ARM pmccntr
|
||||
|
||||
TODO We didn't manage to find a working ARM analogue to <<rdtsc>>: link:kernel_modules/pmccntr.c[] is oopsing, and even it if weren't, it likely won't give the cycle count since boot since it needs to be activate before it starts counting anything:
|
||||
|
||||
* https://stackoverflow.com/questions/40454157/is-there-an-equivalent-instruction-to-rdtsc-in-arm
|
||||
* https://stackoverflow.com/questions/31620375/arm-cortex-a7-returning-pmccntr-0-in-kernel-mode-and-illegal-instruction-in-u/31649809#31649809
|
||||
* https://blog.regehr.org/archives/794
|
||||
|
||||
== arm userland assembly
|
||||
|
||||
Getting started at: <<userland-assembly>>.
|
||||
@@ -12700,15 +12739,15 @@ cat "$(./getvar test_boot_benchmark_file)"
|
||||
Sample results at 8fb9db39316d43a6dbd571e04dd46ae73915027f:
|
||||
|
||||
....
|
||||
cmd ./run --arch x86_64 --eval './poweroff.out'
|
||||
cmd ./run --arch x86_64 --eval './linux/poweroff.out'
|
||||
time 8.25
|
||||
exit_status 0
|
||||
|
||||
cmd ./run --arch x86_64 --eval './poweroff.out' --kvm
|
||||
cmd ./run --arch x86_64 --eval './linux/poweroff.out' --kvm
|
||||
time 1.22
|
||||
exit_status 0
|
||||
|
||||
cmd ./run --arch x86_64 --eval './poweroff.out' --trace exec_tb
|
||||
cmd ./run --arch x86_64 --eval './linux/poweroff.out' --trace exec_tb
|
||||
time 8.83
|
||||
exit_status 0
|
||||
instructions 2244297
|
||||
@@ -12718,10 +12757,10 @@ time 213.39
|
||||
exit_status 0
|
||||
instructions 318486337
|
||||
|
||||
cmd ./run --arch arm --eval './poweroff.out'
|
||||
cmd ./run --arch arm --eval './linux/poweroff.out'
|
||||
time 6.62
|
||||
exit_status 0
|
||||
cmd ./run --arch arm --eval './poweroff.out' --trace exec_tb
|
||||
cmd ./run --arch arm --eval './linux/poweroff.out' --trace exec_tb
|
||||
time 6.90
|
||||
exit_status 0
|
||||
instructions 776374
|
||||
@@ -12736,11 +12775,11 @@ time 2250.40
|
||||
exit_status 0
|
||||
instructions 151981914
|
||||
|
||||
cmd ./run --arch aarch64 --eval './poweroff.out'
|
||||
cmd ./run --arch aarch64 --eval './linux/poweroff.out'
|
||||
time 4.94
|
||||
exit_status 0
|
||||
|
||||
cmd ./run --arch aarch64 --eval './poweroff.out' --trace exec_tb
|
||||
cmd ./run --arch aarch64 --eval './linux/poweroff.out' --trace exec_tb
|
||||
time 5.04
|
||||
exit_status 0
|
||||
instructions 233162
|
||||
@@ -13567,10 +13606,10 @@ We try to keep as much as possible in those files. It bloats builds a little, bu
|
||||
Print out several parameters that normally change randomly from boot to boot:
|
||||
|
||||
....
|
||||
./run --eval-after './rand_check.out;./poweroff.out'
|
||||
./run --eval-after './linux/rand_check.out;./linux/poweroff.out'
|
||||
....
|
||||
|
||||
Source: link:userland/rand_check.c[]
|
||||
Source: link:userland/linux/rand_check.c[]
|
||||
|
||||
This can be used to check the determinism of:
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ set -eu
|
||||
git submodule update --recursive
|
||||
cd ../..
|
||||
./build-qemu --arch aarch64 --qemu-build-id bisect
|
||||
./run --arch aarch64 --kernel-cli 'init=/poweroff.out' --qemu-build-id bisect
|
||||
./run --arch aarch64 --kernel-cli 'init=/lkmc/linux/poweroff.out' --qemu-build-id bisect
|
||||
|
||||
@@ -228,6 +228,7 @@ Default: build all examples that have their package dependencies met, e.g.:
|
||||
do_build_dir = False
|
||||
else:
|
||||
do_build_dir = False
|
||||
in_libs = dirpath_relative_root_components[0] == 'libs'
|
||||
if do_build_dir:
|
||||
out_dir = os.path.join(
|
||||
build_dir,
|
||||
@@ -235,7 +236,7 @@ Default: build all examples that have their package dependencies met, e.g.:
|
||||
)
|
||||
common_objs_dir = [common_obj]
|
||||
ccflags_dir = ccflags.copy()
|
||||
if dirpath_relative_root_components == ['gcc']:
|
||||
if dirpath_relative_root_components in ('gcc', 'kernel_modules', 'linux'):
|
||||
cstd = 'gnu11'
|
||||
cxxstd = 'gnu++17'
|
||||
else:
|
||||
@@ -290,31 +291,32 @@ Default: build all examples that have their package dependencies met, e.g.:
|
||||
out_dir,
|
||||
in_name + self.env['userland_build_ext']
|
||||
)
|
||||
pkg_key = in_name.split('_')[0]
|
||||
ccflags_file = ccflags_dir.copy()
|
||||
ccflags_after = []
|
||||
if pkg_key in pkgs:
|
||||
if pkg_key not in has_packages:
|
||||
continue
|
||||
pkg = pkgs[pkg_key]
|
||||
if 'ccflags' in pkg:
|
||||
ccflags_file.extend(pkg['ccflags'])
|
||||
else:
|
||||
pkg_config_output = subprocess.check_output([
|
||||
self.env['buildroot_pkg_config'],
|
||||
'--cflags',
|
||||
pkg_key
|
||||
]).decode()
|
||||
ccflags_file.extend(self.sh.shlex_split(pkg_config_output))
|
||||
if 'ccflags_after' in pkg:
|
||||
ccflags_file.extend(pkg['ccflags_after'])
|
||||
else:
|
||||
pkg_config_output = subprocess.check_output([
|
||||
self.env['buildroot_pkg_config'],
|
||||
'--libs',
|
||||
pkg_key
|
||||
]).decode()
|
||||
ccflags_after.extend(self.sh.shlex_split(pkg_config_output))
|
||||
if in_libs:
|
||||
pkg_key = in_name.split('_')[0]
|
||||
if pkg_key in pkgs:
|
||||
if pkg_key not in has_packages:
|
||||
continue
|
||||
pkg = pkgs[pkg_key]
|
||||
if 'ccflags' in pkg:
|
||||
ccflags_file.extend(pkg['ccflags'])
|
||||
else:
|
||||
pkg_config_output = subprocess.check_output([
|
||||
self.env['buildroot_pkg_config'],
|
||||
'--cflags',
|
||||
pkg_key
|
||||
]).decode()
|
||||
ccflags_file.extend(self.sh.shlex_split(pkg_config_output))
|
||||
if 'ccflags_after' in pkg:
|
||||
ccflags_file.extend(pkg['ccflags_after'])
|
||||
else:
|
||||
pkg_config_output = subprocess.check_output([
|
||||
self.env['buildroot_pkg_config'],
|
||||
'--libs',
|
||||
pkg_key
|
||||
]).decode()
|
||||
ccflags_after.extend(self.sh.shlex_split(pkg_config_output))
|
||||
error = thread_pool.submit({
|
||||
'in_path': in_path,
|
||||
'out_path': out_path,
|
||||
|
||||
@@ -705,9 +705,9 @@ Valid emulators: {}
|
||||
env['linux_image'] = env['lkmc_linux_image']
|
||||
env['linux_config'] = join(env['linux_build_dir'], '.config')
|
||||
if env['emulator']== 'gem5':
|
||||
env['userland_quit_cmd'] = '/gem5_exit.sh'
|
||||
env['userland_quit_cmd'] = './gem5_exit.sh'
|
||||
else:
|
||||
env['userland_quit_cmd'] = '/poweroff.out'
|
||||
env['userland_quit_cmd'] = './poweroff.out'
|
||||
env['ramfs'] = env['initrd'] or env['initramfs']
|
||||
if env['ramfs']:
|
||||
env['initarg'] = 'rdinit'
|
||||
|
||||
14
file_properties.py
Normal file
14
file_properties.py
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
class FileProperties:
|
||||
def __init__(
|
||||
more_than_1s=False,
|
||||
exits_nonzero=False,
|
||||
interactive=False,
|
||||
):
|
||||
self.more_than_1s = more_than_1s
|
||||
self.exits_nonzero = exits_nonzero
|
||||
|
||||
executable_properties = {
|
||||
'userland/arch/x86_64/c/ring0.c': ExecutableProperties(exits_nonzero=True),
|
||||
}
|
||||
@@ -3,27 +3,26 @@
|
||||
#ifdef THIS_MODULE
|
||||
#include <linux/kernel.h>
|
||||
#if defined(__x86_64__)
|
||||
typedef u64 T;
|
||||
typedef u64 LkmcRing0RegsType;
|
||||
#elif defined(__i386__)
|
||||
typedef u32 T;
|
||||
typedef u32 LkmcRing0RegsType;
|
||||
#endif
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#if defined(__x86_64__)
|
||||
typedef uint64_t T;
|
||||
typedef uint64_t LkmcRing0RegsType;
|
||||
#elif defined(__i386__)
|
||||
typedef uint32_t T;
|
||||
typedef uint32_t LkmcRing0RegsType;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
T cr0;
|
||||
T cr2;
|
||||
T cr3;
|
||||
} Ring0Regs;
|
||||
LkmcRing0RegsType cr0;
|
||||
LkmcRing0RegsType cr2;
|
||||
LkmcRing0RegsType cr3;
|
||||
} LkmcRing0Regs;
|
||||
|
||||
void ring0_get_control_regs(Ring0Regs *ring0_regs)
|
||||
{
|
||||
void lkmc_ring0_get_control_regs(LkmcRing0Regs *ring0_regs) {
|
||||
#if defined(__x86_64__)
|
||||
__asm__ __volatile__ (
|
||||
"mov %%cr0, %%rax;"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#pmccntr */
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-pmccntr */
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/errno.h> /* EFAULT */
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
static int myinit(void)
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
Ring0Regs ring0_regs;
|
||||
ring0_get_control_regs(&ring0_regs);
|
||||
LkmcRing0Regs ring0_regs;
|
||||
lkmc_ring0_get_control_regs(&ring0_regs);
|
||||
pr_info("cr0 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr0);
|
||||
pr_info("cr2 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr2);
|
||||
pr_info("cr3 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr3);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -ex
|
||||
./rand_check.out
|
||||
./linux/rand_check.out
|
||||
|
||||
# Check if network is being replayed.
|
||||
# https://superuser.com/questions/635020/how-to-know-current-time-from-internet-from-command-line-in-linux
|
||||
@@ -9,4 +9,4 @@ set -ex
|
||||
|
||||
# busybox's poweroff panics, TODO why. Likely tries to kill shell.
|
||||
# So just use our super raw command.
|
||||
./poweroff.out
|
||||
./linux/poweroff.out
|
||||
|
||||
2
run
2
run
@@ -109,7 +109,7 @@ timestamps.
|
||||
Pass an extra Linux kernel command line options, and place them before
|
||||
the dash separator `-`. Only options that come before the `-`, i.e.
|
||||
"standard" options, should be passed with this option.
|
||||
Example: `./run --arch arm --kernel-cli 'init=/poweroff.out'`
|
||||
Example: `./run --arch arm --kernel-cli 'init=/lkmc/poweroff.out'`
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
|
||||
14
userland/arch/x86_64/c/rdtsc.c
Normal file
14
userland/arch/x86_64/c/rdtsc.c
Normal file
@@ -0,0 +1,14 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#rdtsc */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <x86intrin.h>
|
||||
|
||||
int main(void) {
|
||||
uintmax_t val;
|
||||
val = __rdtsc();
|
||||
printf("%ju\n", val);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
12
userland/arch/x86_64/c/ring0.c
Normal file
12
userland/arch/x86_64/c/ring0.c
Normal file
@@ -0,0 +1,12 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ring0 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <include/ring0.h>
|
||||
|
||||
int main(void) {
|
||||
LkmcRing0Regs ring0_regs;
|
||||
lkmc_ring0_get_control_regs(&ring0_regs);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
3
userland/libs/README.adoc
Normal file
3
userland/libs/README.adoc
Normal file
@@ -0,0 +1,3 @@
|
||||
Examples in this directory rely on non-libc libraries.
|
||||
|
||||
Each example is prefixed by an identifier of the library it depends on.
|
||||
1
userland/libs/build
Symbolic link
1
userland/libs/build
Symbolic link
@@ -0,0 +1 @@
|
||||
../build
|
||||
@@ -7,8 +7,8 @@
|
||||
int main(void) {
|
||||
FILE *fp;
|
||||
fp = fopen("/dev/kmsg", "w");
|
||||
fputs(__FILE__ "\n", fp);
|
||||
fclose(fp);
|
||||
while (1)
|
||||
sleep(0xFFFFFFFF);
|
||||
fputs(__FILE__ "\n", fp);
|
||||
fclose(fp);
|
||||
while (1)
|
||||
sleep(0xFFFFFFFF);
|
||||
}
|
||||
@@ -13,49 +13,49 @@
|
||||
#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *params;
|
||||
int fd, use_finit;
|
||||
size_t image_size;
|
||||
struct stat st;
|
||||
void *image;
|
||||
const char *params;
|
||||
int fd, use_finit;
|
||||
size_t image_size;
|
||||
struct stat st;
|
||||
void *image;
|
||||
|
||||
/* CLI handling. */
|
||||
if (argc < 2) {
|
||||
puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc < 3) {
|
||||
params = "";
|
||||
} else {
|
||||
params = argv[2];
|
||||
}
|
||||
if (argc < 4) {
|
||||
use_finit = 0;
|
||||
} else {
|
||||
use_finit = (argv[3][0] != '0');
|
||||
}
|
||||
/* CLI handling. */
|
||||
if (argc < 2) {
|
||||
puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc < 3) {
|
||||
params = "";
|
||||
} else {
|
||||
params = argv[2];
|
||||
}
|
||||
if (argc < 4) {
|
||||
use_finit = 0;
|
||||
} else {
|
||||
use_finit = (argv[3][0] != '0');
|
||||
}
|
||||
|
||||
/* Action. */
|
||||
fd = open(argv[1], O_RDONLY);
|
||||
if (use_finit) {
|
||||
puts("finit");
|
||||
if (finit_module(fd, params, 0) != 0) {
|
||||
perror("finit_module");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
puts("init");
|
||||
fstat(fd, &st);
|
||||
image_size = st.st_size;
|
||||
image = malloc(image_size);
|
||||
read(fd, image, image_size);
|
||||
close(fd);
|
||||
if (init_module(image, image_size, params) != 0) {
|
||||
perror("init_module");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
free(image);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
/* Action. */
|
||||
fd = open(argv[1], O_RDONLY);
|
||||
if (use_finit) {
|
||||
puts("finit");
|
||||
if (finit_module(fd, params, 0) != 0) {
|
||||
perror("finit_module");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
puts("init");
|
||||
fstat(fd, &st);
|
||||
image_size = st.st_size;
|
||||
image = malloc(image_size);
|
||||
read(fd, image, image_size);
|
||||
close(fd);
|
||||
if (init_module(image, image_size, params) != 0) {
|
||||
perror("init_module");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
free(image);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
puts("Usage ./prog mymodule");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (delete_module(argv[1], O_NONBLOCK) != 0) {
|
||||
perror("delete_module");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
if (argc != 2) {
|
||||
puts("Usage ./prog mymodule");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (delete_module(argv[1], O_NONBLOCK) != 0) {
|
||||
perror("delete_module");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void) {
|
||||
puts(__FILE__);
|
||||
while (1)
|
||||
sleep(0xFFFFFFFF);
|
||||
puts(__FILE__);
|
||||
while (1)
|
||||
sleep(0xFFFFFFFF);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#rdtsc */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
uintmax_t val;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
val = __rdtsc();
|
||||
#else
|
||||
val = 0;
|
||||
#endif
|
||||
printf("%ju\n", val);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ring0 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../include/ring0.h"
|
||||
|
||||
int main(void) {
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
Ring0Regs ring0_regs;
|
||||
ring0_get_control_regs(&ring0_regs);
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user