1248484Sneel#!/bin/sh 2248484Sneel# 3248484Sneel# Copyright (c) 2013 NetApp, Inc. 4248484Sneel# All rights reserved. 5248484Sneel# 6248484Sneel# Redistribution and use in source and binary forms, with or without 7248484Sneel# modification, are permitted provided that the following conditions 8248484Sneel# are met: 9248484Sneel# 1. Redistributions of source code must retain the above copyright 10248484Sneel# notice, this list of conditions and the following disclaimer. 11248484Sneel# 2. Redistributions in binary form must reproduce the above copyright 12248484Sneel# notice, this list of conditions and the following disclaimer in the 13248484Sneel# documentation and/or other materials provided with the distribution. 14248484Sneel# 15248484Sneel# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16248484Sneel# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17248484Sneel# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18248484Sneel# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19248484Sneel# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20248484Sneel# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21248484Sneel# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22248484Sneel# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23248484Sneel# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24248484Sneel# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25248484Sneel# SUCH DAMAGE. 26248484Sneel# 27248484Sneel# $FreeBSD: stable/11/share/examples/bhyve/vmrun.sh 335698 2018-06-27 07:18:54Z kib $ 28248484Sneel# 29248484Sneel 30248484SneelLOADER=/usr/sbin/bhyveload 31248484SneelBHYVECTL=/usr/sbin/bhyvectl 32248484SneelFBSDRUN=/usr/sbin/bhyve 33248484Sneel 34256176SneelDEFAULT_MEMSIZE=512M 35248484SneelDEFAULT_CPUS=2 36248484SneelDEFAULT_TAPDEV=tap0 37264837SjhbDEFAULT_CONSOLE=stdio 38248484Sneel 39329179SrgrimesDEFAULT_NIC=virtio-net 40329179SrgrimesDEFAULT_DISK=virtio-blk 41248484SneelDEFAULT_VIRTIO_DISK="./diskdev" 42248484SneelDEFAULT_ISOFILE="./release.iso" 43248484Sneel 44329179SrgrimesDEFAULT_VNCHOST="127.0.0.1" 45329179SrgrimesDEFAULT_VNCPORT=5900 46329179SrgrimesDEFAULT_VNCSIZE="w=1024,h=768" 47329179Srgrimes 48277309Sneelerrmsg() { 49277309Sneel echo "*** $1" 50277309Sneel} 51277309Sneel 52248484Sneelusage() { 53277309Sneel local msg=$1 54277309Sneel 55329179Srgrimes echo "Usage: vmrun.sh [-aAEhiTv] [-c <CPUs>] [-C <console>]" \ 56329179Srgrimes "[-d <disk file>]" 57329179Srgrimes echo " [-e <name=value>] [-f <path of firmware>]" \ 58329179Srgrimes "[-F <size>]" 59329178Srgrimes echo " [-g <gdbport> ] [-H <directory>]" 60289001Smarcel echo " [-I <location of installation iso>] [-l <loader>]" 61329178Srgrimes echo " [-L <VNC IP for UEFI framebuffer>]" 62329179Srgrimes echo " [-m <memsize>]" \ 63329179Srgrimes "[-n <network adapter emulation type>]" 64329179Srgrimes echo " [-P <port>] [-t <tapdev>] <vmname>" 65264837Sjhb echo "" 66248484Sneel echo " -h: display this help message" 67264837Sjhb echo " -a: force memory mapped local APIC access" 68329179Srgrimes echo " -A: use AHCI disk emulation instead of ${DEFAULT_DISK}" 69329179Srgrimes echo " -c: number of virtual cpus (default: ${DEFAULT_CPUS})" 70329179Srgrimes echo " -C: console device (default: ${DEFAULT_CONSOLE})" 71329179Srgrimes echo " -d: virtio diskdev file (default: ${DEFAULT_VIRTIO_DISK})" 72256657Sneel echo " -e: set FreeBSD loader environment variable" 73329178Srgrimes echo " -E: Use UEFI mode" 74329178Srgrimes echo " -f: Use a specific UEFI firmware" 75329179Srgrimes echo " -F: Use a custom UEFI GOP framebuffer size" \ 76329179Srgrimes "(default: ${DEFAULT_VNCSIZE}" 77248840Sneel echo " -g: listen for connection from kgdb at <gdbport>" 78264837Sjhb echo " -H: host filesystem to export to the loader" 79248484Sneel echo " -i: force boot of the Installation CDROM image" 80329179Srgrimes echo " -I: Installation CDROM image location" \ 81329179Srgrimes "(default: ${DEFAULT_ISOFILE})" 82329179Srgrimes echo " -l: the OS loader to use (default: /boot/userboot.so)" 83329179Srgrimes echo " -L: IP address for UEFI GOP VNC server" \ 84329179Srgrimes "(default: ${DEFAULT_VNCHOST}" 85329179Srgrimes echo " -m: memory size (default: ${DEFAULT_MEMSIZE})" 86329179Srgrimes echo " -n: network adapter emulation type" \ 87329179Srgrimes "(default: ${DEFAULT_NIC})" 88329179Srgrimes echo " -p: pass-through a host PCI device at bus/slot/func" \ 89329179Srgrimes "(e.g. 10/0/0)" 90329179Srgrimes echo " -P: UEFI GOP VNC port (default: ${DEFAULT_VNCPORT})" 91329179Srgrimes echo " -t: tap device for virtio-net (default: $DEFAULT_TAPDEV)" 92329178Srgrimes echo " -T: Enable tablet device (for UEFI GOP)" 93317303Srgrimes echo " -u: RTC keeps UTC time" 94329178Srgrimes echo " -v: Wait for VNC client connection before booting VM" 95317303Srgrimes echo " -w: ignore unimplemented MSRs" 96248484Sneel echo "" 97277309Sneel [ -n "$msg" ] && errmsg "$msg" 98248484Sneel exit 1 99248484Sneel} 100248484Sneel 101248484Sneelif [ `id -u` -ne 0 ]; then 102277309Sneel errmsg "This script must be executed with superuser privileges" 103277309Sneel exit 1 104248484Sneelfi 105248484Sneel 106248484Sneelkldstat -n vmm > /dev/null 2>&1 107248484Sneelif [ $? -ne 0 ]; then 108277309Sneel errmsg "vmm.ko is not loaded" 109248484Sneel exit 1 110248484Sneelfi 111248484Sneel 112248484Sneelforce_install=0 113248484Sneelisofile=${DEFAULT_ISOFILE} 114248484Sneelmemsize=${DEFAULT_MEMSIZE} 115264837Sjhbconsole=${DEFAULT_CONSOLE} 116248484Sneelcpus=${DEFAULT_CPUS} 117329179Srgrimesnic=${DEFAULT_NIC} 118267559Salfredtap_total=0 119267559Salfreddisk_total=0 120329179Srgrimesdisk_emulation=${DEFAULT_DISK} 121248840Sneelgdbport=0 122264837Sjhbloader_opt="" 123284539Sneelbhyverun_opt="-H -A -P" 124279925Sglebiuspass_total=0 125248484Sneel 126329178Srgrimes# EFI-specific options 127329178Srgrimesefi_mode=0 128329178Srgrimesefi_firmware="/usr/local/share/uefi-firmware/BHYVE_UEFI.fd" 129329178Srgrimesvncwait="" 130329179Srgrimesvnchost=${DEFAULT_VNCHOST} 131329179Srgrimesvncport=${DEFAULT_VNCPORT} 132329179Srgrimesvncsize=${DEFAULT_VNCSIZE} 133329178Srgrimestablet="" 134329178Srgrimes 135335698Skibwhile getopts aAc:C:d:e:Ef:F:g:hH:iI:l:L:m:n:p:P:t:Tuvw c ; do 136248484Sneel case $c in 137248484Sneel a) 138284539Sneel bhyverun_opt="${bhyverun_opt} -a" 139248484Sneel ;; 140327997Savg A) 141327997Savg disk_emulation="ahci-hd" 142327997Savg ;; 143264837Sjhb c) 144264837Sjhb cpus=${OPTARG} 145264837Sjhb ;; 146264837Sjhb C) 147264837Sjhb console=${OPTARG} 148264837Sjhb ;; 149248484Sneel d) 150284023Savg disk_dev=${OPTARG%%,*} 151284023Savg disk_opts=${OPTARG#${disk_dev}} 152284023Savg eval "disk_dev${disk_total}=\"${disk_dev}\"" 153284023Savg eval "disk_opts${disk_total}=\"${disk_opts}\"" 154267559Salfred disk_total=$(($disk_total + 1)) 155248484Sneel ;; 156256657Sneel e) 157264837Sjhb loader_opt="${loader_opt} -e ${OPTARG}" 158256657Sneel ;; 159329178Srgrimes E) 160329178Srgrimes efi_mode=1 161329178Srgrimes ;; 162329178Srgrimes f) 163329178Srgrimes efi_firmware="${OPTARG}" 164329178Srgrimes ;; 165329178Srgrimes F) 166329179Srgrimes vncsize="${OPTARG}" 167329178Srgrimes ;; 168264837Sjhb g) 169264837Sjhb gdbport=${OPTARG} 170248840Sneel ;; 171264837Sjhb H) 172264837Sjhb host_base=`realpath ${OPTARG}` 173264837Sjhb ;; 174248484Sneel i) 175248484Sneel force_install=1 176248484Sneel ;; 177248484Sneel I) 178248484Sneel isofile=${OPTARG} 179248484Sneel ;; 180289001Smarcel l) 181289001Smarcel loader_opt="${loader_opt} -l ${OPTARG}" 182289001Smarcel ;; 183329178Srgrimes L) 184329178Srgrimes vnchost="${OPTARG}" 185329178Srgrimes ;; 186248484Sneel m) 187248484Sneel memsize=${OPTARG} 188248484Sneel ;; 189329179Srgrimes n) 190329179Srgrimes nic=${OPTARG} 191329179Srgrimes ;; 192279925Sglebius p) 193279925Sglebius eval "pass_dev${pass_total}=\"${OPTARG}\"" 194279925Sglebius pass_total=$(($pass_total + 1)) 195279925Sglebius ;; 196329178Srgrimes P) 197329178Srgrimes vncport="${OPTARG}" 198329178Srgrimes ;; 199248484Sneel t) 200267559Salfred eval "tap_dev${tap_total}=\"${OPTARG}\"" 201267559Salfred tap_total=$(($tap_total + 1)) 202248484Sneel ;; 203329178Srgrimes T) 204329178Srgrimes tablet="-s 30,xhci,tablet" 205329178Srgrimes ;; 206317303Srgrimes u) 207317303Srgrimes bhyverun_opt="${bhyverun_opt} -u" 208317303Srgrimes ;; 209329178Srgrimes v) 210329178Srgrimes vncwait=",wait" 211329178Srgrimes ;; 212317303Srgrimes w) 213317303Srgrimes bhyverun_opt="${bhyverun_opt} -w" 214317303Srgrimes ;; 215264837Sjhb *) 216248484Sneel usage 217248484Sneel ;; 218248484Sneel esac 219248484Sneeldone 220248484Sneel 221267559Salfredif [ $tap_total -eq 0 ] ; then 222267559Salfred tap_total=1 223267559Salfred tap_dev0="${DEFAULT_TAPDEV}" 224267559Salfredfi 225267559Salfredif [ $disk_total -eq 0 ] ; then 226267559Salfred disk_total=1 227267559Salfred disk_dev0="${DEFAULT_VIRTIO_DISK}" 228267559Salfred 229267559Salfredfi 230267559Salfred 231248484Sneelshift $((${OPTIND} - 1)) 232248484Sneel 233248484Sneelif [ $# -ne 1 ]; then 234277309Sneel usage "virtual machine name not specified" 235248484Sneelfi 236248484Sneel 237248484Sneelvmname="$1" 238264837Sjhbif [ -n "${host_base}" ]; then 239264837Sjhb loader_opt="${loader_opt} -h ${host_base}" 240264837Sjhbfi 241248484Sneel 242284539Sneel# If PCI passthru devices are configured then guest memory must be wired 243284539Sneelif [ ${pass_total} -gt 0 ]; then 244284539Sneel loader_opt="${loader_opt} -S" 245284539Sneel bhyverun_opt="${bhyverun_opt} -S" 246284539Sneelfi 247284539Sneel 248329178Srgrimesif [ ${efi_mode} -gt 0 ]; then 249329178Srgrimes if [ ! -f ${efi_firmware} ]; then 250329179Srgrimes echo "Error: EFI Firmware ${efi_firmware} doesn't exist." \ 251329179Srgrimes "Try: pkg install uefi-edk2-bhyve" 252329178Srgrimes exit 1 253329178Srgrimes fi 254329178Srgrimesfi 255329178Srgrimes 256267559Salfredmake_and_check_diskdev() 257267559Salfred{ 258267559Salfred local virtio_diskdev="$1" 259267559Salfred # Create the virtio diskdev file if needed 260273102Sneel if [ ! -e ${virtio_diskdev} ]; then 261267559Salfred echo "virtio disk device file \"${virtio_diskdev}\" does not exist." 262267559Salfred echo "Creating it ..." 263267559Salfred truncate -s 8G ${virtio_diskdev} > /dev/null 264267559Salfred fi 265248484Sneel 266267559Salfred if [ ! -r ${virtio_diskdev} ]; then 267267559Salfred echo "virtio disk device file \"${virtio_diskdev}\" is not readable" 268267559Salfred exit 1 269267559Salfred fi 270248484Sneel 271267559Salfred if [ ! -w ${virtio_diskdev} ]; then 272267559Salfred echo "virtio disk device file \"${virtio_diskdev}\" is not writable" 273267559Salfred exit 1 274267559Salfred fi 275267559Salfred} 276248484Sneel 277248484Sneelecho "Launching virtual machine \"$vmname\" ..." 278248484Sneel 279284024Savgfirst_diskdev="$disk_dev0" 280267559Salfred 281270513Srodrigc${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1 282270513Srodrigc 283248484Sneelwhile [ 1 ]; do 284248484Sneel 285284024Savg file -s ${first_diskdev} | grep "boot sector" > /dev/null 286248484Sneel rc=$? 287248484Sneel if [ $rc -ne 0 ]; then 288329179Srgrimes file -s ${first_diskdev} | \ 289329179Srgrimes grep ": Unix Fast File sys" > /dev/null 290248484Sneel rc=$? 291248484Sneel fi 292248484Sneel if [ $rc -ne 0 ]; then 293248484Sneel need_install=1 294248484Sneel else 295248484Sneel need_install=0 296248484Sneel fi 297248484Sneel 298248484Sneel if [ $force_install -eq 1 -o $need_install -eq 1 ]; then 299248484Sneel if [ ! -r ${isofile} ]; then 300248484Sneel echo -n "Installation CDROM image \"${isofile}\" " 301248484Sneel echo "is not readable" 302248484Sneel exit 1 303248484Sneel fi 304284024Savg BOOTDISKS="-d ${isofile}" 305284024Savg installer_opt="-s 31:0,ahci-cd,${isofile}" 306248484Sneel else 307284024Savg BOOTDISKS="" 308284024Savg i=0 309284024Savg while [ $i -lt $disk_total ] ; do 310284024Savg eval "disk=\$disk_dev${i}" 311284024Savg if [ -r ${disk} ] ; then 312284024Savg BOOTDISKS="$BOOTDISKS -d ${disk} " 313284024Savg fi 314284024Savg i=$(($i + 1)) 315284024Savg done 316248484Sneel installer_opt="" 317248484Sneel fi 318248484Sneel 319329178Srgrimes if [ ${efi_mode} -eq 0 ]; then 320329179Srgrimes ${LOADER} -c ${console} -m ${memsize} ${BOOTDISKS} \ 321329179Srgrimes ${loader_opt} ${vmname} 322329178Srgrimes bhyve_exit=$? 323329178Srgrimes if [ $bhyve_exit -ne 0 ]; then 324329178Srgrimes break 325329178Srgrimes fi 326248484Sneel fi 327248484Sneel 328267559Salfred # 329267559Salfred # Build up args for additional tap and disk devices now. 330267559Salfred # 331267559Salfred nextslot=2 # slot 0 is hostbridge, slot 1 is lpc 332267559Salfred devargs="" # accumulate disk/tap args here 333267559Salfred i=0 334267559Salfred while [ $i -lt $tap_total ] ; do 335267559Salfred eval "tapname=\$tap_dev${i}" 336329179Srgrimes devargs="$devargs -s $nextslot:0,${nic},${tapname} " 337267559Salfred nextslot=$(($nextslot + 1)) 338267559Salfred i=$(($i + 1)) 339267559Salfred done 340267559Salfred 341267559Salfred i=0 342267559Salfred while [ $i -lt $disk_total ] ; do 343267559Salfred eval "disk=\$disk_dev${i}" 344284023Savg eval "opts=\$disk_opts${i}" 345267559Salfred make_and_check_diskdev "${disk}" 346327997Savg devargs="$devargs -s $nextslot:0,$disk_emulation,${disk}${opts} " 347267559Salfred nextslot=$(($nextslot + 1)) 348267559Salfred i=$(($i + 1)) 349267559Salfred done 350267559Salfred 351279925Sglebius i=0 352279925Sglebius while [ $i -lt $pass_total ] ; do 353279925Sglebius eval "pass=\$pass_dev${i}" 354279925Sglebius devargs="$devargs -s $nextslot:0,passthru,${pass} " 355279925Sglebius nextslot=$(($nextslot + 1)) 356279925Sglebius i=$(($i + 1)) 357279925Sglebius done 358279925Sglebius 359329178Srgrimes efiargs="" 360329178Srgrimes if [ ${efi_mode} -gt 0 ]; then 361329179Srgrimes efiargs="-s 29,fbuf,tcp=${vnchost}:${vncport}," 362329179Srgrimes efiargs="${efiargs}${vncsize}${vncwait}" 363329178Srgrimes efiargs="${efiargs} -l bootrom,${efi_firmware}" 364329178Srgrimes efiargs="${efiargs} ${tablet}" 365329178Srgrimes fi 366329178Srgrimes 367284539Sneel ${FBSDRUN} -c ${cpus} -m ${memsize} ${bhyverun_opt} \ 368248840Sneel -g ${gdbport} \ 369248484Sneel -s 0:0,hostbridge \ 370257293Sneel -s 1:0,lpc \ 371329178Srgrimes ${efiargs} \ 372267559Salfred ${devargs} \ 373264837Sjhb -l com1,${console} \ 374248484Sneel ${installer_opt} \ 375248484Sneel ${vmname} 376270512Srodrigc 377271496Srodrigc bhyve_exit=$? 378270512Srodrigc # bhyve returns the following status codes: 379270512Srodrigc # 0 - VM has been reset 380270512Srodrigc # 1 - VM has been powered off 381270512Srodrigc # 2 - VM has been halted 382270512Srodrigc # 3 - VM generated a triple fault 383270512Srodrigc # all other non-zero status codes are errors 384270512Srodrigc # 385271496Srodrigc if [ $bhyve_exit -ne 0 ]; then 386248484Sneel break 387248484Sneel fi 388248484Sneeldone 389248484Sneel 390271496Srodrigc 391271496Srodrigccase $bhyve_exit in 392271496Srodrigc 0|1|2) 393271496Srodrigc # Cleanup /dev/vmm entry when bhyve did not exit 394271496Srodrigc # due to an error. 395271496Srodrigc ${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1 396271496Srodrigc ;; 397271496Srodrigcesac 398271496Srodrigc 399271496Srodrigcexit $bhyve_exit 400