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