1#!/bin/sh 2# 3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4# 5# Copyright (c) 2013 NetApp, Inc. 6# All rights reserved. 7# 8# Redistribution and use in source and binary forms, with or without 9# modification, are permitted provided that the following conditions 10# are met: 11# 1. Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27# SUCH DAMAGE. 28# 29# $FreeBSD$ 30# 31 32LOADER=/usr/sbin/bhyveload 33BHYVECTL=/usr/sbin/bhyvectl 34FBSDRUN=/usr/sbin/bhyve 35 36DEFAULT_MEMSIZE=512M 37DEFAULT_CPUS=2 38DEFAULT_TAPDEV=tap0 39DEFAULT_CONSOLE=stdio 40 41DEFAULT_VIRTIO_DISK="./diskdev" 42DEFAULT_ISOFILE="./release.iso" 43 44errmsg() { 45 echo "*** $1" 46} 47 48usage() { 49 local msg=$1 50 51 echo "Usage: vmrun.sh [-aAEhiTv] [-c <CPUs>] [-C <console>] [-d <disk file>]" 52 echo " [-e <name=value>] [-f <path of firmware>] [-F <size>]" 53 echo " [-g <gdbport> ] [-H <directory>]" 54 echo " [-I <location of installation iso>] [-l <loader>]" 55 echo " [-L <VNC IP for UEFI framebuffer>]" 56 echo " [-m <memsize>] [-P <port>] [-t <tapdev>] <vmname>" 57 echo "" 58 echo " -h: display this help message" 59 echo " -a: force memory mapped local APIC access" 60 echo " -A: use AHCI disk emulation instead of virtio" 61 echo " -c: number of virtual cpus (default is ${DEFAULT_CPUS})" 62 echo " -C: console device (default is ${DEFAULT_CONSOLE})" 63 echo " -d: virtio diskdev file (default is ${DEFAULT_VIRTIO_DISK})" 64 echo " -e: set FreeBSD loader environment variable" 65 echo " -E: Use UEFI mode" 66 echo " -f: Use a specific UEFI firmware" 67 echo " -F: Use a custom UEFI GOP framebuffer size (default: w=1024,h=768)" 68 echo " -g: listen for connection from kgdb at <gdbport>" 69 echo " -H: host filesystem to export to the loader" 70 echo " -i: force boot of the Installation CDROM image" 71 echo " -I: Installation CDROM image location (default is ${DEFAULT_ISOFILE})" 72 echo " -l: the OS loader to use (default is /boot/userboot.so)" 73 echo " -L: IP address for UEFI GOP VNC server (default: 127.0.0.1)" 74 echo " -m: memory size (default is ${DEFAULT_MEMSIZE})" 75 echo " -p: pass-through a host PCI device at bus/slot/func (e.g. 10/0/0)" 76 echo " -P: UEFI GOP VNC port (default: 5900)" 77 echo " -t: tap device for virtio-net (default is $DEFAULT_TAPDEV)" 78 echo " -T: Enable tablet device (for UEFI GOP)" 79 echo " -u: RTC keeps UTC time" 80 echo " -v: Wait for VNC client connection before booting VM" 81 echo " -w: ignore unimplemented MSRs" 82 echo "" 83 [ -n "$msg" ] && errmsg "$msg" 84 exit 1 85} 86 87if [ `id -u` -ne 0 ]; then 88 errmsg "This script must be executed with superuser privileges" 89 exit 1 90fi 91 92kldstat -n vmm > /dev/null 2>&1 93if [ $? -ne 0 ]; then 94 errmsg "vmm.ko is not loaded" 95 exit 1 96fi 97 98force_install=0 99isofile=${DEFAULT_ISOFILE} 100memsize=${DEFAULT_MEMSIZE} 101console=${DEFAULT_CONSOLE} 102cpus=${DEFAULT_CPUS} 103tap_total=0 104disk_total=0 105disk_emulation="virtio-blk" 106gdbport=0 107loader_opt="" 108bhyverun_opt="-H -A -P" 109pass_total=0 110 111# EFI-specific options 112efi_mode=0 113efi_firmware="/usr/local/share/uefi-firmware/BHYVE_UEFI.fd" 114vncwait="" 115vnchost="127.0.0.1" 116vncport=5900 117fbsize="w=1024,h=768" 118tablet="" 119 120while getopts aAc:C:d:e:Ef:F:g:hH:iI:l:m:p:P:t:Tuvw c ; do 121 case $c in 122 a) 123 bhyverun_opt="${bhyverun_opt} -a" 124 ;; 125 A) 126 disk_emulation="ahci-hd" 127 ;; 128 c) 129 cpus=${OPTARG} 130 ;; 131 C) 132 console=${OPTARG} 133 ;; 134 d) 135 disk_dev=${OPTARG%%,*} 136 disk_opts=${OPTARG#${disk_dev}} 137 eval "disk_dev${disk_total}=\"${disk_dev}\"" 138 eval "disk_opts${disk_total}=\"${disk_opts}\"" 139 disk_total=$(($disk_total + 1)) 140 ;; 141 e) 142 loader_opt="${loader_opt} -e ${OPTARG}" 143 ;; 144 E) 145 efi_mode=1 146 ;; 147 f) 148 efi_firmware="${OPTARG}" 149 ;; 150 F) 151 fbsize="${OPTARG}" 152 ;; 153 g) 154 gdbport=${OPTARG} 155 ;; 156 H) 157 host_base=`realpath ${OPTARG}` 158 ;; 159 i) 160 force_install=1 161 ;; 162 I) 163 isofile=${OPTARG} 164 ;; 165 l) 166 loader_opt="${loader_opt} -l ${OPTARG}" 167 ;; 168 L) 169 vnchost="${OPTARG}" 170 ;; 171 m) 172 memsize=${OPTARG} 173 ;; 174 p) 175 eval "pass_dev${pass_total}=\"${OPTARG}\"" 176 pass_total=$(($pass_total + 1)) 177 ;; 178 P) 179 vncport="${OPTARG}" 180 ;; 181 t) 182 eval "tap_dev${tap_total}=\"${OPTARG}\"" 183 tap_total=$(($tap_total + 1)) 184 ;; 185 T) 186 tablet="-s 30,xhci,tablet" 187 ;; 188 u) 189 bhyverun_opt="${bhyverun_opt} -u" 190 ;; 191 v) 192 vncwait=",wait" 193 ;; 194 w) 195 bhyverun_opt="${bhyverun_opt} -w" 196 ;; 197 *) 198 usage 199 ;; 200 esac 201done 202 203if [ $tap_total -eq 0 ] ; then 204 tap_total=1 205 tap_dev0="${DEFAULT_TAPDEV}" 206fi 207if [ $disk_total -eq 0 ] ; then 208 disk_total=1 209 disk_dev0="${DEFAULT_VIRTIO_DISK}" 210 211fi 212 213shift $((${OPTIND} - 1)) 214 215if [ $# -ne 1 ]; then 216 usage "virtual machine name not specified" 217fi 218 219vmname="$1" 220if [ -n "${host_base}" ]; then 221 loader_opt="${loader_opt} -h ${host_base}" 222fi 223 224# If PCI passthru devices are configured then guest memory must be wired 225if [ ${pass_total} -gt 0 ]; then 226 loader_opt="${loader_opt} -S" 227 bhyverun_opt="${bhyverun_opt} -S" 228fi 229 230if [ ${efi_mode} -gt 0 ]; then 231 if [ ! -f ${efi_firmware} ]; then 232 echo "Error: EFI Firmware ${efi_firmware} doesn't exist. Try: pkg install uefi-edk2-bhyve" 233 exit 1 234 fi 235fi 236 237make_and_check_diskdev() 238{ 239 local virtio_diskdev="$1" 240 # Create the virtio diskdev file if needed 241 if [ ! -e ${virtio_diskdev} ]; then 242 echo "virtio disk device file \"${virtio_diskdev}\" does not exist." 243 echo "Creating it ..." 244 truncate -s 8G ${virtio_diskdev} > /dev/null 245 fi 246 247 if [ ! -r ${virtio_diskdev} ]; then 248 echo "virtio disk device file \"${virtio_diskdev}\" is not readable" 249 exit 1 250 fi 251 252 if [ ! -w ${virtio_diskdev} ]; then 253 echo "virtio disk device file \"${virtio_diskdev}\" is not writable" 254 exit 1 255 fi 256} 257 258echo "Launching virtual machine \"$vmname\" ..." 259 260first_diskdev="$disk_dev0" 261 262${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1 263 264while [ 1 ]; do 265 266 file -s ${first_diskdev} | grep "boot sector" > /dev/null 267 rc=$? 268 if [ $rc -ne 0 ]; then 269 file -s ${first_diskdev} | grep ": Unix Fast File sys" > /dev/null 270 rc=$? 271 fi 272 if [ $rc -ne 0 ]; then 273 need_install=1 274 else 275 need_install=0 276 fi 277 278 if [ $force_install -eq 1 -o $need_install -eq 1 ]; then 279 if [ ! -r ${isofile} ]; then 280 echo -n "Installation CDROM image \"${isofile}\" " 281 echo "is not readable" 282 exit 1 283 fi 284 BOOTDISKS="-d ${isofile}" 285 installer_opt="-s 31:0,ahci-cd,${isofile}" 286 else 287 BOOTDISKS="" 288 i=0 289 while [ $i -lt $disk_total ] ; do 290 eval "disk=\$disk_dev${i}" 291 if [ -r ${disk} ] ; then 292 BOOTDISKS="$BOOTDISKS -d ${disk} " 293 fi 294 i=$(($i + 1)) 295 done 296 installer_opt="" 297 fi 298 299 if [ ${efi_mode} -eq 0 ]; then 300 ${LOADER} -c ${console} -m ${memsize} ${BOOTDISKS} ${loader_opt} \ 301 ${vmname} 302 bhyve_exit=$? 303 if [ $bhyve_exit -ne 0 ]; then 304 break 305 fi 306 fi 307 308 # 309 # Build up args for additional tap and disk devices now. 310 # 311 nextslot=2 # slot 0 is hostbridge, slot 1 is lpc 312 devargs="" # accumulate disk/tap args here 313 i=0 314 while [ $i -lt $tap_total ] ; do 315 eval "tapname=\$tap_dev${i}" 316 devargs="$devargs -s $nextslot:0,virtio-net,${tapname} " 317 nextslot=$(($nextslot + 1)) 318 i=$(($i + 1)) 319 done 320 321 i=0 322 while [ $i -lt $disk_total ] ; do 323 eval "disk=\$disk_dev${i}" 324 eval "opts=\$disk_opts${i}" 325 make_and_check_diskdev "${disk}" 326 devargs="$devargs -s $nextslot:0,$disk_emulation,${disk}${opts} " 327 nextslot=$(($nextslot + 1)) 328 i=$(($i + 1)) 329 done 330 331 i=0 332 while [ $i -lt $pass_total ] ; do 333 eval "pass=\$pass_dev${i}" 334 devargs="$devargs -s $nextslot:0,passthru,${pass} " 335 nextslot=$(($nextslot + 1)) 336 i=$(($i + 1)) 337 done 338 339 efiargs="" 340 if [ ${efi_mode} -gt 0 ]; then 341 efiargs="-s 29,fbuf,tcp=${vnchost}:${vncport},${fbsize}${vncwait}" 342 efiargs="${efiargs} -l bootrom,${efi_firmware}" 343 efiargs="${efiargs} ${tablet}" 344 fi 345 346 ${FBSDRUN} -c ${cpus} -m ${memsize} ${bhyverun_opt} \ 347 -g ${gdbport} \ 348 -s 0:0,hostbridge \ 349 -s 1:0,lpc \ 350 ${efiargs} \ 351 ${devargs} \ 352 -l com1,${console} \ 353 ${installer_opt} \ 354 ${vmname} 355 356 bhyve_exit=$? 357 # bhyve returns the following status codes: 358 # 0 - VM has been reset 359 # 1 - VM has been powered off 360 # 2 - VM has been halted 361 # 3 - VM generated a triple fault 362 # all other non-zero status codes are errors 363 # 364 if [ $bhyve_exit -ne 0 ]; then 365 break 366 fi 367done 368 369 370case $bhyve_exit in 371 0|1|2) 372 # Cleanup /dev/vmm entry when bhyve did not exit 373 # due to an error. 374 ${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1 375 ;; 376esac 377 378exit $bhyve_exit 379