| #!/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" "$@" |