| #!/usr/bin/env bash | |
| # Copyright 2016 The Fuchsia Authors | |
| # | |
| # Use of this source code is governed by a MIT-style | |
| # license that can be found in the LICENSE file or at | |
| # https://opensource.org/licenses/MIT | |
| function HELP { | |
| echo "help:" | |
| echo "-a <arch> : arm64, or x86" | |
| echo "-b : build first" | |
| echo "-c <text> : add item to kernel commandline" | |
| echo "-C : use Clang build" | |
| echo "-A : use ASan build" | |
| echo "-L : use LTO build" | |
| echo "-l : use ThinLTO build" | |
| echo "-d : run with emulated disk" | |
| echo "-D <disk file|device>: specify disk file or device path on host, default is blk.bin" | |
| echo "--disktype[=<type>] : should be one of (ahci, virtio, nvme), default is ahci" | |
| echo "--diskfmt[=<format>] : disk format (raw, qcow2, etc), default is raw" | |
| echo "-g : use graphical console" | |
| echo "-G <version> : use GIC v2 or v3" | |
| echo "-I <interface name> : network interface name, default is qemu." | |
| echo "-k : use KVM" | |
| echo "-m <memory in MB> : memory size, default is ${MEMSIZE_DEFAULT}MB" | |
| echo "-n : run with emulated nic" | |
| echo "-N : run with emulated nic via tun/tap" | |
| echo "-o <dir> : build directory" | |
| echo "-q <directory> : location of qemu, defaults to looking in ../buildtools/qemu/bin, then \$PATH" | |
| echo "-r : run release build" | |
| echo "-s <number of cpus> : number of cpus, 1 for uniprocessor, default is 4" | |
| echo "-u <path> : execute qemu startUp script, default is no script" | |
| echo "-V : try to use virtio devices" | |
| echo "-x <bootdata> : use specified bootdata" | |
| echo "--audio[=<host_drv>] : use Intel HD Audio" | |
| echo " : <host_drv> should be one of (alsa, pa, wav, none)" | |
| echo "--debugger : Enable gdb stub and wait for connection" | |
| echo "--vnc=<display> : use vnc based display" | |
| echo "--wavfile=<file> : When audio host_drv == wav, output to the specified WAV file" | |
| echo "-h for help" | |
| echo "all arguments after -- are passed to qemu directly" | |
| exit 1 | |
| } | |
| DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | |
| ARCH= | |
| ASAN=0 | |
| AUDIO= | |
| AUDIO_WAVFILE="/tmp/qemu.wav" | |
| BUILD=0 | |
| CLANG=0 | |
| DEBUGGER=0 | |
| DISK=0 | |
| DISKFILE="blk.bin" | |
| DISKTYPE= | |
| DISKFMT="raw" | |
| BUILDDIR= | |
| GIC=0 | |
| GRAPHICS=0 | |
| DO_KVM=0 | |
| LTO=0 | |
| THINLTO=0 | |
| MEMSIZE_DEFAULT=2048 | |
| MEMSIZE=$MEMSIZE_DEFAULT | |
| NET=0 | |
| QEMUDIR= | |
| RELEASE=0 | |
| UPSCRIPT=no | |
| VNC= | |
| VIRTIO=0 | |
| SMP=4 | |
| INITRD= | |
| CMDLINE="" | |
| if [[ "$(uname -s)" == "Darwin" ]]; then | |
| IFNAME="tap0" | |
| else | |
| IFNAME="qemu" | |
| fi | |
| while getopts "Aa:bc:CdD:gG:I:kLlm:nNo:q:rs:u:Vx:h-:" FLAG; do | |
| case $FLAG in | |
| A) ASAN=1;; | |
| a) ARCH=$OPTARG;; | |
| b) BUILD=1;; | |
| c) CMDLINE+="$OPTARG ";; | |
| C) CLANG=1;; | |
| d) DISK=1;; | |
| D) DISKFILE=$OPTARG;; | |
| g) GRAPHICS=1;; | |
| G) GIC=$OPTARG;; | |
| I) IFNAME=$OPTARG;; | |
| k) DO_KVM=1;; | |
| L) LTO=1;; | |
| l) THINLTO=1;; | |
| m) MEMSIZE=$OPTARG;; | |
| n) NET=1;; | |
| N) NET=2;; | |
| o) BUILDDIR=$OPTARG;; | |
| q) QEMUDIR=${OPTARG}/;; | |
| r) RELEASE=1;; | |
| s) SMP=$OPTARG;; | |
| u) UPSCRIPT=$OPTARG;; | |
| V) VIRTIO=1;; | |
| x) INITRD=$OPTARG;; | |
| h) HELP;; | |
| \?) | |
| echo unrecognized option | |
| HELP | |
| ;; | |
| -) | |
| case $OPTARG in | |
| audio) AUDIO=none;; | |
| audio=*) AUDIO=${OPTARG#*=};; | |
| wavfile=*) AUDIO_WAVFILE=${OPTARG#*=};; | |
| debugger) DEBUGGER=1;; | |
| disktype=*) DISKTYPE=${OPTARG#*=};; | |
| diskfmt=*) DISKFMT=${OPTARG#*=};; | |
| vnc=*) VNC=${OPTARG#*=};; | |
| *) | |
| echo unrecognized long option | |
| HELP | |
| ;; | |
| esac | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND-1)) | |
| # arch argument is non optional | |
| if [[ -z $ARCH ]]; then | |
| echo must specify arch | |
| HELP | |
| fi | |
| PROJECT="$ARCH" | |
| BUILDDIR_SUFFIX= | |
| BUILD_ARGS= | |
| if (( $ASAN )); then | |
| BUILDDIR_SUFFIX+=-asan | |
| # at the moment asan implies clang | |
| BUILD_ARGS+=' USE_ASAN=true USE_CLANG=true' | |
| elif (( $LTO )); then | |
| BUILDDIR_SUFFIX+=-lto | |
| BUILD_ARGS+=' USE_LTO=true' | |
| elif (( $THINLTO )); then | |
| BUILDDIR_SUFFIX+=-thinlto | |
| BUILD_ARGS+=' USE_THINLTO=true' | |
| elif (( $CLANG )); then | |
| BUILDDIR_SUFFIX+=-clang | |
| BUILD_ARGS+=' USE_CLANG=true' | |
| fi | |
| if (( $RELEASE )); then | |
| BUILDDIR_SUFFIX+=-release | |
| BUILD_ARGS+=' DEBUG=0' | |
| fi | |
| # build the project if asked for | |
| if (( $BUILD )); then | |
| # DIR is zircon/scripts, we need to make inside zircon. | |
| $DIR/make-parallel -C "$DIR/.." $PROJECT $BUILD_ARGS || exit 1 | |
| fi | |
| # by default use the qemu binary located in the fuchsia buildtools | |
| # repo if we can find it, but allow -q to override it for people | |
| # who want to use their own. | |
| case "$(uname -s)" in | |
| Darwin) | |
| readonly HOST_PLATFORM="mac-x64" | |
| ;; | |
| Linux) | |
| readonly HOST_PLATFORM="linux-x64" | |
| ;; | |
| esac | |
| if [[ -z $QEMUDIR && -d "$DIR/../../buildtools/${HOST_PLATFORM}/qemu/bin" ]]; then | |
| QEMUDIR="$DIR/../../buildtools/${HOST_PLATFORM}/qemu/bin/" | |
| fi | |
| if [[ -z $BUILDDIR ]]; then | |
| BUILDDIR="$(dirname "$DIR")/build-$PROJECT$BUILDDIR_SUFFIX" | |
| fi | |
| # construct the args for qemu | |
| ARGS=" -m $MEMSIZE" | |
| if [[ -n $VNC ]]; then | |
| ARGS+=" -vnc $VNC" | |
| fi | |
| if (( !$GRAPHICS )); then | |
| ARGS+=" -nographic" | |
| else | |
| ARGS+=" -serial stdio" | |
| if [[ "$ARCH" == "x86" && $VIRTIO == 0 ]]; then | |
| # Enable Bochs VBE device, which Zircon has a device for | |
| ARGS+=" -vga std" | |
| else | |
| # use the virtio gpu for display | |
| ARGS+=" -vga none" | |
| ARGS+=" -device virtio-gpu-pci" | |
| fi | |
| fi | |
| if (( $DISK )); then | |
| # if disktype wasn't set on the command line, default to ahci unless VIRTIO is set | |
| if [[ -z $DISKTYPE ]]; then | |
| if (( $VIRTIO )); then | |
| DISKTYPE="virtio" | |
| else | |
| DISKTYPE="ahci" | |
| fi | |
| fi | |
| ARGS+=" -drive file=${DISKFILE},format=${DISKFMT},if=none,id=mydisk" | |
| if [[ "$DISKTYPE" == "virtio" ]]; then | |
| ARGS+=" -device virtio-blk-pci,drive=mydisk" | |
| elif [[ "$DISKTYPE" == "ahci" ]]; then | |
| ARGS+=" -device ich9-ahci,id=ahci -device ide-drive,drive=mydisk,bus=ahci.0" | |
| elif [[ "$DISKTYPE" == "nvme" ]]; then | |
| ARGS+=" -device nvme,drive=mydisk,serial=zircon" | |
| else | |
| echo unrecognized disk type \"$DISKTYPE\" | |
| exit | |
| fi | |
| fi | |
| if (( !$NET )); then | |
| ARGS+=" -net none" | |
| fi | |
| if [[ $NET == 1 ]]; then | |
| ARGS+=" -netdev type=user,hostname=$IFNAME,id=net0" | |
| fi | |
| if [[ $NET == 2 ]]; then | |
| if [[ "$(uname -s)" == "Darwin" ]]; then | |
| if [[ ! -c "/dev/$IFNAME" ]]; then | |
| echo "To use qemu with networking on macOS, install the tun/tap driver:" | |
| echo "http://tuntaposx.sourceforge.net/download.xhtml" | |
| exit 1 | |
| fi | |
| if [[ ! -w "/dev/$IFNAME" ]]; then | |
| echo "For networking /dev/$IFNAME must be owned by $USER. Please run:" | |
| echo " sudo chown $USER /dev/$IFNAME" | |
| exit 1 | |
| fi | |
| ARGS+=" -netdev type=tap,ifname=$IFNAME,script=$UPSCRIPT,downscript=no,id=net0" | |
| else | |
| CHECK=$(tunctl -b -u $USER -t $IFNAME 2>/dev/null) | |
| if [[ "$CHECK" != "$IFNAME" ]]; then | |
| echo "To use qemu with networking on Linux, configure tun/tap:" | |
| if [[ ! -x "/usr/sbin/tunctl" ]]; then | |
| echo "sudo apt-get install uml-utilities" | |
| fi | |
| echo "sudo tunctl -u $USER -t $IFNAME" | |
| echo "sudo ifconfig $IFNAME up" | |
| exit 1 | |
| fi | |
| ARGS+=" -netdev type=tap,ifname=$IFNAME,script=$UPSCRIPT,downscript=no,id=net0" | |
| fi | |
| fi | |
| if (( $NET )); then | |
| MAC="" | |
| if [[ $NET == 2 ]]; then | |
| HASH=$(echo $IFNAME | shasum) | |
| SUFFIX=$(for i in {0..2}; do echo -n :${HASH:$(( 2 * $i )):2}; done) | |
| MAC=",mac=52:54:00$SUFFIX" | |
| fi | |
| if [[ "$ARCH" == "x86" ]] && [[ $VIRTIO == 0 ]]; then | |
| ARGS+=" -device e1000,netdev=net0${MAC}" | |
| else | |
| ARGS+=" -device virtio-net-pci,netdev=net0${MAC}" | |
| fi | |
| fi | |
| if [[ -n $AUDIO ]]; then | |
| ARGS+=" -soundhw hda" | |
| export QEMU_AUDIO_DRV=$AUDIO | |
| export QEMU_AUDIO_DAC_FIXED_FREQ=48000 | |
| export QEMU_AUDIO_TIMER_PERIOD=20 | |
| case $AUDIO in | |
| none) ;; | |
| alsa) ;; | |
| pa) ;; | |
| wav) | |
| export QEMU_WAV_FREQUENCY=48000 | |
| export QEMU_WAV_PATH=${AUDIO_WAVFILE} | |
| ;; | |
| *) | |
| echo unrecognized QEMU host audio driver \"$AUDIO\" | |
| exit | |
| ;; | |
| esac | |
| fi | |
| if [[ $SMP != 1 ]]; then | |
| ARGS+=" -smp $SMP" | |
| if [[ "$ARCH" == "x86" ]]; then | |
| ARGS+=",threads=2" | |
| fi | |
| fi | |
| # start a few extra harmless virtio devices that can be ignored | |
| if (( $VIRTIO )); then | |
| ARGS+=" -device virtio-serial-pci" | |
| ARGS+=" -device virtio-rng-pci" | |
| ARGS+=" -device virtio-mouse-pci" | |
| ARGS+=" -device virtio-keyboard-pci" | |
| fi | |
| if (( $DEBUGGER )); then | |
| ARGS+=" -s -S" | |
| fi | |
| case $ARCH in | |
| arm64) | |
| QEMU=${QEMUDIR}qemu-system-aarch64 | |
| ARGS+=" -kernel $BUILDDIR/zircon.bin" | |
| if (( $DO_KVM )); then | |
| ARGS+=" -enable-kvm -cpu host" | |
| if [[ $GIC == 0 ]]; then | |
| # if the gic isn't overridden, default to 'host' | |
| GIC=host | |
| fi | |
| else | |
| ARGS+=" -machine virtualization=true -cpu cortex-a53" | |
| fi | |
| ARGS+=" -machine virt" | |
| # append a gic version to the machine specifier | |
| if [[ $GIC != 0 ]]; then | |
| ARGS+=",gic_version=${GIC}" | |
| fi | |
| ;; | |
| x86) | |
| QEMU=${QEMUDIR}qemu-system-x86_64 | |
| ARGS+=" -machine q35 -kernel $BUILDDIR/zircon.bin" | |
| if (( $DO_KVM )); then | |
| ARGS+=" -enable-kvm -cpu host,migratable=no" | |
| else | |
| ARGS+=" -cpu Haswell,+smap,-check,-fsgsbase" | |
| fi | |
| ;; | |
| *) | |
| echo unsupported arch | |
| HELP | |
| ;; | |
| esac | |
| # ramdisk image | |
| if [[ -n $INITRD ]]; then | |
| ARGS+=" -initrd $INITRD" | |
| elif [[ -f "$BUILDDIR/bootdata.bin" ]]; then | |
| ARGS+=" -initrd $BUILDDIR/bootdata.bin" | |
| fi | |
| # Propagate our TERM environment variable as a kernel command line | |
| # argument. This is last so that an explicit -c TERM=foo argument | |
| # goes into CMDLINE first. Kernel command line words become environment | |
| # variables, and the first variable in the list wins for getenv calls. | |
| if [[ -n $TERM ]]; then | |
| CMDLINE+="TERM=$TERM " | |
| fi | |
| # Add entropy to the kernel | |
| CMDLINE+="kernel.entropy-mixin=$(head -c 32 /dev/urandom | shasum -a 256 | awk '{ print $1 }') " | |
| # Don't 'reboot' the emulator if the kernel crashes | |
| CMDLINE+="kernel.halt-on-panic=true " | |
| CMDLINE="`echo "$CMDLINE" | sed 's/,/,,/g'`" | |
| # run qemu | |
| set -x | |
| echo CMDLINE: $CMDLINE | |
| exec $QEMU $ARGS -append "$CMDLINE" "$@" |