xref: /freebsd-src/usr.sbin/bhyveload/bhyveload.c (revision 7d9ef309bd09c061e9cad8ace6f7bb4c60f087e6)
1c487da1eSNeel Natu /*-
21de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4c487da1eSNeel Natu  * Copyright (c) 2011 NetApp, Inc.
5c487da1eSNeel Natu  * All rights reserved.
6c487da1eSNeel Natu  *
7c487da1eSNeel Natu  * Redistribution and use in source and binary forms, with or without
8c487da1eSNeel Natu  * modification, are permitted provided that the following conditions
9c487da1eSNeel Natu  * are met:
10c487da1eSNeel Natu  * 1. Redistributions of source code must retain the above copyright
11c487da1eSNeel Natu  *    notice, this list of conditions and the following disclaimer.
12c487da1eSNeel Natu  * 2. Redistributions in binary form must reproduce the above copyright
13c487da1eSNeel Natu  *    notice, this list of conditions and the following disclaimer in the
14c487da1eSNeel Natu  *    documentation and/or other materials provided with the distribution.
15c487da1eSNeel Natu  *
16c487da1eSNeel Natu  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17c487da1eSNeel Natu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c487da1eSNeel Natu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c487da1eSNeel Natu  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20c487da1eSNeel Natu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c487da1eSNeel Natu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c487da1eSNeel Natu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c487da1eSNeel Natu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c487da1eSNeel Natu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c487da1eSNeel Natu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c487da1eSNeel Natu  * SUCH DAMAGE.
27c487da1eSNeel Natu  *
28c487da1eSNeel Natu  * $FreeBSD$
29c487da1eSNeel Natu  */
30c487da1eSNeel Natu 
31c487da1eSNeel Natu /*-
32c487da1eSNeel Natu  * Copyright (c) 2011 Google, Inc.
33c487da1eSNeel Natu  * All rights reserved.
34c487da1eSNeel Natu  *
35c487da1eSNeel Natu  * Redistribution and use in source and binary forms, with or without
36c487da1eSNeel Natu  * modification, are permitted provided that the following conditions
37c487da1eSNeel Natu  * are met:
38c487da1eSNeel Natu  * 1. Redistributions of source code must retain the above copyright
39c487da1eSNeel Natu  *    notice, this list of conditions and the following disclaimer.
40c487da1eSNeel Natu  * 2. Redistributions in binary form must reproduce the above copyright
41c487da1eSNeel Natu  *    notice, this list of conditions and the following disclaimer in the
42c487da1eSNeel Natu  *    documentation and/or other materials provided with the distribution.
43c487da1eSNeel Natu  *
44c487da1eSNeel Natu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45c487da1eSNeel Natu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46c487da1eSNeel Natu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47c487da1eSNeel Natu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48c487da1eSNeel Natu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49c487da1eSNeel Natu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50c487da1eSNeel Natu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51c487da1eSNeel Natu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52c487da1eSNeel Natu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53c487da1eSNeel Natu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54c487da1eSNeel Natu  * SUCH DAMAGE.
55c487da1eSNeel Natu  *
56c487da1eSNeel Natu  * $FreeBSD$
57c487da1eSNeel Natu  */
58c487da1eSNeel Natu 
59c487da1eSNeel Natu #include <sys/cdefs.h>
60c487da1eSNeel Natu __FBSDID("$FreeBSD$");
61c487da1eSNeel Natu 
62c487da1eSNeel Natu #include <sys/ioctl.h>
63c487da1eSNeel Natu #include <sys/stat.h>
64a10c6f55SNeel Natu #include <sys/disk.h>
65b6afa84bSNeel Natu #include <sys/queue.h>
66c487da1eSNeel Natu 
67c487da1eSNeel Natu #include <machine/specialreg.h>
68c487da1eSNeel Natu #include <machine/vmm.h>
69c487da1eSNeel Natu 
70*7d9ef309SJohn Baldwin #include <assert.h>
71c487da1eSNeel Natu #include <dirent.h>
72c487da1eSNeel Natu #include <dlfcn.h>
73c487da1eSNeel Natu #include <errno.h>
74200758f1SNeel Natu #include <err.h>
75c487da1eSNeel Natu #include <fcntl.h>
76c487da1eSNeel Natu #include <getopt.h>
77b5331f4dSNeel Natu #include <libgen.h>
78c487da1eSNeel Natu #include <limits.h>
79d3d381b2SKyle Evans #include <setjmp.h>
80c487da1eSNeel Natu #include <stdio.h>
81c487da1eSNeel Natu #include <stdlib.h>
82c487da1eSNeel Natu #include <string.h>
83200758f1SNeel Natu #include <sysexits.h>
84c487da1eSNeel Natu #include <termios.h>
85c487da1eSNeel Natu #include <unistd.h>
86c487da1eSNeel Natu 
87c487da1eSNeel Natu #include <vmmapi.h>
88c487da1eSNeel Natu 
89c487da1eSNeel Natu #include "userboot.h"
90c487da1eSNeel Natu 
91c487da1eSNeel Natu #define	MB	(1024 * 1024UL)
92c487da1eSNeel Natu #define	GB	(1024 * 1024 * 1024UL)
93c487da1eSNeel Natu #define	BSP	0
94c487da1eSNeel Natu 
95cf087c12SPeter Grehan #define	NDISKS	32
96cf087c12SPeter Grehan 
97384305ffSPeter Grehan static char *host_base;
98c487da1eSNeel Natu static struct termios term, oldterm;
99cf087c12SPeter Grehan static int disk_fd[NDISKS];
100cf087c12SPeter Grehan static int ndisks;
1016380102cSPeter Grehan static int consin_fd, consout_fd;
102c487da1eSNeel Natu 
103d3d381b2SKyle Evans static int need_reinit;
104d3d381b2SKyle Evans 
105d3d381b2SKyle Evans static void *loader_hdl;
106d3d381b2SKyle Evans static char *loader;
107d3d381b2SKyle Evans static int explicit_loader;
108d3d381b2SKyle Evans static jmp_buf jb;
109d3d381b2SKyle Evans 
110b060ba50SNeel Natu static char *vmname, *progname;
111c487da1eSNeel Natu static struct vmctx *ctx;
112*7d9ef309SJohn Baldwin static struct vcpu *vcpu;
113c487da1eSNeel Natu 
114c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp;
115c487da1eSNeel Natu 
116c487da1eSNeel Natu static void cb_exit(void *arg, int v);
117c487da1eSNeel Natu 
118c487da1eSNeel Natu /*
119c487da1eSNeel Natu  * Console i/o callbacks
120c487da1eSNeel Natu  */
121c487da1eSNeel Natu 
122c487da1eSNeel Natu static void
123ad43dd69SMark Johnston cb_putc(void *arg __unused, int ch)
124c487da1eSNeel Natu {
125c487da1eSNeel Natu 	char c = ch;
126c487da1eSNeel Natu 
1276380102cSPeter Grehan 	(void) write(consout_fd, &c, 1);
128c487da1eSNeel Natu }
129c487da1eSNeel Natu 
130c487da1eSNeel Natu static int
131ad43dd69SMark Johnston cb_getc(void *arg __unused)
132c487da1eSNeel Natu {
133c487da1eSNeel Natu 	char c;
134c487da1eSNeel Natu 
1356380102cSPeter Grehan 	if (read(consin_fd, &c, 1) == 1)
136c487da1eSNeel Natu 		return (c);
137c487da1eSNeel Natu 	return (-1);
138c487da1eSNeel Natu }
139c487da1eSNeel Natu 
140c487da1eSNeel Natu static int
141ad43dd69SMark Johnston cb_poll(void *arg __unused)
142c487da1eSNeel Natu {
143c487da1eSNeel Natu 	int n;
144c487da1eSNeel Natu 
1456380102cSPeter Grehan 	if (ioctl(consin_fd, FIONREAD, &n) >= 0)
146c487da1eSNeel Natu 		return (n > 0);
147c487da1eSNeel Natu 	return (0);
148c487da1eSNeel Natu }
149c487da1eSNeel Natu 
150c487da1eSNeel Natu /*
151c487da1eSNeel Natu  * Host filesystem i/o callbacks
152c487da1eSNeel Natu  */
153c487da1eSNeel Natu 
154c487da1eSNeel Natu struct cb_file {
155c487da1eSNeel Natu 	int cf_isdir;
156c487da1eSNeel Natu 	size_t cf_size;
157c487da1eSNeel Natu 	struct stat cf_stat;
158c487da1eSNeel Natu 	union {
159c487da1eSNeel Natu 		int fd;
160c487da1eSNeel Natu 		DIR *dir;
161c487da1eSNeel Natu 	} cf_u;
162c487da1eSNeel Natu };
163c487da1eSNeel Natu 
164c487da1eSNeel Natu static int
165ad43dd69SMark Johnston cb_open(void *arg __unused, const char *filename, void **hp)
166c487da1eSNeel Natu {
167c487da1eSNeel Natu 	struct cb_file *cf;
168c487da1eSNeel Natu 	char path[PATH_MAX];
169c487da1eSNeel Natu 
170c487da1eSNeel Natu 	if (!host_base)
171c487da1eSNeel Natu 		return (ENOENT);
172c487da1eSNeel Natu 
173c487da1eSNeel Natu 	strlcpy(path, host_base, PATH_MAX);
174c487da1eSNeel Natu 	if (path[strlen(path) - 1] == '/')
175c487da1eSNeel Natu 		path[strlen(path) - 1] = 0;
176c487da1eSNeel Natu 	strlcat(path, filename, PATH_MAX);
177c487da1eSNeel Natu 	cf = malloc(sizeof(struct cb_file));
178c487da1eSNeel Natu 	if (stat(path, &cf->cf_stat) < 0) {
179c487da1eSNeel Natu 		free(cf);
180c487da1eSNeel Natu 		return (errno);
181c487da1eSNeel Natu 	}
182c487da1eSNeel Natu 
1838f61276dSPedro F. Giffuni 	cf->cf_size = cf->cf_stat.st_size;
184c487da1eSNeel Natu 	if (S_ISDIR(cf->cf_stat.st_mode)) {
185c487da1eSNeel Natu 		cf->cf_isdir = 1;
186c487da1eSNeel Natu 		cf->cf_u.dir = opendir(path);
187c487da1eSNeel Natu 		if (!cf->cf_u.dir)
188c487da1eSNeel Natu 			goto out;
189c487da1eSNeel Natu 		*hp = cf;
190c487da1eSNeel Natu 		return (0);
191c487da1eSNeel Natu 	}
192c487da1eSNeel Natu 	if (S_ISREG(cf->cf_stat.st_mode)) {
193c487da1eSNeel Natu 		cf->cf_isdir = 0;
194c487da1eSNeel Natu 		cf->cf_u.fd = open(path, O_RDONLY);
195c487da1eSNeel Natu 		if (cf->cf_u.fd < 0)
196c487da1eSNeel Natu 			goto out;
197c487da1eSNeel Natu 		*hp = cf;
198c487da1eSNeel Natu 		return (0);
199c487da1eSNeel Natu 	}
200c487da1eSNeel Natu 
201c487da1eSNeel Natu out:
202c487da1eSNeel Natu 	free(cf);
203c487da1eSNeel Natu 	return (EINVAL);
204c487da1eSNeel Natu }
205c487da1eSNeel Natu 
206c487da1eSNeel Natu static int
207ad43dd69SMark Johnston cb_close(void *arg __unused, void *h)
208c487da1eSNeel Natu {
209c487da1eSNeel Natu 	struct cb_file *cf = h;
210c487da1eSNeel Natu 
211c487da1eSNeel Natu 	if (cf->cf_isdir)
212c487da1eSNeel Natu 		closedir(cf->cf_u.dir);
213c487da1eSNeel Natu 	else
214c487da1eSNeel Natu 		close(cf->cf_u.fd);
215c487da1eSNeel Natu 	free(cf);
216c487da1eSNeel Natu 
217c487da1eSNeel Natu 	return (0);
218c487da1eSNeel Natu }
219c487da1eSNeel Natu 
220c487da1eSNeel Natu static int
221ad43dd69SMark Johnston cb_isdir(void *arg __unused, void *h)
222c487da1eSNeel Natu {
223c487da1eSNeel Natu 	struct cb_file *cf = h;
224c487da1eSNeel Natu 
225c487da1eSNeel Natu 	return (cf->cf_isdir);
226c487da1eSNeel Natu }
227c487da1eSNeel Natu 
228c487da1eSNeel Natu static int
229ad43dd69SMark Johnston cb_read(void *arg __unused, void *h, void *buf, size_t size, size_t *resid)
230c487da1eSNeel Natu {
231c487da1eSNeel Natu 	struct cb_file *cf = h;
232c487da1eSNeel Natu 	ssize_t sz;
233c487da1eSNeel Natu 
234c487da1eSNeel Natu 	if (cf->cf_isdir)
235c487da1eSNeel Natu 		return (EINVAL);
236c487da1eSNeel Natu 	sz = read(cf->cf_u.fd, buf, size);
237c487da1eSNeel Natu 	if (sz < 0)
238c487da1eSNeel Natu 		return (EINVAL);
239c487da1eSNeel Natu 	*resid = size - sz;
240c487da1eSNeel Natu 	return (0);
241c487da1eSNeel Natu }
242c487da1eSNeel Natu 
243c487da1eSNeel Natu static int
244ad43dd69SMark Johnston cb_readdir(void *arg __unused, void *h, uint32_t *fileno_return,
245ad43dd69SMark Johnston     uint8_t *type_return, size_t *namelen_return, char *name)
246c487da1eSNeel Natu {
247c487da1eSNeel Natu 	struct cb_file *cf = h;
248c487da1eSNeel Natu 	struct dirent *dp;
249c487da1eSNeel Natu 
250c487da1eSNeel Natu 	if (!cf->cf_isdir)
251c487da1eSNeel Natu 		return (EINVAL);
252c487da1eSNeel Natu 
253c487da1eSNeel Natu 	dp = readdir(cf->cf_u.dir);
254c487da1eSNeel Natu 	if (!dp)
255c487da1eSNeel Natu 		return (ENOENT);
256c487da1eSNeel Natu 
257c487da1eSNeel Natu 	/*
258c487da1eSNeel Natu 	 * Note: d_namlen is in the range 0..255 and therefore less
259c487da1eSNeel Natu 	 * than PATH_MAX so we don't need to test before copying.
260c487da1eSNeel Natu 	 */
261c487da1eSNeel Natu 	*fileno_return = dp->d_fileno;
262c487da1eSNeel Natu 	*type_return = dp->d_type;
263c487da1eSNeel Natu 	*namelen_return = dp->d_namlen;
264c487da1eSNeel Natu 	memcpy(name, dp->d_name, dp->d_namlen);
265c487da1eSNeel Natu 	name[dp->d_namlen] = 0;
266c487da1eSNeel Natu 
267c487da1eSNeel Natu 	return (0);
268c487da1eSNeel Natu }
269c487da1eSNeel Natu 
270c487da1eSNeel Natu static int
271ad43dd69SMark Johnston cb_seek(void *arg __unused, void *h, uint64_t offset, int whence)
272c487da1eSNeel Natu {
273c487da1eSNeel Natu 	struct cb_file *cf = h;
274c487da1eSNeel Natu 
275c487da1eSNeel Natu 	if (cf->cf_isdir)
276c487da1eSNeel Natu 		return (EINVAL);
277c487da1eSNeel Natu 	if (lseek(cf->cf_u.fd, offset, whence) < 0)
278c487da1eSNeel Natu 		return (errno);
279c487da1eSNeel Natu 	return (0);
280c487da1eSNeel Natu }
281c487da1eSNeel Natu 
282c487da1eSNeel Natu static int
283ad43dd69SMark Johnston cb_stat(void *arg __unused, void *h, struct stat *sbp)
284c487da1eSNeel Natu {
285c487da1eSNeel Natu 	struct cb_file *cf = h;
286c487da1eSNeel Natu 
28753f151f9SSimon J. Gerraty 	memset(sbp, 0, sizeof(struct stat));
28853f151f9SSimon J. Gerraty 	sbp->st_mode = cf->cf_stat.st_mode;
28953f151f9SSimon J. Gerraty 	sbp->st_uid = cf->cf_stat.st_uid;
29053f151f9SSimon J. Gerraty 	sbp->st_gid = cf->cf_stat.st_gid;
29153f151f9SSimon J. Gerraty 	sbp->st_size = cf->cf_stat.st_size;
29253f151f9SSimon J. Gerraty 	sbp->st_mtime = cf->cf_stat.st_mtime;
29353f151f9SSimon J. Gerraty 	sbp->st_dev = cf->cf_stat.st_dev;
29453f151f9SSimon J. Gerraty 	sbp->st_ino = cf->cf_stat.st_ino;
29553f151f9SSimon J. Gerraty 
296c487da1eSNeel Natu 	return (0);
297c487da1eSNeel Natu }
298c487da1eSNeel Natu 
299c487da1eSNeel Natu /*
300c487da1eSNeel Natu  * Disk image i/o callbacks
301c487da1eSNeel Natu  */
302c487da1eSNeel Natu 
303c487da1eSNeel Natu static int
304ad43dd69SMark Johnston cb_diskread(void *arg __unused, int unit, uint64_t from, void *to, size_t size,
305c487da1eSNeel Natu     size_t *resid)
306c487da1eSNeel Natu {
307c487da1eSNeel Natu 	ssize_t n;
308c487da1eSNeel Natu 
309cf087c12SPeter Grehan 	if (unit < 0 || unit >= ndisks)
310c487da1eSNeel Natu 		return (EIO);
311cf087c12SPeter Grehan 	n = pread(disk_fd[unit], to, size, from);
312c487da1eSNeel Natu 	if (n < 0)
313c487da1eSNeel Natu 		return (errno);
314c487da1eSNeel Natu 	*resid = size - n;
315c487da1eSNeel Natu 	return (0);
316c487da1eSNeel Natu }
317c487da1eSNeel Natu 
318a10c6f55SNeel Natu static int
319ad43dd69SMark Johnston cb_diskwrite(void *arg __unused, int unit, uint64_t offset, void *src,
320ad43dd69SMark Johnston     size_t size, size_t *resid)
321cc71ff72SConrad Meyer {
322cc71ff72SConrad Meyer 	ssize_t n;
323cc71ff72SConrad Meyer 
324cc71ff72SConrad Meyer 	if (unit < 0 || unit >= ndisks)
325cc71ff72SConrad Meyer 		return (EIO);
326cc71ff72SConrad Meyer 	n = pwrite(disk_fd[unit], src, size, offset);
327cc71ff72SConrad Meyer 	if (n < 0)
328cc71ff72SConrad Meyer 		return (errno);
329cc71ff72SConrad Meyer 	*resid = size - n;
330cc71ff72SConrad Meyer 	return (0);
331cc71ff72SConrad Meyer }
332cc71ff72SConrad Meyer 
333cc71ff72SConrad Meyer static int
334ad43dd69SMark Johnston cb_diskioctl(void *arg __unused, int unit, u_long cmd, void *data)
335a10c6f55SNeel Natu {
336a10c6f55SNeel Natu 	struct stat sb;
337a10c6f55SNeel Natu 
338cf087c12SPeter Grehan 	if (unit < 0 || unit >= ndisks)
339a10c6f55SNeel Natu 		return (EBADF);
340a10c6f55SNeel Natu 
341a10c6f55SNeel Natu 	switch (cmd) {
342a10c6f55SNeel Natu 	case DIOCGSECTORSIZE:
343a10c6f55SNeel Natu 		*(u_int *)data = 512;
344a10c6f55SNeel Natu 		break;
345a10c6f55SNeel Natu 	case DIOCGMEDIASIZE:
3466589ee29SAndriy Gapon 		if (fstat(disk_fd[unit], &sb) != 0)
347a10c6f55SNeel Natu 			return (ENOTTY);
3486589ee29SAndriy Gapon 		if (S_ISCHR(sb.st_mode) &&
3496589ee29SAndriy Gapon 		    ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0)
3506589ee29SAndriy Gapon 				return (ENOTTY);
3516589ee29SAndriy Gapon 		*(off_t *)data = sb.st_size;
352a10c6f55SNeel Natu 		break;
353a10c6f55SNeel Natu 	default:
354a10c6f55SNeel Natu 		return (ENOTTY);
355a10c6f55SNeel Natu 	}
356a10c6f55SNeel Natu 
357a10c6f55SNeel Natu 	return (0);
358a10c6f55SNeel Natu }
359a10c6f55SNeel Natu 
360c487da1eSNeel Natu /*
361c487da1eSNeel Natu  * Guest virtual machine i/o callbacks
362c487da1eSNeel Natu  */
363c487da1eSNeel Natu static int
364ad43dd69SMark Johnston cb_copyin(void *arg __unused, const void *from, uint64_t to, size_t size)
365c487da1eSNeel Natu {
366b060ba50SNeel Natu 	char *ptr;
367c487da1eSNeel Natu 
368c487da1eSNeel Natu 	to &= 0x7fffffff;
369b060ba50SNeel Natu 
370b060ba50SNeel Natu 	ptr = vm_map_gpa(ctx, to, size);
371b060ba50SNeel Natu 	if (ptr == NULL)
372c487da1eSNeel Natu 		return (EFAULT);
373c487da1eSNeel Natu 
374b060ba50SNeel Natu 	memcpy(ptr, from, size);
375c487da1eSNeel Natu 	return (0);
376c487da1eSNeel Natu }
377c487da1eSNeel Natu 
378c487da1eSNeel Natu static int
379ad43dd69SMark Johnston cb_copyout(void *arg __unused, uint64_t from, void *to, size_t size)
380c487da1eSNeel Natu {
381b060ba50SNeel Natu 	char *ptr;
382c487da1eSNeel Natu 
383c487da1eSNeel Natu 	from &= 0x7fffffff;
384b060ba50SNeel Natu 
385b060ba50SNeel Natu 	ptr = vm_map_gpa(ctx, from, size);
386b060ba50SNeel Natu 	if (ptr == NULL)
387c487da1eSNeel Natu 		return (EFAULT);
388c487da1eSNeel Natu 
389b060ba50SNeel Natu 	memcpy(to, ptr, size);
390c487da1eSNeel Natu 	return (0);
391c487da1eSNeel Natu }
392c487da1eSNeel Natu 
393c487da1eSNeel Natu static void
394ad43dd69SMark Johnston cb_setreg(void *arg __unused, int r, uint64_t v)
395c487da1eSNeel Natu {
396c487da1eSNeel Natu 	int error;
397c487da1eSNeel Natu 	enum vm_reg_name vmreg;
398c487da1eSNeel Natu 
399c487da1eSNeel Natu 	vmreg = VM_REG_LAST;
400c487da1eSNeel Natu 
401c487da1eSNeel Natu 	switch (r) {
402c487da1eSNeel Natu 	case 4:
403c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_RSP;
404c487da1eSNeel Natu 		rsp = v;
405c487da1eSNeel Natu 		break;
406c487da1eSNeel Natu 	default:
407c487da1eSNeel Natu 		break;
408c487da1eSNeel Natu 	}
409c487da1eSNeel Natu 
410c487da1eSNeel Natu 	if (vmreg == VM_REG_LAST) {
411c487da1eSNeel Natu 		printf("test_setreg(%d): not implemented\n", r);
412c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
413c487da1eSNeel Natu 	}
414c487da1eSNeel Natu 
415*7d9ef309SJohn Baldwin 	error = vm_set_register(vcpu, vmreg, v);
416c487da1eSNeel Natu 	if (error) {
417c487da1eSNeel Natu 		perror("vm_set_register");
418c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
419c487da1eSNeel Natu 	}
420c487da1eSNeel Natu }
421c487da1eSNeel Natu 
422c487da1eSNeel Natu static void
423ad43dd69SMark Johnston cb_setmsr(void *arg __unused, int r, uint64_t v)
424c487da1eSNeel Natu {
425c487da1eSNeel Natu 	int error;
426c487da1eSNeel Natu 	enum vm_reg_name vmreg;
427c487da1eSNeel Natu 
428c487da1eSNeel Natu 	vmreg = VM_REG_LAST;
429c487da1eSNeel Natu 
430c487da1eSNeel Natu 	switch (r) {
431c487da1eSNeel Natu 	case MSR_EFER:
432c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_EFER;
433c487da1eSNeel Natu 		break;
434c487da1eSNeel Natu 	default:
435c487da1eSNeel Natu 		break;
436c487da1eSNeel Natu 	}
437c487da1eSNeel Natu 
438c487da1eSNeel Natu 	if (vmreg == VM_REG_LAST) {
439c487da1eSNeel Natu 		printf("test_setmsr(%d): not implemented\n", r);
440c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
441c487da1eSNeel Natu 	}
442c487da1eSNeel Natu 
443*7d9ef309SJohn Baldwin 	error = vm_set_register(vcpu, vmreg, v);
444c487da1eSNeel Natu 	if (error) {
445c487da1eSNeel Natu 		perror("vm_set_msr");
446c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
447c487da1eSNeel Natu 	}
448c487da1eSNeel Natu }
449c487da1eSNeel Natu 
450c487da1eSNeel Natu static void
451ad43dd69SMark Johnston cb_setcr(void *arg __unused, int r, uint64_t v)
452c487da1eSNeel Natu {
453c487da1eSNeel Natu 	int error;
454c487da1eSNeel Natu 	enum vm_reg_name vmreg;
455c487da1eSNeel Natu 
456c487da1eSNeel Natu 	vmreg = VM_REG_LAST;
457c487da1eSNeel Natu 
458c487da1eSNeel Natu 	switch (r) {
459c487da1eSNeel Natu 	case 0:
460c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_CR0;
461c487da1eSNeel Natu 		break;
462c487da1eSNeel Natu 	case 3:
463c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_CR3;
464c487da1eSNeel Natu 		cr3 = v;
465c487da1eSNeel Natu 		break;
466c487da1eSNeel Natu 	case 4:
467c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_CR4;
468c487da1eSNeel Natu 		break;
469c487da1eSNeel Natu 	default:
470c487da1eSNeel Natu 		break;
471c487da1eSNeel Natu 	}
472c487da1eSNeel Natu 
473c487da1eSNeel Natu 	if (vmreg == VM_REG_LAST) {
474c487da1eSNeel Natu 		printf("test_setcr(%d): not implemented\n", r);
475c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
476c487da1eSNeel Natu 	}
477c487da1eSNeel Natu 
478*7d9ef309SJohn Baldwin 	error = vm_set_register(vcpu, vmreg, v);
479c487da1eSNeel Natu 	if (error) {
480c487da1eSNeel Natu 		perror("vm_set_cr");
481c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
482c487da1eSNeel Natu 	}
483c487da1eSNeel Natu }
484c487da1eSNeel Natu 
485c487da1eSNeel Natu static void
486ad43dd69SMark Johnston cb_setgdt(void *arg __unused, uint64_t base, size_t size)
487c487da1eSNeel Natu {
488c487da1eSNeel Natu 	int error;
489c487da1eSNeel Natu 
490*7d9ef309SJohn Baldwin 	error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR, base, size - 1, 0);
491c487da1eSNeel Natu 	if (error != 0) {
492c487da1eSNeel Natu 		perror("vm_set_desc(gdt)");
493c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
494c487da1eSNeel Natu 	}
495c487da1eSNeel Natu 
496c487da1eSNeel Natu 	gdtbase = base;
497c487da1eSNeel Natu }
498c487da1eSNeel Natu 
499c487da1eSNeel Natu static void
500ad43dd69SMark Johnston cb_exec(void *arg __unused, uint64_t rip)
501c487da1eSNeel Natu {
502c487da1eSNeel Natu 	int error;
503c487da1eSNeel Natu 
50400f3efe1SJohn Baldwin 	if (cr3 == 0)
505*7d9ef309SJohn Baldwin 		error = vm_setup_freebsd_registers_i386(vcpu, rip, gdtbase,
50600f3efe1SJohn Baldwin 		    rsp);
50700f3efe1SJohn Baldwin 	else
508*7d9ef309SJohn Baldwin 		error = vm_setup_freebsd_registers(vcpu, rip, cr3, gdtbase,
50900f3efe1SJohn Baldwin 		    rsp);
510c487da1eSNeel Natu 	if (error) {
511c487da1eSNeel Natu 		perror("vm_setup_freebsd_registers");
512c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
513c487da1eSNeel Natu 	}
514c487da1eSNeel Natu 
515c487da1eSNeel Natu 	cb_exit(NULL, 0);
516c487da1eSNeel Natu }
517c487da1eSNeel Natu 
518c487da1eSNeel Natu /*
519c487da1eSNeel Natu  * Misc
520c487da1eSNeel Natu  */
521c487da1eSNeel Natu 
522c487da1eSNeel Natu static void
523ad43dd69SMark Johnston cb_delay(void *arg __unused, int usec)
524c487da1eSNeel Natu {
525c487da1eSNeel Natu 
526c487da1eSNeel Natu 	usleep(usec);
527c487da1eSNeel Natu }
528c487da1eSNeel Natu 
529c487da1eSNeel Natu static void
530ad43dd69SMark Johnston cb_exit(void *arg __unused, int v)
531c487da1eSNeel Natu {
532c487da1eSNeel Natu 
5336380102cSPeter Grehan 	tcsetattr(consout_fd, TCSAFLUSH, &oldterm);
534c487da1eSNeel Natu 	exit(v);
535c487da1eSNeel Natu }
536c487da1eSNeel Natu 
537c487da1eSNeel Natu static void
538ad43dd69SMark Johnston cb_getmem(void *arg __unused, uint64_t *ret_lowmem, uint64_t *ret_highmem)
539c487da1eSNeel Natu {
540c487da1eSNeel Natu 
541be679db4SNeel Natu 	*ret_lowmem = vm_get_lowmem_size(ctx);
542be679db4SNeel Natu 	*ret_highmem = vm_get_highmem_size(ctx);
543c487da1eSNeel Natu }
544c487da1eSNeel Natu 
545b6afa84bSNeel Natu struct env {
546cb37fc82SWarner Losh 	char *str;	/* name=value */
547b6afa84bSNeel Natu 	SLIST_ENTRY(env) next;
548b6afa84bSNeel Natu };
549b6afa84bSNeel Natu 
550b6afa84bSNeel Natu static SLIST_HEAD(envhead, env) envhead;
551b6afa84bSNeel Natu 
552b6afa84bSNeel Natu static void
553ad43dd69SMark Johnston addenv(const char *str)
554b6afa84bSNeel Natu {
555b6afa84bSNeel Natu 	struct env *env;
556b6afa84bSNeel Natu 
557b6afa84bSNeel Natu 	env = malloc(sizeof(struct env));
558ad43dd69SMark Johnston 	if (env == NULL)
559ad43dd69SMark Johnston 		err(EX_OSERR, "malloc");
560ad43dd69SMark Johnston 	env->str = strdup(str);
561ad43dd69SMark Johnston 	if (env->str == NULL)
562ad43dd69SMark Johnston 		err(EX_OSERR, "strdup");
563b6afa84bSNeel Natu 	SLIST_INSERT_HEAD(&envhead, env, next);
564b6afa84bSNeel Natu }
565b6afa84bSNeel Natu 
566e8e6a5f9SWarner Losh static char *
567ad43dd69SMark Johnston cb_getenv(void *arg __unused, int num)
568c3e9ce33SNeel Natu {
569b6afa84bSNeel Natu 	int i;
570b6afa84bSNeel Natu 	struct env *env;
571c3e9ce33SNeel Natu 
572b6afa84bSNeel Natu 	i = 0;
573b6afa84bSNeel Natu 	SLIST_FOREACH(env, &envhead, next) {
574b6afa84bSNeel Natu 		if (i == num)
575b6afa84bSNeel Natu 			return (env->str);
576b6afa84bSNeel Natu 		i++;
577b6afa84bSNeel Natu 	}
578c3e9ce33SNeel Natu 
579c3e9ce33SNeel Natu 	return (NULL);
580c3e9ce33SNeel Natu }
581c3e9ce33SNeel Natu 
58248f337b8SMarcel Moolenaar static int
583*7d9ef309SJohn Baldwin cb_vm_set_register(void *arg __unused, int vcpuid, int reg, uint64_t val)
58448f337b8SMarcel Moolenaar {
58548f337b8SMarcel Moolenaar 
586*7d9ef309SJohn Baldwin 	assert(vcpuid == BSP);
587*7d9ef309SJohn Baldwin 	return (vm_set_register(vcpu, reg, val));
58848f337b8SMarcel Moolenaar }
58948f337b8SMarcel Moolenaar 
59048f337b8SMarcel Moolenaar static int
591*7d9ef309SJohn Baldwin cb_vm_set_desc(void *arg __unused, int vcpuid, int reg, uint64_t base,
592ad43dd69SMark Johnston     u_int limit, u_int access)
59348f337b8SMarcel Moolenaar {
59448f337b8SMarcel Moolenaar 
595*7d9ef309SJohn Baldwin 	assert(vcpuid == BSP);
596*7d9ef309SJohn Baldwin 	return (vm_set_desc(vcpu, reg, base, limit, access));
59748f337b8SMarcel Moolenaar }
59848f337b8SMarcel Moolenaar 
599d3d381b2SKyle Evans static void
600ad43dd69SMark Johnston cb_swap_interpreter(void *arg __unused, const char *interp_req)
601d3d381b2SKyle Evans {
602d3d381b2SKyle Evans 
603d3d381b2SKyle Evans 	/*
604d3d381b2SKyle Evans 	 * If the user specified a loader but we detected a mismatch, we should
605d3d381b2SKyle Evans 	 * not try to pivot to a different loader on them.
606d3d381b2SKyle Evans 	 */
607d3d381b2SKyle Evans 	free(loader);
608d3d381b2SKyle Evans 	if (explicit_loader == 1) {
609d3d381b2SKyle Evans 		perror("requested loader interpreter does not match guest userboot");
610d3d381b2SKyle Evans 		cb_exit(NULL, 1);
611d3d381b2SKyle Evans 	}
612d3d381b2SKyle Evans 	if (interp_req == NULL || *interp_req == '\0') {
613d3d381b2SKyle Evans 		perror("guest failed to request an interpreter");
614d3d381b2SKyle Evans 		cb_exit(NULL, 1);
615d3d381b2SKyle Evans 	}
616d3d381b2SKyle Evans 
617d3d381b2SKyle Evans 	if (asprintf(&loader, "/boot/userboot_%s.so", interp_req) == -1)
618d3d381b2SKyle Evans 		err(EX_OSERR, "malloc");
619d3d381b2SKyle Evans 	need_reinit = 1;
620d3d381b2SKyle Evans 	longjmp(jb, 1);
621d3d381b2SKyle Evans }
622d3d381b2SKyle Evans 
623a10c6f55SNeel Natu static struct loader_callbacks cb = {
624c487da1eSNeel Natu 	.getc = cb_getc,
625c487da1eSNeel Natu 	.putc = cb_putc,
626c487da1eSNeel Natu 	.poll = cb_poll,
627c487da1eSNeel Natu 
628c487da1eSNeel Natu 	.open = cb_open,
629c487da1eSNeel Natu 	.close = cb_close,
630c487da1eSNeel Natu 	.isdir = cb_isdir,
631c487da1eSNeel Natu 	.read = cb_read,
632c487da1eSNeel Natu 	.readdir = cb_readdir,
633c487da1eSNeel Natu 	.seek = cb_seek,
634c487da1eSNeel Natu 	.stat = cb_stat,
635c487da1eSNeel Natu 
636c487da1eSNeel Natu 	.diskread = cb_diskread,
637cc71ff72SConrad Meyer 	.diskwrite = cb_diskwrite,
638a10c6f55SNeel Natu 	.diskioctl = cb_diskioctl,
639c487da1eSNeel Natu 
640c487da1eSNeel Natu 	.copyin = cb_copyin,
641c487da1eSNeel Natu 	.copyout = cb_copyout,
642c487da1eSNeel Natu 	.setreg = cb_setreg,
643c487da1eSNeel Natu 	.setmsr = cb_setmsr,
644c487da1eSNeel Natu 	.setcr = cb_setcr,
645c487da1eSNeel Natu 	.setgdt = cb_setgdt,
646c487da1eSNeel Natu 	.exec = cb_exec,
647c487da1eSNeel Natu 
648c487da1eSNeel Natu 	.delay = cb_delay,
649c487da1eSNeel Natu 	.exit = cb_exit,
650c487da1eSNeel Natu 	.getmem = cb_getmem,
651c3e9ce33SNeel Natu 
652c3e9ce33SNeel Natu 	.getenv = cb_getenv,
65348f337b8SMarcel Moolenaar 
65448f337b8SMarcel Moolenaar 	/* Version 4 additions */
65548f337b8SMarcel Moolenaar 	.vm_set_register = cb_vm_set_register,
65648f337b8SMarcel Moolenaar 	.vm_set_desc = cb_vm_set_desc,
657d3d381b2SKyle Evans 
658d3d381b2SKyle Evans 	/* Version 5 additions */
659d3d381b2SKyle Evans 	.swap_interpreter = cb_swap_interpreter,
660c487da1eSNeel Natu };
661c487da1eSNeel Natu 
6626380102cSPeter Grehan static int
6636380102cSPeter Grehan altcons_open(char *path)
6646380102cSPeter Grehan {
6656380102cSPeter Grehan 	struct stat sb;
6666380102cSPeter Grehan 	int err;
6676380102cSPeter Grehan 	int fd;
6686380102cSPeter Grehan 
6696380102cSPeter Grehan 	/*
6706380102cSPeter Grehan 	 * Allow stdio to be passed in so that the same string
6716380102cSPeter Grehan 	 * can be used for the bhyveload console and bhyve com-port
6726380102cSPeter Grehan 	 * parameters
6736380102cSPeter Grehan 	 */
6746380102cSPeter Grehan 	if (!strcmp(path, "stdio"))
6756380102cSPeter Grehan 		return (0);
6766380102cSPeter Grehan 
6776380102cSPeter Grehan 	err = stat(path, &sb);
6786380102cSPeter Grehan 	if (err == 0) {
6796380102cSPeter Grehan 		if (!S_ISCHR(sb.st_mode))
6806380102cSPeter Grehan 			err = ENOTSUP;
6816380102cSPeter Grehan 		else {
6826380102cSPeter Grehan 			fd = open(path, O_RDWR | O_NONBLOCK);
6836380102cSPeter Grehan 			if (fd < 0)
6846380102cSPeter Grehan 				err = errno;
6856380102cSPeter Grehan 			else
6866380102cSPeter Grehan 				consin_fd = consout_fd = fd;
6876380102cSPeter Grehan 		}
6886380102cSPeter Grehan 	}
6896380102cSPeter Grehan 
6906380102cSPeter Grehan 	return (err);
6916380102cSPeter Grehan }
6926380102cSPeter Grehan 
693cf087c12SPeter Grehan static int
694cf087c12SPeter Grehan disk_open(char *path)
695cf087c12SPeter Grehan {
696a0bc451fSSean Chittenden 	int fd;
697cf087c12SPeter Grehan 
6980db293c1SAllan Jude 	if (ndisks >= NDISKS)
699cf087c12SPeter Grehan 		return (ERANGE);
700cf087c12SPeter Grehan 
7015a023bd2SRobert Wing 	fd = open(path, O_RDWR);
702a0bc451fSSean Chittenden 	if (fd < 0)
703a0bc451fSSean Chittenden 		return (errno);
704cf087c12SPeter Grehan 
705cf087c12SPeter Grehan 	disk_fd[ndisks] = fd;
706cf087c12SPeter Grehan 	ndisks++;
707cf087c12SPeter Grehan 
708a0bc451fSSean Chittenden 	return (0);
709cf087c12SPeter Grehan }
710cf087c12SPeter Grehan 
711c487da1eSNeel Natu static void
712c487da1eSNeel Natu usage(void)
713c487da1eSNeel Natu {
714c487da1eSNeel Natu 
715b060ba50SNeel Natu 	fprintf(stderr,
7169b1aa8d6SNeel Natu 	    "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n"
7176ee52c65SRoman Bogorodskiy 	    "       %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n",
7186380102cSPeter Grehan 	    progname,
719b5331f4dSNeel Natu 	    (int)strlen(progname), "");
720c487da1eSNeel Natu 	exit(1);
721c487da1eSNeel Natu }
722c487da1eSNeel Natu 
723c487da1eSNeel Natu int
724c487da1eSNeel Natu main(int argc, char** argv)
725c487da1eSNeel Natu {
726a10c6f55SNeel Natu 	void (*func)(struct loader_callbacks *, void *, int, int);
727b060ba50SNeel Natu 	uint64_t mem_size;
728d3d381b2SKyle Evans 	int opt, error, memflags;
729c487da1eSNeel Natu 
730b5331f4dSNeel Natu 	progname = basename(argv[0]);
731c487da1eSNeel Natu 
7329b1aa8d6SNeel Natu 	memflags = 0;
733b060ba50SNeel Natu 	mem_size = 256 * MB;
734c487da1eSNeel Natu 
7356380102cSPeter Grehan 	consin_fd = STDIN_FILENO;
7366380102cSPeter Grehan 	consout_fd = STDOUT_FILENO;
7376380102cSPeter Grehan 
738568e3a8dSMarcel Moolenaar 	while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) {
739c487da1eSNeel Natu 		switch (opt) {
7406380102cSPeter Grehan 		case 'c':
7416380102cSPeter Grehan 			error = altcons_open(optarg);
7426380102cSPeter Grehan 			if (error != 0)
7436380102cSPeter Grehan 				errx(EX_USAGE, "Could not open '%s'", optarg);
7446380102cSPeter Grehan 			break;
745cf087c12SPeter Grehan 
746c487da1eSNeel Natu 		case 'd':
747cf087c12SPeter Grehan 			error = disk_open(optarg);
748cf087c12SPeter Grehan 			if (error != 0)
749cf087c12SPeter Grehan 				errx(EX_USAGE, "Could not open '%s'", optarg);
750c487da1eSNeel Natu 			break;
751c487da1eSNeel Natu 
752b6afa84bSNeel Natu 		case 'e':
753b6afa84bSNeel Natu 			addenv(optarg);
754b6afa84bSNeel Natu 			break;
755b6afa84bSNeel Natu 
756c487da1eSNeel Natu 		case 'h':
757c487da1eSNeel Natu 			host_base = optarg;
758c487da1eSNeel Natu 			break;
759c487da1eSNeel Natu 
7608c96dcc1SMarcel Moolenaar 		case 'l':
7618c96dcc1SMarcel Moolenaar 			if (loader != NULL)
7628c96dcc1SMarcel Moolenaar 				errx(EX_USAGE, "-l can only be given once");
7638c96dcc1SMarcel Moolenaar 			loader = strdup(optarg);
7648c96dcc1SMarcel Moolenaar 			if (loader == NULL)
7658c96dcc1SMarcel Moolenaar 				err(EX_OSERR, "malloc");
766d3d381b2SKyle Evans 			explicit_loader = 1;
7678c96dcc1SMarcel Moolenaar 			break;
7688c96dcc1SMarcel Moolenaar 
769c487da1eSNeel Natu 		case 'm':
770200758f1SNeel Natu 			error = vm_parse_memsize(optarg, &mem_size);
771200758f1SNeel Natu 			if (error != 0)
772200758f1SNeel Natu 				errx(EX_USAGE, "Invalid memsize '%s'", optarg);
773c487da1eSNeel Natu 			break;
774568e3a8dSMarcel Moolenaar 		case 'C':
775568e3a8dSMarcel Moolenaar 			memflags |= VM_MEM_F_INCORE;
776568e3a8dSMarcel Moolenaar 			break;
7779b1aa8d6SNeel Natu 		case 'S':
7789b1aa8d6SNeel Natu 			memflags |= VM_MEM_F_WIRED;
7799b1aa8d6SNeel Natu 			break;
780c487da1eSNeel Natu 		case '?':
781c487da1eSNeel Natu 			usage();
782c487da1eSNeel Natu 		}
783c487da1eSNeel Natu 	}
784c487da1eSNeel Natu 
785c487da1eSNeel Natu 	argc -= optind;
786c487da1eSNeel Natu 	argv += optind;
787c487da1eSNeel Natu 
788c487da1eSNeel Natu 	if (argc != 1)
789c487da1eSNeel Natu 		usage();
790c487da1eSNeel Natu 
791c487da1eSNeel Natu 	vmname = argv[0];
792c487da1eSNeel Natu 
7935fcf252fSNeel Natu 	need_reinit = 0;
794c487da1eSNeel Natu 	error = vm_create(vmname);
7955fcf252fSNeel Natu 	if (error) {
7965fcf252fSNeel Natu 		if (errno != EEXIST) {
797c487da1eSNeel Natu 			perror("vm_create");
798c487da1eSNeel Natu 			exit(1);
7995fcf252fSNeel Natu 		}
8005fcf252fSNeel Natu 		need_reinit = 1;
801c487da1eSNeel Natu 	}
802c487da1eSNeel Natu 
803c487da1eSNeel Natu 	ctx = vm_open(vmname);
804c487da1eSNeel Natu 	if (ctx == NULL) {
805c487da1eSNeel Natu 		perror("vm_open");
806c487da1eSNeel Natu 		exit(1);
807c487da1eSNeel Natu 	}
808c487da1eSNeel Natu 
809*7d9ef309SJohn Baldwin 	vcpu = vm_vcpu_open(ctx, BSP);
810*7d9ef309SJohn Baldwin 
811d3d381b2SKyle Evans 	/*
812d3d381b2SKyle Evans 	 * setjmp in the case the guest wants to swap out interpreter,
813d3d381b2SKyle Evans 	 * cb_swap_interpreter will swap out loader as appropriate and set
814d3d381b2SKyle Evans 	 * need_reinit so that we end up in a clean state once again.
815d3d381b2SKyle Evans 	 */
816d3d381b2SKyle Evans 	setjmp(jb);
817d3d381b2SKyle Evans 
8185fcf252fSNeel Natu 	if (need_reinit) {
8195fcf252fSNeel Natu 		error = vm_reinit(ctx);
8205fcf252fSNeel Natu 		if (error) {
8215fcf252fSNeel Natu 			perror("vm_reinit");
8225fcf252fSNeel Natu 			exit(1);
8235fcf252fSNeel Natu 		}
8245fcf252fSNeel Natu 	}
8255fcf252fSNeel Natu 
8269b1aa8d6SNeel Natu 	vm_set_memflags(ctx, memflags);
827b060ba50SNeel Natu 	error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL);
828c487da1eSNeel Natu 	if (error) {
829b060ba50SNeel Natu 		perror("vm_setup_memory");
830c487da1eSNeel Natu 		exit(1);
831c487da1eSNeel Natu 	}
832c487da1eSNeel Natu 
8338c96dcc1SMarcel Moolenaar 	if (loader == NULL) {
8348c96dcc1SMarcel Moolenaar 		loader = strdup("/boot/userboot.so");
8358c96dcc1SMarcel Moolenaar 		if (loader == NULL)
8368c96dcc1SMarcel Moolenaar 			err(EX_OSERR, "malloc");
8378c96dcc1SMarcel Moolenaar 	}
838d3d381b2SKyle Evans 	if (loader_hdl != NULL)
839d3d381b2SKyle Evans 		dlclose(loader_hdl);
840d3d381b2SKyle Evans 	loader_hdl = dlopen(loader, RTLD_LOCAL);
841d3d381b2SKyle Evans 	if (!loader_hdl) {
8428c96dcc1SMarcel Moolenaar 		printf("%s\n", dlerror());
8438c96dcc1SMarcel Moolenaar 		free(loader);
8448c96dcc1SMarcel Moolenaar 		return (1);
8458c96dcc1SMarcel Moolenaar 	}
846d3d381b2SKyle Evans 	func = dlsym(loader_hdl, "loader_main");
8478c96dcc1SMarcel Moolenaar 	if (!func) {
8488c96dcc1SMarcel Moolenaar 		printf("%s\n", dlerror());
8498c96dcc1SMarcel Moolenaar 		free(loader);
8508c96dcc1SMarcel Moolenaar 		return (1);
8518c96dcc1SMarcel Moolenaar 	}
8528c96dcc1SMarcel Moolenaar 
8536380102cSPeter Grehan 	tcgetattr(consout_fd, &term);
854c487da1eSNeel Natu 	oldterm = term;
8556380102cSPeter Grehan 	cfmakeraw(&term);
8566380102cSPeter Grehan 	term.c_cflag |= CLOCAL;
8576380102cSPeter Grehan 
8586380102cSPeter Grehan 	tcsetattr(consout_fd, TCSAFLUSH, &term);
8596380102cSPeter Grehan 
860b6afa84bSNeel Natu 	addenv("smbios.bios.vendor=BHYVE");
861b6afa84bSNeel Natu 	addenv("boot_serial=1");
862b6afa84bSNeel Natu 
863d3d381b2SKyle Evans 	func(&cb, NULL, USERBOOT_VERSION_5, ndisks);
8648c96dcc1SMarcel Moolenaar 
8658c96dcc1SMarcel Moolenaar 	free(loader);
8668c96dcc1SMarcel Moolenaar 	return (0);
867c487da1eSNeel Natu }
868