| #!/usr/bin/env bash |
| |
| DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
| . "$DIR/qemu-shared.sh" |
| |
| function HELP { |
| local ec=${1:-0} |
| echo "help:" |
| echo "-6 : x86-64" |
| echo "-l : legacy mode build (386 emulated machine)" |
| echo "-m <memory in MB> : memory size (default: 512 MB, 4 MB for legacy)" |
| echo "-s <number of cpus> : number of CPUs (default: 1)" |
| echo "-X : print QEMU command and exit (dry run)" |
| echo |
| echo "-A <cmd line> : append command line (may be used multiple times)" |
| echo "-d <disk image> : add an IDE disk device (may be used multiple times)" |
| echo "-g : with graphics (VGA display, keyboard, mouse)" |
| echo "-n : enable user mode networking (default driver: e1000e)" |
| echo "-N <network driver> : specify network driver (requires -n or -t, e.g., virtio-net-pci, e1000e)" |
| echo "-t : use tap interface qemu0 for networking" |
| echo "-f <shared dir> : add a virtio 9p device with a host shared directory" |
| echo "-V : use virtio versions of devices where possible" |
| echo "-k : use KVM acceleration" |
| echo |
| echo "-h : show this help" |
| echo "all arguments after -- are passed to qemu directly" |
| exit $ec |
| } |
| |
| DO_64BIT=0 |
| DO_LEGACY=0 |
| DO_GRAPHICS=0 |
| DO_KVM=0 |
| DISK_IMAGES=() |
| CMDLINE="" |
| DO_NET=0 |
| DO_NET_TAP=0 |
| DO_VIRTIO=0 |
| DO_V9P=0 |
| DO_V9P_DIR="" |
| NETDEV=e1000e |
| DO_NETDEV_OVERRIDE=0 |
| MEMSIZE=0 |
| SMP=1 |
| SUDO="" |
| DO_DRYRUN=0 |
| |
| while getopts A:6d:gf:klm:nN:s:thVX FLAG; do |
| case $FLAG in |
| A) CMDLINE+="${CMDLINE:+ }$(quote_cmdline_arg "$OPTARG")";; |
| 6) DO_64BIT=1;; |
| d) |
| DISK_IMAGES+=("$OPTARG") |
| ;; |
| g) DO_GRAPHICS=1;; |
| f) DO_V9P=1; DO_V9P_DIR=$OPTARG;; |
| k) DO_KVM=1;; |
| l) DO_LEGACY=1;; |
| m) MEMSIZE=$OPTARG;; |
| n) DO_NET=1;; |
| t) DO_NET_TAP=1;; |
| N) NETDEV=$OPTARG; DO_NETDEV_OVERRIDE=1;; |
| s) SMP=$OPTARG;; |
| V) DO_VIRTIO=1;; |
| X) DO_DRYRUN=1;; |
| h) HELP 0;; |
| \?) |
| echo unrecognized option $OPTARG |
| HELP 1 |
| esac |
| done |
| |
| shift $((OPTIND-1)) |
| |
| if (( DO_NET && DO_NET_TAP )); then |
| echo "Error: Cannot use both -n (user network) and -t (tap network) together" |
| exit 1 |
| fi |
| |
| if (( DO_NETDEV_OVERRIDE && ! ( DO_NET || DO_NET_TAP ) )); then |
| echo "Error: -N requires either -n (user network) or -t (tap network)" |
| exit 1 |
| fi |
| |
| # pick the appropriate qemu and project |
| if (( DO_64BIT )); then |
| QEMU="qemu-system-x86_64" |
| PROJECT="pc-x86-64-test" |
| CPU=max |
| MACHINE=q35 |
| elif (( DO_LEGACY )); then |
| QEMU="qemu-system-i386" |
| PROJECT="pc-x86-legacy-test" |
| CPU=486 |
| MACHINE=isapc |
| else |
| QEMU="qemu-system-i386" |
| PROJECT="pc-x86-test" |
| CPU=max |
| MACHINE=q35 |
| fi |
| |
| if (( DO_LEGACY )); then |
| if (( ! MEMSIZE )); then |
| MEMSIZE=4 |
| fi |
| else |
| if (( ! MEMSIZE )); then |
| MEMSIZE=512 |
| fi |
| fi |
| |
| VIRTIO_BLOCK_DEVICE="virtio-blk-pci" |
| VIRTIO_NET_DEVICE="virtio-net-pci" |
| VIRTIO_GPU_DEVICE="virtio-gpu-pci" |
| VIRTIO_KEYBOARD_DEVICE="virtio-keyboard-pci" |
| VIRTIO_MOUSE_DEVICE="virtio-mouse-pci" |
| VIRTIO_9P_DEVICE="virtio-9p-pci" |
| VIRTIO_RNG_DEVICE="virtio-rng-pci" |
| if (( DO_VIRTIO )); then |
| NETDEV=$VIRTIO_NET_DEVICE |
| fi |
| |
| |
| ARGS=() |
| if (( DO_KVM )); then |
| ARGS+=("-accel" "kvm" "-cpu" "host") |
| else |
| ARGS+=("-cpu" "$CPU") |
| fi |
| ARGS+=("-m" "$MEMSIZE") |
| ARGS+=("-smp" "$SMP") |
| ARGS+=("-machine" "$MACHINE") |
| ARGS+=("-kernel" "build-${PROJECT}/lk.elf") |
| |
| if [[ -n "$CMDLINE" ]]; then |
| ARGS+=("-append" "$CMDLINE") |
| fi |
| |
| ARGS+=("-device" "isa-debug-exit,iobase=0xf4,iosize=0x04") |
| ARGS+=("-fw_cfg" "name=etc/sercon-port,string=0") |
| |
| if (( DO_GRAPHICS )); then |
| ARGS+=("-serial" "stdio") |
| # TODO: get -vga virtio working |
| ARGS+=("-vga" "std") |
| if (( DO_VIRTIO )); then |
| # this will create an additional virtio GPU device for graphics output in addition |
| # to the primary VGA device |
| ARGS+=("-device" "${VIRTIO_GPU_DEVICE}") |
| ARGS+=("-device" "${VIRTIO_KEYBOARD_DEVICE}") |
| ARGS+=("-device" "${VIRTIO_MOUSE_DEVICE}") |
| fi |
| else |
| ARGS+=("-nographic") |
| fi |
| |
| function append_disk_image { |
| local disk_image=$1 |
| local disk_number=$2 |
| ARGS+=("-drive" "if=none,file=${disk_image},id=disk${disk_number},discard=on") |
| if (( DO_VIRTIO )); then |
| ARGS+=("-device" "${VIRTIO_BLOCK_DEVICE},drive=disk${disk_number}") |
| else |
| # for q35 machines this will add to an ahci controller |
| # for legacy machines will end up appending to the ISA ide controller |
| ARGS+=("-device" "ide-hd,drive=disk${disk_number},bus=ide.${disk_number}") |
| fi |
| } |
| |
| DISK_COUNT=0 |
| for img in "${DISK_IMAGES[@]}"; do |
| append_disk_image "$img" "$DISK_COUNT" |
| ((DISK_COUNT++)) |
| done |
| |
| if (( DO_NET || DO_NET_TAP )); then |
| if (( ! DO_LEGACY )); then |
| if (( DO_NET )); then |
| ARGS+=("-netdev" "user,id=vmnic,hostname=qemu") |
| elif (( DO_NET_TAP )); then |
| # quick note to enable tap interface |
| # IFNAME=qemu0 |
| # BRIDGE=bridge0 |
| # sudo ip tuntap add name "${IFNAME}" mode tap user $(whoami) |
| # sudo ip link set "${IFNAME}" master "${BRIDGE}" |
| # sudo ip link set "${IFNAME}" up |
| ARGS+=("-netdev" "tap,id=vmnic,ifname=qemu0,script=no,downscript=no") |
| #SUDO="sudo" |
| fi |
| ARGS+=("-device" "$NETDEV,netdev=vmnic") |
| else |
| echo "implement legacy + network config" |
| exit 1 |
| fi |
| else |
| ARGS+=("-net" "none") |
| fi |
| if (( DO_V9P )); then |
| ARGS+=("-fsdev" "local,path=$DO_V9P_DIR,security_model=mapped,id=v9p0") |
| ARGS+=("-device" "${VIRTIO_9P_DEVICE},fsdev=v9p0,mount_tag=V9P0") |
| fi |
| |
| if (( ! DO_LEGACY )); then |
| ARGS+=("-device" "${VIRTIO_RNG_DEVICE}") |
| fi |
| |
| CMD=() |
| if [[ -n "$SUDO" ]]; then |
| CMD+=("sudo") |
| fi |
| CMD+=("$QEMU") |
| CMD+=("${ARGS[@]}") |
| CMD+=("$@") |
| |
| if (( DO_DRYRUN )); then |
| echo "${CMD[@]}" |
| exit 0 |
| fi |
| |
| "$DIR"/make-parallel $PROJECT && |
| echo "${CMD[@]}" && |
| exec "${CMD[@]}" |