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 " -n: NUMA domain specification\n" 95 " -o: set config 'var' to 'value'\n" 96 " -P: vmexit from the guest on pause\n" 97 " -p: pin 'vcpu' to 'hostcpu'\n" 98 #ifdef BHYVE_SNAPSHOT 99 " -r: path to checkpoint file\n" 100 #endif 101 " -S: guest memory cannot be swapped\n" 102 " -s: <slot,driver,configinfo> PCI slot config\n" 103 " -U: UUID\n" 104 " -u: RTC keeps UTC time\n" 105 " -W: force virtio to use single-vector MSI\n" 106 " -w: ignore unimplemented MSRs\n" 107 " -x: local APIC is in x2APIC mode\n" 108 " -Y: disable MPtable generation\n", 109 progname, (int)strlen(progname), "", (int)strlen(progname), "", 110 (int)strlen(progname), ""); 111 exit(code); 112 } 113 114 void 115 bhyve_optparse(int argc, char **argv) 116 { 117 const char *optstr; 118 int c; 119 120 #ifdef BHYVE_SNAPSHOT 121 optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:n:l:K:U:r:"; 122 #else 123 optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:n:l:K:U:"; 124 #endif 125 while ((c = getopt(argc, argv, optstr)) != -1) { 126 switch (c) { 127 case 'a': 128 set_config_bool("x86.x2apic", false); 129 break; 130 case 'A': 131 /* 132 * NOP. For backward compatibility. Most systems don't 133 * work properly without sane ACPI tables. Therefore, 134 * we're always generating them. 135 */ 136 break; 137 case 'D': 138 set_config_bool("destroy_on_poweroff", true); 139 break; 140 case 'p': 141 if (bhyve_pincpu_parse(optarg) != 0) { 142 errx(EX_USAGE, "invalid vcpu pinning " 143 "configuration '%s'", optarg); 144 } 145 break; 146 case 'c': 147 if (bhyve_topology_parse(optarg) != 0) { 148 errx(EX_USAGE, "invalid cpu topology " 149 "'%s'", optarg); 150 } 151 break; 152 case 'C': 153 set_config_bool("memory.guest_in_core", true); 154 break; 155 case 'f': 156 if (qemu_fwcfg_parse_cmdline_arg(optarg) != 0) { 157 errx(EX_USAGE, "invalid fwcfg item '%s'", 158 optarg); 159 } 160 break; 161 case 'G': 162 bhyve_parse_gdb_options(optarg); 163 break; 164 case 'k': 165 bhyve_parse_simple_config_file(optarg); 166 break; 167 case 'K': 168 set_config_value("keyboard.layout", optarg); 169 break; 170 case 'l': 171 if (strncmp(optarg, "help", strlen(optarg)) == 0) { 172 lpc_print_supported_devices(); 173 exit(0); 174 } else if (lpc_device_parse(optarg) != 0) { 175 errx(EX_USAGE, "invalid lpc device " 176 "configuration '%s'", optarg); 177 } 178 break; 179 #ifdef BHYVE_SNAPSHOT 180 case 'r': 181 restore_file = optarg; 182 break; 183 #endif 184 case 's': 185 if (strncmp(optarg, "help", strlen(optarg)) == 0) { 186 pci_print_supported_devices(); 187 exit(0); 188 } else if (pci_parse_slot(optarg) != 0) 189 exit(4); 190 else 191 break; 192 case 'S': 193 set_config_bool("memory.wired", true); 194 break; 195 case 'm': 196 set_config_value("memory.size", optarg); 197 break; 198 case 'n': 199 if (bhyve_numa_parse(optarg) != 0) 200 errx(EX_USAGE, 201 "invalid NUMA configuration " 202 "'%s'", 203 optarg); 204 if (!get_config_bool("acpi_tables")) 205 errx(EX_USAGE, "NUMA emulation requires ACPI"); 206 break; 207 case 'o': 208 if (!bhyve_parse_config_option(optarg)) { 209 errx(EX_USAGE, 210 "invalid configuration option '%s'", 211 optarg); 212 } 213 break; 214 case 'H': 215 set_config_bool("x86.vmexit_on_hlt", true); 216 break; 217 case 'I': 218 /* 219 * The "-I" option was used to add an ioapic to the 220 * virtual machine. 221 * 222 * An ioapic is now provided unconditionally for each 223 * virtual machine and this option is now deprecated. 224 */ 225 break; 226 case 'P': 227 set_config_bool("x86.vmexit_on_pause", true); 228 break; 229 case 'e': 230 set_config_bool("x86.strictio", true); 231 break; 232 case 'u': 233 set_config_bool("rtc.use_localtime", false); 234 break; 235 case 'U': 236 set_config_value("uuid", optarg); 237 break; 238 case 'w': 239 set_config_bool("x86.strictmsr", false); 240 break; 241 case 'W': 242 set_config_bool("virtio_msix", false); 243 break; 244 case 'x': 245 set_config_bool("x86.x2apic", true); 246 break; 247 case 'Y': 248 set_config_bool("x86.mptable", false); 249 break; 250 case 'h': 251 bhyve_usage(0); 252 default: 253 bhyve_usage(1); 254 } 255 } 256 257 /* Handle backwards compatibility aliases in config options. */ 258 if (get_config_value("lpc.bootrom") != NULL && 259 get_config_value("bootrom") == NULL) { 260 warnx("lpc.bootrom is deprecated, use '-o bootrom' instead"); 261 set_config_value("bootrom", get_config_value("lpc.bootrom")); 262 } 263 if (get_config_value("lpc.bootvars") != NULL && 264 get_config_value("bootvars") == NULL) { 265 warnx("lpc.bootvars is deprecated, use '-o bootvars' instead"); 266 set_config_value("bootvars", get_config_value("lpc.bootvars")); 267 } 268 } 269 270 void 271 bhyve_init_vcpu(struct vcpu *vcpu) 272 { 273 int err, tmp; 274 275 if (get_config_bool_default("x86.vmexit_on_hlt", false)) { 276 err = vm_get_capability(vcpu, VM_CAP_HALT_EXIT, &tmp); 277 if (err < 0) { 278 EPRINTLN("VM exit on HLT not supported"); 279 exit(4); 280 } 281 vm_set_capability(vcpu, VM_CAP_HALT_EXIT, 1); 282 } 283 284 if (get_config_bool_default("x86.vmexit_on_pause", false)) { 285 /* 286 * pause exit support required for this mode 287 */ 288 err = vm_get_capability(vcpu, VM_CAP_PAUSE_EXIT, &tmp); 289 if (err < 0) { 290 EPRINTLN("SMP mux requested, no pause support"); 291 exit(4); 292 } 293 vm_set_capability(vcpu, VM_CAP_PAUSE_EXIT, 1); 294 } 295 296 if (get_config_bool_default("x86.x2apic", false)) 297 err = vm_set_x2apic_state(vcpu, X2APIC_ENABLED); 298 else 299 err = vm_set_x2apic_state(vcpu, X2APIC_DISABLED); 300 301 if (err) { 302 EPRINTLN("Unable to set x2apic state (%d)", err); 303 exit(4); 304 } 305 306 vm_set_capability(vcpu, VM_CAP_ENABLE_INVPCID, 1); 307 308 err = vm_set_capability(vcpu, VM_CAP_IPI_EXIT, 1); 309 assert(err == 0); 310 } 311 312 void 313 bhyve_start_vcpu(struct vcpu *vcpu, bool bsp) 314 { 315 int error; 316 317 if (bsp) { 318 if (bootrom_boot()) { 319 error = vm_set_capability(vcpu, 320 VM_CAP_UNRESTRICTED_GUEST, 1); 321 if (error != 0) { 322 err(4, "ROM boot failed: unrestricted guest " 323 "capability not available"); 324 } 325 error = vcpu_reset(vcpu); 326 assert(error == 0); 327 } 328 } else { 329 bhyve_init_vcpu(vcpu); 330 331 /* 332 * Enable the 'unrestricted guest' mode for APs. 333 * 334 * APs startup in power-on 16-bit mode. 335 */ 336 error = vm_set_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, 1); 337 assert(error == 0); 338 } 339 340 fbsdrun_addcpu(vcpu_id(vcpu)); 341 } 342 343 int 344 bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp __unused) 345 { 346 int error; 347 348 error = init_msr(); 349 if (error != 0) 350 return (error); 351 init_inout(); 352 kernemu_dev_init(); 353 atkbdc_init(ctx); 354 pci_irq_init(ctx); 355 ioapic_init(ctx); 356 rtc_init(ctx); 357 sci_init(ctx); 358 error = e820_init(ctx); 359 if (error != 0) 360 return (error); 361 error = bootrom_loadrom(ctx); 362 if (error != 0) 363 return (error); 364 365 return (0); 366 } 367 368 int 369 bhyve_init_platform_late(struct vmctx *ctx, struct vcpu *bsp __unused) 370 { 371 int error; 372 373 if (get_config_bool_default("x86.mptable", true)) { 374 error = mptable_build(ctx, guest_ncpus); 375 if (error != 0) 376 return (error); 377 } 378 error = smbios_build(ctx); 379 if (error != 0) 380 return (error); 381 error = e820_finalize(); 382 if (error != 0) 383 return (error); 384 385 if (bootrom_boot() && strcmp(lpc_fwcfg(), "bhyve") == 0) 386 fwctl_init(); 387 388 if (get_config_bool("acpi_tables")) { 389 error = acpi_build(ctx, guest_ncpus); 390 assert(error == 0); 391 } 392 393 return (0); 394 } 395