diff --git a/README.adoc b/README.adoc index e8d383d..9a39956 100644 --- a/README.adoc +++ b/README.adoc @@ -248,88 +248,7 @@ root every time. -Here are some methods to automate that. - -==== Replace init - -This method replaces init and evals a command from the <>: - -.... -./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 -.... - -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 ' -insmod /hello.ko -/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 -chmod +x rootfs_overlay/ignore.sh -./build -./run -e 'init=/ignore.sh' -n -.... - -==== 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;"' -.... - -or add them to a new `init.d` entry to run at the end o the BusyBox init: - -.... -cp rootfs_overlay/etc/init.d/S98 rootfs_overlay/etc/init.d/S99 -vim S99 -./build -./run -.... - -and they will be run automatically before the login prompt. - -`S99` is a git tracked convenience symlink to the gitignored `rootfs_overlay/etc/init.d/S99` - -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? +To automate that, use the methods described at: <> === Kernel command line parameters @@ -367,6 +286,12 @@ When dealing with real boards, extra command line options are provided on some m * GRUB configuration files: https://askubuntu.com/questions/19486/how-do-i-add-a-kernel-boot-parameter * Raspberry pi `/boot/cmdline.txt` on a magic partition: https://raspberrypi.stackexchange.com/questions/14839/how-to-change-the-kernel-commandline-for-archlinuxarm-on-raspberry-pi-effectly +=== Kernel command line parameters escaping + +Double quotes can be used to escape spaces as in `opt="a b"`, but double quotes themselves cannot be escaped, e.g. `opt"a\"b"` + +This even lead us to use base64 encoding with `-E`! + === What command was actually run? When asking for help on upstream repositories outside of this repository, you will need to provide the commands that you are running in detail without referencing our scripts. @@ -408,6 +333,12 @@ If you want to break immediately at a symbol, e.g. `start_kernel` of the boot se ./rungdb start_kernel .... +or at a given line: + +.... +./rungdb init/main.c:1088 +.... + Now QEMU will stop there, and you can use the normal GDB commands: .... @@ -948,37 +879,140 @@ TODOs: When the Linux kernel finishes booting, it runs an executable as the first and only userland process. -The default path is `/init`, but we an set a custom one with the `init=` <>. - -This process is then responsible for setting up the entire userland (or destroying everything when you want to have fun). +This init process is then responsible for setting up the entire userland (or destroying everything when you want to have fun). This typically means reading some configuration files (e.g. `/etc/initrc`) and forking a bunch of userland executables based on those files. -systemd is a "popular" `/init` implementation for desktop distros as of 2017. +systemd provides a "popular" init implementation for desktop distros as of 2017. -BusyBox provides its own minimalistic init implementation which Buildroot uses by default. +BusyBox provides its own minimalistic init implementation which Buildroot, and therefore this repo, uses by default. -=== Custom init +=== Replace init -Is the default BusyBox `/init` too bloated for you, minimalism freak? +To have more control over the system, you can replace BusyBox's init with your own. -No problem, just use the `init` kernel boot parameter: +The following method replaces init and evals a command from the <>: .... -./run -e 'init=/sleep_forever.out' +./run -E 'echo "asdf qwer";insmod /hello.ko;/poweroff.out' -n .... -Remember that shell scripts can also be used for `init` https://unix.stackexchange.com/questions/174062/init-as-a-shell-script/395375#395375: +It is basically a shortcut for: .... -./run -e 'init=/count.sh' +./run -e 'init=/eval.sh - lkmc_eval="insmod /hello.ko;/poweroff.out"' -n .... -Also remember that if your init returns, the kernel will panic, there are just two non-panic possibilities: +although `-E` is smarter: + +* allows quoting and newlines by using base64 encoding, see: <> +* automatically chooses between `init=` and `rcinit=` for you, see: <> + +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 ' +insmod /hello.ko +/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 +chmod +x rootfs_overlay/ignore.sh +./build +./run -e 'init=/ignore.sh' -n +.... + +Remember that if your init returns, the kernel will panic, there are just two non-panic possibilities: * run forever in a loop or long sleep * `poweroff` the machine +==== 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? + +=== Run command at the end of BusyBox init + +If you rely on something that BusyBox' init set up for you like networking, you caould do: + +.... +./run -e '- lkmc_eval="insmod /hello.ko;wget -S google.com;poweroff.out;"' +.... + +The `lkmc_eval` option gets evaled by our default `S98` startup script if present. + +Alternatively, add them to a new `init.d` entry to run at the end o the BusyBox init: + +.... +cp rootfs_overlay/etc/init.d/S98 rootfs_overlay/etc/init.d/S99 +vim S99 +./build +./run +.... + +and they will be run automatically before the login prompt. + +`S99` is a git tracked convenience symlink to the gitignored `rootfs_overlay/etc/init.d/S99` + +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`. + +=== Path to init + +The init is selected at: + +- initrd or initramfs system: `/init`, a custom one can be set with the `rdinit=` <> +- otherwise: default is `/sbin/init`, followed by some other paths, a custom one can be set with `init=` + +More details: https://unix.stackexchange.com/questions/30414/what-can-make-passing-init-path-to-program-to-the-kernel-not-start-program-as-i/430614#430614 + +=== Init environment + +Documented at link:https://www.kernel.org/doc/html/v4.14/admin-guide/kernel-parameters.html[]: + +____ +The kernel parses parameters from the kernel command line up to "-"; if it doesn't recognize a parameter and it doesn't contain a '.', the parameter gets passed to init: parameters with '=' go into init's environment, others are passed as command line arguments to init. Everything after "-" is passed as an argument to init. +____ + +And you can try it out with: + +.... +./run -e 'init=/init_env_poweroff.sh - asdf=qwer zxcv' -n +.... + +Also note how the annoying dash `-` also gets passed as a parameter to `init`, which makes it impossible to use this method for most executables. + +Finally, the docs are lying, arguments with dots that come after `-` are still treated specially (of the form `subsystem.somevalue`) and disappear: + +.... +./run -e 'init=/init_env_poweroff.sh - /poweroff.out' -n +.... + === Disable networking The default BusyBox init scripts enable networking, and there is a 15 second timeout in case your network is down or if your kernel / emulator setup does not support it. @@ -995,20 +1029,6 @@ To restore it, run: ./build -- initscripts-reconfigure .... -=== The init environment - -The docs make it clear https://www.kernel.org/doc/html/v4.14/admin-guide/kernel-parameters.html - -____ -The kernel parses parameters from the kernel command line up to “–”; if it doesn’t recognize a parameter and it doesn’t contain a ‘.’, the parameter gets passed to init: parameters with ‘=’ go into init’s environment, others are passed as command line arguments to init. Everything after “–” is passed as an argument to init. -____ - -And you can try it out with: - -.... -./run -e 'init=/init_env_poweroff.sh - asdf=qwer zxcv' -n -.... - == modprobe If you are feeling fancy, you can also insert modules with: @@ -1088,7 +1108,7 @@ Only tested successfully in `x86_64`. Build: .... -./build -i br2_x11 +./build -b br2_x11 ./run .... @@ -1257,13 +1277,18 @@ The bootloader, which for us is QEMU itself, is then configured to put that CPIO With this setup, you don't even need to give a root filesystem to the kernel, it just does everything in memory in a ramfs. -Try it out with: +To enable initrd instead of the default ext2 disk image, do: .... +./build -i ./run -i .... -Notice how it boots fine, even though `-drive` is not given. +Notice how it boots fine, even though this leads to not giving QEMU the `-drive` option, as can be verified with: + +.... +cat ./run.log +.... Also as expected, there is no filesystem persistency, since we are doing everything in memory: @@ -1274,9 +1299,21 @@ cat f # can't open 'f': No such file or directory .... -This can be good for automated tests, as it ensures that you are using a pristine unmodified system image every time. +which can be good for automated tests, as it ensures that you are using a pristine unmodified system image every time. -The main ingredients to get this working are: +One downside of this method is that it has to put the entire filesystem into memory, and could lead to a panic: + +.... +end Kernel panic - not syncing: Out of memory and no killable processes... +.... + +This can be solved by increasing the memory with: + +.... +./run -im 256M +.... + +The main ingredients to get initrd working are: * `BR2_TARGET_ROOTFS_CPIO=y`: make Buildroot generate `output/images/rootfs.cpio` in addition to the other images. + @@ -1311,15 +1348,43 @@ So the only argument that QEMU needs is the `-kernel`, no `-drive` not even `-in Try it out with: .... -./run -a aarch64 +rm -f buildroot/output.x86_64~/build/linux-custom/.config +./build -I +./run -I .... -since our <> setup uses it by default. +The line: + +.... +rm -f buildroot/output.x86_64~/build/linux-custom/.config +.... + +is only needed the first time you move from a different root filesystem method (ext2 or cpio) to initramfs. It is needed because Buildroot is not automatically updating `CONFIG_INITRAMFS_SOURCE` in the kernel config for some reason: https://stackoverflow.com/questions/49260466/why-when-i-change-br2-linux-kernel-custom-config-file-and-run-make-linux-reconfi + +Then to go back to another boot method such as ext filesystems to: + +.... +rm -f buildroot/output.x86_64~/build/linux-custom/.config +./build +./run +.... + +It is interesting to see how this increases the size of the kernel image if you do a: + +.... +ls -lh buildroot/output.x86_64~/images/bzImage +.... + +before and after using initramfs, since the `.cpio` is now glued to the kernel image. In the background, it uses `BR2_TARGET_ROOTFS_INITRAMFS`, and this makes the kernel config option `CONFIG_INITRAMFS_SOURCE` point to the CPIO that will be embedded in the kernel image. http://nairobi-embedded.org/initramfs_tutorial.html shows a full manual setup. +=== gem5 initrd + +TODO we were not able to get it working yet: https://stackoverflow.com/questions/49261801/how-to-boot-the-linux-kernel-with-initrd-or-initramfs-with-gem5 + == Linux kernel === Use your own kernel config @@ -1992,6 +2057,18 @@ TODO These look promising: TODO: now to verify this with the Linux kernel? Besides raw performance benchmarks. +===== gem5 memory size + +.... +./run -a arm -m 512M +.... + +and verify inside the guest with: + +.... +free -m +.... + ===== gem5 disk and network latency TODO These look promising: @@ -2080,7 +2157,7 @@ Buildroot supports it, which makes everything just trivial: .... printf 'BR2_PACKAGE_OPENBLAS=y\n' >> br2_local printf 'BR2_TARGET_ROOTFS_EXT2_SIZE="128M"\n' >> br2_local -./build -a arm -g -i br2_local -- kernel_module-reconfigure +./build -a arm -g -b br2_local -- kernel_module-reconfigure .... and then inside the guest run our test program: @@ -2113,7 +2190,7 @@ There are two ways to run PARSEC with this repo: ====== PARSEC benchmark without parsecmgmt .... -configure -gpq && ./build -a arm -g -i br2_parsec +configure -gpq && ./build -a arm -g -b br2_parsec ./run -a arm -g .... @@ -2146,7 +2223,7 @@ Running a benchmark of a different size requires a rebuild wit: -c 'BR2_PACKAGE_PARSEC_BENCHMARK_INPUT_SIZE="simsmall"' \ -c BR2_TARGET_ROOTFS_EXT2_SIZE="500M" \ -g \ - -i br2_parsec \ + -b br2_parsec \ -- parsec-benchmark-reconfigure \ ; .... @@ -2198,7 +2275,7 @@ If you still want to run this, try it out with: ./build -a arm \ -c BR2_TARGET_ROOTFS_EXT2_SIZE="3G" \ -g - -i br2_parsec + -b br2_parsec -- parsec-benchmark-reconfigure \ ; .... @@ -2225,7 +2302,7 @@ BR2_PACKAGE_PARSEC_BENCHMARK_INPUT_SIZE=simsmall and then rebuild with: .... -./build -a arm -g -i br2_parsec -- parsec-benchmark-reconfigure +./build -a arm -g -b br2_parsec -- parsec-benchmark-reconfigure .... This limitation exists because `parsecmgmt` generates the input files just before running via the Bash scripts, but we can't run `parsecmgmt` on gem5 as it is too slow! @@ -2272,7 +2349,7 @@ before going for the cross compile build. Don't forget to explicitly rebuild PARSEC with: + .... -./build -a arm -g -i br2_parsec parsec-benchmark-reconfigure +./build -a arm -g -b br2_parsec parsec-benchmark-reconfigure .... + You may also want to test if your patches are still functionally correct inside of QEMU first, which is a faster emulator. @@ -2627,7 +2704,7 @@ dmesg We provide the following mechanisms: -* `./build -i br2_local`: append the file `br2_local` to a single build. Must be passed every time you run `./build`. +* `./build -b br2_local`: append the file `br2_local` to a single build. Must be passed every time you run `./build`. + For convenience, we already gitignore `br2_local` for you. + diff --git a/br2 b/br2 index b822a4d..52238ce 100644 --- a/br2 +++ b/br2 @@ -1,6 +1,11 @@ # Custom packages BR2_PACKAGE_KERNEL_MODULE=y +# Rootfs +BR2_TARGET_ROOTFS_CPIO=n +BR2_TARGET_ROOTFS_EXT2=y +BR2_TARGET_ROOTFS_INITRAMFS=n + BR2_CCACHE=y # Otherwise our precious debug would break! BR2_CCACHE_USE_BASEDIR=n @@ -19,8 +24,6 @@ BR2_ROOTFS_OVERLAY="../rootfs_overlay" BR2_ROOTFS_POST_BUILD_SCRIPT="../rootfs_post_build_script" BR2_ROOTFS_POST_IMAGE_SCRIPT="../rootfs_post_image_script" BR2_ROOTFS_USERS_TABLES="../user_table" -BR2_TARGET_ROOTFS_CPIO=y -BR2_TARGET_ROOTFS_EXT2=y BR2_TOOLCHAIN_BUILDROOT_CXX=y BR2_TOOLCHAIN_BUILDROOT_FORTRAN=y BR2_TOOLCHAIN_BUILDROOT_WCHAR=y diff --git a/build b/build index 5fe7881..1c3c654 100755 --- a/build +++ b/build @@ -12,11 +12,14 @@ linux_kernel_custom_config_file='' post_script_args='' qemu_sdl='--enable-sdl --with-sdlabi=2.0' v=0 -while getopts 'a:c:Cgj:i:kK:lp:qS:v' OPT; do +while getopts 'a:b:c:Cgj:IiKk:lp:qS:v' OPT; do case "$OPT" in a) arch="$OPTARG" ;; + b) + config_fragments="$config_fragments $OPTARG" + ;; c) echo "$OPTARG" >> br2_cli ;; @@ -26,11 +29,22 @@ while getopts 'a:c:Cgj:i:kK:lp:qS:v' OPT; do g) gem5=true ;; - j) - j="$OPTARG" + I) + echo " +BR2_TARGET_ROOTFS_CPIO=n +BR2_TARGET_ROOTFS_EXT2=n +BR2_TARGET_ROOTFS_INITRAMFS=y +" >> br2_cli ;; i) - config_fragments="$config_fragments $OPTARG" + echo " +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_EXT2=n +BR2_TARGET_ROOTFS_INITRAMFS=n +" >> br2_cli + ;; + j) + echo "$OPTARG" >> br2_cli ;; k) extra_make_args="$extra_make_args kernel_module-reconfigure" diff --git a/run b/run index e957ac4..4a02ae9 100755 --- a/run +++ b/run @@ -19,8 +19,11 @@ gem5=false gem5opts='' lkmc_eval='' initrd=false +initramfs=false +memory=128M +nographic=false root='' -while getopts a:c:DdE:e:G:giKknt:x OPT; do +while getopts a:c:DdE:e:G:gIiKkm:nt:x OPT; do case "$OPT" in a) arch="$OPTARG" @@ -29,7 +32,7 @@ while getopts a:c:DdE:e:G:giKknt:x OPT; do cpus="$OPTARG" ;; d) - extra_flags_qemu="$extra_flags -S -s" + extra_flags_qemu="$extra_flags_qemu -S -s" ;; D) debug_vm='gdb -q -ex start --args' @@ -47,7 +50,7 @@ while getopts a:c:DdE:e:G:giKknt:x OPT; do extra_append="$extra_append kgdbwait" # For those who want to try KDB. #extra_append="$extra_append kgdbwait kgdboc=kbd" - extra_flags_qemu="$extra_flags -serial tcp::1234,server,nowait" + extra_flags_qemu="$extra_flags_qemu -serial tcp::1234,server,nowait" kgdb=true ;; g) @@ -56,12 +59,17 @@ while getopts a:c:DdE:e:G:giKknt:x OPT; do G) gem5opts="$OPTARG" ;; + I) + initramfs=true + ;; i) initrd=true ;; + m) + memory="$OPTARG" + ;; n) - extra_append="$extra_append console=ttyS0" - extra_flags_qemu="$extra_flags -nographic" + nographic=true ;; esac done @@ -75,12 +83,27 @@ root_dir="$(pwd)" buildroot_dir="${root_dir}/buildroot" out_dir="${root_dir}/buildroot/output.${arch_dir}~" images_dir="${out_dir}/images" +if "$initrd" || "$initramfs"; then + ramfs=true +else + ramfs=false +fi if [ -n "$lkmc_eval" ]; then - extra_append="$extra_append init=/eval_base64.sh - lkmc_eval=\"$(printf "$lkmc_eval" | base64)\"" + if "$ramfs"; then + initarg="rdinit" + else + initarg="init" + fi + extra_append="${extra_append} ${initarg}=/eval_base64.sh - lkmc_eval=\"$(printf "$lkmc_eval" | base64)\"" +fi +if "$nographic" && [ "$arch" = x86_64 ]; then + extra_append="$extra_append console=ttyS0" + extra_flags_qemu="$extra_flags_qemu -nographic" fi if "$gem5"; then build_dir="${out_dir}/build/gem5-1.0" + memory="${memory}B" gem5_dir="${build_dir}/gem5" if [ "$arch" = x86_64 ]; then gem5_arch=X86 @@ -98,6 +121,7 @@ ${gem5opts} \ --checkpoint-dir='${gem5_cpt_dir}' \ --disk-image='${out_dir}/images/rootfs.ext2' \ --kernel='${out_dir}/build/linux-custom/vmlinux' \ +--mem-size=${memory} \ --num-cpus='${cpus}' \ " if [ "$arch" = x86_64 ]; then @@ -109,11 +133,13 @@ ${gem5opts} \ $extra_flags \ " elif [ "$arch" = arm ] || [ "$arch" = aarch64 ]; then + # TODO why is it mandatory to pass mem= here? Not true for QEMU. + # Anything smaller than physical blows up as expected, but why can't it auto-detect the right value? cmd="${gem5_common} \ ---command-line='earlyprintk=pl011,0x1c090000 console=ttyAMA0 lpj=19988480 rw loglevel=8 mem=512MB root=/dev/sda $extra_append' \ +--command-line='earlyprintk=pl011,0x1c090000 console=ttyAMA0 lpj=19988480 rw loglevel=8 mem=${memory} root=/dev/sda $extra_append' \ --dtb-file='${gem5_dir}/system/arm/dt/$([ "$arch" = arm ] && echo "armv7_gem5_v1_${cpus}cpu" || echo "armv8_gem5_v1_${cpus}cpu").dtb' \ --machine-type=VExpress_GEM5_V1 \ -$extra_flags \ +${extra_flags} \ " fi else @@ -125,7 +151,7 @@ else qemu_common="\ ${debug_vm} \ '${out_dir}/host/usr/bin/qemu-system-${arch}' \ --m 128M \ +-m ${memory} \ -monitor telnet::45454,server,nowait \ -netdev user,hostfwd=tcp::45455-:45455,id=net0 \ -smp $cpus \ @@ -139,15 +165,17 @@ ${debug_vm} \ case "$arch" in x86_64) if "$kgdb"; then - extra_append="$extra_append kgdboc=ttyS0,115200" + extra_append="${extra_append} kgdboc=ttyS0,115200" fi - if ! "$initrd"; then + if "$ramfs"; then + root='root=/dev/anything' + else root='root=/dev/vda' - extra_flags="$extra_flags -drive file='${images_dir}/rootfs.ext2.qcow2,if=virtio,format=qcow2'" + extra_flags="${extra_flags} -drive file='${images_dir}/rootfs.ext2.qcow2,if=virtio,format=qcow2'" fi - cmd="$qemu_common \ + cmd="${qemu_common} \ -M pc \ --append '$root nopat $extra_append' \ +-append '${root} nopat ${extra_append}' \ -device edu \ -device lkmc_pci_min \ -device virtio-net-pci,netdev=net0 \ @@ -157,15 +185,17 @@ ${extra_flags} \ ;; arm) if "$kgdb"; then - extra_append="$extra_append kgdboc=ttyAMA0,115200" + extra_append="${extra_append} kgdboc=ttyAMA0,115200" fi - if ! "$initrd"; then + if "$ramfs"; then + root='root=/dev/anything' + else + extra_flags="${extra_flags} -drive file='${images_dir}/rootfs.ext2.qcow2,if=scsi,format=qcow2'" root='root=/dev/sda' - extra_flags="$extra_flags -drive file='${images_dir}/rootfs.ext2.qcow2,if=scsi,format=qcow2'" fi cmd="$qemu_common \ -M versatilepb \ --append '$root $extra_append' \ +-append '${root} ${extra_append}' \ -device rtl8139,netdev=net0 \ -dtb '${images_dir}/versatile-pb.dtb' \ -kernel '${images_dir}/zImage' \ @@ -177,9 +207,15 @@ $extra_flags \ if "$kgdb"; then extra_append="${extra_append} kgdboc=ttyAMA0,115200" fi + if "$ramfs"; then + root='root=/dev/anything' + else + root='root=/dev/vda' + extra_flags="${extra_flags} -drive file='${images_dir}/rootfs.ext2.qcow2,if=virtio,format=qcow2'" + fi cmd="${qemu_common} \ -M virt \ --append 'root=/dev/sda ${extra_append}' \ +-append '${root} ${extra_append}' \ -cpu cortex-a57 \ -device virtio-net-device,netdev=net0 \ -kernel '${images_dir}/Image' \ @@ -189,13 +225,15 @@ ${extra_flags} \ " ;; mips64) - if ! "$initrd"; then + if "$ramfs"; then + root='root=/dev/anything' + else root='root=/dev/hda' extra_flags="${extra_flags} -drive file='${images_dir}/rootfs.ext2.qcow2,format=qcow2'" fi - cmd="$qemu_common \ + cmd="${qemu_common} \ -M malta \ --append 'root=/dev/hda ${extra_append}' \ +-append '${root} ${extra_append}' \ -cpu I6400 \ -device pcnet \ -kernel '${images_dir}/vmlinux' \