migrate all

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-05-05 00:00:00 +00:00
parent ecef42be81
commit 0ef494b681
27 changed files with 280 additions and 230 deletions

View File

@@ -440,11 +440,11 @@ OK, now time to hack GCC.
For convenience, let's use the <<user-mode-simulation>>. 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 ./build-userland --static
./run --static --userland gcc_hack ./run --static --userland c/gcc_hack
.... ....
it produces the normal boring output: 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-buildroot -- host-gcc-final-rebuild
./build-userland --static ./build-userland --static
./run --static --userland gcc_hack ./run --static --userland c/gcc_hack
.... ....
and the new ouptut is now: 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" "$(./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 ===== Userland setup getting started full system
First ensure that <<qemu-buildroot-setup>> is working. 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: 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. 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: 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: 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: 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: 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[]. 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 ' echo '
cd /lkmc cd /lkmc
insmod hello.ko insmod hello.ko
./poweroff.out ./linux/poweroff.out
' > data/gitignore.sh ' > data/gitignore.sh
./run --eval "$(cat 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 echo '#!/bin/sh
cd /lkmc cd /lkmc
insmod hello.ko insmod hello.ko
./poweroff.out ./linux/poweroff.out
' > rootfs_overlay/lkmc/gitignore.sh ' > rootfs_overlay/lkmc/gitignore.sh
chmod +x rootfs_overlay/lkmc/gitignore.sh chmod +x rootfs_overlay/lkmc/gitignore.sh
./build-buildroot ./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! 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' ./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 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: 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. This executable is a convenient simple init that does not panic and sleeps instead.
==== time_boot.out ==== 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 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: 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. 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.: 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: outputs:
@@ -3399,6 +3407,33 @@ If you modify the userland programs, rebuild simply with:
./build-userland ./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 ==== 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: 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: 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: 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? 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 \ ./run \
@@ -3708,7 +3743,7 @@ QEMU full system:
time \ time \
./run \ ./run \
--arch arm \ --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: 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 './linux/rand_check.out;./linux/poweroff.out'
./run --eval-after './rand_check.out;./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: 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: * 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: 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: 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: 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-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
./build-userland --has-package libdrm -- libdrm_modeset ./build-userland --has-package libdrm -- libs/libdrm_modeset
./run --eval-after './libdrm_modeset.out' --graphic ./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. 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-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
./build-userland --has-package libdrm ./build-userland --has-package libdrm
./build-buildroot ./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? <<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: 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: 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`: 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 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. # 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. # 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: 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: 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: 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: after the message:
@@ -9334,7 +9369,7 @@ Then, when I tried with <<initrd>> and no disk:
.... ....
./build-buildroot --arch aarch64 --initrd ./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: 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[]: 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 './linux/rand_check.out;./linux/poweroff.out;' --record
./run --eval-after './rand_check.out;./poweroff.out;' --replay --wait-gdb ./run --eval-after './linux/rand_check.out;./linux/poweroff.out;' --replay --wait-gdb
.... ....
On another shell: 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: 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 ./qemu-trace2txt
.... ....
@@ -9874,8 +9909,8 @@ Buildroot supports it, which makes everything just trivial:
.... ....
./build-buildroot --config 'BR2_PACKAGE_OPENBLAS=y' ./build-buildroot --config 'BR2_PACKAGE_OPENBLAS=y'
./build-userland --has-package openblas -- openblas_hello ./build-userland --has-package openblas -- libs/openblas_hello
./run --eval-after './openblas_hello.out; echo $?' ./run --eval-after './libs/openblas_hello.out; echo $?'
.... ....
Outcome: the test passes: Outcome: the test passes:
@@ -9884,7 +9919,7 @@ Outcome: the test passes:
0 0
.... ....
Source: link:userland/openblas.c[] Source: link:userland/libs/openblas.c[]
The test performs a general matrix multiplication: 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-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: Just create an array and print it:
.... ....
./run --eval-after './eigen_hello.out' ./run --eval-after './libs/eigen_hello.out'
.... ....
Output: Output:
@@ -9930,7 +9965,7 @@ Output:
2.5 1.5 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. 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>>: 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. 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 system.cpu.dtb.inst_hits
.... ....
==== rdtsc For x86, it is interesting to try and correlate `numCycles` with:
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
==== config.ini ==== config.ini
@@ -11575,6 +11578,42 @@ Getting started at: <<userland-assembly>>.
TODO 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 == arm userland assembly
Getting started at: <<userland-assembly>>. Getting started at: <<userland-assembly>>.
@@ -12700,15 +12739,15 @@ cat "$(./getvar test_boot_benchmark_file)"
Sample results at 8fb9db39316d43a6dbd571e04dd46ae73915027f: Sample results at 8fb9db39316d43a6dbd571e04dd46ae73915027f:
.... ....
cmd ./run --arch x86_64 --eval './poweroff.out' cmd ./run --arch x86_64 --eval './linux/poweroff.out'
time 8.25 time 8.25
exit_status 0 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 time 1.22
exit_status 0 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 time 8.83
exit_status 0 exit_status 0
instructions 2244297 instructions 2244297
@@ -12718,10 +12757,10 @@ time 213.39
exit_status 0 exit_status 0
instructions 318486337 instructions 318486337
cmd ./run --arch arm --eval './poweroff.out' cmd ./run --arch arm --eval './linux/poweroff.out'
time 6.62 time 6.62
exit_status 0 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 time 6.90
exit_status 0 exit_status 0
instructions 776374 instructions 776374
@@ -12736,11 +12775,11 @@ time 2250.40
exit_status 0 exit_status 0
instructions 151981914 instructions 151981914
cmd ./run --arch aarch64 --eval './poweroff.out' cmd ./run --arch aarch64 --eval './linux/poweroff.out'
time 4.94 time 4.94
exit_status 0 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 time 5.04
exit_status 0 exit_status 0
instructions 233162 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: 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: This can be used to check the determinism of:

View File

@@ -3,4 +3,4 @@ set -eu
git submodule update --recursive git submodule update --recursive
cd ../.. cd ../..
./build-qemu --arch aarch64 --qemu-build-id bisect ./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

View File

@@ -228,6 +228,7 @@ Default: build all examples that have their package dependencies met, e.g.:
do_build_dir = False do_build_dir = False
else: else:
do_build_dir = False do_build_dir = False
in_libs = dirpath_relative_root_components[0] == 'libs'
if do_build_dir: if do_build_dir:
out_dir = os.path.join( out_dir = os.path.join(
build_dir, build_dir,
@@ -235,7 +236,7 @@ Default: build all examples that have their package dependencies met, e.g.:
) )
common_objs_dir = [common_obj] common_objs_dir = [common_obj]
ccflags_dir = ccflags.copy() ccflags_dir = ccflags.copy()
if dirpath_relative_root_components == ['gcc']: if dirpath_relative_root_components in ('gcc', 'kernel_modules', 'linux'):
cstd = 'gnu11' cstd = 'gnu11'
cxxstd = 'gnu++17' cxxstd = 'gnu++17'
else: else:
@@ -290,31 +291,32 @@ Default: build all examples that have their package dependencies met, e.g.:
out_dir, out_dir,
in_name + self.env['userland_build_ext'] in_name + self.env['userland_build_ext']
) )
pkg_key = in_name.split('_')[0]
ccflags_file = ccflags_dir.copy() ccflags_file = ccflags_dir.copy()
ccflags_after = [] ccflags_after = []
if pkg_key in pkgs: if in_libs:
if pkg_key not in has_packages: pkg_key = in_name.split('_')[0]
continue if pkg_key in pkgs:
pkg = pkgs[pkg_key] if pkg_key not in has_packages:
if 'ccflags' in pkg: continue
ccflags_file.extend(pkg['ccflags']) pkg = pkgs[pkg_key]
else: if 'ccflags' in pkg:
pkg_config_output = subprocess.check_output([ ccflags_file.extend(pkg['ccflags'])
self.env['buildroot_pkg_config'], else:
'--cflags', pkg_config_output = subprocess.check_output([
pkg_key self.env['buildroot_pkg_config'],
]).decode() '--cflags',
ccflags_file.extend(self.sh.shlex_split(pkg_config_output)) pkg_key
if 'ccflags_after' in pkg: ]).decode()
ccflags_file.extend(pkg['ccflags_after']) ccflags_file.extend(self.sh.shlex_split(pkg_config_output))
else: if 'ccflags_after' in pkg:
pkg_config_output = subprocess.check_output([ ccflags_file.extend(pkg['ccflags_after'])
self.env['buildroot_pkg_config'], else:
'--libs', pkg_config_output = subprocess.check_output([
pkg_key self.env['buildroot_pkg_config'],
]).decode() '--libs',
ccflags_after.extend(self.sh.shlex_split(pkg_config_output)) pkg_key
]).decode()
ccflags_after.extend(self.sh.shlex_split(pkg_config_output))
error = thread_pool.submit({ error = thread_pool.submit({
'in_path': in_path, 'in_path': in_path,
'out_path': out_path, 'out_path': out_path,

View File

@@ -705,9 +705,9 @@ Valid emulators: {}
env['linux_image'] = env['lkmc_linux_image'] env['linux_image'] = env['lkmc_linux_image']
env['linux_config'] = join(env['linux_build_dir'], '.config') env['linux_config'] = join(env['linux_build_dir'], '.config')
if env['emulator']== 'gem5': if env['emulator']== 'gem5':
env['userland_quit_cmd'] = '/gem5_exit.sh' env['userland_quit_cmd'] = './gem5_exit.sh'
else: else:
env['userland_quit_cmd'] = '/poweroff.out' env['userland_quit_cmd'] = './poweroff.out'
env['ramfs'] = env['initrd'] or env['initramfs'] env['ramfs'] = env['initrd'] or env['initramfs']
if env['ramfs']: if env['ramfs']:
env['initarg'] = 'rdinit' env['initarg'] = 'rdinit'

14
file_properties.py Normal file
View 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),
}

View File

@@ -3,27 +3,26 @@
#ifdef THIS_MODULE #ifdef THIS_MODULE
#include <linux/kernel.h> #include <linux/kernel.h>
#if defined(__x86_64__) #if defined(__x86_64__)
typedef u64 T; typedef u64 LkmcRing0RegsType;
#elif defined(__i386__) #elif defined(__i386__)
typedef u32 T; typedef u32 LkmcRing0RegsType;
#endif #endif
#else #else
#include <stdint.h> #include <stdint.h>
#if defined(__x86_64__) #if defined(__x86_64__)
typedef uint64_t T; typedef uint64_t LkmcRing0RegsType;
#elif defined(__i386__) #elif defined(__i386__)
typedef uint32_t T; typedef uint32_t LkmcRing0RegsType;
#endif #endif
#endif #endif
typedef struct { typedef struct {
T cr0; LkmcRing0RegsType cr0;
T cr2; LkmcRing0RegsType cr2;
T cr3; LkmcRing0RegsType cr3;
} Ring0Regs; } LkmcRing0Regs;
void ring0_get_control_regs(Ring0Regs *ring0_regs) void lkmc_ring0_get_control_regs(LkmcRing0Regs *ring0_regs) {
{
#if defined(__x86_64__) #if defined(__x86_64__)
__asm__ __volatile__ ( __asm__ __volatile__ (
"mov %%cr0, %%rax;" "mov %%cr0, %%rax;"

View File

@@ -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/debugfs.h>
#include <linux/errno.h> /* EFAULT */ #include <linux/errno.h> /* EFAULT */

View File

@@ -8,8 +8,8 @@
static int myinit(void) static int myinit(void)
{ {
#if defined(__x86_64__) || defined(__i386__) #if defined(__x86_64__) || defined(__i386__)
Ring0Regs ring0_regs; LkmcRing0Regs ring0_regs;
ring0_get_control_regs(&ring0_regs); lkmc_ring0_get_control_regs(&ring0_regs);
pr_info("cr0 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr0); 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("cr2 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr2);
pr_info("cr3 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr3); pr_info("cr3 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr3);

View File

@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
set -ex set -ex
./rand_check.out ./linux/rand_check.out
# Check if network is being replayed. # Check if network is being replayed.
# https://superuser.com/questions/635020/how-to-know-current-time-from-internet-from-command-line-in-linux # 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. # busybox's poweroff panics, TODO why. Likely tries to kill shell.
# So just use our super raw command. # So just use our super raw command.
./poweroff.out ./linux/poweroff.out

2
run
View File

@@ -109,7 +109,7 @@ timestamps.
Pass an extra Linux kernel command line options, and place them before Pass an extra Linux kernel command line options, and place them before
the dash separator `-`. Only options that come before the `-`, i.e. the dash separator `-`. Only options that come before the `-`, i.e.
"standard" options, should be passed with this option. "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( self.add_argument(

View 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;
}

View 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;
}

View 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
View File

@@ -0,0 +1 @@
../build

View File

@@ -7,8 +7,8 @@
int main(void) { int main(void) {
FILE *fp; FILE *fp;
fp = fopen("/dev/kmsg", "w"); fp = fopen("/dev/kmsg", "w");
fputs(__FILE__ "\n", fp); fputs(__FILE__ "\n", fp);
fclose(fp); fclose(fp);
while (1) while (1)
sleep(0xFFFFFFFF); sleep(0xFFFFFFFF);
} }

View File

@@ -13,49 +13,49 @@
#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags) #define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)
int main(int argc, char **argv) { int main(int argc, char **argv) {
const char *params; const char *params;
int fd, use_finit; int fd, use_finit;
size_t image_size; size_t image_size;
struct stat st; struct stat st;
void *image; void *image;
/* CLI handling. */ /* CLI handling. */
if (argc < 2) { if (argc < 2) {
puts("Usage ./prog mymodule.ko [args="" [use_finit=0]"); puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (argc < 3) { if (argc < 3) {
params = ""; params = "";
} else { } else {
params = argv[2]; params = argv[2];
} }
if (argc < 4) { if (argc < 4) {
use_finit = 0; use_finit = 0;
} else { } else {
use_finit = (argv[3][0] != '0'); use_finit = (argv[3][0] != '0');
} }
/* Action. */ /* Action. */
fd = open(argv[1], O_RDONLY); fd = open(argv[1], O_RDONLY);
if (use_finit) { if (use_finit) {
puts("finit"); puts("finit");
if (finit_module(fd, params, 0) != 0) { if (finit_module(fd, params, 0) != 0) {
perror("finit_module"); perror("finit_module");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
close(fd); close(fd);
} else { } else {
puts("init"); puts("init");
fstat(fd, &st); fstat(fd, &st);
image_size = st.st_size; image_size = st.st_size;
image = malloc(image_size); image = malloc(image_size);
read(fd, image, image_size); read(fd, image, image_size);
close(fd); close(fd);
if (init_module(image, image_size, params) != 0) { if (init_module(image, image_size, params) != 0) {
perror("init_module"); perror("init_module");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
free(image); free(image);
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -12,13 +12,13 @@
#define delete_module(name, flags) syscall(__NR_delete_module, name, flags) #define delete_module(name, flags) syscall(__NR_delete_module, name, flags)
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc != 2) { if (argc != 2) {
puts("Usage ./prog mymodule"); puts("Usage ./prog mymodule");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (delete_module(argv[1], O_NONBLOCK) != 0) { if (delete_module(argv[1], O_NONBLOCK) != 0) {
perror("delete_module"); perror("delete_module");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -5,7 +5,7 @@
#include <unistd.h> #include <unistd.h>
int main(void) { int main(void) {
puts(__FILE__); puts(__FILE__);
while (1) while (1)
sleep(0xFFFFFFFF); sleep(0xFFFFFFFF);
} }

View File

@@ -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;
}

View File

@@ -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;
}