1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 NetApp, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <assert.h> 30 #include <err.h> 31 #include <stdbool.h> 32 #include <stdlib.h> 33 #include <sysexits.h> 34 35 #include <vmmapi.h> 36 37 #include "acpi.h" 38 #include "atkbdc.h" 39 #include "bhyverun.h" 40 #include "bootrom.h" 41 #include "config.h" 42 #include "debug.h" 43 #include "e820.h" 44 #include "fwctl.h" 45 #include "ioapic.h" 46 #include "inout.h" 47 #include "kernemu_dev.h" 48 #include "mptbl.h" 49 #include "pci_emul.h" 50 #include "pci_irq.h" 51 #include "pci_lpc.h" 52 #include "rtc.h" 53 #include "smbiostbl.h" 54 #include "xmsr.h" 55 56 void 57 bhyve_init_config(void) 58 { 59 init_config(); 60 61 /* Set default values prior to option parsing. */ 62 set_config_bool("acpi_tables", true); 63 set_config_bool("acpi_tables_in_memory", true); 64 set_config_value("memory.size", "256M"); 65 set_config_bool("x86.strictmsr", true); 66 set_config_bool("x86.verbosemsr", false); 67 set_config_value("lpc.fwcfg", "bhyve"); 68 } 69 70 void 71 bhyve_usage(int code) 72 { 73 const char *progname; 74 75 progname = getprogname(); 76 77 fprintf(stderr, 78 "Usage: %s [-aCDeHhPSuWwxY]\n" 79 " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n" 80 " %*s [-G port] [-k config_file] [-l lpc] [-m mem] [-o var=value]\n" 81 " %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n" 82 " -a: local apic is in xAPIC mode (deprecated)\n" 83 " -C: include guest memory in core file\n" 84 " -c: number of CPUs and/or topology specification\n" 85 " -D: destroy on power-off\n" 86 " -e: exit on unhandled I/O access\n" 87 " -G: start a debug server\n" 88 " -H: vmexit from the guest on HLT\n" 89 " -h: help\n" 90 " -k: key=value flat config file\n" 91 " -K: PS2 keyboard layout\n" 92 " -l: LPC device configuration\n" 93 " -m: memory size\n" 94 " -o: set config 'var' to 'value'\n" 95 " -P: vmexit from the guest on pause\n" 96 " -p: pin 'vcpu' to 'hostcpu'\n" 97 #ifdef BHYVE_SNAPSHOT 98 " -r: path to checkpoint file\n" 99 #endif 100 " -S: guest memory cannot be swapped\n" 101 " -s: <slot,driver,configinfo> PCI slot config\n" 102 " -U: UUID\n" 103 " -u: RTC keeps UTC time\n" 104 " -W: force virtio to use single-vector MSI\n" 105 " -w: ignore unimplemented MSRs\n" 106 " -x: local APIC is in x2APIC mode\n" 107 " -Y: disable MPtable generation\n", 108 progname, (int)strlen(progname), "", (int)strlen(progname), "", 109 (int)strlen(progname), ""); 110 exit(code); 111 } 112 113 void 114 bhyve_optparse(int argc, char **argv) 115 { 116 const char *optstr; 117 int c; 118 119 #ifdef BHYVE_SNAPSHOT 120 optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:"; 121 #else 122 optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:"; 123 #endif 124 while ((c = getopt(argc, argv, optstr)) != -1) { 125 switch (c) { 126 case 'a': 127 set_config_bool("x86.x2apic", false); 128 break; 129 case 'A': 130 /* 131 * NOP. For backward compatibility. Most systems don't 132 * work properly without sane ACPI tables. Therefore, 133 * we're always generating them. 134 */ 135 break; 136 case 'D': 137 set_config_bool("destroy_on_poweroff", true); 138 break; 139 case 'p': 140 if (bhyve_pincpu_parse(optarg) != 0) { 141 errx(EX_USAGE, "invalid vcpu pinning " 142 "configuration '%s'", optarg); 143 } 144 break; 145 case 'c': 146 if (bhyve_topology_parse(optarg) != 0) { 147 errx(EX_USAGE, "invalid cpu topology " 148 "'%s'", optarg); 149 } 150 break; 151 case 'C': 152 set_config_bool("memory.guest_in_core", true); 153 break; 154 case 'f': 155 if (qemu_fwcfg_parse_cmdline_arg(optarg) != 0) { 156 errx(EX_USAGE, "invalid fwcfg item '%s'", 157 optarg); 158 } 159 break; 160 case 'G': 161 bhyve_parse_gdb_options(optarg); 162 break; 163 case 'k': 164 bhyve_parse_simple_config_file(optarg); 165 break; 166 case 'K': 167 set_config_value("keyboard.layout", optarg); 168 break; 169 case 'l': 170 if (strncmp(optarg, "help", strlen(optarg)) == 0) { 171 lpc_print_supported_devices(); 172 exit(0); 173 } else if (lpc_device_parse(optarg) != 0) { 174 errx(EX_USAGE, "invalid lpc device " 175 "configuration '%s'", optarg); 176 } 177 break; 178 #ifdef BHYVE_SNAPSHOT 179 case 'r': 180 restore_file = optarg; 181 break; 182 #endif 183 case 's': 184 if (strncmp(optarg, "help", strlen(optarg)) == 0) { 185 pci_print_supported_devices(); 186 exit(0); 187 } else if (pci_parse_slot(optarg) != 0) 188 exit(4); 189 else 190 break; 191 case 'S': 192 set_config_bool("memory.wired", true); 193 break; 194 case 'm': 195 set_config_value("memory.size", optarg); 196 break; 197 case 'o': 198 if (!bhyve_parse_config_option(optarg)) { 199 errx(EX_USAGE, 200 "invalid configuration option '%s'", 201 optarg); 202 } 203 break; 204 case 'H': 205 set_config_bool("x86.vmexit_on_hlt", true); 206 break; 207 case 'I': 208 /* 209 * The "-I" option was used to add an ioapic to the 210 * virtual machine. 211 * 212 * An ioapic is now provided unconditionally for each 213 * virtual machine and this option is now deprecated. 214 */ 215 break; 216 case 'P': 217 set_config_bool("x86.vmexit_on_pause", true); 218 break; 219 case 'e': 220 set_config_bool("x86.strictio", true); 221 break; 222 case 'u': 223 set_config_bool("rtc.use_localtime", false); 224 break; 225 case 'U': 226 set_config_value("uuid", optarg); 227 break; 228 case 'w': 229 set_config_bool("x86.strictmsr", false); 230 break; 231 case 'W': 232 set_config_bool("virtio_msix", false); 233 break; 234 case 'x': 235 set_config_bool("x86.x2apic", true); 236 break; 237 case 'Y': 238 set_config_bool("x86.mptable", false); 239 break; 240 case 'h': 241 bhyve_usage(0); 242 default: 243 bhyve_usage(1); 244 } 245 } 246 247 /* Handle backwards compatibility aliases in config options. */ 248 if (get_config_value("lpc.bootrom") != NULL && 249 get_config_value("bootrom") == NULL) { 250 warnx("lpc.bootrom is deprecated, use '-o bootrom' instead"); 251 set_config_value("bootrom", get_config_value("lpc.bootrom")); 252 } 253 if (get_config_value("lpc.bootvars") != NULL && 254 get_config_value("bootvars") == NULL) { 255 warnx("lpc.bootvars is deprecated, use '-o bootvars' instead"); 256 set_config_value("bootvars", get_config_value("lpc.bootvars")); 257 } 258 } 259 260 void 261 bhyve_init_vcpu(struct vcpu *vcpu) 262 { 263 int err, tmp; 264 265 if (get_config_bool_default("x86.vmexit_on_hlt", false)) { 266 err = vm_get_capability(vcpu, VM_CAP_HALT_EXIT, &tmp); 267 if (err < 0) { 268 EPRINTLN("VM exit on HLT not supported"); 269 exit(4); 270 } 271 vm_set_capability(vcpu, VM_CAP_HALT_EXIT, 1); 272 } 273 274 if (get_config_bool_default("x86.vmexit_on_pause", false)) { 275 /* 276 * pause exit support required for this mode 277 */ 278 err = vm_get_capability(vcpu, VM_CAP_PAUSE_EXIT, &tmp); 279 if (err < 0) { 280 EPRINTLN("SMP mux requested, no pause support"); 281 exit(4); 282 } 283 vm_set_capability(vcpu, VM_CAP_PAUSE_EXIT, 1); 284 } 285 286 if (get_config_bool_default("x86.x2apic", false)) 287 err = vm_set_x2apic_state(vcpu, X2APIC_ENABLED); 288 else 289 err = vm_set_x2apic_state(vcpu, X2APIC_DISABLED); 290 291 if (err) { 292 EPRINTLN("Unable to set x2apic state (%d)", err); 293 exit(4); 294 } 295 296 vm_set_capability(vcpu, VM_CAP_ENABLE_INVPCID, 1); 297 298 err = vm_set_capability(vcpu, VM_CAP_IPI_EXIT, 1); 299 assert(err == 0); 300 } 301 302 void 303 bhyve_start_vcpu(struct vcpu *vcpu, bool bsp) 304 { 305 int error; 306 307 if (bsp) { 308 if (bootrom_boot()) { 309 error = vm_set_capability(vcpu, 310 VM_CAP_UNRESTRICTED_GUEST, 1); 311 if (error != 0) { 312 err(4, "ROM boot failed: unrestricted guest " 313 "capability not available"); 314 } 315 error = vcpu_reset(vcpu); 316 assert(error == 0); 317 } 318 } else { 319 bhyve_init_vcpu(vcpu); 320 321 /* 322 * Enable the 'unrestricted guest' mode for APs. 323 * 324 * APs startup in power-on 16-bit mode. 325 */ 326 error = vm_set_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, 1); 327 assert(error == 0); 328 } 329 330 fbsdrun_addcpu(vcpu_id(vcpu)); 331 } 332 333 int 334 bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp __unused) 335 { 336 int error; 337 338 error = init_msr(); 339 if (error != 0) 340 return (error); 341 init_inout(); 342 kernemu_dev_init(); 343 atkbdc_init(ctx); 344 pci_irq_init(ctx); 345 ioapic_init(ctx); 346 rtc_init(ctx); 347 sci_init(ctx); 348 error = e820_init(ctx); 349 if (error != 0) 350 return (error); 351 error = bootrom_loadrom(ctx); 352 if (error != 0) 353 return (error); 354 355 return (0); 356 } 357 358 int 359 bhyve_init_platform_late(struct vmctx *ctx, struct vcpu *bsp __unused) 360 { 361 int error; 362 363 if (get_config_bool_default("x86.mptable", true)) { 364 error = mptable_build(ctx, guest_ncpus); 365 if (error != 0) 366 return (error); 367 } 368 error = smbios_build(ctx); 369 if (error != 0) 370 return (error); 371 error = e820_finalize(); 372 if (error != 0) 373 return (error); 374 375 if (bootrom_boot() && strcmp(lpc_fwcfg(), "bhyve") == 0) 376 fwctl_init(); 377 378 if (get_config_bool("acpi_tables")) { 379 error = acpi_build(ctx, guest_ncpus); 380 assert(error == 0); 381 } 382 383 return (0); 384 } 385