1#!/usr/bin/env bash 2 3# Copyright 2016 The Fuchsia Authors 4# 5# Use of this source code is governed by a MIT-style 6# license that can be found in the LICENSE file or at 7# https://opensource.org/licenses/MIT 8 9function HELP { 10 echo "help:" 11 echo "-a <arch> : arm64, or x64" 12 echo "-b : build first" 13 echo "-c <text> : add item to kernel commandline" 14 echo "-C : use Clang build" 15 echo "-A : use ASan build" 16 echo "-P : use profile build" 17 echo "-L : use LTO build" 18 echo "-l : use ThinLTO build" 19 echo "-d : run with emulated disk" 20 echo "-D <disk file|device>: specify disk file or device path on host, default is blk.bin" 21 echo "--disktype[=<type>] : should be one of (ahci, virtio, nvme), default is ahci" 22 echo "--diskfmt[=<format>] : disk format (raw, qcow2, etc), default is raw" 23 echo "-g : use graphical console" 24 echo "-G <version> : use GIC v2 or v3" 25 echo "-I <interface name> : network interface name, default is qemu." 26 echo "-k : use KVM" 27 echo "-m <memory in MB> : memory size, default is ${MEMSIZE_DEFAULT}MB" 28 echo "-n : run with emulated nic" 29 echo "-N : run with emulated nic via tun/tap" 30 echo "-o <dir> : build directory" 31 echo "-q <directory> : location of qemu, defaults to looking in prebuilt/downloads/qemu/bin, then \$PATH" 32 echo "-r : run release build" 33 echo "-s <number of cpus> : number of cpus, 1 for uniprocessor, default is 4" 34 echo "-t <binary> : use <binary> as the QEMU->ZBI trampoline" 35 echo "-u <path> : execute qemu startUp script, default is no script" 36 echo "-V : try to use virtio devices" 37 echo "-z <zbi> : boot specified complete ZBI via trampoline" 38 echo "--audio[=<host_drv>] : use Intel HD Audio" 39 echo " : <host_drv> should be one of (alsa, pa, wav, none)" 40 echo "--ahci=<disk image> : run with disk image file as raw ahci drive" 41 echo "--build-debug : build an image for use with gdb (equivalent to -d to build-zircon)" 42 echo "--debugger : Enable gdb stub and wait for connection" 43 echo "--no-serial : Disable writing out to the guest's serial port" 44 echo "--vnc=<display> : use vnc based display" 45 echo "--wavfile=<file> : When audio host_drv == wav, output to the specified WAV file" 46 echo "-h for help" 47 echo "all arguments after -- are passed to qemu directly" 48 exit 1 49} 50 51DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 52 53AHCI=() 54ARCH= 55ASAN=0 56AUDIO= 57AUDIO_WAVFILE="/tmp/qemu.wav" 58BUILD=0 59CLANG=0 60DEBUGGER=0 61BUILD_DEBUG=0 62DISK=0 63DISKFILE="blk.bin" 64DISKTYPE= 65DISKFMT="raw" 66BUILDDIR= 67GIC=3 68GRAPHICS=0 69DO_KVM=0 70LTO=0 71THINLTO=0 72PROFILE=0 73MEMSIZE_DEFAULT=2048 74MEMSIZE=$MEMSIZE_DEFAULT 75NET=0 76QEMUDIR= 77RELEASE=0 78UPSCRIPT=no 79VNC= 80VIRTIO=0 81SERIAL=1 82SMP=4 83CMDLINE="" 84QEMU_KERNEL= 85QEMU_INITRD= 86 87if [[ "$(uname -s)" == "Darwin" ]]; then 88 IFNAME="tap0" 89else 90 IFNAME="qemu" 91fi 92 93# QEMU looks for its own files in its current directory before looking in its 94# data directory (.../share/qemu/). So a file in the current directory that 95# happens to match one of those internal files' names will be used instead of 96# the proper file and make things go awry. There's no way to tell QEMU not to 97# look in the current directory first. So to make it safe to have files by any 98# name in the current directory, we cd to / before running QEMU (on the more 99# reasonable presumption that / won't contain any files by those names). Hence, 100# we have to convert any relative file names we're passing to QEMU to absolute. 101abspath() { 102 local path="$1" 103 case "$path" in 104 /*) echo "$path";; 105 *) echo "`pwd`/$path";; 106 esac 107} 108 109while getopts "Aa:bc:CdD:gG:I:kLlm:nNo:Pq:rs:t::u:Vz:h-:" FLAG; do 110 case $FLAG in 111 A) ASAN=1;; 112 a) ARCH=$OPTARG;; 113 b) BUILD=1;; 114 c) CMDLINE+="$OPTARG ";; 115 C) CLANG=1;; 116 d) DISK=1;; 117 D) DISKFILE="$(abspath "$OPTARG")";; 118 g) GRAPHICS=1;; 119 G) GIC=$OPTARG;; 120 I) IFNAME=$OPTARG;; 121 k) DO_KVM=1;; 122 L) LTO=1;; 123 l) THINLTO=1;; 124 m) MEMSIZE=$OPTARG;; 125 n) NET=1;; 126 N) NET=2;; 127 o) BUILDDIR=$OPTARG;; 128 P) PROFILE=1;; 129 q) QEMUDIR=${OPTARG}/;; 130 r) RELEASE=1;; 131 s) SMP=$OPTARG;; 132 t) QEMU_KERNEL="$(abspath "$OPTARG")";; 133 u) UPSCRIPT="$(abspath "$OPTARG")";; 134 V) VIRTIO=1;; 135 z) QEMU_INITRD="$(abspath "$OPTARG")";; 136 h) HELP;; 137 \?) 138 echo unrecognized option 139 HELP 140 ;; 141 -) 142 case $OPTARG in 143 ahci=*) AHCI+=("$(abspath "${OPTARG#*=}")");; 144 audio) AUDIO=none;; 145 audio=*) AUDIO=${OPTARG#*=};; 146 wavfile=*) AUDIO_WAVFILE="$(abspath "${OPTARG#*=}")";; 147 build-debug) BUILD_DEBUG=1;; 148 debugger) DEBUGGER=1;; 149 disktype=*) DISKTYPE=${OPTARG#*=};; 150 diskfmt=*) DISKFMT=${OPTARG#*=};; 151 no-serial) SERIAL=0;; 152 vnc=*) VNC=${OPTARG#*=};; 153 *) 154 echo unrecognized long option 155 HELP 156 ;; 157 esac 158 ;; 159 esac 160done 161shift $((OPTIND-1)) 162 163# arch argument is non optional 164if [[ -z $ARCH ]]; then 165 echo must specify arch 166 HELP 167fi 168 169PROJECT="$ARCH" 170 171BUILDDIR_SUFFIX= 172BUILD_ARGS= 173 174if (( $ASAN )); then 175 BUILDDIR_SUFFIX+=-asan 176 BUILD_ARGS+=' -A' 177elif (( $LTO )); then 178 BUILDDIR_SUFFIX+=-lto 179 BUILD_ARGS+=' -L' 180elif (( $THINLTO )); then 181 BUILDDIR_SUFFIX+=-thinlto 182 BUILD_ARGS+=' -l' 183elif (( $PROFILE )); then 184 BUILDDIR_SUFFIX+=-profile 185 BUILD_ARGS+=' -P' 186elif (( $CLANG )); then 187 BUILDDIR_SUFFIX+=-clang 188 BUILD_ARGS+=' -C' 189fi 190 191if (( $RELEASE )); then 192 BUILDDIR_SUFFIX+=-release 193 BUILD_ARGS+=' -r' 194fi 195 196if (( $BUILD_DEBUG )); then 197 BUILD=1 198 BUILD_ARGS+=' -d' 199fi 200 201# build the project if asked for 202if (( $BUILD )); then 203 # DIR is zircon/scripts, we need to make inside zircon. 204 $DIR/build-zircon -a $ARCH $BUILD_ARGS -- -C "$DIR/.." || exit 1 205fi 206 207# by default use the qemu binary located in the fuchsia buildtools 208# repo if we can find it, but allow -q to override it for people 209# who want to use their own. 210case "$(uname -s)" in 211 Darwin) 212 readonly HOST_PLATFORM="mac-x64" 213 ;; 214 Linux) 215 readonly HOST_PLATFORM="linux-x64" 216 ;; 217esac 218 219if [[ -z $QEMUDIR && -d "$DIR/../prebuilt/downloads/qemu/bin" ]]; then 220 QEMUDIR="$DIR/../prebuilt/downloads/qemu/bin/" 221fi 222 223if [[ -z $BUILDDIR ]]; then 224 BUILDDIR="$(dirname "$DIR")/build-$PROJECT$BUILDDIR_SUFFIX" 225fi 226 227if [[ -z "$QEMU_INITRD" ]]; then 228 QEMU_INITRD="$(abspath "$BUILDDIR/zircon.zbi")" 229fi 230 231if [[ -z "$QEMU_KERNEL" ]]; then 232 case $ARCH in 233 arm64) QEMU_KERNEL="$(abspath "$BUILDDIR/qemu-boot-shim.bin")" ;; 234 x64) QEMU_KERNEL="$(abspath "$BUILDDIR/multiboot.bin")" ;; 235 *) 236 echo >&2 "No QEMU trampoline for $ARCH" 237 exit 2 238 ;; 239 esac 240fi 241 242if (( $BUILD )); then 243 if [[ -n "$QEMU_INITRD" && "$QEMU_INITRD" != $BUILDDIR/* ]]; then 244 echo >&2 "WARNING: ZBI $QEMU_INITRD not in $BUILDDIR just built" 245 fi 246 if [[ -n "$QEMU_KERNEL" && "$QEMU_KERNEL" != $BUILDDIR/* ]]; then 247 echo >&2 "WARNING: trampoline $QEMU_KERNEL not in $BUILDDIR just built" 248 fi 249fi 250 251# construct the args for qemu 252ARGS=" -m $MEMSIZE" 253if [[ -n $VNC ]]; then 254 ARGS+=" -vnc $VNC" 255fi 256 257if (( !$GRAPHICS )); then 258 ARGS+=" -nographic" 259else 260 ARGS+=" -serial stdio" 261 if [[ "$ARCH" == "x64" && $VIRTIO == 0 ]]; then 262 # Enable Bochs VBE device, which Zircon has a device for 263 ARGS+=" -vga std" 264 else 265 # use the virtio gpu for display 266 ARGS+=" -vga none" 267 ARGS+=" -device virtio-gpu-pci" 268 fi 269fi 270 271if (( $DISK )); then 272 # if disktype wasn't set on the command line, default to ahci unless VIRTIO is set 273 if [[ -z $DISKTYPE ]]; then 274 if (( $VIRTIO )); then 275 DISKTYPE="virtio" 276 else 277 DISKTYPE="ahci" 278 fi 279 fi 280 281 ARGS+=" -drive file=${DISKFILE},format=${DISKFMT},if=none,id=mydisk" 282 if [[ "$DISKTYPE" == "virtio" ]]; then 283 ARGS+=" -device virtio-blk-pci,drive=mydisk" 284 elif [[ "$DISKTYPE" == "ahci" ]]; then 285 ARGS+=" -device ich9-ahci,id=ahci -device ide-drive,drive=mydisk,bus=ahci.0" 286 elif [[ "$DISKTYPE" == "nvme" ]]; then 287 ARGS+=" -device nvme,drive=mydisk,serial=zircon" 288 else 289 echo unrecognized disk type \"$DISKTYPE\" 290 exit 291 fi 292fi 293 294ahcinum=1 295for ahcifile in ${AHCI[@]}; do 296 ARGS+=" -drive file=${ahcifile},format=raw,if=none,id=ahcidisk${ahcinum}" 297 ARGS+=" -device ich9-ahci,id=ahci${ahcinum}" 298 ARGS+=" -device ide-drive,drive=ahcidisk${ahcinum},bus=ahci.${ahcinum}" 299 ahcinum=$((ahcinum + 1)) 300done 301 302if (( !$NET )); then 303 ARGS+=" -net none" 304fi 305 306if [[ $NET == 1 ]]; then 307 ARGS+=" -netdev type=user,hostname=$IFNAME,id=net0" 308fi 309 310if [[ $NET == 2 ]]; then 311 if [[ "$(uname -s)" == "Darwin" ]]; then 312 if [[ ! -c "/dev/$IFNAME" ]]; then 313 echo "To use qemu with networking on macOS, install the tun/tap driver:" 314 echo "http://tuntaposx.sourceforge.net/download.xhtml" 315 exit 1 316 fi 317 if [[ ! -w "/dev/$IFNAME" ]]; then 318 echo "For networking /dev/$IFNAME must be owned by $USER. Please run:" 319 echo " sudo chown $USER /dev/$IFNAME" 320 exit 1 321 fi 322 ARGS+=" -netdev type=tap,ifname=$IFNAME,script=$UPSCRIPT,downscript=no,id=net0" 323 else 324 CHECK=$(tunctl -b -u $USER -t $IFNAME 2>/dev/null) 325 if [[ "$CHECK" != "$IFNAME" ]]; then 326 echo "To use qemu with networking on Linux, configure tun/tap:" 327 if [[ ! -x "/usr/sbin/tunctl" ]]; then 328 echo "sudo apt-get install uml-utilities" 329 fi 330 echo "sudo tunctl -u $USER -t $IFNAME" 331 echo "sudo ifconfig $IFNAME up" 332 exit 1 333 fi 334 ARGS+=" -netdev type=tap,ifname=$IFNAME,script=$UPSCRIPT,downscript=no,id=net0" 335 fi 336fi 337 338if (( $NET )); then 339 MAC="" 340 if [[ $NET == 2 ]]; then 341 HASH=$(echo $IFNAME | shasum) 342 SUFFIX=$(for i in {0..2}; do echo -n :${HASH:$(( 2 * $i )):2}; done) 343 MAC=",mac=52:54:00$SUFFIX" 344 fi 345 if [[ "$ARCH" == "x64" ]] && [[ $VIRTIO == 0 ]]; then 346 ARGS+=" -device e1000,netdev=net0${MAC}" 347 else 348 ARGS+=" -device virtio-net-pci,netdev=net0${MAC}" 349 fi 350fi 351 352if [[ -n $AUDIO ]]; then 353 ARGS+=" -soundhw hda" 354 export QEMU_AUDIO_DRV=$AUDIO 355 export QEMU_AUDIO_DAC_FIXED_FREQ=48000 356 export QEMU_AUDIO_TIMER_PERIOD=20 357 358 case $AUDIO in 359 none) ;; 360 alsa) ;; 361 pa) ;; 362 wav) 363 export QEMU_WAV_FREQUENCY=48000 364 export QEMU_WAV_PATH=${AUDIO_WAVFILE} 365 ;; 366 *) 367 echo unrecognized QEMU host audio driver \"$AUDIO\" 368 exit 369 ;; 370 esac 371fi 372 373if [[ $SMP != 1 ]]; then 374 ARGS+=" -smp $SMP" 375 if [[ "$ARCH" == "x64" ]]; then 376 ARGS+=",threads=2" 377 fi 378fi 379 380# start a few extra harmless virtio devices that can be ignored 381if (( $VIRTIO )); then 382 ARGS+=" -device virtio-serial-pci" 383 ARGS+=" -device virtio-rng-pci" 384 ARGS+=" -device virtio-mouse-pci" 385 ARGS+=" -device virtio-keyboard-pci" 386fi 387 388if (( $DEBUGGER )); then 389 ARGS+=" -s -S" 390fi 391 392case $ARCH in 393 arm64) 394 QEMU=${QEMUDIR}qemu-system-aarch64 395 if (( $DO_KVM )); then 396 ARGS+=" -enable-kvm -cpu host" 397 GIC=host 398 else 399 ARGS+=" -machine virtualization=true -cpu cortex-a53" 400 fi 401 ARGS+=" -machine virt" 402 # append a gic version to the machine specifier 403 if [[ $GIC != 0 ]]; then 404 ARGS+=",gic_version=${GIC}" 405 fi 406 407 if (( !$SERIAL )); then 408 CMDLINE+="kernel.serial=none " 409 fi 410 ;; 411 x64) 412 QEMU=${QEMUDIR}qemu-system-x86_64 413 ARGS+=" -machine q35" 414 ARGS+=" -device isa-debug-exit,iobase=0xf4,iosize=0x04" 415 if (( $DO_KVM )); then 416 ARGS+=" -enable-kvm -cpu host,migratable=no,+invtsc" 417 else 418 ARGS+=" -cpu Haswell,+smap,-check,-fsgsbase" 419 fi 420 421 if (( $SERIAL )); then 422 CMDLINE+="kernel.serial=legacy " 423 else 424 CMDLINE+="kernel.serial=none " 425 fi 426 ;; 427 *) 428 echo unsupported arch 429 HELP 430 ;; 431esac 432 433# Propagate our TERM environment variable as a kernel command line 434# argument. This is last so that an explicit -c TERM=foo argument 435# goes into CMDLINE first. Kernel command line words become environment 436# variables, and the first variable in the list wins for getenv calls. 437if [[ -n $TERM ]]; then 438 CMDLINE+="TERM=$TERM " 439fi 440 441# Add entropy to the kernel 442CMDLINE+="kernel.entropy-mixin=$(head -c 32 /dev/urandom | shasum -a 256 | awk '{ print $1 }') " 443 444# Don't 'reboot' the emulator if the kernel crashes 445CMDLINE+="kernel.halt-on-panic=true " 446 447CMDLINE="`echo "$CMDLINE" | sed 's/,/,,/g'`" 448 449# run qemu 450echo CMDLINE: $CMDLINE 451cd / 452set -x 453exec $QEMU -kernel "$QEMU_KERNEL" -initrd "$QEMU_INITRD" \ 454 $ARGS -append "$CMDLINE" "$@" 455