This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-05-05 00:00:00 +00:00
parent 0ef494b681
commit aea97698c3
48 changed files with 840 additions and 798 deletions

View File

@@ -977,23 +977,38 @@ Build, run and example, and clean it in-tree with:
.... ....
cd userland cd userland
./build ./build c/hello
./c/hello.out ./c/hello.out
./build --clean ./build --clean
.... ....
Source: link:userland/c/hello.c[]. Source: link:userland/c/hello.c[].
Or build just one directory: Build an entire directory:
.... ....
./build c ./build c
.... ....
or just one executable: Build the current directory:
.... ....
./build c/hello ./build
....
Note however that this would try to build the link:userland/libs/[] folder, which depends on certain libraries being installed on the host, e.g. <<blas>>.
You can install those libraries and do the build in one go with:
....
cd linux-kernel-module-cheat
./build --download-dependencies userland-host
....
If you modify a dependency that is not currently considered such as a header file, force the rebuild with:
....
./build --force-rebuild
.... ....
Do a more clean out of tree build and run the program instead: Do a more clean out of tree build and run the program instead:
@@ -1003,11 +1018,7 @@ 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: Here we put the host executables in a separate <<build-variants,build-variant>> to avoid conflict with Buildroot builds.
....
./build --force-rebuild
....
===== Userland setup getting started full system ===== Userland setup getting started full system
@@ -1699,7 +1710,7 @@ Alternatively, if the module panics before you can read `/proc/modules`, there i
.... ....
echo 8 > /proc/sys/kernel/printk echo 8 > /proc/sys/kernel/printk
echo 'file kernel/module.c +p' > /sys/kernel/debug/dynamic_debug/control echo 'file kernel/module.c +p' > /sys/kernel/debug/dynamic_debug/control
./myinsmod.out hello.ko ./linux/myinsmod.out hello.ko
.... ....
And then search for a line of type: And then search for a line of type:
@@ -1874,12 +1885,12 @@ Non-init process:
* Shell 2: * Shell 2:
+ +
.... ....
./run-gdb-user myinsmod main ./run-gdb-user linux/myinsmod main
.... ....
* Shell 1 after the boot finishes: * Shell 1 after the boot finishes:
+ +
.... ....
./myinsmod.out hello.ko ./linux/myinsmod.out hello.ko
.... ....
This is the least reliable setup as there might be other processes that use the given virtual address. This is the least reliable setup as there might be other processes that use the given virtual address.
@@ -1995,10 +2006,10 @@ For a more minimal baremetal multicore setup, see: <<arm-multicore>>.
We can set and get which cores the Linux kernel allows a program to run on with `sched_getaffinity` and `sched_setaffinity`: We can set and get which cores the Linux kernel allows a program to run on with `sched_getaffinity` and `sched_setaffinity`:
.... ....
./run --cpus 2 --eval-after './sched_getaffinity.out' ./run --cpus 2 --eval-after './linux/sched_getaffinity.out'
.... ....
Source: link:userland/sched_getaffinity.c[] Source: link:userland/linux/sched_getaffinity.c[]
Sample output: Sample output:
@@ -2025,7 +2036,7 @@ The number of cores is modified as explained at: <<number-of-cores>>
--config 'BR2_PACKAGE_UTIL_LINUX=y' \ --config 'BR2_PACKAGE_UTIL_LINUX=y' \
--config 'BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS=y' \ --config 'BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS=y' \
; ;
./run --eval-after 'taskset -c 1,1 ./sched_getaffinity.out' ./run --eval-after 'taskset -c 1,1 ./linux/sched_getaffinity.out'
.... ....
output: output:
@@ -2041,20 +2052,20 @@ so we see that the affinity was restricted to the second core from the start.
Let's do a QEMU observation to justify this example being in the repository with <<gdb-step-debug-userland-non-init,userland breakpoints>>. Let's do a QEMU observation to justify this example being in the repository with <<gdb-step-debug-userland-non-init,userland breakpoints>>.
We will run our `./sched_getaffinity.out` infinitely many time, on core 0 and core 1 alternatively: We will run our `./linux/sched_getaffinity.out` infinitely many time, on core 0 and core 1 alternatively:
.... ....
./run \ ./run \
--cpus 2 \ --cpus 2 \
--wait-gdb \ --wait-gdb \
--eval-after 'i=0; while true; do taskset -c $i,$i ./sched_getaffinity.out; i=$((! $i)); done' \ --eval-after 'i=0; while true; do taskset -c $i,$i ./linux/sched_getaffinity.out; i=$((! $i)); done' \
; ;
.... ....
on another shell: on another shell:
.... ....
./run-gdb-user "$(./getvar userland_build_dir)/sched_getaffinity.out" main ./run-gdb-user "$(./getvar userland_build_dir)/linux/sched_getaffinity.out" main
.... ....
Then, inside GDB: Then, inside GDB:
@@ -2079,13 +2090,13 @@ We should also try it out with kernel modules: https://stackoverflow.com/questio
TODO we then tried: TODO we then tried:
.... ....
./run --cpus 2 --eval-after './sched_getaffinity_threads.out' ./run --cpus 2 --eval-after './linux/sched_getaffinity_threads.out'
.... ....
and: and:
.... ....
./run-gdb-user "$(./getvar userland_build_dir)/sched_getaffinity_threads.out" ./run-gdb-user "$(./getvar userland_build_dir)/linux/sched_getaffinity_threads.out"
.... ....
to switch between two simultaneous live threads with different affinities, it just didn't break on our threads: to switch between two simultaneous live threads with different affinities, it just didn't break on our threads:
@@ -2431,10 +2442,10 @@ First build `gdbserver` into the root filesystem:
./build-buildroot --config 'BR2_PACKAGE_GDB=y' ./build-buildroot --config 'BR2_PACKAGE_GDB=y'
.... ....
Then on guest, to debug link:userland/myinsmod.c[]: Then on guest, to debug link:userland/linux/myinsmod.c[]:
.... ....
./gdbserver.sh ./myinsmod.out hello.ko ./gdbserver.sh ./linux/myinsmod.out hello.ko
.... ....
Source: link:rootfs_overlay/lkmc/gdbserver.sh[]. Source: link:rootfs_overlay/lkmc/gdbserver.sh[].
@@ -2442,13 +2453,13 @@ Source: link:rootfs_overlay/lkmc/gdbserver.sh[].
And on host: And on host:
.... ....
./run-gdbserver myinsmod ./run-gdbserver linux/myinsmod
.... ....
or alternatively with the full path: or alternatively with the full path:
.... ....
./run-gdbserver "$(./getvar userland_build_dir)/myinsmod.out" ./run-gdbserver "$(./getvar userland_build_dir)/linux/myinsmod.out"
.... ....
https://reverseengineering.stackexchange.com/questions/8829/cross-debugging-for-arm-mips-elf-with-qemu-toolchain/16214#16214 https://reverseengineering.stackexchange.com/questions/8829/cross-debugging-for-arm-mips-elf-with-qemu-toolchain/16214#16214
@@ -2587,7 +2598,7 @@ traps: ring0.out[55] general protection ip:40054c sp:7fffffffec20 error:0 in rin
Sources: Sources:
* link:kernel_modules/ring0.c[] * link:kernel_modules/ring0.c[]
* link:kernel_modules/ring0.h[] * link:include/ring0.h[]
* link:userland/ring0.c[] * link:userland/ring0.c[]
In both cases, we attempt to run the exact same code which is shared on the `ring0.h` header file. In both cases, we attempt to run the exact same code which is shared on the `ring0.h` header file.
@@ -2832,14 +2843,14 @@ ____
And you can try it out with: And you can try it out with:
.... ....
./run --kernel-cli 'init=/lkmc/init_env_poweroff.out - asdf=qwer zxcv' ./run --kernel-cli 'init=/lkmc/linux/init_env_poweroff.out - asdf=qwer zxcv'
.... ....
Output: Output:
.... ....
args: args:
/lkmc/init_env_poweroff.out /lkmc/linux/init_env_poweroff.out
- -
zxcv zxcv
@@ -2849,7 +2860,7 @@ TERM=linux
asdf=qwer asdf=qwer
.... ....
Source: link:userland/init_env_poweroff.c[]. Source: link:userland/linux/init_env_poweroff.c[].
==== init arguments ==== init arguments
@@ -2858,14 +2869,14 @@ 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/linux/poweroff.out' ./run --kernel-cli 'init=/lkmc/linux/init_env_poweroff.out - /lkmc/linux/poweroff.out'
.... ....
outputs: outputs:
.... ....
args args
/lkmc/init_env_poweroff.out /lkmc/linux/init_env_poweroff.out
- -
ab ab
.... ....
@@ -3380,12 +3391,12 @@ See also: <<user-mode-simulation-with-glibc>>
=== QEMU user mode getting started === QEMU user mode getting started
Let's run link:userland/print_argv.c[] built with the Buildroot toolchain on QEMU user mode: Let's run link:userland/c/print_argv.c[] built with the Buildroot toolchain on QEMU user mode:
.... ....
./build user-mode-qemu ./build user-mode-qemu
./run \ ./run \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
; ;
.... ....
@@ -3413,12 +3424,12 @@ The commands are analogous to full system <<gdb>>, e.g. without tmux:
.... ....
./run \ ./run \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
--wait-gdb \ --wait-gdb \
; ;
./run-gdb \ ./run-gdb \
--userland print_argv \ --userland c/print_argv \
main main
; ;
.... ....
@@ -3427,7 +3438,7 @@ or with <<tmux>>:
.... ....
./run \ ./run \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
--tmux-args main \ --tmux-args main \
--wait-gdb \ --wait-gdb \
@@ -3449,7 +3460,7 @@ sudo apt-get install gcc-aarch64-linux-gnu qemu-system-aarch64
--arch aarch64 \ --arch aarch64 \
--qemu-which host --qemu-which host
--userland-build-id host \ --userland-build-id host \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
; ;
.... ....
@@ -3544,7 +3555,7 @@ Example:
./run \ ./run \
--arch aarch64 \ --arch aarch64 \
--static \ --static \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
; ;
.... ....
@@ -3567,7 +3578,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 -- libs/openblas_hello ./build-userland --has-package openblas --static -- libs/openblas/hello
.... ....
it fails with: it fails with:
@@ -3583,7 +3594,7 @@ It's nice when <<gdb,the obvious>> just works, right?
.... ....
./run \ ./run \
--arch aarch64 \ --arch aarch64 \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
--wait-gdb \ --wait-gdb \
; ;
@@ -3594,7 +3605,7 @@ and on another shell:
.... ....
./run-gdb \ ./run-gdb \
--arch aarch64 \ --arch aarch64 \
--userland print_argv \ --userland c/print_argv \
main \ main \
; ;
.... ....
@@ -3605,7 +3616,7 @@ Or alternatively, if you are using <<tmux>>, do everything in one go with:
./run \ ./run \
--arch aarch64 \ --arch aarch64 \
--tmux-args main \ --tmux-args main \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
--wait-gdb \ --wait-gdb \
; ;
@@ -3643,7 +3654,7 @@ So let's just play with some static ones:
./run \ ./run \
--arch aarch64 \ --arch aarch64 \
--emulator gem5 \ --emulator gem5 \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
; ;
.... ....
@@ -3657,7 +3668,7 @@ TODO: how to escape spaces on the command line arguments?
--arch aarch64 \ --arch aarch64 \
--emulator gem5 \ --emulator gem5 \
--static \ --static \
--userland print_argv \ --userland c/print_argv \
--userland-args 'asdf "qw er"' \ --userland-args 'asdf "qw er"' \
--wait-gdb \ --wait-gdb \
; ;
@@ -3665,7 +3676,7 @@ TODO: how to escape spaces on the command line arguments?
--arch aarch64 \ --arch aarch64 \
--emulator gem5 \ --emulator gem5 \
--static \ --static \
--userland print_argv \ --userland c/print_argv \
main \ main \
; ;
.... ....
@@ -3794,18 +3805,18 @@ If you are feeling raw, you can insert and remove modules with our own minimal m
.... ....
# init_module # init_module
./myinsmod.out hello.ko ./linux/myinsmod.out hello.ko
# finit_module # finit_module
./myinsmod.out hello.ko "" 1 ./linux/myinsmod.out hello.ko "" 1
./myrmmod.out hello ./linux/myrmmod.out hello
.... ....
which teaches you how it is done from C code. which teaches you how it is done from C code.
Source: Source:
* link:userland/myinsmod.c[] * link:userland/linux/myinsmod.c[]
* link:userland/myrmmod.c[] * link:userland/linux/myrmmod.c[]
The Linux kernel offers two system calls for module insertion: The Linux kernel offers two system calls for module insertion:
@@ -5252,7 +5263,7 @@ But the awesome `CONFIG_DYNAMIC_DEBUG=y` option which we enable by default allow
.... ....
echo 8 > /proc/sys/kernel/printk echo 8 > /proc/sys/kernel/printk
echo 'file kernel/module.c +p' > /sys/kernel/debug/dynamic_debug/control echo 'file kernel/module.c +p' > /sys/kernel/debug/dynamic_debug/control
./myinsmod.out hello.ko ./linux/myinsmod.out hello.ko
.... ....
and we have a shortcut at: and we have a shortcut at:
@@ -6375,7 +6386,7 @@ Outcome: `jiffies` gets printed to stdout every second from userland.
Sources: Sources:
* link:kernel_modules/poll.c[] * link:kernel_modules/poll.c[]
* link:kernel_modules/poll.c[] * link:include/poll.h[]
* link:rootfs_overlay/lkmc/poll.sh[] * link:rootfs_overlay/lkmc/poll.sh[]
Typically, we are waiting for some hardware to make some piece of data available available to the kernel. Typically, we are waiting for some hardware to make some piece of data available available to the kernel.
@@ -6404,8 +6415,8 @@ Outcome: the test passes:
Sources: Sources:
* link:kernel_modules/ioctl.c[] * link:kernel_modules/ioctl.c[]
* link:kernel_modules/ioctl.h[] * link:include/ioctl.h[]
* link:userland/ioctl.c[] * link:userland/kernel_modules/ioctl.c[]
* link:rootfs_overlay/lkmc/ioctl.sh[] * link:rootfs_overlay/lkmc/ioctl.sh[]
`ioctl` is one of the most important methods of communication with real device drivers, which often take several fields as input. `ioctl` is one of the most important methods of communication with real device drivers, which often take several fields as input.
@@ -6489,8 +6500,8 @@ Outcome: the test passes:
Sources: Sources:
* link:kernel_modules/anonymous_inode.c[] * link:kernel_modules/anonymous_inode.c[]
* link:kernel_modules/anonymous_inode.h[] * link:include/anonymous_inode.h[]
* link:userland/anonymous_inode.c[] * link:userland/kernel_modules/anonymous_inode.c[]
* link:rootfs_overlay/lkmc/anonymous_inode.sh[] * link:rootfs_overlay/lkmc/anonymous_inode.sh[]
This example gets an anonymous inode via <<ioctl>> from a debugfs entry by using `anon_inode_getfd`. This example gets an anonymous inode via <<ioctl>> from a debugfs entry by using `anon_inode_getfd`.
@@ -6517,8 +6528,8 @@ Outcome: the test passes:
Sources: Sources:
* link:kernel_modules/netlink.c[] * link:kernel_modules/netlink.c[]
* link:kernel_modules/netlink.h[] * link:include/netlink.h[]
* link:userland/netlink.c[] * link:userland/kernel_modules/netlink.c[]
* link:rootfs_overlay/lkmc/netlink.sh[] * link:rootfs_overlay/lkmc/netlink.sh[]
Launch multiple user requests in parallel to stress our socket: Launch multiple user requests in parallel to stress our socket:
@@ -6993,10 +7004,10 @@ In this section we will play with them.
First get a virtual address to play with: First get a virtual address to play with:
.... ....
./virt_to_phys_test.out & ./posix/virt_to_phys_test.out &
.... ....
Source: link:userland/virt_to_phys_test.c[] Source: link:userland/posix/virt_to_phys_test.c[]
Sample output: Sample output:
@@ -7091,7 +7102,7 @@ After one second, we see on the screen:
.... ....
i 9abcdef0 i 9abcdef0
[1]+ Done ./virt_to_phys_test.out [1]+ Done ./posix/virt_to_phys_test.out
.... ....
so the value changed, and the `while` loop exited! so the value changed, and the `while` loop exited!
@@ -7116,7 +7127,7 @@ Dump the physical address of all pages mapped to a given process using `/proc/<p
First launch `linux/virt_to_phys_user.out` as described at <<userland-physical-address-experiments>>. Suppose that the output was: First launch `linux/virt_to_phys_user.out` as described at <<userland-physical-address-experiments>>. Suppose that the output was:
.... ....
# ./virt_to_phys_test.out & # ./posix/virt_to_phys_test.out &
vaddr 0x601048 vaddr 0x601048
pid 63 pid 63
# ./linux/virt_to_phys_user.out 63 0x601048 # ./linux/virt_to_phys_user.out 63 0x601048
@@ -7133,9 +7144,9 @@ Sample output excerpt:
.... ....
vaddr pfn soft-dirty file/shared swapped present library vaddr pfn soft-dirty file/shared swapped present library
400000 1ede 0 1 0 1 ./virt_to_phys_test.out 400000 1ede 0 1 0 1 ./posix/virt_to_phys_test.out
600000 1a6f 0 0 0 1 ./virt_to_phys_test.out 600000 1a6f 0 0 0 1 ./posix/virt_to_phys_test.out
601000 1a61 0 0 0 1 ./virt_to_phys_test.out 601000 1a61 0 0 0 1 ./posix/virt_to_phys_test.out
602000 2208 0 0 0 1 [heap] 602000 2208 0 0 0 1 [heap]
603000 220b 0 0 0 1 [heap] 603000 220b 0 0 0 1 [heap]
7ffff78ec000 1fd4 0 1 0 1 /lib/libuClibc-1.0.30.so 7ffff78ec000 1fd4 0 1 0 1 /lib/libuClibc-1.0.30.so
@@ -7150,7 +7161,7 @@ Meaning of the flags:
* `vaddr`: first virtual address of a page the belongs to the process. Notably: * `vaddr`: first virtual address of a page the belongs to the process. Notably:
+ +
.... ....
./run-toolchain readelf -- -l "$(./getvar userland_build_dir)/virt_to_phys_test.out" ./run-toolchain readelf -- -l "$(./getvar userland_build_dir)/posix/virt_to_phys_test.out"
.... ....
+ +
contains: contains:
@@ -7222,7 +7233,7 @@ Logs proc events such as process creation to a link:kernel_modules/netlink.c[net
We then have a userland program that listens to the events and prints them out: We then have a userland program that listens to the events and prints them out:
.... ....
# ./proc_events.out & # ./linux/proc_events.out &
# set mcast listen ok # set mcast listen ok
# sleep 2 & sleep 1 # sleep 2 & sleep 1
fork: parent tid=48 pid=48 -> child tid=79 pid=79 fork: parent tid=48 pid=48 -> child tid=79 pid=79
@@ -7236,7 +7247,7 @@ a
# #
.... ....
Source: link:userland/proc_events.c[] Source: link:userland/linux/proc_events.c[]
TODO: why `exit: tid=79` shows after `exit: tid=80`? TODO: why `exit: tid=79` shows after `exit: tid=80`?
@@ -7245,7 +7256,7 @@ Note how `echo a` is a Bash built-in, and therefore does not spawn a new process
TODO: why does this produce no output? TODO: why does this produce no output?
.... ....
./proc_events.out >f & ./linux/proc_events.out >f &
.... ....
* https://stackoverflow.com/questions/6075013/detect-launching-of-programs-on-linux-platform/8255487#8255487 * https://stackoverflow.com/questions/6075013/detect-launching-of-programs-on-linux-platform/8255487#8255487
@@ -7725,7 +7736,7 @@ UIO interface in a nutshell:
Sources: Sources:
* link:userland/uio_read.c[] * link:userland/kernel_modules/uio_read.c[]
* link:rootfs_overlay/lkmc/uio_read.sh[] * link:rootfs_overlay/lkmc/uio_read.sh[]
Bibliography: Bibliography:
@@ -8169,8 +8180,8 @@ 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 -- libs/libdrm_modeset ./build-userland --has-package libdrm -- libs/libdrm/modeset
./run --eval-after './libs/libdrm_modeset.out' --graphic ./run --eval-after './libs/libdrm/modeset.out' --graphic
.... ....
Source: link:userland/libs/libdrm_modeset.c[] Source: link:userland/libs/libdrm_modeset.c[]
@@ -8183,7 +8194,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 './libs/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?
@@ -8208,7 +8219,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 './libs/libdrm_modeset.out' --graphic ./run --eval-after './libs/libdrm/modeset.out' --graphic
.... ....
Bibliography: Bibliography:
@@ -9909,8 +9920,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 -- libs/openblas_hello ./build-userland --has-package openblas -- libs/openblas/hello
./run --eval-after './libs/openblas_hello.out; echo $?' ./run --eval-after './libs/openblas/hello.out; echo $?'
.... ....
Outcome: the test passes: Outcome: the test passes:
@@ -9919,7 +9930,7 @@ Outcome: the test passes:
0 0
.... ....
Source: link:userland/libs/openblas.c[] Source: link:userland/libs/openblas/hello.c[]
The test performs a general matrix multiplication: The test performs a general matrix multiplication:
@@ -9949,13 +9960,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 -- libs/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 './libs/eigen_hello.out' ./run --eval-after './libs/eigen/hello.out'
.... ....
Output: Output:
@@ -9965,7 +9976,7 @@ Output:
2.5 1.5 2.5 1.5
.... ....
Source: link:userland/libs/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.
@@ -10192,7 +10203,7 @@ The alternative is to do as in <<gdb-step-debug-userland-processes>>.
Next, follow the exact same steps explained at <<gdb-step-debug-userland-non-init-without--d>>, but passing `-g` to every command as usual. Next, follow the exact same steps explained at <<gdb-step-debug-userland-non-init-without--d>>, but passing `-g` to every command as usual.
But then TODO (I'll still go crazy one of those days): for `arm`, while debugging `./myinsmod.out hello.ko`, after then line: But then TODO (I'll still go crazy one of those days): for `arm`, while debugging `./linux/myinsmod.out hello.ko`, after then line:
.... ....
23 if (argc < 3) { 23 if (argc < 3) {

8
build
View File

@@ -339,6 +339,14 @@ so looping over all of them would waste time.
self._build_file('build-userland'), self._build_file('build-userland'),
dependencies=['buildroot'], dependencies=['buildroot'],
), ),
'userland-host': _Component(
self._build_file('build-userland'),
apt_get_pkgs={
'libdrm-dev',
'libeigen3-dev',
'libopenblas-dev',
},
),
'userland-gem5': _Component( 'userland-gem5': _Component(
self._build_file('build-userland', static=True, userland_build_id='static'), self._build_file('build-userland', static=True, userland_build_id='static'),
dependencies=['buildroot'], dependencies=['buildroot'],

View File

@@ -25,6 +25,13 @@ Build our compiled userland examples.
help='''\ help='''\
Indicate that a given package is present in the root filesystem, which Indicate that a given package is present in the root filesystem, which
allows us to build examples that rely on it. allows us to build examples that rely on it.
''',
)
self.add_argument(
'--has-all-packages',
action='store_true',
help='''\
Indicate that all packages from --has-package are available.
''', ''',
) )
self.add_argument( self.add_argument(
@@ -138,6 +145,7 @@ Default: build all examples that have their package dependencies met, e.g.:
def build(self): def build(self):
build_dir = self.get_build_dir() build_dir = self.get_build_dir()
has_packages = set(self.env['has_package']) has_packages = set(self.env['has_package'])
has_all_packages = self.env['has_all_packages']
ccflags = [ ccflags = [
'-I', self.env['root_dir'], LF, '-I', self.env['root_dir'], LF,
'-O0', LF, '-O0', LF,
@@ -179,6 +187,10 @@ Default: build all examples that have their package dependencies met, e.g.:
extra_deps=[self.env['common_h']], extra_deps=[self.env['common_h']],
link=False, link=False,
) )
if self.env['gcc_which'] == 'host':
eigen_root = '/'
else:
eigen_root = self.env['buildroot_staging_dir']
pkgs = { pkgs = {
'eigen': { 'eigen': {
# TODO: was failing with: # TODO: was failing with:
@@ -188,7 +200,7 @@ Default: build all examples that have their package dependencies met, e.g.:
'ccflags': [ 'ccflags': [
'-I', '-I',
os.path.join( os.path.join(
self.env['buildroot_staging_dir'], eigen_root,
'usr', 'usr',
'include', 'include',
'eigen3' 'eigen3'
@@ -217,26 +229,19 @@ Default: build all examples that have their package dependencies met, e.g.:
dirpath_relative_root = path_abs[rootdir_abs_len + 1:] dirpath_relative_root = path_abs[rootdir_abs_len + 1:]
dirpath_relative_root_components = dirpath_relative_root.split(os.sep) dirpath_relative_root_components = dirpath_relative_root.split(os.sep)
dirpath_relative_root_components_len = len(dirpath_relative_root_components) dirpath_relative_root_components_len = len(dirpath_relative_root_components)
do_build_dir = True out_dir = os.path.join(
in_arch = False build_dir,
dirpath_relative_root
)
common_objs_dir = [common_obj]
ccflags_after = []
ccflags_dir = ccflags.copy()
if dirpath_relative_root_components_len > 0: if dirpath_relative_root_components_len > 0:
if dirpath_relative_root_components[0] == 'arch': if dirpath_relative_root_components[0] in (
if dirpath_relative_root_components_len > 1: 'gcc',
if dirpath_relative_root_components[1] == self.env['arch']: 'kernel_modules',
in_arch = True 'linux',
else: ):
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,
dirpath_relative_root
)
common_objs_dir = [common_obj]
ccflags_dir = ccflags.copy()
if dirpath_relative_root_components in ('gcc', 'kernel_modules', 'linux'):
cstd = 'gnu11' cstd = 'gnu11'
cxxstd = 'gnu++17' cxxstd = 'gnu++17'
else: else:
@@ -244,90 +249,94 @@ Default: build all examples that have their package dependencies met, e.g.:
cxxstd = self.default_cxxstd cxxstd = self.default_cxxstd
# -pedantic complains even if we use -std=gnu11. # -pedantic complains even if we use -std=gnu11.
ccflags_dir.extend(['-pedantic', LF]) ccflags_dir.extend(['-pedantic', LF])
if in_arch: if dirpath_relative_root_components[0] == 'arch':
ccflags_dir.extend([ if dirpath_relative_root_components_len > 1:
'-I', os.path.join(self.env['userland_source_arch_arch_dir']), LF, if dirpath_relative_root_components[1] == self.env['arch']:
'-I', os.path.join(self.env['userland_source_arch_dir']), LF, ccflags_dir.extend([
'-fno-pie', LF, '-I', os.path.join(self.env['userland_source_arch_arch_dir']), LF,
'-no-pie', LF, '-I', os.path.join(self.env['userland_source_arch_dir']), LF,
]) '-fno-pie', LF,
if 'freestanding' in dirpath_relative_root_components: '-no-pie', LF,
common_objs_dir = [] ])
ccflags_dir.extend([ if 'freestanding' in dirpath_relative_root_components:
'-ffreestanding', LF, common_objs_dir = []
'-nostdlib', LF, ccflags_dir.extend([
'-static', LF, '-ffreestanding', LF,
]) '-nostdlib', LF,
else: '-static', LF,
if 'c' in dirpath_relative_root_components: ])
common_objs_dir = [] else:
if 'c' in dirpath_relative_root_components:
common_objs_dir = []
else:
common_objs_dir = [common_obj_asm]
if self.env['arch'] == 'arm':
ccflags_dir.extend([
'-Xassembler', '-mcpu=cortex-a72', LF,
# To prevent:
# > vfp.S: Error: selected processor does not support <FPU instruction> in ARM mode
# https://stackoverflow.com/questions/41131432/cross-compiling-error-selected-processor-does-not-support-fmrx-r3-fpexc-in/52875732#52875732
# We aim to take the most extended mode currently available that works on QEMU.
'-Xassembler', '-mfpu=crypto-neon-fp-armv8.1', LF,
'-Xassembler', '-meabi=5', LF,
# Treat inline assembly as arm instead of thumb
# The opposite of -mthumb.
'-marm', LF,
# Make gcc generate .syntax unified for inline assembly.
# However, it gets ignored if -marm is given, which a GCC bug that was recently fixed:
# https://stackoverflow.com/questions/54078112/how-to-write-syntax-unified-ual-armv7-inline-assembly-in-gcc/54132097#54132097
# So we just write divided inline assembly for now.
'-masm-syntax-unified', LF,
])
else: else:
common_objs_dir = [common_obj_asm] continue
if self.env['arch'] == 'arm': else:
ccflags_dir.extend([ continue
'-Xassembler', '-mcpu=cortex-a72', LF, elif dirpath_relative_root_components[0] == 'libs':
# To prevent: if dirpath_relative_root_components_len > 1:
# > vfp.S: Error: selected processor does not support <FPU instruction> in ARM mode pkg_key = dirpath_relative_root_components[1]
# https://stackoverflow.com/questions/41131432/cross-compiling-error-selected-processor-does-not-support-fmrx-r3-fpexc-in/52875732#52875732 if not (has_all_packages or pkg_key in has_packages):
# We aim to take the most extended mode currently available that works on QEMU.
'-Xassembler', '-mfpu=crypto-neon-fp-armv8.1', LF,
'-Xassembler', '-meabi=5', LF,
# Treat inline assembly as arm instead of thumb
# The opposite of -mthumb.
'-marm', LF,
# Make gcc generate .syntax unified for inline assembly.
# However, it gets ignored if -marm is given, which a GCC bug that was recently fixed:
# https://stackoverflow.com/questions/54078112/how-to-write-syntax-unified-ual-armv7-inline-assembly-in-gcc/54132097#54132097
# So we just write divided inline assembly for now.
'-masm-syntax-unified', LF,
])
for in_filename in in_filenames:
path_relative_root = os.path.join(dirpath_relative_root, in_filename)
if path_relative_root == common_obj_asm_relpath:
continue
in_path = os.path.join(path, in_filename)
in_name, in_ext = os.path.splitext(in_filename)
out_path = os.path.join(
out_dir,
in_name + self.env['userland_build_ext']
)
ccflags_file = ccflags_dir.copy()
ccflags_after = []
if in_libs:
pkg_key = in_name.split('_')[0]
if pkg_key in pkgs:
if pkg_key not in has_packages:
continue continue
pkg = pkgs[pkg_key] pkg = pkgs[pkg_key]
if 'ccflags' in pkg: if 'ccflags' in pkg:
ccflags_file.extend(pkg['ccflags']) ccflags_dir.extend(pkg['ccflags'])
else: else:
pkg_config_output = subprocess.check_output([ pkg_config_output = subprocess.check_output([
self.env['buildroot_pkg_config'], self.env['pkg_config'],
'--cflags', '--cflags',
pkg_key pkg_key
]).decode() ]).decode()
ccflags_file.extend(self.sh.shlex_split(pkg_config_output)) ccflags_dir.extend(self.sh.shlex_split(pkg_config_output))
if 'ccflags_after' in pkg: if 'ccflags_after' in pkg:
ccflags_file.extend(pkg['ccflags_after']) ccflags_dir.extend(pkg['ccflags_after'])
else: else:
pkg_config_output = subprocess.check_output([ pkg_config_output = subprocess.check_output([
self.env['buildroot_pkg_config'], self.env['pkg_config'],
'--libs', '--libs',
pkg_key pkg_key
]).decode() ]).decode()
ccflags_after.extend(self.sh.shlex_split(pkg_config_output)) ccflags_after.extend(self.sh.shlex_split(pkg_config_output))
error = thread_pool.submit({ for in_filename in in_filenames:
'in_path': in_path, path_relative_root = os.path.join(dirpath_relative_root, in_filename)
'out_path': out_path, if path_relative_root == common_obj_asm_relpath:
'ccflags': ccflags_file, continue
'cstd': cstd, in_path = os.path.join(path, in_filename)
'cxxstd': cxxstd, in_name, in_ext = os.path.splitext(in_filename)
'extra_objs': common_objs_dir, out_path = os.path.join(
'ccflags_after': ccflags_after, out_dir,
}) in_name + self.env['userland_build_ext']
if error is not None: )
raise ExitLoop() error = thread_pool.submit({
'in_path': in_path,
'out_path': out_path,
'ccflags': ccflags_dir,
'cstd': cstd,
'cxxstd': cxxstd,
'extra_objs': common_objs_dir,
'ccflags_after': ccflags_after,
})
if error is not None:
raise ExitLoop()
except ExitLoop: except ExitLoop:
pass pass
error = thread_pool.join() error = thread_pool.join()

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
"$(git rev-parse --show-toplevel)/build-userland" \ "$(git rev-parse --show-toplevel)/build-userland" \
--gcc-which host \ --gcc-which host \
--has-all-packages \
--in-tree \ --in-tree \
--target-cwd \ --target-cwd \
"$@" \ "$@" \

View File

@@ -10,7 +10,6 @@ import imp
import inspect import inspect
import json import json
import math import math
import multiprocessing
import os import os
import platform import platform
import re import re
@@ -824,6 +823,7 @@ lunch aosp_{}-eng
env['buildroot_toolchain_prefix'] env['buildroot_toolchain_prefix']
) )
env['userland_library_dir'] = env['buildroot_target_dir'] env['userland_library_dir'] = env['buildroot_target_dir']
env['pkg_config'] = env['buildroot_pkg_config']
elif env['gcc_which'] == 'crosstool-ng': elif env['gcc_which'] == 'crosstool-ng':
env['toolchain_prefix'] = os.path.join( env['toolchain_prefix'] = os.path.join(
env['crosstool_ng_bin_dir'], env['crosstool_ng_bin_dir'],
@@ -837,6 +837,7 @@ lunch aosp_{}-eng
env['userland_library_dir'] = '/usr/arm-linux-gnueabihf' env['userland_library_dir'] = '/usr/arm-linux-gnueabihf'
elif env['arch'] == 'aarch64': elif env['arch'] == 'aarch64':
env['userland_library_dir'] = '/usr/aarch64-linux-gnu/' env['userland_library_dir'] = '/usr/aarch64-linux-gnu/'
env['pkg_config'] = 'pkg-config'
elif env['gcc_which'] == 'host-baremetal': elif env['gcc_which'] == 'host-baremetal':
if env['arch'] == 'arm': if env['arch'] == 'arm':
env['toolchain_prefix'] = 'arm-none-eabi' env['toolchain_prefix'] = 'arm-none-eabi'
@@ -1249,7 +1250,7 @@ TODO: not yet implemented on all scripts.
self.add_argument( self.add_argument(
'-j', '-j',
'--nproc', '--nproc',
default=multiprocessing.cpu_count(), default=len(os.sched_getaffinity(0)),
type=int, type=int,
help='Number of processors to use for the build.', help='Number of processors to use for the build.',
) )

View File

@@ -1,5 +1,6 @@
#!/bin/sh #!/bin/sh
# https://github.com/cirosantilli/linux-kernel-module-cheat#anonymous-inode
set -e set -e
insmod anonymous_inode.ko insmod anonymous_inode.ko
[ "$(/anonymous_inode.out /sys/kernel/debug/lkmc_anonymous_inode 3)" = "$(printf '1\n10\n100')" ] [ "$(./kernel_modules/anonymous_inode.out /sys/kernel/debug/lkmc_anonymous_inode 3)" = "$(printf '1\n10\n100')" ]
rmmod anonymous_inode rmmod anonymous_inode

View File

@@ -1,7 +1,8 @@
#!/bin/sh #!/bin/sh
# https://github.com/cirosantilli/linux-kernel-module-cheat#ioctl
set -e set -e
f=/sys/kernel/debug/lkmc_ioctl f=/sys/kernel/debug/lkmc_ioctl
insmod ioctl.ko insmod ioctl.ko
[ "$(/ioctl.out "$f" 0 1)" = 2 ] [ "$(./kernel_modules/ioctl.out "$f" 0 1)" = 2 ]
[ "$(/ioctl.out "$f" 1 1 1)" = '2 0' ] [ "$(./kernel_modules/ioctl.out "$f" 1 1 1)" = '2 0' ]
rmmod ioctl rmmod ioctl

View File

@@ -1,7 +1,8 @@
#!/bin/sh #!/bin/sh
# https://github.com/cirosantilli/linux-kernel-module-cheat#netlink-sockets
set -e set -e
insmod netlink.ko insmod netlink.ko
[ "$(/netlink.out)" = 0 ] [ "$(./linux/netlink.out)" = 0 ]
[ "$(/netlink.out)" = 1 ] [ "$(./linux/netlink.out)" = 1 ]
[ "$(/netlink.out)" = 2 ] [ "$(./linux/netlink.out)" = 2 ]
rmmod netlink rmmod netlink

View File

@@ -1,5 +1,6 @@
#!/bin/sh #!/bin/sh
# https://github.com/cirosantilli/linux-kernel-module-cheat#poll
set -e set -e
insmod poll.ko insmod poll.ko
./poll.out /sys/kernel/debug/lkmc_poll ./kernel_modules/poll.out /sys/kernel/debug/lkmc_poll
#rmmod poll #rmmod poll

View File

@@ -4,7 +4,7 @@ set -e
modprobe uio_pci_generic modprobe uio_pci_generic
# pci_min device # pci_min device
echo '1234 11e9' > /sys/bus/pci/drivers/uio_pci_generic/new_id echo '1234 11e9' > /sys/bus/pci/drivers/uio_pci_generic/new_id
./uio_read.out & ./kernel_modules/uio_read.out &
# Helper to observe interrupts. # Helper to observe interrupts.
insmod irq.ko insmod irq.ko
base="$(setpci -d 1234:11e9 BASE_ADDRESS_0)" base="$(setpci -d 1234:11e9 BASE_ADDRESS_0)"

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from typing import Any, Callable, Dict, Iterable, Union from typing import Any, Callable, Dict, Iterable, Union
import multiprocessing
import queue import queue
import sys import sys
import threading import threading
@@ -66,7 +65,7 @@ class ThreadPool:
handle_output = lambda input, output, exception: exception handle_output = lambda input, output, exception: exception
self.handle_output = handle_output self.handle_output = handle_output
if nthreads is None: if nthreads is None:
nthreads = multiprocessing.cpu_count() nthreads = len(os.sched_getaffinity(0))
self.nthreads = nthreads self.nthreads = nthreads
self.error_output = None self.error_output = None
self.error_output_lock = threading.Lock() self.error_output_lock = threading.Lock()

View File

@@ -1,46 +0,0 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#anonymous-inode */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> /* sleep */
#include "../include/anonymous_inode.h"
int main(int argc, char **argv)
{
char buf[1024];
int fd_ioctl, fd_ioctl_anon, ret;
size_t i, nreads;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file> [<nreads>]");
return EXIT_FAILURE;
} else if (argc > 2) {
nreads = strtol(argv[2], NULL, 10);
} else {
nreads = 3;
}
fd_ioctl = open(argv[1], O_RDONLY);
if (fd_ioctl == -1) {
perror("open");
return EXIT_FAILURE;
}
ret = ioctl(fd_ioctl, LKMC_ANONYMOUS_INODE_GET_FD, &fd_ioctl_anon);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
for (i = 0; i < nreads; ++i) {
ret = read(fd_ioctl_anon, buf, sizeof(buf));
printf("%.*s\n", ret, buf);
}
close(fd_ioctl_anon);
close(fd_ioctl);
return EXIT_SUCCESS;
}

View File

@@ -5,13 +5,13 @@
#define ASSERT_EQ(reg, const) \ #define ASSERT_EQ(reg, const) \
ldr x11, =const; \ ldr x11, =const; \
cmp reg, x11; \ cmp reg, x11; \
ASSERT(beq); \ ASSERT(beq); \
; ;
#define ASSERT_MEMCMP(s1, s2, n) \ #define ASSERT_MEMCMP(s1, s2, n) \
MEMCMP(s1, s2, n); \ MEMCMP(s1, s2, n); \
ASSERT_EQ(x0, 0); \ ASSERT_EQ(x0, 0); \
; ;
#define ENTRY \ #define ENTRY \

View File

@@ -12,14 +12,14 @@
*/ */
#define ASSERT_EQ(reg, const) \ #define ASSERT_EQ(reg, const) \
ldr r11, =const; \ ldr r11, =const; \
cmp reg, r11; \ cmp reg, r11; \
ASSERT(beq); \ ASSERT(beq); \
; ;
/* Assert that two arrays are the same. */ /* Assert that two arrays are the same. */
#define ASSERT_MEMCMP(s1, s2, n) \ #define ASSERT_MEMCMP(s1, s2, n) \
MEMCMP(s1, s2, n); \ MEMCMP(s1, s2, n); \
ASSERT_EQ(r0, 0); \ ASSERT_EQ(r0, 0); \
; ;
/* Store all callee saved registers, and LR in case we make further BL calls. /* Store all callee saved registers, and LR in case we make further BL calls.

View File

@@ -23,8 +23,8 @@
/* Assert that a register equals another register. */ /* Assert that a register equals another register. */
#define ASSERT_EQ_REG(reg1, reg2) \ #define ASSERT_EQ_REG(reg1, reg2) \
cmp reg1, reg2; \ cmp reg1, reg2; \
ASSERT(beq); \ ASSERT(beq); \
; ;
#endif #endif

View File

@@ -5,16 +5,16 @@
int main(void) { int main(void) {
#if 0 #if 0
uint64_t in = 0xFFFFFFFF; uint64_t in = 0xFFFFFFFF;
uint64_t out = 0; uint64_t out = 0;
__asm__ ( __asm__ (
"mov %[in], %%rax;" "mov %[in], %%rax;"
"myinc %%rax;" "myinc %%rax;"
"movq %%rax, %[out]" "movq %%rax, %[out]"
: [out] "=g" (out) : [out] "=g" (out)
: [in] "g" (in) : [in] "g" (in)
: "rax" : "rax"
); );
assert(out == in + 1); assert(out == in + 1);
#endif #endif
} }

View File

@@ -4,15 +4,15 @@
#include <inttypes.h> #include <inttypes.h>
int main(void) { int main(void) {
uint64_t in = 0xFFFFFFFF; uint64_t in = 0xFFFFFFFF;
uint64_t out = 0; uint64_t out = 0;
__asm__ ( __asm__ (
"mov %[in], %%rax;" "mov %[in], %%rax;"
"inc %%rax;" "inc %%rax;"
"movq %%rax, %[out]" "movq %%rax, %[out]"
: [out] "=g" (out) : [out] "=g" (out)
: [in] "g" (in) : [in] "g" (in)
: "rax" : "rax"
); );
assert(out == in + 1); assert(out == in + 1);
} }

View File

@@ -29,16 +29,16 @@ int main(int argc, char **argv) {
} }
std::shuffle(randoms.begin(), randoms.end(), std::mt19937(seed)); std::shuffle(randoms.begin(), randoms.end(), std::mt19937(seed));
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
auto random = randoms[i]; auto random = randoms[i];
// Heap. // Heap.
m5_resetstats(); m5_resetstats();
heap.emplace(random); heap.emplace(random);
m5_dumpstats(); m5_dumpstats();
// BST. // BST.
m5_resetstats(); m5_resetstats();
bst.insert(random); bst.insert(random);
m5_dumpstats(); m5_dumpstats();
} }
} }

View File

@@ -13,5 +13,5 @@ int main(int argc, char **argv) {
} else { } else {
ret = strtoull(argv[1], NULL, 0); ret = strtoull(argv[1], NULL, 0);
} }
return ret; return ret;
} }

View File

@@ -4,6 +4,6 @@
#include <stdlib.h> #include <stdlib.h>
int main(void) { int main(void) {
puts("hello"); puts("hello");
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

14
userland/c/print_argv.c Normal file
View File

@@ -0,0 +1,14 @@
/* Print each command line argument received, one per line.
*
* Good sanity check for user mode:
* https://github.com/cirosantilli/linux-kernel-module-cheat#qemu-user-mode-getting-started
*/
#include <stdio.h>
int main(int argc, char **argv) {
size_t i;
for (i = 0; i < (size_t)argc; ++i)
printf("%s\n", argv[i]);
return 0;
}

View File

@@ -26,8 +26,7 @@ typedef struct {
* @param[in] vaddr virtual address to get entry for * @param[in] vaddr virtual address to get entry for
* @return 0 for success, 1 for failure * @return 0 for success, 1 for failure
*/ */
int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr) int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr) {
{
size_t nread; size_t nread;
ssize_t ret; ssize_t ret;
uint64_t data; uint64_t data;
@@ -62,8 +61,7 @@ int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr)
* @param[in] vaddr virtual address to get entry for * @param[in] vaddr virtual address to get entry for
* @return 0 for success, 1 for failure * @return 0 for success, 1 for failure
*/ */
int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr) int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr) {
{
char pagemap_file[BUFSIZ]; char pagemap_file[BUFSIZ];
int pagemap_fd; int pagemap_fd;

View File

@@ -1,26 +0,0 @@
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <sys/reboot.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
puts("args:");
for (i = 0; i < argc; ++i)
puts(argv[i]);
puts("");
puts("env:");
extern char **environ;
char **env = environ;
while (*env) {
printf("%s\n", *env);
env++;
}
puts("");
/* Poweroff. */
reboot(RB_POWER_OFF);
}

View File

@@ -1,67 +0,0 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ioctl */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "../include/ioctl.h"
int main(int argc, char **argv)
{
char *ioctl_path;
int fd, request, arg0, arg1, arg_int, ret;
lkmc_ioctl_struct arg_struct;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file> <request> [<arg>...]");
return EXIT_FAILURE;
}
ioctl_path = argv[1];
request = strtol(argv[2], NULL, 10);
if (argc > 3) {
arg0 = strtol(argv[3], NULL, 10);
}
if (argc > 4) {
arg1 = strtol(argv[4], NULL, 10);
}
fd = open(ioctl_path, O_RDONLY);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
switch (request)
{
case 0:
arg_int = arg0;
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
if (ret != -1) {
printf("%d\n", arg_int);
}
break;
case 1:
arg_struct.i = arg0;
arg_struct.j = arg1;
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
if (ret != -1) {
printf("%d %d\n", arg_struct.i, arg_struct.j);
}
break;
default:
puts("error: unknown request");
return EXIT_FAILURE;
}
if (ret == -1) {
perror("ioctl");
printf("errno = %d\n", errno);
return EXIT_FAILURE;
}
close(fd);
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,45 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#anonymous-inode */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> /* sleep */
#include <include/anonymous_inode.h>
int main(int argc, char **argv) {
char buf[1024];
int fd_ioctl, fd_ioctl_anon, ret;
size_t i, nreads;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file> [<nreads>]");
return EXIT_FAILURE;
} else if (argc > 2) {
nreads = strtol(argv[2], NULL, 10);
} else {
nreads = 3;
}
fd_ioctl = open(argv[1], O_RDONLY);
if (fd_ioctl == -1) {
perror("open");
return EXIT_FAILURE;
}
ret = ioctl(fd_ioctl, LKMC_ANONYMOUS_INODE_GET_FD, &fd_ioctl_anon);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
for (i = 0; i < nreads; ++i) {
ret = read(fd_ioctl_anon, buf, sizeof(buf));
printf("%.*s\n", ret, buf);
}
close(fd_ioctl_anon);
close(fd_ioctl);
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,66 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ioctl */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <include/ioctl.h>
int main(int argc, char **argv) {
char *ioctl_path;
int fd, request, arg0, arg1, arg_int, ret;
lkmc_ioctl_struct arg_struct;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file> <request> [<arg>...]");
return EXIT_FAILURE;
}
ioctl_path = argv[1];
request = strtol(argv[2], NULL, 10);
if (argc > 3) {
arg0 = strtol(argv[3], NULL, 10);
}
if (argc > 4) {
arg1 = strtol(argv[4], NULL, 10);
}
fd = open(ioctl_path, O_RDONLY);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
switch (request)
{
case 0:
arg_int = arg0;
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
if (ret != -1) {
printf("%d\n", arg_int);
}
break;
case 1:
arg_struct.i = arg0;
arg_struct.j = arg1;
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
if (ret != -1) {
printf("%d %d\n", arg_struct.i, arg_struct.j);
}
break;
default:
puts("error: unknown request");
return EXIT_FAILURE;
}
if (ret == -1) {
perror("ioctl");
printf("errno = %d\n", errno);
return EXIT_FAILURE;
}
close(fd);
return EXIT_SUCCESS;
}

View File

@@ -7,7 +7,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include "../include/netlink.h" #include <include/netlink.h>
#define MAX_PAYLOAD 1024 #define MAX_PAYLOAD 1024

View File

@@ -0,0 +1,41 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#poll */
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */
int main(int argc, char **argv) {
char buf[1024];
int fd, i, n;
short revents;
struct pollfd pfd;
if (argc < 2) {
fprintf(stderr, "usage: %s <poll-device>\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
pfd.fd = fd;
pfd.events = POLLIN;
while (1) {
puts("loop");
i = poll(&pfd, 1, -1);
if (i == -1) {
perror("poll");
assert(0);
}
revents = pfd.revents;
if (revents & POLLIN) {
n = read(pfd.fd, buf, sizeof(buf));
printf("POLLIN n=%d buf=%.*s\n", n, n, buf);
}
}
}

View File

@@ -16,8 +16,7 @@
#include <assert.h> #include <assert.h>
#include <sys/mman.h> #include <sys/mman.h>
int main(int argc, char **argv) int main(int argc, char **argv) {
{
char *dev = "/dev/uio0"; char *dev = "/dev/uio0";
if (argc > 1) { if (argc > 1) {
dev = argv[1]; dev = argv[1];
@@ -30,12 +29,14 @@ int main(int argc, char **argv)
} }
/* TODO not supported by this kernel module? */ /* TODO not supported by this kernel module? */
/*int *addr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);*/ #if 0
/*if (addr == MAP_FAILED) {*/ int *addr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
/*perror("mmap");*/ if (addr == MAP_FAILED) {
/*assert(0);*/ perror("mmap");
/*}*/ assert(0);
/**addr = 0x12345678;*/ }
*addr = 0x12345678;
#endif
while (1) { while (1) {
uint32_t info = 1; uint32_t info = 1;
@@ -66,8 +67,7 @@ int main(int argc, char **argv)
#include <unistd.h> #include <unistd.h>
#include <unistd.h> #include <unistd.h>
int main(void) int main(void) {
{
int uiofd; int uiofd;
int configfd; int configfd;
int err; int err;

1
userland/libs/eigen/build Symbolic link
View File

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

View File

@@ -1,13 +1,16 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#eigen /* https://github.com/cirosantilli/linux-kernel-module-cheat#eigen
* Adapted from: https://eigen.tuxfamily.org/dox/GettingStarted.html * Adapted from: https://eigen.tuxfamily.org/dox/GettingStarted.html
*/ */
#include <iostream> #include <iostream>
#include <Eigen/Dense> #include <Eigen/Dense>
int main() { int main() {
Eigen::MatrixXd m(2,2); Eigen::MatrixXd m(2,2);
m(0,0) = 3; m(0,0) = 3;
m(1,0) = 2.5; m(1,0) = 2.5;
m(0,1) = -1; m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1); m(1,1) = m(1,0) + m(0,1);
std::cout << m << std::endl; std::cout << m << std::endl;
} }

1
userland/libs/libdrm/build Symbolic link
View File

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

View File

@@ -45,10 +45,10 @@
struct modeset_dev; struct modeset_dev;
static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
struct modeset_dev *dev); struct modeset_dev *dev);
static int modeset_create_fb(int fd, struct modeset_dev *dev); static int modeset_create_fb(int fd, struct modeset_dev *dev);
static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
struct modeset_dev *dev); struct modeset_dev *dev);
static int modeset_open(int *out, const char *node); static int modeset_open(int *out, const char *node);
static int modeset_prepare(int fd); static int modeset_prepare(int fd);
static void modeset_draw(void); static void modeset_draw(void);
@@ -81,26 +81,26 @@ static void modeset_cleanup(int fd);
static int modeset_open(int *out, const char *node) static int modeset_open(int *out, const char *node)
{ {
int fd, ret; int fd, ret;
uint64_t has_dumb; uint64_t has_dumb;
fd = open(node, O_RDWR | O_CLOEXEC); fd = open(node, O_RDWR | O_CLOEXEC);
if (fd < 0) { if (fd < 0) {
ret = -errno; ret = -errno;
fprintf(stderr, "cannot open '%s': %m\n", node); fprintf(stderr, "cannot open '%s': %s\n", node, strerror(errno));
return ret; return ret;
} }
if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||
!has_dumb) { !has_dumb) {
fprintf(stderr, "drm device '%s' does not support dumb buffers\n", fprintf(stderr, "drm device '%s' does not support dumb buffers\n",
node); node);
close(fd); close(fd);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
*out = fd; *out = fd;
return 0; return 0;
} }
/* /*
@@ -149,20 +149,20 @@ static int modeset_open(int *out, const char *node)
*/ */
struct modeset_dev { struct modeset_dev {
struct modeset_dev *next; struct modeset_dev *next;
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
uint32_t stride; uint32_t stride;
uint32_t size; uint32_t size;
uint32_t handle; uint32_t handle;
uint8_t *map; uint8_t *map;
drmModeModeInfo mode; drmModeModeInfo mode;
uint32_t fb; uint32_t fb;
uint32_t conn; uint32_t conn;
uint32_t crtc; uint32_t crtc;
drmModeCrtc *saved_crtc; drmModeCrtc *saved_crtc;
}; };
static struct modeset_dev *modeset_list = NULL; static struct modeset_dev *modeset_list = NULL;
@@ -188,57 +188,57 @@ static struct modeset_dev *modeset_list = NULL;
static int modeset_prepare(int fd) static int modeset_prepare(int fd)
{ {
drmModeRes *res; drmModeRes *res;
drmModeConnector *conn; drmModeConnector *conn;
unsigned int i; unsigned int i;
struct modeset_dev *dev; struct modeset_dev *dev;
int ret; int ret;
/* retrieve resources */ /* retrieve resources */
res = drmModeGetResources(fd); res = drmModeGetResources(fd);
if (!res) { if (!res) {
fprintf(stderr, "cannot retrieve DRM resources (%d): %m\n", fprintf(stderr, "cannot retrieve DRM resources (%d): %s\n",
errno); errno, strerror(errno));
return -errno; return -errno;
} }
/* iterate all connectors */ /* iterate all connectors */
for (i = 0; i < (unsigned int)res->count_connectors; ++i) { for (i = 0; i < (unsigned int)res->count_connectors; ++i) {
/* get information for each connector */ /* get information for each connector */
conn = drmModeGetConnector(fd, res->connectors[i]); conn = drmModeGetConnector(fd, res->connectors[i]);
if (!conn) { if (!conn) {
fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %m\n", fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %s\n",
i, res->connectors[i], errno); i, res->connectors[i], errno, strerror(errno));
continue; continue;
} }
/* create a device structure */ /* create a device structure */
dev = malloc(sizeof(*dev)); dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev)); memset(dev, 0, sizeof(*dev));
dev->conn = conn->connector_id; dev->conn = conn->connector_id;
/* call helper function to prepare this connector */ /* call helper function to prepare this connector */
ret = modeset_setup_dev(fd, res, conn, dev); ret = modeset_setup_dev(fd, res, conn, dev);
if (ret) { if (ret) {
if (ret != -ENOENT) { if (ret != -ENOENT) {
errno = -ret; errno = -ret;
fprintf(stderr, "cannot setup device for connector %u:%u (%d): %m\n", fprintf(stderr, "cannot setup device for connector %u:%u (%d): %s\n",
i, res->connectors[i], errno); i, res->connectors[i], errno, strerror(errno));
} }
free(dev); free(dev);
drmModeFreeConnector(conn); drmModeFreeConnector(conn);
continue; continue;
} }
/* free connector data and link device into global list */ /* free connector data and link device into global list */
drmModeFreeConnector(conn); drmModeFreeConnector(conn);
dev->next = modeset_list; dev->next = modeset_list;
modeset_list = dev; modeset_list = dev;
} }
/* free resources again */ /* free resources again */
drmModeFreeResources(res); drmModeFreeResources(res);
return 0; return 0;
} }
/* /*
@@ -271,48 +271,48 @@ static int modeset_prepare(int fd)
*/ */
static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
struct modeset_dev *dev) struct modeset_dev *dev)
{ {
int ret; int ret;
/* check if a monitor is connected */ /* check if a monitor is connected */
if (conn->connection != DRM_MODE_CONNECTED) { if (conn->connection != DRM_MODE_CONNECTED) {
fprintf(stderr, "ignoring unused connector %u\n", fprintf(stderr, "ignoring unused connector %u\n",
conn->connector_id); conn->connector_id);
return -ENOENT; return -ENOENT;
} }
/* check if there is at least one valid mode */ /* check if there is at least one valid mode */
if (conn->count_modes == 0) { if (conn->count_modes == 0) {
fprintf(stderr, "no valid mode for connector %u\n", fprintf(stderr, "no valid mode for connector %u\n",
conn->connector_id); conn->connector_id);
return -EFAULT; return -EFAULT;
} }
/* copy the mode information into our device structure */ /* copy the mode information into our device structure */
memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode)); memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode));
dev->width = conn->modes[0].hdisplay; dev->width = conn->modes[0].hdisplay;
dev->height = conn->modes[0].vdisplay; dev->height = conn->modes[0].vdisplay;
fprintf(stderr, "mode for connector %u is %ux%u\n", fprintf(stderr, "mode for connector %u is %ux%u\n",
conn->connector_id, dev->width, dev->height); conn->connector_id, dev->width, dev->height);
/* find a crtc for this connector */ /* find a crtc for this connector */
ret = modeset_find_crtc(fd, res, conn, dev); ret = modeset_find_crtc(fd, res, conn, dev);
if (ret) { if (ret) {
fprintf(stderr, "no valid crtc for connector %u\n", fprintf(stderr, "no valid crtc for connector %u\n",
conn->connector_id); conn->connector_id);
return ret; return ret;
} }
/* create a framebuffer for this CRTC */ /* create a framebuffer for this CRTC */
ret = modeset_create_fb(fd, dev); ret = modeset_create_fb(fd, dev);
if (ret) { if (ret) {
fprintf(stderr, "cannot create framebuffer for connector %u\n", fprintf(stderr, "cannot create framebuffer for connector %u\n",
conn->connector_id); conn->connector_id);
return ret; return ret;
} }
return 0; return 0;
} }
/* /*
@@ -338,80 +338,80 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
*/ */
static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
struct modeset_dev *dev) struct modeset_dev *dev)
{ {
drmModeEncoder *enc; drmModeEncoder *enc;
unsigned int i, j; unsigned int i, j;
int32_t crtc; int32_t crtc;
struct modeset_dev *iter; struct modeset_dev *iter;
/* first try the currently conected encoder+crtc */ /* first try the currently conected encoder+crtc */
if (conn->encoder_id) if (conn->encoder_id)
enc = drmModeGetEncoder(fd, conn->encoder_id); enc = drmModeGetEncoder(fd, conn->encoder_id);
else else
enc = NULL; enc = NULL;
if (enc) { if (enc) {
if (enc->crtc_id) { if (enc->crtc_id) {
crtc = enc->crtc_id; crtc = enc->crtc_id;
for (iter = modeset_list; iter; iter = iter->next) { for (iter = modeset_list; iter; iter = iter->next) {
if ((int32_t)iter->crtc == crtc) { if ((int32_t)iter->crtc == crtc) {
crtc = -1; crtc = -1;
break; break;
} }
} }
if (crtc >= 0) { if (crtc >= 0) {
drmModeFreeEncoder(enc); drmModeFreeEncoder(enc);
dev->crtc = crtc; dev->crtc = crtc;
return 0; return 0;
} }
} }
drmModeFreeEncoder(enc); drmModeFreeEncoder(enc);
} }
/* If the connector is not currently bound to an encoder or if the /* If the connector is not currently bound to an encoder or if the
* encoder+crtc is already used by another connector (actually unlikely * encoder+crtc is already used by another connector (actually unlikely
* but lets be safe), iterate all other available encoders to find a * but lets be safe), iterate all other available encoders to find a
* matching CRTC. */ * matching CRTC. */
for (i = 0; i < (unsigned int)conn->count_encoders; ++i) { for (i = 0; i < (unsigned int)conn->count_encoders; ++i) {
enc = drmModeGetEncoder(fd, conn->encoders[i]); enc = drmModeGetEncoder(fd, conn->encoders[i]);
if (!enc) { if (!enc) {
fprintf(stderr, "cannot retrieve encoder %u:%u (%d): %m\n", fprintf(stderr, "cannot retrieve encoder %u:%u (%d): %s\n",
i, conn->encoders[i], errno); i, conn->encoders[i], errno, strerror(errno));
continue; continue;
} }
/* iterate all global CRTCs */ /* iterate all global CRTCs */
for (j = 0; j < (unsigned int)res->count_crtcs; ++j) { for (j = 0; j < (unsigned int)res->count_crtcs; ++j) {
/* check whether this CRTC works with the encoder */ /* check whether this CRTC works with the encoder */
if (!(enc->possible_crtcs & (1 << j))) if (!(enc->possible_crtcs & (1 << j)))
continue; continue;
/* check that no other device already uses this CRTC */ /* check that no other device already uses this CRTC */
crtc = res->crtcs[j]; crtc = res->crtcs[j];
for (iter = modeset_list; iter; iter = iter->next) { for (iter = modeset_list; iter; iter = iter->next) {
if ((int32_t)iter->crtc == crtc) { if ((int32_t)iter->crtc == crtc) {
crtc = -1; crtc = -1;
break; break;
} }
} }
/* we have found a CRTC, so save it and return */ /* we have found a CRTC, so save it and return */
if (crtc >= 0) { if (crtc >= 0) {
drmModeFreeEncoder(enc); drmModeFreeEncoder(enc);
dev->crtc = crtc; dev->crtc = crtc;
return 0; return 0;
} }
} }
drmModeFreeEncoder(enc); drmModeFreeEncoder(enc);
} }
fprintf(stderr, "cannot find suitable CRTC for connector %u\n", fprintf(stderr, "cannot find suitable CRTC for connector %u\n",
conn->connector_id); conn->connector_id);
return -ENOENT; return -ENOENT;
} }
/* /*
@@ -441,69 +441,69 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
static int modeset_create_fb(int fd, struct modeset_dev *dev) static int modeset_create_fb(int fd, struct modeset_dev *dev)
{ {
struct drm_mode_create_dumb creq; struct drm_mode_create_dumb creq;
struct drm_mode_destroy_dumb dreq; struct drm_mode_destroy_dumb dreq;
struct drm_mode_map_dumb mreq; struct drm_mode_map_dumb mreq;
int ret; int ret;
/* create dumb buffer */ /* create dumb buffer */
memset(&creq, 0, sizeof(creq)); memset(&creq, 0, sizeof(creq));
creq.width = dev->width; creq.width = dev->width;
creq.height = dev->height; creq.height = dev->height;
creq.bpp = 32; creq.bpp = 32;
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "cannot create dumb buffer (%d): %m\n", fprintf(stderr, "cannot create dumb buffer (%d): %s\n",
errno); errno, strerror(errno));
return -errno; return -errno;
} }
dev->stride = creq.pitch; dev->stride = creq.pitch;
dev->size = creq.size; dev->size = creq.size;
dev->handle = creq.handle; dev->handle = creq.handle;
/* create framebuffer object for the dumb-buffer */ /* create framebuffer object for the dumb-buffer */
ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride, ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,
dev->handle, &dev->fb); dev->handle, &dev->fb);
if (ret) { if (ret) {
fprintf(stderr, "cannot create framebuffer (%d): %m\n", fprintf(stderr, "cannot create framebuffer (%d): %s\n",
errno); errno, strerror(errno));
ret = -errno; ret = -errno;
goto err_destroy; goto err_destroy;
} }
/* prepare buffer for memory mapping */ /* prepare buffer for memory mapping */
memset(&mreq, 0, sizeof(mreq)); memset(&mreq, 0, sizeof(mreq));
mreq.handle = dev->handle; mreq.handle = dev->handle;
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (ret) { if (ret) {
fprintf(stderr, "cannot map dumb buffer (%d): %m\n", fprintf(stderr, "cannot map dumb buffer (%d): %s\n",
errno); errno, strerror(errno));
ret = -errno; ret = -errno;
goto err_fb; goto err_fb;
} }
/* perform actual memory mapping */ /* perform actual memory mapping */
dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED, dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, mreq.offset); fd, mreq.offset);
if (dev->map == MAP_FAILED) { if (dev->map == MAP_FAILED) {
fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n", fprintf(stderr, "cannot mmap dumb buffer (%d): %s\n",
errno); errno, strerror(errno));
ret = -errno; ret = -errno;
goto err_fb; goto err_fb;
} }
/* clear the framebuffer to 0 */ /* clear the framebuffer to 0 */
memset(dev->map, 0, dev->size); memset(dev->map, 0, dev->size);
return 0; return 0;
err_fb: err_fb:
drmModeRmFB(fd, dev->fb); drmModeRmFB(fd, dev->fb);
err_destroy: err_destroy:
memset(&dreq, 0, sizeof(dreq)); memset(&dreq, 0, sizeof(dreq));
dreq.handle = dev->handle; dreq.handle = dev->handle;
drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return ret; return ret;
} }
/* /*
@@ -543,56 +543,56 @@ err_destroy:
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret, fd; int ret, fd;
const char *card; const char *card;
struct modeset_dev *iter; struct modeset_dev *iter;
/* check which DRM device to open */ /* check which DRM device to open */
if (argc > 1) if (argc > 1)
card = argv[1]; card = argv[1];
else else
card = "/dev/dri/card0"; card = "/dev/dri/card0";
fprintf(stderr, "using card '%s'\n", card); fprintf(stderr, "using card '%s'\n", card);
/* open the DRM device */ /* open the DRM device */
ret = modeset_open(&fd, card); ret = modeset_open(&fd, card);
if (ret) if (ret)
goto out_return; goto out_return;
/* prepare all connectors and CRTCs */ /* prepare all connectors and CRTCs */
ret = modeset_prepare(fd); ret = modeset_prepare(fd);
if (ret) if (ret)
goto out_close; goto out_close;
/* perform actual modesetting on each found connector+CRTC */ /* perform actual modesetting on each found connector+CRTC */
for (iter = modeset_list; iter; iter = iter->next) { for (iter = modeset_list; iter; iter = iter->next) {
iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc); iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc);
ret = drmModeSetCrtc(fd, iter->crtc, iter->fb, 0, 0, ret = drmModeSetCrtc(fd, iter->crtc, iter->fb, 0, 0,
&iter->conn, 1, &iter->mode); &iter->conn, 1, &iter->mode);
if (ret) if (ret)
fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n", fprintf(stderr, "cannot set CRTC for connector %u (%d): %s\n",
iter->conn, errno); iter->conn, errno, strerror(errno));
} }
/* draw some colors for 5seconds */ /* draw some colors for 5seconds */
modeset_draw(); modeset_draw();
/* cleanup everything */ /* cleanup everything */
modeset_cleanup(fd); modeset_cleanup(fd);
ret = 0; ret = 0;
out_close: out_close:
close(fd); close(fd);
out_return: out_return:
if (ret) { if (ret) {
errno = -ret; errno = -ret;
fprintf(stderr, "modeset failed with error %d: %m\n", errno); fprintf(stderr, "modeset failed with error %d: %s\n", errno, strerror(errno));
} else { } else {
fprintf(stderr, "exiting\n"); fprintf(stderr, "exiting\n");
} }
return ret; return ret;
} }
/* /*
@@ -602,15 +602,15 @@ out_return:
static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod) static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod)
{ {
uint8_t next; uint8_t next;
next = cur + (*up ? 1 : -1) * (rand() % mod); next = cur + (*up ? 1 : -1) * (rand() % mod);
if ((*up && next < cur) || (!*up && next > cur)) { if ((*up && next < cur) || (!*up && next > cur)) {
*up = !*up; *up = !*up;
next = cur; next = cur;
} }
return next; return next;
} }
/* /*
@@ -635,34 +635,34 @@ static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod)
static void modeset_draw(void) static void modeset_draw(void)
{ {
uint8_t r, g, b; uint8_t r, g, b;
bool r_up, g_up, b_up; bool r_up, g_up, b_up;
unsigned int i, j, k, off; unsigned int i, j, k, off;
struct modeset_dev *iter; struct modeset_dev *iter;
srand(time(NULL)); srand(time(NULL));
r = rand() % 0xff; r = rand() % 0xff;
g = rand() % 0xff; g = rand() % 0xff;
b = rand() % 0xff; b = rand() % 0xff;
r_up = g_up = b_up = true; r_up = g_up = b_up = true;
for (i = 0; i < 50; ++i) { for (i = 0; i < 50; ++i) {
r = next_color(&r_up, r, 20); r = next_color(&r_up, r, 20);
g = next_color(&g_up, g, 10); g = next_color(&g_up, g, 10);
b = next_color(&b_up, b, 5); b = next_color(&b_up, b, 5);
for (iter = modeset_list; iter; iter = iter->next) { for (iter = modeset_list; iter; iter = iter->next) {
for (j = 0; j < iter->height; ++j) { for (j = 0; j < iter->height; ++j) {
for (k = 0; k < iter->width; ++k) { for (k = 0; k < iter->width; ++k) {
off = iter->stride * j + k * 4; off = iter->stride * j + k * 4;
*(uint32_t*)&iter->map[off] = *(uint32_t*)&iter->map[off] =
(r << 16) | (g << 8) | b; (r << 16) | (g << 8) | b;
} }
} }
} }
usleep(100000); usleep(100000);
} }
} }
/* /*
@@ -674,39 +674,41 @@ static void modeset_draw(void)
static void modeset_cleanup(int fd) static void modeset_cleanup(int fd)
{ {
struct modeset_dev *iter; struct modeset_dev *iter;
struct drm_mode_destroy_dumb dreq; struct drm_mode_destroy_dumb dreq;
while (modeset_list) { while (modeset_list) {
/* remove from global list */ /* remove from global list */
iter = modeset_list; iter = modeset_list;
modeset_list = iter->next; modeset_list = iter->next;
/* restore saved CRTC configuration */ /* restore saved CRTC configuration */
drmModeSetCrtc(fd, drmModeSetCrtc(
iter->saved_crtc->crtc_id, fd,
iter->saved_crtc->buffer_id, iter->saved_crtc->crtc_id,
iter->saved_crtc->x, iter->saved_crtc->buffer_id,
iter->saved_crtc->y, iter->saved_crtc->x,
&iter->conn, iter->saved_crtc->y,
1, &iter->conn,
&iter->saved_crtc->mode); 1,
drmModeFreeCrtc(iter->saved_crtc); &iter->saved_crtc->mode
);
drmModeFreeCrtc(iter->saved_crtc);
/* unmap buffer */ /* unmap buffer */
munmap(iter->map, iter->size); munmap(iter->map, iter->size);
/* delete framebuffer */ /* delete framebuffer */
drmModeRmFB(fd, iter->fb); drmModeRmFB(fd, iter->fb);
/* delete dumb buffer */ /* delete dumb buffer */
memset(&dreq, 0, sizeof(dreq)); memset(&dreq, 0, sizeof(dreq));
dreq.handle = iter->handle; dreq.handle = iter->handle;
drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
/* free allocated memory */ /* free allocated memory */
free(iter); free(iter);
} }
} }
/* /*

View File

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

View File

@@ -1,3 +1,5 @@
Programs in this directory rely on Linux kernel specific functionality such as `/proc`. Programs in this directory rely on Linux kernel specific functionality such as `/proc` or raw system calls.
These programs may also conform to ANSI C or POSIX, but we put them here because you can only observe them at work under Linux. These programs may also conform to ANSI C or POSIX, but we put them here because you can only observe them at work under Linux.
Many of these programs use glibc or GCC extensions.

View File

@@ -0,0 +1,25 @@
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <sys/reboot.h>
#include <unistd.h>
int main(int argc, char **argv) {
int i;
puts("args:");
for (i = 0; i < argc; ++i)
puts(argv[i]);
puts("");
puts("env:");
extern char **environ;
char **env = environ;
while (*env) {
printf("%s\n", *env);
env++;
}
puts("");
/* Poweroff. */
reboot(RB_POWER_OFF);
}

View File

@@ -5,5 +5,5 @@
#include <unistd.h> #include <unistd.h>
int main(void) { int main(void) {
reboot(RB_POWER_OFF); reboot(RB_POWER_OFF);
} }

View File

@@ -13,29 +13,29 @@ int bss = 0;
int data = 1; int data = 1;
int main(__attribute__((unused)) int argc, char **argv) { int main(__attribute__((unused)) int argc, char **argv) {
int i, *ip; int i, *ip;
uint64_t uint64; uint64_t uint64;
FILE *fp; FILE *fp;
/* Loaded addresses. */ /* Loaded addresses. */
printf("&i = %p\n", (void *)&i); printf("&i = %p\n", (void *)&i);
printf("&argv[0] = %p\n", (void *)&argv[0]); printf("&argv[0] = %p\n", (void *)&argv[0]);
printf("&main = %p\n", (void *)(intptr_t)main); printf("&main = %p\n", (void *)(intptr_t)main);
printf("&bss = %p\n", (void *)&bss); printf("&bss = %p\n", (void *)&bss);
printf("&data = %p\n", (void *)&data); printf("&data = %p\n", (void *)&data);
/* Misc syscalls. */ /* Misc syscalls. */
printf("time(NULL) = %ju\n", (uintmax_t)time(NULL)); printf("time(NULL) = %ju\n", (uintmax_t)time(NULL));
printf("pid = %ju\n", (uintmax_t)getpid()); printf("pid = %ju\n", (uintmax_t)getpid());
/* malloc */ /* malloc */
ip = malloc(sizeof(*ip)); ip = malloc(sizeof(*ip));
printf("&malloc = %p\n", (void *)ip); printf("&malloc = %p\n", (void *)ip);
free(ip); free(ip);
/* /dev/urandom */ /* /dev/urandom */
fp = fopen("/dev/urandom", "rb"); fp = fopen("/dev/urandom", "rb");
fread(&uint64, sizeof(uint64), 1, fp); fread(&uint64, sizeof(uint64), 1, fp);
printf("/dev/urandom = %" PRIx64 "\n", uint64); printf("/dev/urandom = %" PRIx64 "\n", uint64);
fclose(fp); fclose(fp);
} }

View File

@@ -10,31 +10,31 @@
#include <unistd.h> #include <unistd.h>
void* main_thread_0(void *arg) { void* main_thread_0(void *arg) {
int i; int i;
cpu_set_t mask; cpu_set_t mask;
CPU_ZERO(&mask); CPU_ZERO(&mask);
CPU_SET(*((int*)arg), &mask); CPU_SET(*((int*)arg), &mask);
sched_setaffinity(0, sizeof(cpu_set_t), &mask); sched_setaffinity(0, sizeof(cpu_set_t), &mask);
i = 0; i = 0;
while (true) { while (true) {
printf("0 %d\n", i); printf("0 %d\n", i);
sleep(1); sleep(1);
i++; i++;
} }
return NULL; return NULL;
} }
void* main_thread_1(void *arg) { void* main_thread_1(void *arg) {
int i; int i;
cpu_set_t mask; cpu_set_t mask;
CPU_ZERO(&mask); CPU_ZERO(&mask);
CPU_SET(*((int*)arg), &mask); CPU_SET(*((int*)arg), &mask);
sched_setaffinity(1, sizeof(cpu_set_t), &mask); sched_setaffinity(1, sizeof(cpu_set_t), &mask);
i = 0; i = 0;
while (true) { while (true) {
printf("1 %d\n", i); printf("1 %d\n", i);
sleep(1); sleep(1);
i++; i++;
} }
return NULL; return NULL;
} }
@@ -43,8 +43,8 @@ int main(void) {
enum NUM_THREADS {NUM_THREADS = 2}; enum NUM_THREADS {NUM_THREADS = 2};
pthread_t threads[NUM_THREADS]; pthread_t threads[NUM_THREADS];
int thread_args[NUM_THREADS]; int thread_args[NUM_THREADS];
pthread_create(&threads[0], NULL, main_thread_0, (void*)&thread_args[0]); pthread_create(&threads[0], NULL, main_thread_0, (void*)&thread_args[0]);
pthread_create(&threads[1], NULL, main_thread_1, (void*)&thread_args[1]); pthread_create(&threads[1], NULL, main_thread_1, (void*)&thread_args[1]);
pthread_join(threads[0], NULL); pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL); pthread_join(threads[1], NULL);
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@@ -1,41 +0,0 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#poll */
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */
int main(int argc, char **argv) {
char buf[1024];
int fd, i, n;
short revents;
struct pollfd pfd;
if (argc < 2) {
fprintf(stderr, "usage: %s <poll-device>\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
pfd.fd = fd;
pfd.events = POLLIN;
while (1) {
puts("loop");
i = poll(&pfd, 1, -1);
if (i == -1) {
perror("poll");
assert(0);
}
revents = pfd.revents;
if (revents & POLLIN) {
n = read(pfd.fd, buf, sizeof(buf));
printf("POLLIN n=%d buf=%.*s\n", n, n, buf);
}
}
}

View File

@@ -11,11 +11,11 @@ enum { I0 = 0x12345678 };
static volatile uint32_t i = I0; static volatile uint32_t i = I0;
int main(void) { int main(void) {
printf("vaddr %p\n", (void *)&i); printf("vaddr %p\n", (void *)&i);
printf("pid %ju\n", (uintmax_t)getpid()); printf("pid %ju\n", (uintmax_t)getpid());
while (i == I0) { while (i == I0) {
sleep(1); sleep(1);
} }
printf("i %jx\n", (uintmax_t)i); printf("i %jx\n", (uintmax_t)i);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -1,10 +0,0 @@
/* Print each command line argument received, one per line. */
#include <stdio.h>
int main(int argc, char **argv) {
size_t i;
for (i = 0; i < (size_t)argc; ++i)
printf("%s\n", argv[i]);
return 0;
}