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