Add a shortcute for /eval.sh

Create /eval_base64.sh to overcome quoting and newline limitations.

Documente poweroff's failure on readme.
This commit is contained in:
Ciro Santilli
2018-03-14 21:11:02 +00:00
parent 54feab9f00
commit e8f09a76e6
7 changed files with 91 additions and 10 deletions

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@
.tmp_versions .tmp_versions
/br2_cli /br2_cli
/br2_local /br2_local
/ignore.sh
/rootfs_overlay/etc/init.d/S99 /rootfs_overlay/etc/init.d/S99
/rootfs_overlay/ignore.sh /rootfs_overlay/ignore.sh
/9p /9p

View File

@@ -139,7 +139,7 @@ The root filesystem is persistent across:
.... ....
./run ./run
date >f date >f
sync # poweroff syncs by default without -n.
poweroff poweroff
.... ....
@@ -150,6 +150,14 @@ then:
cat f cat f
.... ....
The command:
....
sync
....
also saves the disk.
This is particularly useful to re-run shell commands from the history of a previous session with `Ctrl + R`. This is particularly useful to re-run shell commands from the history of a previous session with `Ctrl + R`.
However, when you do: However, when you do:
@@ -240,23 +248,49 @@ root
every time. every time.
Instead, you can either run them from a minimal init: Here are some methods to automate that.
==== Replace init
This method replaces init and evals a command from the <<kernel-command-line-parameters>>:
....
./run -E 'echo "asdf qwer";insmod /hello.ko;/poweroff.out' -n
....
It is basically a shortcut for:
.... ....
./run -e 'init=/eval.sh - lkmc_eval="insmod /hello.ko;/poweroff.out"' -n ./run -e 'init=/eval.sh - lkmc_eval="insmod /hello.ko;/poweroff.out"' -n
.... ....
or if the script is large, add it to a gitignored file that will go into the guest: although `-E` allows for quoting and newlines by using base64 encoding, so you should almost always use it, unless you are really counting each cycle ;-)
If the script is large, you can add it to a gitignored file and pass that to `-E` as in:
.... ....
echo ' echo '
insmod /hello.ko insmod /hello.ko
/poweroff.out /poweroff.out
' > ignore.sh
./run -E "$(cat ignore.sh)" -n
....
or add it to a file to the root filesystem guest and rebuild:
....
echo '#!/bin/sh
insmod /hello.ko
/poweroff.out
' > rootfs_overlay/ignore.sh ' > rootfs_overlay/ignore.sh
chmod +x rootfs_overlay/ignore.sh
./build
./run -e 'init=/ignore.sh' -n ./run -e 'init=/ignore.sh' -n
.... ....
or run them at the end of the BusyBox init, which does things like setting up networking: ==== Run command at the end of BusyBox init
If you rely on something that BusyBox' init set up for you like networking, this is the way to go:
.... ....
./run -e '- lkmc_eval="insmod /hello.ko;wget -S google.com;poweroff.out;"' ./run -e '- lkmc_eval="insmod /hello.ko;wget -S google.com;poweroff.out;"'
@@ -277,6 +311,26 @@ and they will be run automatically before the login prompt.
Scripts under `/etc/init.d` are run by `/etc/init.d/rcS`, which gets called by the line `::sysinit:/etc/init.d/rcS` in `/etc/inittab`. Scripts under `/etc/init.d` are run by `/etc/init.d/rcS`, which gets called by the line `::sysinit:/etc/init.d/rcS` in `/etc/inittab`.
==== The kernel panics despite poweroff
Just using Busybox' `poweroff` at the end of the `init` does not work and the kernel panics:
....
./run -E poweroff
....
because BusyBox' `poweroff` tries to do some fancy stuff like killing init, likely to allow userland to shutdown nicely.
But this fails when we are `init` itself!
`poweroff` works more brutally and effectively if you add `-f`:
....
./run -E 'poweroff -f'
....
but why not just use your super simple and effective `/poweroff.out` and be done with it?
=== Kernel command line parameters === Kernel command line parameters
Bootloaders can pass a string as input to the Linux kernel when it is booting to control its behaviour, much like the `execve` system call does to userland processes. Bootloaders can pass a string as input to the Linux kernel when it is booting to control its behaviour, much like the `execve` system call does to userland processes.
@@ -1110,9 +1164,9 @@ wc -l trace-boot.txt
gem5: gem5:
.... ....
./run -a arm -g -e 'init=/eval.sh - lkmc_eval="m5 exit"' ./run -a arm -g -E 'm5 exit'
# Or: # Or:
# ./run -a arm -g -e 'init=/eval.sh - lkmc_eval="m5 exit"' -- --cpu-type=HPI --caches # ./run -a arm -g -E 'm5 exit' -- --cpu-type=HPI --caches
grep sim_insts m5out/stats.txt grep sim_insts m5out/stats.txt
.... ....
@@ -1810,7 +1864,7 @@ Those problems should be insignificant if the benchmark runs for long enough how
TODO: even if we don't switch to the detailed CPU model, the cycle counts on the original run and the one with checkpoint restore differ slightly. Why? Multiple checkpoint restores give the same results as expected however: TODO: even if we don't switch to the detailed CPU model, the cycle counts on the original run and the one with checkpoint restore differ slightly. Why? Multiple checkpoint restores give the same results as expected however:
.... ....
./run -a arm -e 'init=/eval.sh - lkmc_eval="m5 checkpoint;m5 resetstats;dhrystone 1000;m5 exit"' -g ./run -a arm -E 'm5 checkpoint;m5 resetstats;dhrystone 1000;m5 exit' -g
./run -a arm -g -- -r 1 ./run -a arm -g -- -r 1
.... ....
@@ -2337,7 +2391,7 @@ contains the `date`. The file `f` wouldn't exist had we used the first checkpoin
If you automate things with <<kernel-command-line-parameters>> as in: If you automate things with <<kernel-command-line-parameters>> as in:
.... ....
./run -a arm -e 'init=/eval.sh - lkmc_eval="m5 checkpoint;m5 resetstats;dhrystone 1000;m5 exit"' -g ./run -a arm -E 'm5 checkpoint;m5 resetstats;dhrystone 1000;m5 exit' -g
.... ....
Then there is no need to pass the kernel command line again to gem5 for replay: Then there is no need to pass the kernel command line again to gem5 for replay:

View File

@@ -1,3 +1,4 @@
CONFIG_BASE64=y
CONFIG_DEPMOD=y CONFIG_DEPMOD=y
CONFIG_MODINFO=y CONFIG_MODINFO=y
CONFIG_NC=y CONFIG_NC=y

View File

@@ -1,6 +1,6 @@
/* Userspace is for the weak. Die. /* Userspace is for the weak. Die.
* https://stackoverflow.com/questions/28812514/how-to-shutdown-linux-using-c-or-qt-without-call-to-system * https://stackoverflow.com/questions/28812514/how-to-shutdown-linux-using-c-or-qt-without-call-to-system
* BusyBox's /sbin/poweroff is under init/halt.c, but it does extra crap like killing init, so I don't trust it. */ **/
#include <stdio.h> #include <stdio.h>
#include <sys/reboot.h> #include <sys/reboot.h>

View File

@@ -1,2 +1,18 @@
#!/bin/sh #!/bin/sh
echo "$lkmc_eval"
eval "$lkmc_eval" eval "$lkmc_eval"
# Ideally, this script would do just:
#
## Get rid of the '-'.
#shift
#echo "$@"
#
# However, the kernel CLI parsing is crap, and the 4.14 docs lie.
#
# In particular, not all that is passed after "-" goes to an argument to init,
# e.g. stuff with dots like "- /poweroff.out" still gets treated specially and
# does not go to init.
#
# This also likely means that the above solution is also unreliable in some cases,
# and that in the end you just have to add a script to the root filesystem.

2
rootfs_overlay/eval_base64.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
eval "$(printf "$lkmc_eval" | base64 -d)"

9
run
View File

@@ -17,9 +17,10 @@ extra_flags=''
extra_flags_qemu='' extra_flags_qemu=''
gem5=false gem5=false
gem5opts='' gem5opts=''
lkmc_eval=''
initrd=false initrd=false
root='' root=''
while getopts a:c:Dde:G:giKknt:x OPT; do while getopts a:c:DdE:e:G:giKknt:x OPT; do
case "$OPT" in case "$OPT" in
a) a)
arch="$OPTARG" arch="$OPTARG"
@@ -33,6 +34,9 @@ while getopts a:c:Dde:G:giKknt:x OPT; do
D) D)
debug_vm='gdb -q -ex start --args' debug_vm='gdb -q -ex start --args'
;; ;;
E)
lkmc_eval="$OPTARG"
;;
e) e)
extra_append="$extra_append $OPTARG" extra_append="$extra_append $OPTARG"
;; ;;
@@ -71,6 +75,9 @@ root_dir="$(pwd)"
buildroot_dir="${root_dir}/buildroot" buildroot_dir="${root_dir}/buildroot"
out_dir="${root_dir}/buildroot/output.${arch_dir}~" out_dir="${root_dir}/buildroot/output.${arch_dir}~"
images_dir="${out_dir}/images" images_dir="${out_dir}/images"
if [ -n "$lkmc_eval" ]; then
extra_append="$extra_append init=/eval_base64.sh - lkmc_eval=\"$(printf "$lkmc_eval" | base64)\""
fi
if "$gem5"; then if "$gem5"; then
build_dir="${out_dir}/build/gem5-1.0" build_dir="${out_dir}/build/gem5-1.0"