qemu-runlinux 5.6 KB
Newer Older
1
#!/bin/sh -e
Kirill Smelkov's avatar
Kirill Smelkov committed
2 3
# qemu-runlinux [options] <kernel> <program> ...
# run kernel/program in QEMU with root fs taken from host
4
#
Kirill Smelkov's avatar
Kirill Smelkov committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
# Copyright (C) 2014-2019  Nexedi SA and Contributors.
#                          Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.

# qemu-runlinux spawns linux kernel under qemu, setups rootfs to be taken from
# / of host, and runs specified program inside.
#
# It might be useful, for example, to test/debug just compiled kernel via
# running programs edited/compiled on host.

# ---- init under spawned kernel ----

# pid=1: we are running inside booted kernel as init.
# mount /sys /proc etc and tail to the program.
if [ $$ == 1 ]; then
35 36 37 38 39 40
	qinfo() {
		test "$qrun_loglevel" -le 6 && return	# <= KERN_INFO
		echo "$*"
	}

	qinfo "qinit ..."
Kirill Smelkov's avatar
Kirill Smelkov committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54

	qshutdown() {
		echo 1 >/proc/sys/kernel/sysrq
		echo o >/proc/sysrq-trigger	# shutdown

	}

	qdie() {
		echo "E: $*" 1>&2
		qshutdown
		sleep 1d # give time for shutdown to happen
		exit 1	 # just in case
	}

55 56 57 58
	# mount proc early & set loglevel for run phase
	mount -t proc       none /proc
	echo "$qrun_loglevel" >/proc/sys/kernel/printk

Kirill Smelkov's avatar
Kirill Smelkov committed
59 60
	mount -t sysfs      none /sys
	mount -t debugfs    none /sys/kernel/debug
61 62
	mount -t bpf        none /sys/fs/bpf
	mount -t fusectl    none /sys/fs/fuse/connections
Kirill Smelkov's avatar
Kirill Smelkov committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

	mount -t devtmpfs   none /dev
	mkdir /dev/{pts,mqueue,hugepages,shm}
	mount -t devpts     none /dev/pts
	mount -t mqueue     none /dev/mqueue
	mount -t hugetlbfs  none /dev/hugepages
	mount -t tmpfs      none /dev/shm
	# XXX securityfs

	mount -t tmpfs	none /run
	mkdir /run/lock
	mount -t tmpfs	none /run/lock
	mount -t tmpfs	none /tmp

	# run program in cwd in new terminal session attached to console
	# (if we don't establish a session accessing /dev/tty will give "No such device or address")
	test -n "$CWD" || qdie "CWD=?"
	cd "$CWD"

	test $# != 0 || qdie "no program to run"
	#cat /proc/cmdline
	#env
	#set -x
	set +e
87
	setsid "$0" .qinit2 "$@" <>/dev/ttyS0 >&0 2>&1	# run qinit2 with argv[1:] passed to init
88
	qinfo "exit code: $?"
Kirill Smelkov's avatar
Kirill Smelkov committed
89 90 91 92 93 94

	qshutdown
	sleep 1d # give time to shutdown
	qdie "unreachable"
fi

95 96 97
# init part spawned from under setsid.
# $0 .qinit2 <command> ...
if [ "$1" == .qinit2 ]; then
98 99 100 101
	# initialize terminal. In particular this has the effect to restore
	# line wrapping for xterm, as kernel, initially assuming it has "linux"
	# type terminal, somehow messes xterm settings.
	command -v tput >/dev/null && tput init
102 103 104 105 106 107 108 109
	# resize terminal to current host's xterm
	command -v resize >/dev/null && eval `resize`

	# tail to argv[1:] passed to init
	shift
	exec "$@"
fi

Kirill Smelkov's avatar
Kirill Smelkov committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

# ---- qemu setup ----

die() {
	echo "$*" 1>&2
	exit 1
}

usage() {
	cat <<EOF
Usage: qemu-runlinux [options] <kernel> <program> ...
Run linux/program under QEMU with rootfs taken from host.

<kernel>	is path vmlinuz-like kernel image
<program> ...	is program to run and arguments to it.

Options:

128 129 130 131 132 133 134
	-v	increase verbosity

			0: ERROR+ on boot/run
			1: INFO+  on      run
			2: INFO+  on boot/run
			3: DEBUG+ on boot/run

Kirill Smelkov's avatar
Kirill Smelkov committed
135 136 137 138 139 140
	-g	run with graphics
EOF
}

# by default output goes to stdout with both /dev/console and /dev/ttyS0 (where
# program is run) attached there.
141
verbose=0
Kirill Smelkov's avatar
Kirill Smelkov committed
142 143 144 145 146
nographic=y

while test $# != 0
do
	case "$1" in
147 148 149 150 151 152 153
	-v)
		verbose=$(($verbose + 1));;
	-vv)
		verbose=$(($verbose + 2));;
	-vvv)
		verbose=$(($verbose + 3));;

Kirill Smelkov's avatar
Kirill Smelkov committed
154 155 156 157 158 159 160 161 162 163 164
	-g)	# run with graphics UI, /dev/console goes to VGA; program to /dev/ttyS0
		nographic=;;
	-h)
		usage
		exit 0
		;;
	*)
		break;;
	esac
	shift
done
165 166

kernel=$1
Kirill Smelkov's avatar
Kirill Smelkov committed
167 168 169 170 171
test -n "$kernel" || die "kernel not specified"

shift
prog="$@"
test -n "$prog" || die "program not specified"
172

Kirill Smelkov's avatar
Kirill Smelkov committed
173
dir=`pwd`
174

175 176 177 178 179 180 181 182
# loglevel: default ERROR+ on boot/run
loglevel=4
qrun_loglevel=4
test $verbose -ge 1 && qrun_loglevel=7	# INFO+ on run
test $verbose -ge 2 && loglevel=7	# INFO+  on boot/run
test $verbose -ge 3 && loglevel=8	# DEBUG+ on boot/run
test $loglevel -gt 4 && qrun_loglevel=$loglevel

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
# may be also useful:
#   -serial  stdio
#   -serial  file:ttyS0
#   -monitor stdio
#   -serial  stdio
#   -S -gdb tcp::1234

# NOTES
#   - for kernel to mount root, 9P support must be compiled in:
#       CONFIG_NET_9P=y
#       CONFIG_NET_9P_VIRTIO=y
#       CONFIG_9P_FS=y
#
#   - mount_tag *must* be /dev/root - as of 3.17-rc1 the kernel hardcodes it
#
# References
#   http://unix.stackexchange.com/questions/90423/can-virtfs-9p-be-used-as-root-file-system
#   http://stackoverflow.com/questions/11408041/kernel-debugging-with-gdb-and-qemu
Kirill Smelkov's avatar
Kirill Smelkov committed
201
arch=`uname -m`
202 203
qemu-system-$arch   \
    -enable-kvm \
Kirill Smelkov's avatar
Kirill Smelkov committed
204
    ${nographic:+-nographic}	\
205
 \
Kirill Smelkov's avatar
Kirill Smelkov committed
206
    -m 512M `# default 128M is too limiting` \
207 208 209 210 211
 \
    -fsdev  local,id=R,path=/,security_model=none,readonly  \
    -device virtio-9p-pci,fsdev=R,mount_tag=/dev/root   \
 \
    -kernel $kernel \
Kirill Smelkov's avatar
Kirill Smelkov committed
212
    -append "ro rootfstype=9p rootflags=trans=virtio \
213 214
${nographic:+console=ttyS0} loglevel=$loglevel qrun_loglevel=$qrun_loglevel \
init="$(realpath $0)" \
215
CWD="$dir" HOME="$HOME" LANG="$LANG" ${nographic:+TERM="$TERM"} PATH="$PATH" \
Kirill Smelkov's avatar
Kirill Smelkov committed
216 217
-- $prog \
"