1#!/bin/sh
2##########################################################################
3# Copyright (c) 2009-2015 ETH Zurich.
4# All rights reserved.
5#
6# This file is distributed under the terms in the attached LICENSE file.
7# If you do not find this file, copies can be found by writing to:
8# ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
9# Attn: Systems Group.
10#
11# Shell script for running Qemu with a Barrelfish image
12#
13##########################################################################
14
15HDFILE=hd.img
16EFI_FLASH0=flash0.img
17EFI_FLASH1=flash1.img
18HAGFISH_LOCATION="/home/netos/tftpboot/Hagfish.efi"
19MENUFILE=""
20ARCH=""
21DEBUG_SCRIPT=""
22BIOS="/home/netos/tftpboot/QEMU_EFI.fd"
23# Grab SMP from env, if unset default to 1
24SMP=${SMP:-4}
25# Grab the MEMORY from the enf
26MEMORY=${MEMORY:-4G}
27# Grab the KVM fenable from the env
28KVM=${KVM:-"-enable-kvm"}
29
30# Grab NIC_MODEL from env, if unset default to e1000
31NIC_MODEL="${NIC_MODEL:-e1000}"
32# U-Boot options
33UBOOT=false
34UBOOT_IMAGE=/home/netos/tftpboot/u-boot.bin
35
36
37usage () {
38    echo "Usage: $0 --menu <file> --arch <arch>  [options]"
39    echo "  where:"
40    echo "    'arch' is one of: x86_64, a15ve, armv8, zynq7"
41    echo "    'file' is a menu.lst format file to read module list from"
42    echo "  and options can be:"
43    echo "    --debug <script>   (run under the specified GDB script)"
44    echo "    --hdfile <file>    (hard disk image to be build for AHCI, defaults to $HDFILE"
45    echo "    --kernel <file>    (kernel binary, if no menu.lst given)"
46    echo "    --initrd <file>    (initial RAM disk, if no menu.lst given)"
47    echo "    --image  <file>    (prebaked boot image, instead of kernel/initrd)"
48    echo "    --args <args>      (kernel command-line args, if no menu.lst given)"
49    echo "    --smp <cores>      (number of cores to use, defaults to $SMP)"
50    echo "    --nic-model <name> (nic model to use, defaults to $NIC_MODEL)"
51    echo "    --hagfish <file>   (Hagfish boot loader, defaults to $HAGFISH_LOCATION)"
52    echo "    --bios <file>      (ARMv8 QEMU bios,  defaults to $BIOS)"
53    echo "    --uboot            (boot U-Boot instead of EFI on ARMv8)"
54    echo "    --uboot-img <file> (U-Boot binary, defaults to $UBOOT_IMAGE)"
55    echo "  "
56    echo "  The following environment variables are considered:"
57    echo "    QEMU_PATH         (Path for qemu-system-* binary)"
58    echo "    NIC_MODEL         (Same as --nic-model)"
59    echo "    SMP               (Same as --smp)"
60    exit 1
61}
62
63# Result in $?
64qemu_supports_device() {
65    ${QEMU_PATH}qemu-system-x86_64 -device help 2>&1 | grep \"$1\" > /dev/null
66}
67
68
69if test $# = 0; then usage ; fi
70while test $# != 0; do
71    case $1 in
72    "--help"|"-h")
73        usage
74        exit 0
75        ;;
76    "--menu")
77        shift; MENUFILE="$1"
78        ;;
79    "--arch")
80        shift; ARCH="$1"
81        ;;
82    "--hdfile")
83        shift; HDFILE="$1"
84        ;;
85    "--debug")
86        shift; DEBUG_SCRIPT="$1"
87        ;;
88    "--initrd")
89        shift; INITRD="$1"
90        ;;
91    "--kernel")
92        shift; KERNEL="$1"
93        ;;
94    "--image")
95        shift; IMAGE="$1"
96        ;;
97    "--args")
98        shift; KERNEL_CMDS="$1"
99        ;;
100    "--smp")
101        shift; SMP="$1"
102        ;;
103    "--hagfish")
104        shift; HAGFISH_LOCATION="$1"
105        ;;
106    "--bios")
107        shift; BIOS="$1"
108        ;;
109    "--nic-model")
110        shift; NIC_MODEL="$1"
111        ;;
112    "--uboot")
113        UBOOT=true
114        ;;
115    "--uboot-img")
116        UBOOT=true
117	shift; UBOOT_IMAGE="$1"
118        ;;
119    *)
120        echo "Unknown option $1 (try: --help)" >&2
121        exit 1
122        ;;
123    esac
124    shift
125done
126
127if test -z "$IMAGE"; then
128    if test -z "$MENUFILE"; then
129        echo "No menu.lst file specified."
130        if test -z "$KERNEL"; then
131        echo "ERROR: No initial kernel given and no menu.lst file." >&2; exit 1
132        fi
133        if test -z "$INITRD"; then
134        echo "ERROR: No initial RAM disk given and no menu.lst file." >&2; exit 1
135        fi
136    else
137        echo "Using menu file $MENUFILE"
138        ROOT=`sed -rne 's,^root[ \t]*([^ ]*).*,\1,p' "$MENUFILE"`
139        if test "$ROOT" != "(nd)"; then
140            echo "Root: $ROOT"
141        fi
142        KERNEL=`sed -rne 's,^kernel[ \t]*/([^ ]*).*,\1,p' "$MENUFILE"`
143        if test "$ROOT" != "(nd)"; then
144            KERNEL="$ROOT/$KERNEL"
145        fi
146        if test -z "$KERNEL"; then
147        echo "ERROR: No initial kernel specified in menu.lst file." >&2; exit 1
148        fi
149        KERNEL_CMDS=`sed -rne 's,^kernel[ \t]*[^ ]*[ \t]*(.*),\1,p' "$MENUFILE"`
150        if test "$ROOT" != "(nd)"; then
151            AWKSCRIPT='{ if (NR == 1) printf(root "/" $$0); else printf("," root "/" $$0) }'
152            AWKARGS="-v root=$ROOT"
153        else
154            AWKSCRIPT='{ if (NR == 1) printf($$0); else printf("," $$0) }'
155        fi
156        INITRD=`sed -rne 's,^module(nounzip)?[ \t]*/(.*),\2,p' "$MENUFILE" | awk $AWKARGS "$AWKSCRIPT"`
157        if test -z "$INITRD"; then
158        echo "ERROR: No initial ram disk modules specified in menu.lst file." >&2; exit 1
159        fi
160    fi
161    echo "Initial kernel file: $KERNEL"
162    echo "Initial RAM disk contents: $INITRD"
163else
164    echo "Booting image: $IMAGE"
165fi
166
167echo "Kernel command line arguments: $KERNEL_CMDS"
168echo "Requested architecture is $ARCH."
169
170case "$ARCH" in
171    "x86_64")
172    qemu_supports_device $NIC_MODEL
173    if [ $? = 1 ] ; then
174        echo "$NIC_MODEL not supported. Fall back to e1000"
175        NIC_MODEL=e1000 ;
176    fi
177
178    # Two NIC qemu conf
179    #QEMU_CMD="${QEMU_PATH}qemu-system-x86_64 \
180    #    -machine type=q35 \
181    #    -smp $SMP \
182    #    -enable-kvm \
183    #    -m 1024 \
184    #    -netdev user,id=network0 \
185    #    -netdev user,id=network1 \
186    #    -device $NIC_MODEL,netdev=network0
187    #    -device $NIC_MODEL,netdev=network1
188    #    -device ahci,id=ahci \
189    #    -device ide-drive,drive=disk,bus=ahci.0 \
190    #    -drive id=disk,file="$HDFILE",if=none"
191
192    QEMU_CMD="${QEMU_PATH}qemu-system-x86_64 \
193        -machine type=q35 \
194        -smp ${SMP} \
195        -m ${MEMORY} \
196        ${KVM} \
197        -netdev user,id=network0 \
198        -device $NIC_MODEL,netdev=network0 \
199        -device ahci,id=ahci \
200        -device ide-drive,drive=disk,bus=ahci.0 \
201        -drive id=disk,file="$HDFILE",if=none"
202    QEMU_NONDEBUG=-nographic
203    GDB=gdb-multiarch
204    echo "Creating hard disk image $HDFILE"
205    qemu-img create "$HDFILE" 10M
206    ;;
207    "a15ve")
208        QEMU_CMD="${QEMU_PATH}qemu-system-arm \
209        -m 2G \
210        -smp $SMP \
211        -machine vexpress-a15"
212    GDB=gdb
213    QEMU_NONDEBUG=-nographic
214    ;;
215    "armv8")
216       QEMU_CMD="${QEMU_PATH}qemu-system-aarch64 \
217                 -m ${MEMORY} \
218                 -cpu cortex-a57 \
219                 -M virt -d guest_errors \
220                 -M gic_version=3 \
221                 -smp ${SMP}"
222       if $UBOOT; then
223          QEMU_CMD="$QEMU_CMD -bios $UBOOT_IMAGE \
224                    -device loader,addr=0x50000000,file=$IMAGE"
225       else
226           QEMU_CMD="$QEMU_CMD -bios $BIOS \
227                    -device virtio-blk-device,drive=image \
228                    -drive if=none,id=image,file=$IMAGE,format=raw"
229       fi
230       GDB=gdb-multiarch
231       QEMU_NONDEBUG=-nographic
232       EFI=1
233       ;;
234    "zynq7")
235        QEMU_CMD="${QEMU_PATH}qemu-system-arm \
236        -machine xilinx-zynq-a9 \
237        -m 2G \
238        -serial /dev/null \
239        -serial mon:stdio"
240    GDB=gdb
241    QEMU_NONDEBUG=-nographic
242    ;;
243    *)
244    echo "No QEmu environment defined for architecture=$ARCH." >&2
245    exit 1
246    ;;
247esac
248
249export QEMU_AUDIO_DRV=none
250
251if test "$DEBUG_SCRIPT" = ""; then
252    echo "OK: about to run the follow qemu command:"
253    if test -z "$EFI"; then
254        if test -z "$IMAGE"; then
255            echo "$QEMU_CMD $QEMU_NONDEBUG -kernel $KERNEL -append '$KERNEL_CMDS' -initrd $INITRD"
256            exec $QEMU_CMD $QEMU_NONDEBUG -kernel $KERNEL -append '$KERNEL_CMDS'  -initrd "$INITRD"
257        else
258            echo "$QEMU_CMD $QEMU_NONDEBUG -kernel $IMAGE"
259            exec $QEMU_CMD $QEMU_NONDEBUG -kernel "$IMAGE"
260        fi
261    else
262        echo $QEMU_CMD $QEMU_NONDEBUG
263        exec $QEMU_CMD $QEMU_NONDEBUG
264    fi
265fi
266
267
268# Now we run the debugger instead
269GDB_ARGS="-x $DEBUG_SCRIPT"
270SERIAL_OUTPUT=file:/dev/stdout
271PORT=$((10000 + UID))
272
273if test "${SERIAL_OUTPUT}" = ""; then
274    # Assuming session is interactive. Use terminal for serial output because
275    # stdout does not work for daemonized qemu and output is lost. This likely
276    # only matters on ARM where there is no video driver at time of writing.
277    SERIAL_OUTPUT=`tty`
278fi
279
280PIDFILE=/tmp/qemu_debugsim_${USER}_${PORT}.pid
281if test -f $PIDFILE; then
282    if ps `cat $PIDFILE` >/dev/null; then
283    echo "Another QEMU already running (PID: `cat $PIDFILE` PIDFILE: $PIDFILE)"
284    exit 1
285    else
286    echo "Deleting stale lockfile $PIDFILE"
287    rm -f $PIDFILE
288    fi
289fi
290
291echo args = $GDB_ARGS
292
293cat > barrelfish_debug.gdb <<EOF
294# Connect to QEMU instance
295target remote localhost:$PORT
296EOF
297
298if test -z "$EFI"; then
299    if test -z "$IMAGE"; then
300        QEMU_INVOCATION="${QEMU_CMD} \
301            -kernel \"$KERNEL\" \
302            -append \"$KERNEL_CMDS\" \
303            -initrd \"$INITRD\" \
304            -serial $SERIAL_OUTPUT \
305            -gdb tcp::$PORT \
306            -S \
307            -display none \
308            -daemonize \
309            -pidfile $PIDFILE"
310    else
311        QEMU_INVOCATION="${QEMU_CMD} \
312            -kernel \"$IMAGE\" \
313            -append \"$KERNEL_CMDS\" \
314            -serial $SERIAL_OUTPUT \
315            -gdb tcp::$PORT \
316            -S \
317            -display none \
318            -daemonize \
319            -pidfile $PIDFILE"
320    fi
321else
322    QEMU_INVOCATION="${QEMU_CMD} \
323        -serial $SERIAL_OUTPUT \
324        -gdb tcp::$PORT \
325        -S \
326        -display none \
327        -daemonize \
328        -pidfile $PIDFILE"
329fi
330
331echo $QEMU_INVOCATION
332set -x
333
334eval $QEMU_INVOCATION
335
336if test $? -eq 0; then
337    stty sane
338    trap '' INT
339    ${GDB} -x barrelfish_debug.gdb ${GDB_ARGS}
340    PID=`cat ${PIDFILE}`
341    kill ${PID} > /dev/null || true
342    rm -f $PIDFILE
343else
344    echo Failed to launch qemu with:
345    echo "   ${QEMU_INVOCATION}"
346fi
347