#!/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>           : arm32, arm64, or x86-64"
    echo "-A                  : use Intel HD Audio"
    echo "-b                  : build first"
    echo "-c                  : add item to kernel commandline"
    echo "-C                  : use Clang build"
    echo "-d                  : run with emulated disk"
    echo "-g                  : use graphical console"
    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 on \$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                  : use vnc based display"
    echo "-V                  : try to use virtio devices"
    echo "-x <bootfs>         : add eXtra bootfs"
    echo "-h for help"
    echo "all arguments after -- are passed to qemu directly"
    exit 1
}

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

ARCH=
AUDIO=0
BUILD=0
CLANG=0
DISK=0
BUILDDIR=
GRAPHICS=0
DO_KVM=0
MEMSIZE_DEFAULT=2048
MEMSIZE=$MEMSIZE_DEFAULT
NET=0
QEMUDIR=
RELEASE=0
UPSCRIPT=no
VNC=0
VIRTIO=0
SMP=4
INITRD=
CMDLINE=""

if [ $(uname -s) == "Darwin" ]; then
  IFNAME="tap0"
else
  IFNAME="qemu"
fi

while getopts a:Abc:CdgI:km:nNo:q:rs:u:vVx:h FLAG; do
    case $FLAG in
        a) ARCH=$OPTARG;;
        A) AUDIO=1;;
        b) BUILD=1;;
        c) CMDLINE+="$OPTARG ";;
        C) CLANG=1;;
        d) DISK=1;;
        g) GRAPHICS=1;;
        I) IFNAME=$OPTARG;;
        k) DO_KVM=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) VNC=1;;
        V) VIRTIO=1;;
        x) INITRD=$OPTARG;;
        h) HELP;;
        \?)
            echo unrecognized option
            HELP
    esac
done
shift $((OPTIND-1))

# arch argument is non optional
if [ "$ARCH" == "" ]; then
    echo must specify arch
    HELP
fi

if [ "$ARCH" = "x86-64" ]; then
    PROJECT=magenta-pc-x86-64
else
    PROJECT=magenta-qemu-$ARCH
fi

if [ "$CLANG" -eq 1 ]; then
    BUILDDIR_SUFFIX=-clang
    BUILD_ARGS=USE_CLANG=true
else
    BUILDDIR_SUFFIX=
    BUILD_ARGS=
fi

# build the project if asked for
if [ "$BUILD" -eq 1 ]; then
    if [ "$RELEASE" -eq 1 ]; then
        $DIR/make-release $PROJECT $BUILD_ARGS || exit 1
    else
        $DIR/make-parallel $PROJECT $BUILD_ARGS || exit 1
    fi
fi

# append the release path if requested
if [ "$RELEASE" -eq 1 ]; then
    PROJECT=$PROJECT-release
fi

if [ "$BUILDDIR" == "" ]; then
  BUILDDIR="$(dirname "$DIR")/build-$PROJECT$BUILDDIR_SUFFIX"
fi

# construct the args for qemu
ARGS=" -m $MEMSIZE"
if [ "$VNC" -eq 1 ]; then
    ARGS+=" -vnc :0"
fi

if [ "$GRAPHICS" -eq 0 ]; then
    ARGS+=" -nographic"
else
    ARGS+=" -serial stdio"
    if [ "$ARCH" = "x86-64" ] && [ "$VIRTIO" -eq 0 ]; then
        # Enable Bochs VBE device, which Magenta 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" -eq 1 ]; then
    ARGS+=" -drive file=blk.bin,format=raw,if=none,id=mydisk"
    if [ "$ARCH" == "x86-64" ] && [ "$VIRTIO" -eq 0 ]; then
        # ahci
        ARGS+=" -device ich9-ahci,id=ahci -device ide-drive,drive=mydisk,bus=ahci.0"
    else
        # virtio based block device, pci, transitional
        ARGS+=" -device virtio-blk-pci,disable-modern=true,drive=mydisk"
    fi
fi

if [ "$NET" -eq 0 ]; then
  ARGS+=" -net none"
fi

if [ "$NET" -eq 1 ]; then
    ARGS+=" -netdev type=user,hostname=$IFNAME,id=net0"
fi

if [ "$NET" -eq 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:"
          echo "sudo apt-get install uml-utilities"
          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" -ne 0 ]; then
    if [ "$ARCH" == "x86-64" ] && [ "$VIRTIO" -eq 0 ]; then
        ARGS+=" -device e1000,netdev=net0"
    else
        ARGS+=" -device virtio-net-pci,netdev=net0"
    fi
fi

if [ "$AUDIO" -ne 0 ]; then
    ARGS+=" -soundhw hda"
    export QEMU_AUDIO_DRV=none
fi

if [ "$SMP" -ne 1 ]; then
    ARGS+=" -smp $SMP"
fi

# start a few extra harmless virtio devices that can be ignored
if [ "$VIRTIO" -ne 0 ]; then
    ARGS+=" -device virtio-serial-pci"
    ARGS+=" -device virtio-rng-pci"
    ARGS+=" -device virtio-mouse-pci"
    ARGS+=" -device virtio-keyboard-pci"
fi

case $ARCH in
    arm32)
        QEMU=${QEMUDIR}qemu-system-arm
        ARGS+=" -machine virt -cpu cortex-a15 -kernel $BUILDDIR/magenta.elf"
        ;;
    arm64)
        QEMU=${QEMUDIR}qemu-system-aarch64
        ARGS+=" -machine virt -cpu cortex-a53 -kernel $BUILDDIR/magenta.elf"
        ;;
    x86-64)
        QEMU=${QEMUDIR}qemu-system-x86_64
        ARGS+=" -machine q35 -kernel $BUILDDIR/magenta.bin"
        if [ $DO_KVM -ne 0 ]; then
          ARGS+=" -enable-kvm -cpu host"
        else
          ARGS+=" -cpu Haswell,+smap"
        fi
        ;;
    *)
        echo unsupported arch
        HELP
        ;;
esac

# ramdisk image
if [ "$INITRD" != "" ]; then
    ARGS+=" -initrd $INITRD"
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 [ "$TERM" != "" ]; then
    CMDLINE+="TERM=$TERM "
fi

# run qemu
echo $QEMU $ARGS -append "$CMDLINE" $@
$QEMU $ARGS -append "$CMDLINE" $@
