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
55void
56bhyve_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
68void
69bhyve_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
111void
112bhyve_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
246void
247bhyve_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
288void
289bhyve_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
319int
320bhyve_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
341int
342bhyve_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