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
bhyve_init_config(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
bhyve_usage(int code)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
bhyve_optparse(int argc,char ** argv)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
bhyve_init_vcpu(struct vcpu * vcpu)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
bhyve_start_vcpu(struct vcpu * vcpu,bool bsp)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
bhyve_init_platform(struct vmctx * ctx,struct vcpu * bsp __unused)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
bhyve_init_platform_late(struct vmctx * ctx,struct vcpu * bsp __unused)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