xref: /freebsd/usr.sbin/bhyveload/bhyveload.c (revision 22cf89c938886d14f5796fc49f9f020c23ea8eaf)
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 /*-
30  * Copyright (c) 2011 Google, Inc.
31  * All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52  * SUCH DAMAGE.
53  */
54 
55 #include <sys/cdefs.h>
56 #include <sys/ioctl.h>
57 #include <sys/stat.h>
58 #include <sys/disk.h>
59 #include <sys/queue.h>
60 
61 #include <machine/specialreg.h>
62 #include <machine/vmm.h>
63 
64 #include <assert.h>
65 #include <dirent.h>
66 #include <dlfcn.h>
67 #include <errno.h>
68 #include <err.h>
69 #include <fcntl.h>
70 #include <getopt.h>
71 #include <libgen.h>
72 #include <limits.h>
73 #include <setjmp.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <sysexits.h>
78 #include <termios.h>
79 #include <unistd.h>
80 
81 #include <vmmapi.h>
82 
83 #include "userboot.h"
84 
85 #define	MB	(1024 * 1024UL)
86 #define	GB	(1024 * 1024 * 1024UL)
87 #define	BSP	0
88 
89 #define	NDISKS	32
90 
91 static char *host_base;
92 static struct termios term, oldterm;
93 static int disk_fd[NDISKS];
94 static int ndisks;
95 static int consin_fd, consout_fd;
96 
97 static int need_reinit;
98 
99 static void *loader_hdl;
100 static char *loader;
101 static int explicit_loader;
102 static jmp_buf jb;
103 
104 static char *vmname, *progname;
105 static struct vmctx *ctx;
106 static struct vcpu *vcpu;
107 
108 static uint64_t gdtbase, cr3, rsp;
109 
110 static void cb_exit(void *arg, int v);
111 
112 /*
113  * Console i/o callbacks
114  */
115 
116 static void
117 cb_putc(void *arg __unused, int ch)
118 {
119 	char c = ch;
120 
121 	(void) write(consout_fd, &c, 1);
122 }
123 
124 static int
125 cb_getc(void *arg __unused)
126 {
127 	char c;
128 
129 	if (read(consin_fd, &c, 1) == 1)
130 		return (c);
131 	return (-1);
132 }
133 
134 static int
135 cb_poll(void *arg __unused)
136 {
137 	int n;
138 
139 	if (ioctl(consin_fd, FIONREAD, &n) >= 0)
140 		return (n > 0);
141 	return (0);
142 }
143 
144 /*
145  * Host filesystem i/o callbacks
146  */
147 
148 struct cb_file {
149 	int cf_isdir;
150 	size_t cf_size;
151 	struct stat cf_stat;
152 	union {
153 		int fd;
154 		DIR *dir;
155 	} cf_u;
156 };
157 
158 static int
159 cb_open(void *arg __unused, const char *filename, void **hp)
160 {
161 	struct cb_file *cf;
162 	char path[PATH_MAX];
163 
164 	if (!host_base)
165 		return (ENOENT);
166 
167 	strlcpy(path, host_base, PATH_MAX);
168 	if (path[strlen(path) - 1] == '/')
169 		path[strlen(path) - 1] = 0;
170 	strlcat(path, filename, PATH_MAX);
171 	cf = malloc(sizeof(struct cb_file));
172 	if (stat(path, &cf->cf_stat) < 0) {
173 		free(cf);
174 		return (errno);
175 	}
176 
177 	cf->cf_size = cf->cf_stat.st_size;
178 	if (S_ISDIR(cf->cf_stat.st_mode)) {
179 		cf->cf_isdir = 1;
180 		cf->cf_u.dir = opendir(path);
181 		if (!cf->cf_u.dir)
182 			goto out;
183 		*hp = cf;
184 		return (0);
185 	}
186 	if (S_ISREG(cf->cf_stat.st_mode)) {
187 		cf->cf_isdir = 0;
188 		cf->cf_u.fd = open(path, O_RDONLY);
189 		if (cf->cf_u.fd < 0)
190 			goto out;
191 		*hp = cf;
192 		return (0);
193 	}
194 
195 out:
196 	free(cf);
197 	return (EINVAL);
198 }
199 
200 static int
201 cb_close(void *arg __unused, void *h)
202 {
203 	struct cb_file *cf = h;
204 
205 	if (cf->cf_isdir)
206 		closedir(cf->cf_u.dir);
207 	else
208 		close(cf->cf_u.fd);
209 	free(cf);
210 
211 	return (0);
212 }
213 
214 static int
215 cb_isdir(void *arg __unused, void *h)
216 {
217 	struct cb_file *cf = h;
218 
219 	return (cf->cf_isdir);
220 }
221 
222 static int
223 cb_read(void *arg __unused, void *h, void *buf, size_t size, size_t *resid)
224 {
225 	struct cb_file *cf = h;
226 	ssize_t sz;
227 
228 	if (cf->cf_isdir)
229 		return (EINVAL);
230 	sz = read(cf->cf_u.fd, buf, size);
231 	if (sz < 0)
232 		return (EINVAL);
233 	*resid = size - sz;
234 	return (0);
235 }
236 
237 static int
238 cb_readdir(void *arg __unused, void *h, uint32_t *fileno_return,
239     uint8_t *type_return, size_t *namelen_return, char *name)
240 {
241 	struct cb_file *cf = h;
242 	struct dirent *dp;
243 
244 	if (!cf->cf_isdir)
245 		return (EINVAL);
246 
247 	dp = readdir(cf->cf_u.dir);
248 	if (!dp)
249 		return (ENOENT);
250 
251 	/*
252 	 * Note: d_namlen is in the range 0..255 and therefore less
253 	 * than PATH_MAX so we don't need to test before copying.
254 	 */
255 	*fileno_return = dp->d_fileno;
256 	*type_return = dp->d_type;
257 	*namelen_return = dp->d_namlen;
258 	memcpy(name, dp->d_name, dp->d_namlen);
259 	name[dp->d_namlen] = 0;
260 
261 	return (0);
262 }
263 
264 static int
265 cb_seek(void *arg __unused, void *h, uint64_t offset, int whence)
266 {
267 	struct cb_file *cf = h;
268 
269 	if (cf->cf_isdir)
270 		return (EINVAL);
271 	if (lseek(cf->cf_u.fd, offset, whence) < 0)
272 		return (errno);
273 	return (0);
274 }
275 
276 static int
277 cb_stat(void *arg __unused, void *h, struct stat *sbp)
278 {
279 	struct cb_file *cf = h;
280 
281 	memset(sbp, 0, sizeof(struct stat));
282 	sbp->st_mode = cf->cf_stat.st_mode;
283 	sbp->st_uid = cf->cf_stat.st_uid;
284 	sbp->st_gid = cf->cf_stat.st_gid;
285 	sbp->st_size = cf->cf_stat.st_size;
286 	sbp->st_mtime = cf->cf_stat.st_mtime;
287 	sbp->st_dev = cf->cf_stat.st_dev;
288 	sbp->st_ino = cf->cf_stat.st_ino;
289 
290 	return (0);
291 }
292 
293 /*
294  * Disk image i/o callbacks
295  */
296 
297 static int
298 cb_diskread(void *arg __unused, int unit, uint64_t from, void *to, size_t size,
299     size_t *resid)
300 {
301 	ssize_t n;
302 
303 	if (unit < 0 || unit >= ndisks)
304 		return (EIO);
305 	n = pread(disk_fd[unit], to, size, from);
306 	if (n < 0)
307 		return (errno);
308 	*resid = size - n;
309 	return (0);
310 }
311 
312 static int
313 cb_diskwrite(void *arg __unused, int unit, uint64_t offset, void *src,
314     size_t size, size_t *resid)
315 {
316 	ssize_t n;
317 
318 	if (unit < 0 || unit >= ndisks)
319 		return (EIO);
320 	n = pwrite(disk_fd[unit], src, size, offset);
321 	if (n < 0)
322 		return (errno);
323 	*resid = size - n;
324 	return (0);
325 }
326 
327 static int
328 cb_diskioctl(void *arg __unused, int unit, u_long cmd, void *data)
329 {
330 	struct stat sb;
331 
332 	if (unit < 0 || unit >= ndisks)
333 		return (EBADF);
334 
335 	switch (cmd) {
336 	case DIOCGSECTORSIZE:
337 		*(u_int *)data = 512;
338 		break;
339 	case DIOCGMEDIASIZE:
340 		if (fstat(disk_fd[unit], &sb) != 0)
341 			return (ENOTTY);
342 		if (S_ISCHR(sb.st_mode) &&
343 		    ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0)
344 				return (ENOTTY);
345 		*(off_t *)data = sb.st_size;
346 		break;
347 	default:
348 		return (ENOTTY);
349 	}
350 
351 	return (0);
352 }
353 
354 /*
355  * Guest virtual machine i/o callbacks
356  */
357 static int
358 cb_copyin(void *arg __unused, const void *from, uint64_t to, size_t size)
359 {
360 	char *ptr;
361 
362 	to &= 0x7fffffff;
363 
364 	ptr = vm_map_gpa(ctx, to, size);
365 	if (ptr == NULL)
366 		return (EFAULT);
367 
368 	memcpy(ptr, from, size);
369 	return (0);
370 }
371 
372 static int
373 cb_copyout(void *arg __unused, uint64_t from, void *to, size_t size)
374 {
375 	char *ptr;
376 
377 	from &= 0x7fffffff;
378 
379 	ptr = vm_map_gpa(ctx, from, size);
380 	if (ptr == NULL)
381 		return (EFAULT);
382 
383 	memcpy(to, ptr, size);
384 	return (0);
385 }
386 
387 static void
388 cb_setreg(void *arg __unused, int r, uint64_t v)
389 {
390 	int error;
391 	enum vm_reg_name vmreg;
392 
393 	vmreg = VM_REG_LAST;
394 
395 	switch (r) {
396 	case 4:
397 		vmreg = VM_REG_GUEST_RSP;
398 		rsp = v;
399 		break;
400 	default:
401 		break;
402 	}
403 
404 	if (vmreg == VM_REG_LAST) {
405 		printf("test_setreg(%d): not implemented\n", r);
406 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
407 	}
408 
409 	error = vm_set_register(vcpu, vmreg, v);
410 	if (error) {
411 		perror("vm_set_register");
412 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
413 	}
414 }
415 
416 static void
417 cb_setmsr(void *arg __unused, int r, uint64_t v)
418 {
419 	int error;
420 	enum vm_reg_name vmreg;
421 
422 	vmreg = VM_REG_LAST;
423 
424 	switch (r) {
425 	case MSR_EFER:
426 		vmreg = VM_REG_GUEST_EFER;
427 		break;
428 	default:
429 		break;
430 	}
431 
432 	if (vmreg == VM_REG_LAST) {
433 		printf("test_setmsr(%d): not implemented\n", r);
434 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
435 	}
436 
437 	error = vm_set_register(vcpu, vmreg, v);
438 	if (error) {
439 		perror("vm_set_msr");
440 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
441 	}
442 }
443 
444 static void
445 cb_setcr(void *arg __unused, int r, uint64_t v)
446 {
447 	int error;
448 	enum vm_reg_name vmreg;
449 
450 	vmreg = VM_REG_LAST;
451 
452 	switch (r) {
453 	case 0:
454 		vmreg = VM_REG_GUEST_CR0;
455 		break;
456 	case 3:
457 		vmreg = VM_REG_GUEST_CR3;
458 		cr3 = v;
459 		break;
460 	case 4:
461 		vmreg = VM_REG_GUEST_CR4;
462 		break;
463 	default:
464 		break;
465 	}
466 
467 	if (vmreg == VM_REG_LAST) {
468 		printf("test_setcr(%d): not implemented\n", r);
469 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
470 	}
471 
472 	error = vm_set_register(vcpu, vmreg, v);
473 	if (error) {
474 		perror("vm_set_cr");
475 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
476 	}
477 }
478 
479 static void
480 cb_setgdt(void *arg __unused, uint64_t base, size_t size)
481 {
482 	int error;
483 
484 	error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR, base, size - 1, 0);
485 	if (error != 0) {
486 		perror("vm_set_desc(gdt)");
487 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
488 	}
489 
490 	gdtbase = base;
491 }
492 
493 static void
494 cb_exec(void *arg __unused, uint64_t rip)
495 {
496 	int error;
497 
498 	if (cr3 == 0)
499 		error = vm_setup_freebsd_registers_i386(vcpu, rip, gdtbase,
500 		    rsp);
501 	else
502 		error = vm_setup_freebsd_registers(vcpu, rip, cr3, gdtbase,
503 		    rsp);
504 	if (error) {
505 		perror("vm_setup_freebsd_registers");
506 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
507 	}
508 
509 	cb_exit(NULL, 0);
510 }
511 
512 /*
513  * Misc
514  */
515 
516 static void
517 cb_delay(void *arg __unused, int usec)
518 {
519 
520 	usleep(usec);
521 }
522 
523 static void
524 cb_exit(void *arg __unused, int v)
525 {
526 
527 	tcsetattr(consout_fd, TCSAFLUSH, &oldterm);
528 	exit(v);
529 }
530 
531 static void
532 cb_getmem(void *arg __unused, uint64_t *ret_lowmem, uint64_t *ret_highmem)
533 {
534 
535 	*ret_lowmem = vm_get_lowmem_size(ctx);
536 	*ret_highmem = vm_get_highmem_size(ctx);
537 }
538 
539 struct env {
540 	char *str;	/* name=value */
541 	SLIST_ENTRY(env) next;
542 };
543 
544 static SLIST_HEAD(envhead, env) envhead;
545 
546 static void
547 addenv(const char *str)
548 {
549 	struct env *env;
550 
551 	env = malloc(sizeof(struct env));
552 	if (env == NULL)
553 		err(EX_OSERR, "malloc");
554 	env->str = strdup(str);
555 	if (env->str == NULL)
556 		err(EX_OSERR, "strdup");
557 	SLIST_INSERT_HEAD(&envhead, env, next);
558 }
559 
560 static char *
561 cb_getenv(void *arg __unused, int num)
562 {
563 	int i;
564 	struct env *env;
565 
566 	i = 0;
567 	SLIST_FOREACH(env, &envhead, next) {
568 		if (i == num)
569 			return (env->str);
570 		i++;
571 	}
572 
573 	return (NULL);
574 }
575 
576 static int
577 cb_vm_set_register(void *arg __unused, int vcpuid, int reg, uint64_t val)
578 {
579 
580 	assert(vcpuid == BSP);
581 	return (vm_set_register(vcpu, reg, val));
582 }
583 
584 static int
585 cb_vm_set_desc(void *arg __unused, int vcpuid, int reg, uint64_t base,
586     u_int limit, u_int access)
587 {
588 
589 	assert(vcpuid == BSP);
590 	return (vm_set_desc(vcpu, reg, base, limit, access));
591 }
592 
593 static void
594 cb_swap_interpreter(void *arg __unused, const char *interp_req)
595 {
596 
597 	/*
598 	 * If the user specified a loader but we detected a mismatch, we should
599 	 * not try to pivot to a different loader on them.
600 	 */
601 	free(loader);
602 	if (explicit_loader == 1) {
603 		perror("requested loader interpreter does not match guest userboot");
604 		cb_exit(NULL, 1);
605 	}
606 	if (interp_req == NULL || *interp_req == '\0') {
607 		perror("guest failed to request an interpreter");
608 		cb_exit(NULL, 1);
609 	}
610 
611 	if (asprintf(&loader, "/boot/userboot_%s.so", interp_req) == -1)
612 		err(EX_OSERR, "malloc");
613 	need_reinit = 1;
614 	longjmp(jb, 1);
615 }
616 
617 static struct loader_callbacks cb = {
618 	.getc = cb_getc,
619 	.putc = cb_putc,
620 	.poll = cb_poll,
621 
622 	.open = cb_open,
623 	.close = cb_close,
624 	.isdir = cb_isdir,
625 	.read = cb_read,
626 	.readdir = cb_readdir,
627 	.seek = cb_seek,
628 	.stat = cb_stat,
629 
630 	.diskread = cb_diskread,
631 	.diskwrite = cb_diskwrite,
632 	.diskioctl = cb_diskioctl,
633 
634 	.copyin = cb_copyin,
635 	.copyout = cb_copyout,
636 	.setreg = cb_setreg,
637 	.setmsr = cb_setmsr,
638 	.setcr = cb_setcr,
639 	.setgdt = cb_setgdt,
640 	.exec = cb_exec,
641 
642 	.delay = cb_delay,
643 	.exit = cb_exit,
644 	.getmem = cb_getmem,
645 
646 	.getenv = cb_getenv,
647 
648 	/* Version 4 additions */
649 	.vm_set_register = cb_vm_set_register,
650 	.vm_set_desc = cb_vm_set_desc,
651 
652 	/* Version 5 additions */
653 	.swap_interpreter = cb_swap_interpreter,
654 };
655 
656 static int
657 altcons_open(char *path)
658 {
659 	struct stat sb;
660 	int err;
661 	int fd;
662 
663 	/*
664 	 * Allow stdio to be passed in so that the same string
665 	 * can be used for the bhyveload console and bhyve com-port
666 	 * parameters
667 	 */
668 	if (!strcmp(path, "stdio"))
669 		return (0);
670 
671 	err = stat(path, &sb);
672 	if (err == 0) {
673 		if (!S_ISCHR(sb.st_mode))
674 			err = ENOTSUP;
675 		else {
676 			fd = open(path, O_RDWR | O_NONBLOCK);
677 			if (fd < 0)
678 				err = errno;
679 			else
680 				consin_fd = consout_fd = fd;
681 		}
682 	}
683 
684 	return (err);
685 }
686 
687 static int
688 disk_open(char *path)
689 {
690 	int fd;
691 
692 	if (ndisks >= NDISKS)
693 		return (ERANGE);
694 
695 	fd = open(path, O_RDWR);
696 	if (fd < 0)
697 		return (errno);
698 
699 	disk_fd[ndisks] = fd;
700 	ndisks++;
701 
702 	return (0);
703 }
704 
705 static void
706 usage(void)
707 {
708 
709 	fprintf(stderr,
710 	    "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n"
711 	    "       %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n",
712 	    progname,
713 	    (int)strlen(progname), "");
714 	exit(1);
715 }
716 
717 int
718 main(int argc, char** argv)
719 {
720 	void (*func)(struct loader_callbacks *, void *, int, int);
721 	uint64_t mem_size;
722 	int opt, error, memflags;
723 
724 	progname = basename(argv[0]);
725 
726 	memflags = 0;
727 	mem_size = 256 * MB;
728 
729 	consin_fd = STDIN_FILENO;
730 	consout_fd = STDOUT_FILENO;
731 
732 	while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) {
733 		switch (opt) {
734 		case 'c':
735 			error = altcons_open(optarg);
736 			if (error != 0)
737 				errx(EX_USAGE, "Could not open '%s'", optarg);
738 			break;
739 
740 		case 'd':
741 			error = disk_open(optarg);
742 			if (error != 0)
743 				errx(EX_USAGE, "Could not open '%s'", optarg);
744 			break;
745 
746 		case 'e':
747 			addenv(optarg);
748 			break;
749 
750 		case 'h':
751 			host_base = optarg;
752 			break;
753 
754 		case 'l':
755 			if (loader != NULL)
756 				errx(EX_USAGE, "-l can only be given once");
757 			loader = strdup(optarg);
758 			if (loader == NULL)
759 				err(EX_OSERR, "malloc");
760 			explicit_loader = 1;
761 			break;
762 
763 		case 'm':
764 			error = vm_parse_memsize(optarg, &mem_size);
765 			if (error != 0)
766 				errx(EX_USAGE, "Invalid memsize '%s'", optarg);
767 			break;
768 		case 'C':
769 			memflags |= VM_MEM_F_INCORE;
770 			break;
771 		case 'S':
772 			memflags |= VM_MEM_F_WIRED;
773 			break;
774 		case '?':
775 			usage();
776 		}
777 	}
778 
779 	argc -= optind;
780 	argv += optind;
781 
782 	if (argc != 1)
783 		usage();
784 
785 	vmname = argv[0];
786 
787 	need_reinit = 0;
788 	error = vm_create(vmname);
789 	if (error) {
790 		if (errno != EEXIST) {
791 			perror("vm_create");
792 			exit(1);
793 		}
794 		need_reinit = 1;
795 	}
796 
797 	ctx = vm_open(vmname);
798 	if (ctx == NULL) {
799 		perror("vm_open");
800 		exit(1);
801 	}
802 
803 	vcpu = vm_vcpu_open(ctx, BSP);
804 
805 	/*
806 	 * setjmp in the case the guest wants to swap out interpreter,
807 	 * cb_swap_interpreter will swap out loader as appropriate and set
808 	 * need_reinit so that we end up in a clean state once again.
809 	 */
810 	setjmp(jb);
811 
812 	if (need_reinit) {
813 		error = vm_reinit(ctx);
814 		if (error) {
815 			perror("vm_reinit");
816 			exit(1);
817 		}
818 	}
819 
820 	vm_set_memflags(ctx, memflags);
821 	error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL);
822 	if (error) {
823 		perror("vm_setup_memory");
824 		exit(1);
825 	}
826 
827 	if (loader == NULL) {
828 		loader = strdup("/boot/userboot.so");
829 		if (loader == NULL)
830 			err(EX_OSERR, "malloc");
831 	}
832 	if (loader_hdl != NULL)
833 		dlclose(loader_hdl);
834 	loader_hdl = dlopen(loader, RTLD_LOCAL);
835 	if (!loader_hdl) {
836 		printf("%s\n", dlerror());
837 		free(loader);
838 		return (1);
839 	}
840 	func = dlsym(loader_hdl, "loader_main");
841 	if (!func) {
842 		printf("%s\n", dlerror());
843 		free(loader);
844 		return (1);
845 	}
846 
847 	tcgetattr(consout_fd, &term);
848 	oldterm = term;
849 	cfmakeraw(&term);
850 	term.c_cflag |= CLOCAL;
851 
852 	tcsetattr(consout_fd, TCSAFLUSH, &term);
853 
854 	addenv("smbios.bios.vendor=BHYVE");
855 	addenv("boot_serial=1");
856 
857 	func(&cb, NULL, USERBOOT_VERSION_5, ndisks);
858 
859 	free(loader);
860 	return (0);
861 }
862