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 "config.h" 41 #include "debug.h" 42 #include "e820.h" 43 #include "fwctl.h" 44 #include "ioapic.h" 45 #include "inout.h" 46 #include "kernemu_dev.h" 47 #include "mptbl.h" 48 #include "pci_emul.h" 49 #include "pci_irq.h" 50 #include "pci_lpc.h" 51 #include "rtc.h" 52 #include "smbiostbl.h" 53 #include "xmsr.h" 54 55 void 56 bhyve_init_config(void) 57 { 58 init_config(); 59 60 /* Set default values prior to option parsing. */ 61 set_config_bool("acpi_tables", true); 62 set_config_bool("acpi_tables_in_memory", true); 63 set_config_value("memory.size", "256M"); 64 set_config_bool("x86.strictmsr", true); 65 set_config_value("lpc.fwcfg", "bhyve"); 66 } 67 68 void 69 bhyve_usage(int code) 70 { 71 const char *progname; 72 73 progname = getprogname(); 74 75 fprintf(stderr, 76 "Usage: %s [-AaCDeHhPSuWwxY]\n" 77 " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n" 78 " %*s [-G port] [-k config_file] [-l lpc] [-m mem] [-o var=value]\n" 79 " %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n" 80 " -A: create ACPI tables\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 247 void 248 bhyve_init_vcpu(struct vcpu *vcpu) 249 { 250 int err, tmp; 251 252 if (get_config_bool_default("x86.vmexit_on_hlt", false)) { 253 err = vm_get_capability(vcpu, VM_CAP_HALT_EXIT, &tmp); 254 if (err < 0) { 255 EPRINTLN("VM exit on HLT not supported"); 256 exit(4); 257 } 258 vm_set_capability(vcpu, VM_CAP_HALT_EXIT, 1); 259 } 260 261 if (get_config_bool_default("x86.vmexit_on_pause", false)) { 262 /* 263 * pause exit support required for this mode 264 */ 265 err = vm_get_capability(vcpu, VM_CAP_PAUSE_EXIT, &tmp); 266 if (err < 0) { 267 EPRINTLN("SMP mux requested, no pause support"); 268 exit(4); 269 } 270 vm_set_capability(vcpu, VM_CAP_PAUSE_EXIT, 1); 271 } 272 273 if (get_config_bool_default("x86.x2apic", false)) 274 err = vm_set_x2apic_state(vcpu, X2APIC_ENABLED); 275 else 276 err = vm_set_x2apic_state(vcpu, X2APIC_DISABLED); 277 278 if (err) { 279 EPRINTLN("Unable to set x2apic state (%d)", err); 280 exit(4); 281 } 282 283 vm_set_capability(vcpu, VM_CAP_ENABLE_INVPCID, 1); 284 285 err = vm_set_capability(vcpu, VM_CAP_IPI_EXIT, 1); 286 assert(err == 0); 287 } 288 289 void 290 bhyve_start_vcpu(struct vcpu *vcpu, bool bsp) 291 { 292 int error; 293 294 if (bsp) { 295 if (lpc_bootrom()) { 296 error = vm_set_capability(vcpu, 297 VM_CAP_UNRESTRICTED_GUEST, 1); 298 if (error != 0) { 299 err(4, "ROM boot failed: unrestricted guest " 300 "capability not available"); 301 } 302 error = vcpu_reset(vcpu); 303 assert(error == 0); 304 } 305 } else { 306 bhyve_init_vcpu(vcpu); 307 308 /* 309 * Enable the 'unrestricted guest' mode for APs. 310 * 311 * APs startup in power-on 16-bit mode. 312 */ 313 error = vm_set_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, 1); 314 assert(error == 0); 315 } 316 317 fbsdrun_addcpu(vcpu_id(vcpu)); 318 } 319 320 int 321 bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp __unused) 322 { 323 int error; 324 325 error = init_msr(); 326 if (error != 0) 327 return (error); 328 init_inout(); 329 kernemu_dev_init(); 330 atkbdc_init(ctx); 331 pci_irq_init(ctx); 332 ioapic_init(ctx); 333 rtc_init(ctx); 334 sci_init(ctx); 335 error = e820_init(ctx); 336 if (error != 0) 337 return (error); 338 339 return (0); 340 } 341 342 int 343 bhyve_init_platform_late(struct vmctx *ctx, struct vcpu *bsp __unused) 344 { 345 int error; 346 347 if (get_config_bool_default("x86.mptable", true)) { 348 error = mptable_build(ctx, guest_ncpus); 349 if (error != 0) 350 return (error); 351 } 352 error = smbios_build(ctx); 353 if (error != 0) 354 return (error); 355 error = e820_finalize(); 356 if (error != 0) 357 return (error); 358 359 if (lpc_bootrom() && strcmp(lpc_fwcfg(), "bhyve") == 0) 360 fwctl_init(); 361 362 if (get_config_bool("acpi_tables")) { 363 error = acpi_build(ctx, guest_ncpus); 364 assert(error == 0); 365 } 366 367 return (0); 368 } 369