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