armv8: fixing menu.lst files and adding bootdriver to the platforms
[barrelfish] / tools / qemu-wrapper.sh
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
15 HDFILE=hd.img
16 EFI_FLASH0=flash0.img
17 EFI_FLASH1=flash1.img
18 HAGFISH_LOCATION="/home/netos/tftpboot/Hagfish.efi"
19 MENUFILE=""
20 ARCH=""
21 DEBUG_SCRIPT=""
22 # Grab SMP from env, if unset default to 2
23 SMP=${SMP:-2}
24 # Grab NIC_MODEL from env, if unset default to e1000
25 NIC_MODEL="${NIC_MODEL:-e1000}"
26
27
28 usage () {
29     echo "Usage: $0 --menu <file> --arch <arch>  [options]"
30     echo "  where:"
31     echo "    'arch' is one of: x86_64, a15ve, armv8, zynq7"
32     echo "    'file' is a menu.lst format file to read module list from"
33     echo "  and options can be:"
34     echo "    --debug <script>   (run under the specified GDB script)"
35     echo "    --hdfile <file>    (hard disk image to be build for AHCI, defaults to $HDFILE"
36     echo "    --kernel <file>    (kernel binary, if no menu.lst given)"
37     echo "    --initrd <file>    (initial RAM disk, if no menu.lst given)"
38     echo "    --image  <file>    (prebaked boot image, instead of kernel/initrd)"
39     echo "    --args <args>      (kernel command-line args, if no menu.lst given)"
40     echo "    --smp <cores>      (number of cores to use, defaults to $SMP)"
41     echo "    --nic-model <name> (nic model to use, defaults to $NIC_MODEL)"
42     echo "    --hagfish <file>   (Hagfish boot loader, defaults to $HAGFISH_LOCATION)"
43     echo "  "
44     echo "  The following environment variables are considered:"
45     echo "    QEMU_PATH         (Path for qemu-system-* binary)"
46     echo "    NIC_MODEL         (Same as --nic-model)"
47     echo "    SMP               (Same as --smp)"
48     exit 1
49 }
50
51
52 if test $# = 0; then usage ; fi
53 while test $# != 0; do
54     case $1 in
55     "--help"|"-h")
56         usage
57         exit 0
58         ;;
59     "--menu")
60         shift; MENUFILE="$1"
61         ;;
62     "--arch")
63         shift; ARCH="$1"
64         ;;
65     "--hdfile")
66         shift; HDFILE="$1"
67         ;;
68     "--debug")
69         shift; DEBUG_SCRIPT="$1"
70         ;;
71     "--initrd")
72         shift; INITRD="$1"
73         ;;
74     "--kernel")
75         shift; KERNEL="$1"
76         ;;
77     "--image")
78         shift; IMAGE="$1"
79         ;;
80     "--args")
81         shift; KERNEL_CMDS="$1"
82         ;;
83     "--smp")
84         shift; SMP="$1"
85         ;;
86     "--hagfish")
87         shift; HAGFISH_LOCATION="$1"
88         ;;
89     "--nic-model")
90         shift; NIC_MODEL="$1"
91         ;;
92     *)
93         echo "Unknown option $1 (try: --help)" >&2
94         exit 1
95         ;;
96     esac
97     shift
98 done
99
100 if test -z "$IMAGE"; then
101     if test -z "$MENUFILE"; then
102         echo "No menu.lst file specified."
103         if test -z "$KERNEL"; then
104         echo "ERROR: No initial kernel given and no menu.lst file." >&2; exit 1
105         fi
106         if test -z "$INITRD"; then
107         echo "ERROR: No initial RAM disk given and no menu.lst file." >&2; exit 1
108         fi
109     else
110         echo "Using menu file $MENUFILE"
111         ROOT=`sed -rne 's,^root[ \t]*([^ ]*).*,\1,p' "$MENUFILE"`
112         if test "$ROOT" != "(nd)"; then
113             echo "Root: $ROOT"
114         fi
115         KERNEL=`sed -rne 's,^kernel[ \t]*/([^ ]*).*,\1,p' "$MENUFILE"`
116         if test "$ROOT" != "(nd)"; then
117             KERNEL="$ROOT/$KERNEL"
118         fi
119         if test -z "$KERNEL"; then
120         echo "ERROR: No initial kernel specified in menu.lst file." >&2; exit 1
121         fi
122         KERNEL_CMDS=`sed -rne 's,^kernel[ \t]*[^ ]*[ \t]*(.*),\1,p' "$MENUFILE"`
123         if test "$ROOT" != "(nd)"; then
124             AWKSCRIPT='{ if (NR == 1) printf(root "/" $$0); else printf("," root "/" $$0) }'
125             AWKARGS="-v root=$ROOT"
126         else
127             AWKSCRIPT='{ if (NR == 1) printf($$0); else printf("," $$0) }'
128         fi
129         INITRD=`sed -rne 's,^module(nounzip)?[ \t]*/(.*),\2,p' "$MENUFILE" | awk $AWKARGS "$AWKSCRIPT"`
130         if test -z "$INITRD"; then
131         echo "ERROR: No initial ram disk modules specified in menu.lst file." >&2; exit 1
132         fi
133     fi
134     echo "Initial kernel file: $KERNEL"
135     echo "Initial RAM disk contents: $INITRD"
136 else
137     echo "Booting image: $IMAGE"
138 fi
139
140 echo "Kernel command line arguments: $KERNEL_CMDS"
141 echo "Requested architecture is $ARCH."
142
143 case "$ARCH" in
144     "x86_64")
145     QEMU_CMD="${QEMU_PATH}qemu-system-x86_64 \
146         -machine type=q35 \
147         -smp $SMP \
148         -m 1024 \
149         -net nic,model=$NIC_MODEL \
150         -net user \
151         -device ahci,id=ahci \
152         -device ide-drive,drive=disk,bus=ahci.0 \
153         -drive id=disk,file="$HDFILE",if=none"
154     QEMU_NONDEBUG=-nographic
155     GDB=gdb-multiarch
156     echo "Creating hard disk image $HDFILE"
157     qemu-img create "$HDFILE" 10M
158     ;;
159     "a15ve")
160         QEMU_CMD="${QEMU_PATH}qemu-system-arm \
161         -m 1024 \
162         -smp $SMP \
163         -machine vexpress-a15"
164     GDB=gdb
165     QEMU_NONDEBUG=-nographic
166     ;;
167     "armv8")
168        #
169        # The next steps create the EFI directory for QEMU.
170        #    qemu-efi/
171        #        - Hagfish.efi   the UEFI bootloader
172        #        - Hagfish.cfg   'menu.lst' specifying what Hagfish should boot
173        #        - startup.nsh   script executed by the EFI shell
174        #        - ...           remaining files in the disk
175        #
176        # NOTE: Qemu is only able to support FAT16, hence the directory specified
177        #       by -drive must be smaller than 500M.
178        #       We currently copy the created binary into this directory
179        #
180        mkdir -p qemu-efi/armv8/sbin
181        # create the startup script
182        echo "\\Hagfish.efi Hagfish.cfg" > qemu-efi/startup.nsh
183        chmod +x qemu-efi/startup.nsh
184        # setup hagfish location
185        cp $HAGFISH_LOCATION qemu-efi/Hagfish.efi
186        cp platforms/arm/menu.lst.armv8_a57v qemu-efi/Hagfish.cfg
187        # copy install files
188        cp *.gz qemu-efi
189        cp -r armv8/sbin/* qemu-efi/armv8/sbin/
190        QEMU_CMD="${QEMU_PATH}qemu-system-aarch64 \
191                 -m 1024 \
192                 -cpu cortex-a57 \
193                 -M virt \
194                 -smp $SMP \
195                 -pflash $EFI_FLASH0 \
196                 -pflash $EFI_FLASH1 \
197                 -drive if=none,file=fat:rw:qemu-efi,id=drv \
198                 -device virtio-blk-device,drive=drv"
199        GDB=gdb-multiarch
200        QEMU_NONDEBUG=-nographic
201        # Now you'll need to create pflash volumes for UEFI. Two volumes are required,
202        # one static one for the UEFI firmware, and another dynamic one to store variables.
203        # Both need to be exactly 64M in size. //https://wiki.ubuntu.com/ARM64/QEMU
204        if ! [ -e $EFI_FLASH0 ] ; then
205             dd if=/dev/zero of="$EFI_FLASH0" bs=1M count=64
206             dd if=/usr/share/qemu-efi/QEMU_EFI.fd of="$EFI_FLASH0" conv=notrunc
207        fi
208        [ -e $EFI_FLASH1 ] || dd if=/dev/zero of="$EFI_FLASH1" bs=1M count=64
209        EFI=1
210        ;;
211     "zynq7")
212         QEMU_CMD="${QEMU_PATH}qemu-system-arm \
213         -machine xilinx-zynq-a9 \
214         -m 1024 \
215         -serial /dev/null \
216         -serial mon:stdio"
217     GDB=gdb
218     QEMU_NONDEBUG=-nographic
219     ;;
220     *)
221     echo "No QEmu environment defined for architecture=$ARCH." >&2
222     exit 1
223     ;;
224 esac
225
226 export QEMU_AUDIO_DRV=none
227
228 if test "$DEBUG_SCRIPT" = ""; then
229     echo "OK: about to run the follow qemu command:"
230     if test -z "$EFI"; then
231         if test -z "$IMAGE"; then
232             echo "$QEMU_CMD $QEMU_NONDEBUG -kernel $KERNEL -append '$KERNEL_CMDS' -initrd $INITRD"
233             exec $QEMU_CMD $QEMU_NONDEBUG -kernel $KERNEL -append '$KERNEL_CMDS'  -initrd "$INITRD"
234         else
235             echo "$QEMU_CMD $QEMU_NONDEBUG -kernel $IMAGE"
236             exec $QEMU_CMD $QEMU_NONDEBUG -kernel "$IMAGE"
237         fi
238     else
239         echo $QEMU_CMD $QEMU_NONDEBUG
240         exec $QEMU_CMD $QEMU_NONDEBUG
241     fi
242 fi
243
244
245 # Now we run the debugger instead
246 GDB_ARGS="-x $DEBUG_SCRIPT"
247 SERIAL_OUTPUT=file:/dev/stdout
248 PORT=$((10000 + UID))
249
250 if test "${SERIAL_OUTPUT}" = ""; then
251     # Assuming session is interactive. Use terminal for serial output because
252     # stdout does not work for daemonized qemu and output is lost. This likely
253     # only matters on ARM where there is no video driver at time of writing.
254     SERIAL_OUTPUT=`tty`
255 fi
256
257 PIDFILE=/tmp/qemu_debugsim_${USER}_${PORT}.pid
258 if test -f $PIDFILE; then
259     if ps `cat $PIDFILE` >/dev/null; then
260     echo "Another QEMU already running (PID: `cat $PIDFILE` PIDFILE: $PIDFILE)"
261     exit 1
262     else
263     echo "Deleting stale lockfile $PIDFILE"
264     rm -f $PIDFILE
265     fi
266 fi
267
268 echo args = $GDB_ARGS
269
270 cat > barrelfish_debug.gdb <<EOF
271 # Connect to QEMU instance
272 target remote localhost:$PORT
273 EOF
274
275 if test -z "$EFI"; then
276     if test -z "$IMAGE"; then
277         QEMU_INVOCATION="${QEMU_CMD} \
278             -kernel \"$KERNEL\" \
279             -append \"$KERNEL_CMDS\" \
280             -initrd \"$INITRD\" \
281             -serial $SERIAL_OUTPUT \
282             -gdb tcp::$PORT \
283             -S \
284             -display none \
285             -daemonize \
286             -pidfile $PIDFILE"
287     else
288         QEMU_INVOCATION="${QEMU_CMD} \
289             -kernel \"$IMAGE\" \
290             -append \"$KERNEL_CMDS\" \
291             -serial $SERIAL_OUTPUT \
292             -gdb tcp::$PORT \
293             -S \
294             -display none \
295             -daemonize \
296             -pidfile $PIDFILE"
297     fi
298 else
299     QEMU_INVOCATION="${QEMU_CMD} \
300         -serial $SERIAL_OUTPUT \
301         -gdb tcp::$PORT \
302         -S \
303         -display none \
304         -daemonize \
305         -pidfile $PIDFILE"
306 fi
307
308 echo $QEMU_INVOCATION
309 set -x
310
311 eval $QEMU_INVOCATION
312
313 if test $? -eq 0; then
314     stty sane
315     trap '' INT
316     ${GDB} -x barrelfish_debug.gdb ${GDB_ARGS}
317     PID=`cat ${PIDFILE}`
318     kill ${PID} > /dev/null || true
319     rm -f $PIDFILE
320 else
321     echo Failed to launch qemu with:
322     echo "   ${QEMU_INVOCATION}"
323 fi