1c487da1eSNeel Natu /*-
2eebd9d53SWarner Losh * SPDX-License-Identifier: 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
29c487da1eSNeel Natu /*-
30c487da1eSNeel Natu * Copyright (c) 2011 Google, Inc.
31c487da1eSNeel Natu * All rights reserved.
32c487da1eSNeel Natu *
33c487da1eSNeel Natu * Redistribution and use in source and binary forms, with or without
34c487da1eSNeel Natu * modification, are permitted provided that the following conditions
35c487da1eSNeel Natu * are met:
36c487da1eSNeel Natu * 1. Redistributions of source code must retain the above copyright
37c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer.
38c487da1eSNeel Natu * 2. Redistributions in binary form must reproduce the above copyright
39c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer in the
40c487da1eSNeel Natu * documentation and/or other materials provided with the distribution.
41c487da1eSNeel Natu *
42c487da1eSNeel Natu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43c487da1eSNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44c487da1eSNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45c487da1eSNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46c487da1eSNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47c487da1eSNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48c487da1eSNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49c487da1eSNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50c487da1eSNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51c487da1eSNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52c487da1eSNeel Natu * SUCH DAMAGE.
53c487da1eSNeel Natu */
54c487da1eSNeel Natu
55c487da1eSNeel Natu #include <sys/cdefs.h>
56c487da1eSNeel Natu #include <sys/ioctl.h>
57c487da1eSNeel Natu #include <sys/stat.h>
58a10c6f55SNeel Natu #include <sys/disk.h>
59b6afa84bSNeel Natu #include <sys/queue.h>
60c487da1eSNeel Natu
61c487da1eSNeel Natu #include <machine/specialreg.h>
62c487da1eSNeel Natu #include <machine/vmm.h>
63c487da1eSNeel Natu
647d9ef309SJohn Baldwin #include <assert.h>
65c487da1eSNeel Natu #include <dirent.h>
66c487da1eSNeel Natu #include <dlfcn.h>
67c487da1eSNeel Natu #include <errno.h>
68200758f1SNeel Natu #include <err.h>
69c487da1eSNeel Natu #include <fcntl.h>
70c487da1eSNeel Natu #include <getopt.h>
71b5331f4dSNeel Natu #include <libgen.h>
72c487da1eSNeel Natu #include <limits.h>
73d3d381b2SKyle Evans #include <setjmp.h>
74c487da1eSNeel Natu #include <stdio.h>
75c487da1eSNeel Natu #include <stdlib.h>
76c487da1eSNeel Natu #include <string.h>
77200758f1SNeel Natu #include <sysexits.h>
78c487da1eSNeel Natu #include <termios.h>
79c487da1eSNeel Natu #include <unistd.h>
80c487da1eSNeel Natu
818bf0882eSKyle Evans #include <capsicum_helpers.h>
82c487da1eSNeel Natu #include <vmmapi.h>
83c487da1eSNeel Natu
84c487da1eSNeel Natu #include "userboot.h"
85c487da1eSNeel Natu
86c487da1eSNeel Natu #define MB (1024 * 1024UL)
87c487da1eSNeel Natu #define GB (1024 * 1024 * 1024UL)
88c487da1eSNeel Natu #define BSP 0
89c487da1eSNeel Natu
90cf087c12SPeter Grehan #define NDISKS 32
91cf087c12SPeter Grehan
9224cd5c26SKyle Evans /*
9324cd5c26SKyle Evans * Reason for our loader reload and reentry, though these aren't really used
9424cd5c26SKyle Evans * at the moment.
9524cd5c26SKyle Evans */
9624cd5c26SKyle Evans enum {
9724cd5c26SKyle Evans /* 0 cannot be allocated; setjmp(3) return. */
9824cd5c26SKyle Evans JMP_SWAPLOADER = 0x01,
9924cd5c26SKyle Evans JMP_REBOOT,
10024cd5c26SKyle Evans };
10124cd5c26SKyle Evans
102c487da1eSNeel Natu static struct termios term, oldterm;
103cf087c12SPeter Grehan static int disk_fd[NDISKS];
104cf087c12SPeter Grehan static int ndisks;
1056380102cSPeter Grehan static int consin_fd, consout_fd;
1066779d44bSKyle Evans static int hostbase_fd = -1;
107c487da1eSNeel Natu
108d3d381b2SKyle Evans static void *loader_hdl;
109d3d381b2SKyle Evans static char *loader;
11067082f07SKyle Evans static int explicit_loader_fd = -1;
111d3d381b2SKyle Evans static jmp_buf jb;
112d3d381b2SKyle Evans
113b060ba50SNeel Natu static char *vmname, *progname;
114c487da1eSNeel Natu static struct vmctx *ctx;
1157d9ef309SJohn Baldwin static struct vcpu *vcpu;
116c487da1eSNeel Natu
117c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp;
118c487da1eSNeel Natu
119c487da1eSNeel Natu static void cb_exit(void *arg, int v);
120c487da1eSNeel Natu
121c487da1eSNeel Natu /*
122c487da1eSNeel Natu * Console i/o callbacks
123c487da1eSNeel Natu */
124c487da1eSNeel Natu
125c487da1eSNeel Natu static void
cb_putc(void * arg __unused,int ch)126ad43dd69SMark Johnston cb_putc(void *arg __unused, int ch)
127c487da1eSNeel Natu {
128c487da1eSNeel Natu char c = ch;
129c487da1eSNeel Natu
1306380102cSPeter Grehan (void) write(consout_fd, &c, 1);
131c487da1eSNeel Natu }
132c487da1eSNeel Natu
133c487da1eSNeel Natu static int
cb_getc(void * arg __unused)134ad43dd69SMark Johnston cb_getc(void *arg __unused)
135c487da1eSNeel Natu {
136c487da1eSNeel Natu char c;
137c487da1eSNeel Natu
1386380102cSPeter Grehan if (read(consin_fd, &c, 1) == 1)
139c487da1eSNeel Natu return (c);
140c487da1eSNeel Natu return (-1);
141c487da1eSNeel Natu }
142c487da1eSNeel Natu
143c487da1eSNeel Natu static int
cb_poll(void * arg __unused)144ad43dd69SMark Johnston cb_poll(void *arg __unused)
145c487da1eSNeel Natu {
146c487da1eSNeel Natu int n;
147c487da1eSNeel Natu
1486380102cSPeter Grehan if (ioctl(consin_fd, FIONREAD, &n) >= 0)
149c487da1eSNeel Natu return (n > 0);
150c487da1eSNeel Natu return (0);
151c487da1eSNeel Natu }
152c487da1eSNeel Natu
153c487da1eSNeel Natu /*
154c487da1eSNeel Natu * Host filesystem i/o callbacks
155c487da1eSNeel Natu */
156c487da1eSNeel Natu
157c487da1eSNeel Natu struct cb_file {
158c487da1eSNeel Natu int cf_isdir;
159c487da1eSNeel Natu size_t cf_size;
160c487da1eSNeel Natu struct stat cf_stat;
161c487da1eSNeel Natu union {
162c487da1eSNeel Natu int fd;
163c487da1eSNeel Natu DIR *dir;
164c487da1eSNeel Natu } cf_u;
165c487da1eSNeel Natu };
166c487da1eSNeel Natu
167c487da1eSNeel Natu static int
cb_open(void * arg __unused,const char * filename,void ** hp)168ad43dd69SMark Johnston cb_open(void *arg __unused, const char *filename, void **hp)
169c487da1eSNeel Natu {
170c487da1eSNeel Natu struct cb_file *cf;
1716779d44bSKyle Evans struct stat sb;
1726779d44bSKyle Evans int fd, flags;
173c487da1eSNeel Natu
1746779d44bSKyle Evans cf = NULL;
1756779d44bSKyle Evans fd = -1;
1766779d44bSKyle Evans flags = O_RDONLY | O_RESOLVE_BENEATH;
1776779d44bSKyle Evans if (hostbase_fd == -1)
178c487da1eSNeel Natu return (ENOENT);
179c487da1eSNeel Natu
1806779d44bSKyle Evans /* Absolute paths are relative to our hostbase, chop off leading /. */
1816779d44bSKyle Evans if (filename[0] == '/')
1826779d44bSKyle Evans filename++;
1836779d44bSKyle Evans
1846779d44bSKyle Evans /* Lookup of /, use . instead. */
1856779d44bSKyle Evans if (filename[0] == '\0')
1866779d44bSKyle Evans filename = ".";
1876779d44bSKyle Evans
1886779d44bSKyle Evans if (fstatat(hostbase_fd, filename, &sb, AT_RESOLVE_BENEATH) < 0)
189c487da1eSNeel Natu return (errno);
1906779d44bSKyle Evans
1916779d44bSKyle Evans if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode))
1926779d44bSKyle Evans return (EINVAL);
1936779d44bSKyle Evans
1946779d44bSKyle Evans if (S_ISDIR(sb.st_mode))
1956779d44bSKyle Evans flags |= O_DIRECTORY;
1966779d44bSKyle Evans
1976779d44bSKyle Evans /* May be opening the root dir */
1986779d44bSKyle Evans fd = openat(hostbase_fd, filename, flags);
1996779d44bSKyle Evans if (fd < 0)
2006779d44bSKyle Evans return (errno);
2016779d44bSKyle Evans
2026779d44bSKyle Evans cf = malloc(sizeof(struct cb_file));
2036779d44bSKyle Evans if (cf == NULL) {
2046779d44bSKyle Evans close(fd);
2056779d44bSKyle Evans return (ENOMEM);
206c487da1eSNeel Natu }
207c487da1eSNeel Natu
2086779d44bSKyle Evans cf->cf_stat = sb;
2098f61276dSPedro F. Giffuni cf->cf_size = cf->cf_stat.st_size;
2106779d44bSKyle Evans
211c487da1eSNeel Natu if (S_ISDIR(cf->cf_stat.st_mode)) {
212c487da1eSNeel Natu cf->cf_isdir = 1;
2136779d44bSKyle Evans cf->cf_u.dir = fdopendir(fd);
2146779d44bSKyle Evans if (cf->cf_u.dir == NULL) {
2156779d44bSKyle Evans close(fd);
216c487da1eSNeel Natu free(cf);
2176779d44bSKyle Evans return (ENOMEM);
2186779d44bSKyle Evans }
2196779d44bSKyle Evans } else {
2206779d44bSKyle Evans assert(S_ISREG(cf->cf_stat.st_mode));
2216779d44bSKyle Evans cf->cf_isdir = 0;
2226779d44bSKyle Evans cf->cf_u.fd = fd;
2236779d44bSKyle Evans }
2246779d44bSKyle Evans *hp = cf;
2256779d44bSKyle Evans return (0);
226c487da1eSNeel Natu }
227c487da1eSNeel Natu
228c487da1eSNeel Natu static int
cb_close(void * arg __unused,void * h)229ad43dd69SMark Johnston cb_close(void *arg __unused, void *h)
230c487da1eSNeel Natu {
231c487da1eSNeel Natu struct cb_file *cf = h;
232c487da1eSNeel Natu
233c487da1eSNeel Natu if (cf->cf_isdir)
234c487da1eSNeel Natu closedir(cf->cf_u.dir);
235c487da1eSNeel Natu else
236c487da1eSNeel Natu close(cf->cf_u.fd);
237c487da1eSNeel Natu free(cf);
238c487da1eSNeel Natu
239c487da1eSNeel Natu return (0);
240c487da1eSNeel Natu }
241c487da1eSNeel Natu
242c487da1eSNeel Natu static int
cb_isdir(void * arg __unused,void * h)243ad43dd69SMark Johnston cb_isdir(void *arg __unused, void *h)
244c487da1eSNeel Natu {
245c487da1eSNeel Natu struct cb_file *cf = h;
246c487da1eSNeel Natu
247c487da1eSNeel Natu return (cf->cf_isdir);
248c487da1eSNeel Natu }
249c487da1eSNeel Natu
250c487da1eSNeel Natu static int
cb_read(void * arg __unused,void * h,void * buf,size_t size,size_t * resid)251ad43dd69SMark Johnston cb_read(void *arg __unused, void *h, void *buf, size_t size, size_t *resid)
252c487da1eSNeel Natu {
253c487da1eSNeel Natu struct cb_file *cf = h;
254c487da1eSNeel Natu ssize_t sz;
255c487da1eSNeel Natu
256c487da1eSNeel Natu if (cf->cf_isdir)
257c487da1eSNeel Natu return (EINVAL);
258c487da1eSNeel Natu sz = read(cf->cf_u.fd, buf, size);
259c487da1eSNeel Natu if (sz < 0)
260c487da1eSNeel Natu return (EINVAL);
261c487da1eSNeel Natu *resid = size - sz;
262c487da1eSNeel Natu return (0);
263c487da1eSNeel Natu }
264c487da1eSNeel Natu
265c487da1eSNeel Natu static int
cb_readdir(void * arg __unused,void * h,uint32_t * fileno_return,uint8_t * type_return,size_t * namelen_return,char * name)266ad43dd69SMark Johnston cb_readdir(void *arg __unused, void *h, uint32_t *fileno_return,
267ad43dd69SMark Johnston uint8_t *type_return, size_t *namelen_return, char *name)
268c487da1eSNeel Natu {
269c487da1eSNeel Natu struct cb_file *cf = h;
270c487da1eSNeel Natu struct dirent *dp;
271c487da1eSNeel Natu
272c487da1eSNeel Natu if (!cf->cf_isdir)
273c487da1eSNeel Natu return (EINVAL);
274c487da1eSNeel Natu
275c487da1eSNeel Natu dp = readdir(cf->cf_u.dir);
276c487da1eSNeel Natu if (!dp)
277c487da1eSNeel Natu return (ENOENT);
278c487da1eSNeel Natu
279c487da1eSNeel Natu /*
280c487da1eSNeel Natu * Note: d_namlen is in the range 0..255 and therefore less
281c487da1eSNeel Natu * than PATH_MAX so we don't need to test before copying.
282c487da1eSNeel Natu */
283c487da1eSNeel Natu *fileno_return = dp->d_fileno;
284c487da1eSNeel Natu *type_return = dp->d_type;
285c487da1eSNeel Natu *namelen_return = dp->d_namlen;
286c487da1eSNeel Natu memcpy(name, dp->d_name, dp->d_namlen);
287c487da1eSNeel Natu name[dp->d_namlen] = 0;
288c487da1eSNeel Natu
289c487da1eSNeel Natu return (0);
290c487da1eSNeel Natu }
291c487da1eSNeel Natu
292c487da1eSNeel Natu static int
cb_seek(void * arg __unused,void * h,uint64_t offset,int whence)293ad43dd69SMark Johnston cb_seek(void *arg __unused, void *h, uint64_t offset, int whence)
294c487da1eSNeel Natu {
295c487da1eSNeel Natu struct cb_file *cf = h;
296c487da1eSNeel Natu
297c487da1eSNeel Natu if (cf->cf_isdir)
298c487da1eSNeel Natu return (EINVAL);
299c487da1eSNeel Natu if (lseek(cf->cf_u.fd, offset, whence) < 0)
300c487da1eSNeel Natu return (errno);
301c487da1eSNeel Natu return (0);
302c487da1eSNeel Natu }
303c487da1eSNeel Natu
304c487da1eSNeel Natu static int
cb_stat(void * arg __unused,void * h,struct stat * sbp)305ad43dd69SMark Johnston cb_stat(void *arg __unused, void *h, struct stat *sbp)
306c487da1eSNeel Natu {
307c487da1eSNeel Natu struct cb_file *cf = h;
308c487da1eSNeel Natu
30953f151f9SSimon J. Gerraty memset(sbp, 0, sizeof(struct stat));
31053f151f9SSimon J. Gerraty sbp->st_mode = cf->cf_stat.st_mode;
31153f151f9SSimon J. Gerraty sbp->st_uid = cf->cf_stat.st_uid;
31253f151f9SSimon J. Gerraty sbp->st_gid = cf->cf_stat.st_gid;
31353f151f9SSimon J. Gerraty sbp->st_size = cf->cf_stat.st_size;
31453f151f9SSimon J. Gerraty sbp->st_mtime = cf->cf_stat.st_mtime;
31553f151f9SSimon J. Gerraty sbp->st_dev = cf->cf_stat.st_dev;
31653f151f9SSimon J. Gerraty sbp->st_ino = cf->cf_stat.st_ino;
31753f151f9SSimon J. Gerraty
318c487da1eSNeel Natu return (0);
319c487da1eSNeel Natu }
320c487da1eSNeel Natu
321c487da1eSNeel Natu /*
322c487da1eSNeel Natu * Disk image i/o callbacks
323c487da1eSNeel Natu */
324c487da1eSNeel Natu
325c487da1eSNeel Natu static int
cb_diskread(void * arg __unused,int unit,uint64_t from,void * to,size_t size,size_t * resid)326ad43dd69SMark Johnston cb_diskread(void *arg __unused, int unit, uint64_t from, void *to, size_t size,
327c487da1eSNeel Natu size_t *resid)
328c487da1eSNeel Natu {
329c487da1eSNeel Natu ssize_t n;
330c487da1eSNeel Natu
331cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks)
332c487da1eSNeel Natu return (EIO);
333cf087c12SPeter Grehan n = pread(disk_fd[unit], to, size, from);
334c487da1eSNeel Natu if (n < 0)
335c487da1eSNeel Natu return (errno);
336c487da1eSNeel Natu *resid = size - n;
337c487da1eSNeel Natu return (0);
338c487da1eSNeel Natu }
339c487da1eSNeel Natu
340a10c6f55SNeel Natu static int
cb_diskwrite(void * arg __unused,int unit,uint64_t offset,void * src,size_t size,size_t * resid)341ad43dd69SMark Johnston cb_diskwrite(void *arg __unused, int unit, uint64_t offset, void *src,
342ad43dd69SMark Johnston size_t size, size_t *resid)
343cc71ff72SConrad Meyer {
344cc71ff72SConrad Meyer ssize_t n;
345cc71ff72SConrad Meyer
346cc71ff72SConrad Meyer if (unit < 0 || unit >= ndisks)
347cc71ff72SConrad Meyer return (EIO);
348cc71ff72SConrad Meyer n = pwrite(disk_fd[unit], src, size, offset);
349cc71ff72SConrad Meyer if (n < 0)
350cc71ff72SConrad Meyer return (errno);
351cc71ff72SConrad Meyer *resid = size - n;
352cc71ff72SConrad Meyer return (0);
353cc71ff72SConrad Meyer }
354cc71ff72SConrad Meyer
355cc71ff72SConrad Meyer static int
cb_diskioctl(void * arg __unused,int unit,u_long cmd,void * data)356ad43dd69SMark Johnston cb_diskioctl(void *arg __unused, int unit, u_long cmd, void *data)
357a10c6f55SNeel Natu {
358a10c6f55SNeel Natu struct stat sb;
359a10c6f55SNeel Natu
360cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks)
361a10c6f55SNeel Natu return (EBADF);
362a10c6f55SNeel Natu
363a10c6f55SNeel Natu switch (cmd) {
364a10c6f55SNeel Natu case DIOCGSECTORSIZE:
365a10c6f55SNeel Natu *(u_int *)data = 512;
366a10c6f55SNeel Natu break;
367a10c6f55SNeel Natu case DIOCGMEDIASIZE:
3686589ee29SAndriy Gapon if (fstat(disk_fd[unit], &sb) != 0)
369a10c6f55SNeel Natu return (ENOTTY);
3706589ee29SAndriy Gapon if (S_ISCHR(sb.st_mode) &&
3716589ee29SAndriy Gapon ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0)
3726589ee29SAndriy Gapon return (ENOTTY);
3736589ee29SAndriy Gapon *(off_t *)data = sb.st_size;
374a10c6f55SNeel Natu break;
375a10c6f55SNeel Natu default:
376a10c6f55SNeel Natu return (ENOTTY);
377a10c6f55SNeel Natu }
378a10c6f55SNeel Natu
379a10c6f55SNeel Natu return (0);
380a10c6f55SNeel Natu }
381a10c6f55SNeel Natu
382c487da1eSNeel Natu /*
383c487da1eSNeel Natu * Guest virtual machine i/o callbacks
384c487da1eSNeel Natu */
385c487da1eSNeel Natu static int
cb_copyin(void * arg __unused,const void * from,uint64_t to,size_t size)386ad43dd69SMark Johnston cb_copyin(void *arg __unused, const void *from, uint64_t to, size_t size)
387c487da1eSNeel Natu {
388b060ba50SNeel Natu char *ptr;
389c487da1eSNeel Natu
390c487da1eSNeel Natu to &= 0x7fffffff;
391b060ba50SNeel Natu
392b060ba50SNeel Natu ptr = vm_map_gpa(ctx, to, size);
393b060ba50SNeel Natu if (ptr == NULL)
394c487da1eSNeel Natu return (EFAULT);
395c487da1eSNeel Natu
396b060ba50SNeel Natu memcpy(ptr, from, size);
397c487da1eSNeel Natu return (0);
398c487da1eSNeel Natu }
399c487da1eSNeel Natu
400c487da1eSNeel Natu static int
cb_copyout(void * arg __unused,uint64_t from,void * to,size_t size)401ad43dd69SMark Johnston cb_copyout(void *arg __unused, uint64_t from, void *to, size_t size)
402c487da1eSNeel Natu {
403b060ba50SNeel Natu char *ptr;
404c487da1eSNeel Natu
405c487da1eSNeel Natu from &= 0x7fffffff;
406b060ba50SNeel Natu
407b060ba50SNeel Natu ptr = vm_map_gpa(ctx, from, size);
408b060ba50SNeel Natu if (ptr == NULL)
409c487da1eSNeel Natu return (EFAULT);
410c487da1eSNeel Natu
411b060ba50SNeel Natu memcpy(to, ptr, size);
412c487da1eSNeel Natu return (0);
413c487da1eSNeel Natu }
414c487da1eSNeel Natu
415c487da1eSNeel Natu static void
cb_setreg(void * arg __unused,int r,uint64_t v)416ad43dd69SMark Johnston cb_setreg(void *arg __unused, int r, uint64_t v)
417c487da1eSNeel Natu {
418c487da1eSNeel Natu int error;
419c487da1eSNeel Natu enum vm_reg_name vmreg;
420c487da1eSNeel Natu
421c487da1eSNeel Natu vmreg = VM_REG_LAST;
422c487da1eSNeel Natu
423c487da1eSNeel Natu switch (r) {
424c487da1eSNeel Natu case 4:
425c487da1eSNeel Natu vmreg = VM_REG_GUEST_RSP;
426c487da1eSNeel Natu rsp = v;
427c487da1eSNeel Natu break;
428c487da1eSNeel Natu default:
429c487da1eSNeel Natu break;
430c487da1eSNeel Natu }
431c487da1eSNeel Natu
432c487da1eSNeel Natu if (vmreg == VM_REG_LAST) {
433c487da1eSNeel Natu printf("test_setreg(%d): not implemented\n", r);
434c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
435c487da1eSNeel Natu }
436c487da1eSNeel Natu
4377d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v);
438c487da1eSNeel Natu if (error) {
439c487da1eSNeel Natu perror("vm_set_register");
440c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
441c487da1eSNeel Natu }
442c487da1eSNeel Natu }
443c487da1eSNeel Natu
444c487da1eSNeel Natu static void
cb_setmsr(void * arg __unused,int r,uint64_t v)445ad43dd69SMark Johnston cb_setmsr(void *arg __unused, int r, uint64_t v)
446c487da1eSNeel Natu {
447c487da1eSNeel Natu int error;
448c487da1eSNeel Natu enum vm_reg_name vmreg;
449c487da1eSNeel Natu
450c487da1eSNeel Natu vmreg = VM_REG_LAST;
451c487da1eSNeel Natu
452c487da1eSNeel Natu switch (r) {
453c487da1eSNeel Natu case MSR_EFER:
454c487da1eSNeel Natu vmreg = VM_REG_GUEST_EFER;
455c487da1eSNeel Natu break;
456c487da1eSNeel Natu default:
457c487da1eSNeel Natu break;
458c487da1eSNeel Natu }
459c487da1eSNeel Natu
460c487da1eSNeel Natu if (vmreg == VM_REG_LAST) {
461c487da1eSNeel Natu printf("test_setmsr(%d): not implemented\n", r);
462c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
463c487da1eSNeel Natu }
464c487da1eSNeel Natu
4657d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v);
466c487da1eSNeel Natu if (error) {
467c487da1eSNeel Natu perror("vm_set_msr");
468c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
469c487da1eSNeel Natu }
470c487da1eSNeel Natu }
471c487da1eSNeel Natu
472c487da1eSNeel Natu static void
cb_setcr(void * arg __unused,int r,uint64_t v)473ad43dd69SMark Johnston cb_setcr(void *arg __unused, int r, uint64_t v)
474c487da1eSNeel Natu {
475c487da1eSNeel Natu int error;
476c487da1eSNeel Natu enum vm_reg_name vmreg;
477c487da1eSNeel Natu
478c487da1eSNeel Natu vmreg = VM_REG_LAST;
479c487da1eSNeel Natu
480c487da1eSNeel Natu switch (r) {
481c487da1eSNeel Natu case 0:
482c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR0;
483c487da1eSNeel Natu break;
484c487da1eSNeel Natu case 3:
485c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR3;
486c487da1eSNeel Natu cr3 = v;
487c487da1eSNeel Natu break;
488c487da1eSNeel Natu case 4:
489c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR4;
490c487da1eSNeel Natu break;
491c487da1eSNeel Natu default:
492c487da1eSNeel Natu break;
493c487da1eSNeel Natu }
494c487da1eSNeel Natu
495c487da1eSNeel Natu if (vmreg == VM_REG_LAST) {
496c487da1eSNeel Natu printf("test_setcr(%d): not implemented\n", r);
497c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
498c487da1eSNeel Natu }
499c487da1eSNeel Natu
5007d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v);
501c487da1eSNeel Natu if (error) {
502c487da1eSNeel Natu perror("vm_set_cr");
503c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
504c487da1eSNeel Natu }
505c487da1eSNeel Natu }
506c487da1eSNeel Natu
507c487da1eSNeel Natu static void
cb_setgdt(void * arg __unused,uint64_t base,size_t size)508ad43dd69SMark Johnston cb_setgdt(void *arg __unused, uint64_t base, size_t size)
509c487da1eSNeel Natu {
510c487da1eSNeel Natu int error;
511c487da1eSNeel Natu
5127d9ef309SJohn Baldwin error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR, base, size - 1, 0);
513c487da1eSNeel Natu if (error != 0) {
514c487da1eSNeel Natu perror("vm_set_desc(gdt)");
515c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
516c487da1eSNeel Natu }
517c487da1eSNeel Natu
518c487da1eSNeel Natu gdtbase = base;
519c487da1eSNeel Natu }
520c487da1eSNeel Natu
521c487da1eSNeel Natu static void
cb_exec(void * arg __unused,uint64_t rip)522ad43dd69SMark Johnston cb_exec(void *arg __unused, uint64_t rip)
523c487da1eSNeel Natu {
524c487da1eSNeel Natu int error;
525c487da1eSNeel Natu
52600f3efe1SJohn Baldwin if (cr3 == 0)
5277d9ef309SJohn Baldwin error = vm_setup_freebsd_registers_i386(vcpu, rip, gdtbase,
52800f3efe1SJohn Baldwin rsp);
52900f3efe1SJohn Baldwin else
5307d9ef309SJohn Baldwin error = vm_setup_freebsd_registers(vcpu, rip, cr3, gdtbase,
53100f3efe1SJohn Baldwin rsp);
532c487da1eSNeel Natu if (error) {
533c487da1eSNeel Natu perror("vm_setup_freebsd_registers");
534c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT);
535c487da1eSNeel Natu }
536c487da1eSNeel Natu
537c487da1eSNeel Natu cb_exit(NULL, 0);
538c487da1eSNeel Natu }
539c487da1eSNeel Natu
540c487da1eSNeel Natu /*
541c487da1eSNeel Natu * Misc
542c487da1eSNeel Natu */
543c487da1eSNeel Natu
544c487da1eSNeel Natu static void
cb_delay(void * arg __unused,int usec)545ad43dd69SMark Johnston cb_delay(void *arg __unused, int usec)
546c487da1eSNeel Natu {
547c487da1eSNeel Natu
548c487da1eSNeel Natu usleep(usec);
549c487da1eSNeel Natu }
550c487da1eSNeel Natu
551c487da1eSNeel Natu static void
cb_exit(void * arg __unused,int v)552ad43dd69SMark Johnston cb_exit(void *arg __unused, int v)
553c487da1eSNeel Natu {
554c487da1eSNeel Natu
5556380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &oldterm);
55624cd5c26SKyle Evans if (v == USERBOOT_EXIT_REBOOT)
55724cd5c26SKyle Evans longjmp(jb, JMP_REBOOT);
558c487da1eSNeel Natu exit(v);
559c487da1eSNeel Natu }
560c487da1eSNeel Natu
561c487da1eSNeel Natu static void
cb_getmem(void * arg __unused,uint64_t * ret_lowmem,uint64_t * ret_highmem)562ad43dd69SMark Johnston cb_getmem(void *arg __unused, uint64_t *ret_lowmem, uint64_t *ret_highmem)
563c487da1eSNeel Natu {
564c487da1eSNeel Natu
565be679db4SNeel Natu *ret_lowmem = vm_get_lowmem_size(ctx);
566be679db4SNeel Natu *ret_highmem = vm_get_highmem_size(ctx);
567c487da1eSNeel Natu }
568c487da1eSNeel Natu
569b6afa84bSNeel Natu struct env {
570cb37fc82SWarner Losh char *str; /* name=value */
571b6afa84bSNeel Natu SLIST_ENTRY(env) next;
572b6afa84bSNeel Natu };
573b6afa84bSNeel Natu
574b6afa84bSNeel Natu static SLIST_HEAD(envhead, env) envhead;
575b6afa84bSNeel Natu
576b6afa84bSNeel Natu static void
addenv(const char * str)577ad43dd69SMark Johnston addenv(const char *str)
578b6afa84bSNeel Natu {
579b6afa84bSNeel Natu struct env *env;
580b6afa84bSNeel Natu
581b6afa84bSNeel Natu env = malloc(sizeof(struct env));
582ad43dd69SMark Johnston if (env == NULL)
583ad43dd69SMark Johnston err(EX_OSERR, "malloc");
584ad43dd69SMark Johnston env->str = strdup(str);
585ad43dd69SMark Johnston if (env->str == NULL)
586ad43dd69SMark Johnston err(EX_OSERR, "strdup");
587b6afa84bSNeel Natu SLIST_INSERT_HEAD(&envhead, env, next);
588b6afa84bSNeel Natu }
589b6afa84bSNeel Natu
590e8e6a5f9SWarner Losh static char *
cb_getenv(void * arg __unused,int num)591ad43dd69SMark Johnston cb_getenv(void *arg __unused, int num)
592c3e9ce33SNeel Natu {
593b6afa84bSNeel Natu int i;
594b6afa84bSNeel Natu struct env *env;
595c3e9ce33SNeel Natu
596b6afa84bSNeel Natu i = 0;
597b6afa84bSNeel Natu SLIST_FOREACH(env, &envhead, next) {
598b6afa84bSNeel Natu if (i == num)
599b6afa84bSNeel Natu return (env->str);
600b6afa84bSNeel Natu i++;
601b6afa84bSNeel Natu }
602c3e9ce33SNeel Natu
603c3e9ce33SNeel Natu return (NULL);
604c3e9ce33SNeel Natu }
605c3e9ce33SNeel Natu
60648f337b8SMarcel Moolenaar static int
cb_vm_set_register(void * arg __unused,int vcpuid,int reg,uint64_t val)6077d9ef309SJohn Baldwin cb_vm_set_register(void *arg __unused, int vcpuid, int reg, uint64_t val)
60848f337b8SMarcel Moolenaar {
60948f337b8SMarcel Moolenaar
6107d9ef309SJohn Baldwin assert(vcpuid == BSP);
6117d9ef309SJohn Baldwin return (vm_set_register(vcpu, reg, val));
61248f337b8SMarcel Moolenaar }
61348f337b8SMarcel Moolenaar
61448f337b8SMarcel Moolenaar static int
cb_vm_set_desc(void * arg __unused,int vcpuid,int reg,uint64_t base,u_int limit,u_int access)6157d9ef309SJohn Baldwin cb_vm_set_desc(void *arg __unused, int vcpuid, int reg, uint64_t base,
616ad43dd69SMark Johnston u_int limit, u_int access)
61748f337b8SMarcel Moolenaar {
61848f337b8SMarcel Moolenaar
6197d9ef309SJohn Baldwin assert(vcpuid == BSP);
6207d9ef309SJohn Baldwin return (vm_set_desc(vcpu, reg, base, limit, access));
62148f337b8SMarcel Moolenaar }
62248f337b8SMarcel Moolenaar
623d3d381b2SKyle Evans static void
cb_swap_interpreter(void * arg __unused,const char * interp_req)624ad43dd69SMark Johnston cb_swap_interpreter(void *arg __unused, const char *interp_req)
625d3d381b2SKyle Evans {
626d3d381b2SKyle Evans
627d3d381b2SKyle Evans /*
628d3d381b2SKyle Evans * If the user specified a loader but we detected a mismatch, we should
629d3d381b2SKyle Evans * not try to pivot to a different loader on them.
630d3d381b2SKyle Evans */
631d3d381b2SKyle Evans free(loader);
632bf7c4fcbSKyle Evans if (explicit_loader_fd != -1) {
633d3d381b2SKyle Evans perror("requested loader interpreter does not match guest userboot");
634d3d381b2SKyle Evans cb_exit(NULL, 1);
635d3d381b2SKyle Evans }
636d3d381b2SKyle Evans if (interp_req == NULL || *interp_req == '\0') {
637d3d381b2SKyle Evans perror("guest failed to request an interpreter");
638d3d381b2SKyle Evans cb_exit(NULL, 1);
639d3d381b2SKyle Evans }
640d3d381b2SKyle Evans
641bf7c4fcbSKyle Evans if (asprintf(&loader, "userboot_%s.so", interp_req) == -1)
642d3d381b2SKyle Evans err(EX_OSERR, "malloc");
64324cd5c26SKyle Evans longjmp(jb, JMP_SWAPLOADER);
644d3d381b2SKyle Evans }
645d3d381b2SKyle Evans
646a10c6f55SNeel Natu static struct loader_callbacks cb = {
647c487da1eSNeel Natu .getc = cb_getc,
648c487da1eSNeel Natu .putc = cb_putc,
649c487da1eSNeel Natu .poll = cb_poll,
650c487da1eSNeel Natu
651c487da1eSNeel Natu .open = cb_open,
652c487da1eSNeel Natu .close = cb_close,
653c487da1eSNeel Natu .isdir = cb_isdir,
654c487da1eSNeel Natu .read = cb_read,
655c487da1eSNeel Natu .readdir = cb_readdir,
656c487da1eSNeel Natu .seek = cb_seek,
657c487da1eSNeel Natu .stat = cb_stat,
658c487da1eSNeel Natu
659c487da1eSNeel Natu .diskread = cb_diskread,
660cc71ff72SConrad Meyer .diskwrite = cb_diskwrite,
661a10c6f55SNeel Natu .diskioctl = cb_diskioctl,
662c487da1eSNeel Natu
663c487da1eSNeel Natu .copyin = cb_copyin,
664c487da1eSNeel Natu .copyout = cb_copyout,
665c487da1eSNeel Natu .setreg = cb_setreg,
666c487da1eSNeel Natu .setmsr = cb_setmsr,
667c487da1eSNeel Natu .setcr = cb_setcr,
668c487da1eSNeel Natu .setgdt = cb_setgdt,
669c487da1eSNeel Natu .exec = cb_exec,
670c487da1eSNeel Natu
671c487da1eSNeel Natu .delay = cb_delay,
672c487da1eSNeel Natu .exit = cb_exit,
673c487da1eSNeel Natu .getmem = cb_getmem,
674c3e9ce33SNeel Natu
675c3e9ce33SNeel Natu .getenv = cb_getenv,
67648f337b8SMarcel Moolenaar
67748f337b8SMarcel Moolenaar /* Version 4 additions */
67848f337b8SMarcel Moolenaar .vm_set_register = cb_vm_set_register,
67948f337b8SMarcel Moolenaar .vm_set_desc = cb_vm_set_desc,
680d3d381b2SKyle Evans
681d3d381b2SKyle Evans /* Version 5 additions */
682d3d381b2SKyle Evans .swap_interpreter = cb_swap_interpreter,
683c487da1eSNeel Natu };
684c487da1eSNeel Natu
6856380102cSPeter Grehan static int
altcons_open(char * path)6866380102cSPeter Grehan altcons_open(char *path)
6876380102cSPeter Grehan {
6886380102cSPeter Grehan struct stat sb;
6896380102cSPeter Grehan int err;
6906380102cSPeter Grehan int fd;
6916380102cSPeter Grehan
6926380102cSPeter Grehan /*
6936380102cSPeter Grehan * Allow stdio to be passed in so that the same string
6946380102cSPeter Grehan * can be used for the bhyveload console and bhyve com-port
6956380102cSPeter Grehan * parameters
6966380102cSPeter Grehan */
6976380102cSPeter Grehan if (!strcmp(path, "stdio"))
6986380102cSPeter Grehan return (0);
6996380102cSPeter Grehan
7006380102cSPeter Grehan err = stat(path, &sb);
7016380102cSPeter Grehan if (err == 0) {
7026380102cSPeter Grehan if (!S_ISCHR(sb.st_mode))
7036380102cSPeter Grehan err = ENOTSUP;
7046380102cSPeter Grehan else {
7056380102cSPeter Grehan fd = open(path, O_RDWR | O_NONBLOCK);
7066380102cSPeter Grehan if (fd < 0)
7076380102cSPeter Grehan err = errno;
7086380102cSPeter Grehan else
7096380102cSPeter Grehan consin_fd = consout_fd = fd;
7106380102cSPeter Grehan }
7116380102cSPeter Grehan }
7126380102cSPeter Grehan
7136380102cSPeter Grehan return (err);
7146380102cSPeter Grehan }
7156380102cSPeter Grehan
716cf087c12SPeter Grehan static int
disk_open(char * path)717cf087c12SPeter Grehan disk_open(char *path)
718cf087c12SPeter Grehan {
719a0bc451fSSean Chittenden int fd;
720cf087c12SPeter Grehan
7210db293c1SAllan Jude if (ndisks >= NDISKS)
722cf087c12SPeter Grehan return (ERANGE);
723cf087c12SPeter Grehan
7245a023bd2SRobert Wing fd = open(path, O_RDWR);
725a0bc451fSSean Chittenden if (fd < 0)
726a0bc451fSSean Chittenden return (errno);
727cf087c12SPeter Grehan
728cf087c12SPeter Grehan disk_fd[ndisks] = fd;
729cf087c12SPeter Grehan ndisks++;
730cf087c12SPeter Grehan
731a0bc451fSSean Chittenden return (0);
732cf087c12SPeter Grehan }
733cf087c12SPeter Grehan
734c487da1eSNeel Natu static void
usage(void)735c487da1eSNeel Natu usage(void)
736c487da1eSNeel Natu {
737c487da1eSNeel Natu
738b060ba50SNeel Natu fprintf(stderr,
7399b1aa8d6SNeel Natu "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n"
7406ee52c65SRoman Bogorodskiy " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n",
7416380102cSPeter Grehan progname,
742b5331f4dSNeel Natu (int)strlen(progname), "");
743c487da1eSNeel Natu exit(1);
744c487da1eSNeel Natu }
745c487da1eSNeel Natu
7466779d44bSKyle Evans static void
hostbase_open(const char * base)7476779d44bSKyle Evans hostbase_open(const char *base)
7486779d44bSKyle Evans {
749c067be72SKyle Evans cap_rights_t rights;
7506779d44bSKyle Evans
7516779d44bSKyle Evans if (hostbase_fd != -1)
7526779d44bSKyle Evans close(hostbase_fd);
7536779d44bSKyle Evans hostbase_fd = open(base, O_DIRECTORY | O_PATH);
7546779d44bSKyle Evans if (hostbase_fd == -1)
7556779d44bSKyle Evans err(EX_OSERR, "open");
756c067be72SKyle Evans
757c067be72SKyle Evans if (caph_rights_limit(hostbase_fd, cap_rights_init(&rights, CAP_FSTATAT,
758*cef5e56fSKyle Evans CAP_LOOKUP, CAP_PREAD)) < 0)
759c067be72SKyle Evans err(EX_OSERR, "caph_rights_limit");
7606779d44bSKyle Evans }
7616779d44bSKyle Evans
762bf7c4fcbSKyle Evans static void
loader_open(int bootfd)763bf7c4fcbSKyle Evans loader_open(int bootfd)
764bf7c4fcbSKyle Evans {
765bf7c4fcbSKyle Evans int fd;
766bf7c4fcbSKyle Evans
767bf7c4fcbSKyle Evans if (loader == NULL) {
768bf7c4fcbSKyle Evans loader = strdup("userboot.so");
769bf7c4fcbSKyle Evans if (loader == NULL)
770bf7c4fcbSKyle Evans err(EX_OSERR, "malloc");
771bf7c4fcbSKyle Evans }
772bf7c4fcbSKyle Evans
773bf7c4fcbSKyle Evans assert(bootfd >= 0 || explicit_loader_fd >= 0);
774bf7c4fcbSKyle Evans if (explicit_loader_fd >= 0)
775bf7c4fcbSKyle Evans fd = explicit_loader_fd;
776bf7c4fcbSKyle Evans else
777bf7c4fcbSKyle Evans fd = openat(bootfd, loader, O_RDONLY | O_RESOLVE_BENEATH);
778bf7c4fcbSKyle Evans if (fd == -1)
779bf7c4fcbSKyle Evans err(EX_OSERR, "openat");
780bf7c4fcbSKyle Evans
781bf7c4fcbSKyle Evans loader_hdl = fdlopen(fd, RTLD_LOCAL);
782bf7c4fcbSKyle Evans if (!loader_hdl)
783bf7c4fcbSKyle Evans errx(EX_OSERR, "dlopen: %s", dlerror());
78424cd5c26SKyle Evans if (fd != explicit_loader_fd)
78524cd5c26SKyle Evans close(fd);
786bf7c4fcbSKyle Evans }
787bf7c4fcbSKyle Evans
788c487da1eSNeel Natu int
main(int argc,char ** argv)789c487da1eSNeel Natu main(int argc, char** argv)
790c487da1eSNeel Natu {
791a10c6f55SNeel Natu void (*func)(struct loader_callbacks *, void *, int, int);
792b060ba50SNeel Natu uint64_t mem_size;
793bf7c4fcbSKyle Evans int bootfd, opt, error, memflags, need_reinit;
794c487da1eSNeel Natu
795bf7c4fcbSKyle Evans bootfd = -1;
796b5331f4dSNeel Natu progname = basename(argv[0]);
797c487da1eSNeel Natu
7989b1aa8d6SNeel Natu memflags = 0;
799b060ba50SNeel Natu mem_size = 256 * MB;
800c487da1eSNeel Natu
8016380102cSPeter Grehan consin_fd = STDIN_FILENO;
8026380102cSPeter Grehan consout_fd = STDOUT_FILENO;
8036380102cSPeter Grehan
804568e3a8dSMarcel Moolenaar while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) {
805c487da1eSNeel Natu switch (opt) {
8066380102cSPeter Grehan case 'c':
8076380102cSPeter Grehan error = altcons_open(optarg);
8086380102cSPeter Grehan if (error != 0)
8096380102cSPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg);
8106380102cSPeter Grehan break;
811cf087c12SPeter Grehan
812c487da1eSNeel Natu case 'd':
813cf087c12SPeter Grehan error = disk_open(optarg);
814cf087c12SPeter Grehan if (error != 0)
815cf087c12SPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg);
816c487da1eSNeel Natu break;
817c487da1eSNeel Natu
818b6afa84bSNeel Natu case 'e':
819b6afa84bSNeel Natu addenv(optarg);
820b6afa84bSNeel Natu break;
821b6afa84bSNeel Natu
822c487da1eSNeel Natu case 'h':
8236779d44bSKyle Evans hostbase_open(optarg);
824c487da1eSNeel Natu break;
825c487da1eSNeel Natu
8268c96dcc1SMarcel Moolenaar case 'l':
8278c96dcc1SMarcel Moolenaar if (loader != NULL)
8288c96dcc1SMarcel Moolenaar errx(EX_USAGE, "-l can only be given once");
8298c96dcc1SMarcel Moolenaar loader = strdup(optarg);
8308c96dcc1SMarcel Moolenaar if (loader == NULL)
8318c96dcc1SMarcel Moolenaar err(EX_OSERR, "malloc");
832bf7c4fcbSKyle Evans explicit_loader_fd = open(loader, O_RDONLY);
833bf7c4fcbSKyle Evans if (explicit_loader_fd == -1)
834bf7c4fcbSKyle Evans err(EX_OSERR, "%s", loader);
8358c96dcc1SMarcel Moolenaar break;
8368c96dcc1SMarcel Moolenaar
837c487da1eSNeel Natu case 'm':
838200758f1SNeel Natu error = vm_parse_memsize(optarg, &mem_size);
839200758f1SNeel Natu if (error != 0)
840200758f1SNeel Natu errx(EX_USAGE, "Invalid memsize '%s'", optarg);
841c487da1eSNeel Natu break;
842568e3a8dSMarcel Moolenaar case 'C':
843568e3a8dSMarcel Moolenaar memflags |= VM_MEM_F_INCORE;
844568e3a8dSMarcel Moolenaar break;
8459b1aa8d6SNeel Natu case 'S':
8469b1aa8d6SNeel Natu memflags |= VM_MEM_F_WIRED;
8479b1aa8d6SNeel Natu break;
848c487da1eSNeel Natu case '?':
849c487da1eSNeel Natu usage();
850c487da1eSNeel Natu }
851c487da1eSNeel Natu }
852c487da1eSNeel Natu
853c487da1eSNeel Natu argc -= optind;
854c487da1eSNeel Natu argv += optind;
855c487da1eSNeel Natu
856c487da1eSNeel Natu if (argc != 1)
857c487da1eSNeel Natu usage();
858c487da1eSNeel Natu
859c487da1eSNeel Natu vmname = argv[0];
860c487da1eSNeel Natu
8615fcf252fSNeel Natu need_reinit = 0;
862c487da1eSNeel Natu error = vm_create(vmname);
8635fcf252fSNeel Natu if (error) {
864a4a838a3SKyle Evans if (errno != EEXIST)
865a4a838a3SKyle Evans err(1, "vm_create");
8665fcf252fSNeel Natu need_reinit = 1;
867c487da1eSNeel Natu }
868c487da1eSNeel Natu
869c487da1eSNeel Natu ctx = vm_open(vmname);
870a4a838a3SKyle Evans if (ctx == NULL)
871a4a838a3SKyle Evans err(1, "vm_open");
872c487da1eSNeel Natu
873bf7c4fcbSKyle Evans /*
874bf7c4fcbSKyle Evans * If we weren't given an explicit loader to use, we need to support the
875bf7c4fcbSKyle Evans * guest requesting a different one.
876bf7c4fcbSKyle Evans */
877bf7c4fcbSKyle Evans if (explicit_loader_fd == -1) {
878c067be72SKyle Evans cap_rights_t rights;
879c067be72SKyle Evans
880bf7c4fcbSKyle Evans bootfd = open("/boot", O_DIRECTORY | O_PATH);
881a4a838a3SKyle Evans if (bootfd == -1)
882a4a838a3SKyle Evans err(1, "open");
883c067be72SKyle Evans
884c067be72SKyle Evans /*
885c067be72SKyle Evans * bootfd will be used to do a lookup of our loader and do an
886c067be72SKyle Evans * fdlopen(3) on the loader; thus, we need mmap(2) in addition
887c067be72SKyle Evans * to the more usual lookup rights.
888c067be72SKyle Evans */
889c067be72SKyle Evans if (caph_rights_limit(bootfd, cap_rights_init(&rights,
890*cef5e56fSKyle Evans CAP_FSTATAT, CAP_LOOKUP, CAP_MMAP_RX, CAP_PREAD)) < 0)
891a4a838a3SKyle Evans err(1, "caph_rights_limit");
892bf7c4fcbSKyle Evans }
893bf7c4fcbSKyle Evans
8947d9ef309SJohn Baldwin vcpu = vm_vcpu_open(ctx, BSP);
8957d9ef309SJohn Baldwin
8968bf0882eSKyle Evans caph_cache_catpages();
897a4a838a3SKyle Evans if (caph_enter() < 0)
898a4a838a3SKyle Evans err(1, "caph_enter");
8998bf0882eSKyle Evans
900d3d381b2SKyle Evans /*
901d3d381b2SKyle Evans * setjmp in the case the guest wants to swap out interpreter,
902d3d381b2SKyle Evans * cb_swap_interpreter will swap out loader as appropriate and set
903d3d381b2SKyle Evans * need_reinit so that we end up in a clean state once again.
904d3d381b2SKyle Evans */
905bf7c4fcbSKyle Evans if (setjmp(jb) != 0) {
906bf7c4fcbSKyle Evans dlclose(loader_hdl);
907bf7c4fcbSKyle Evans loader_hdl = NULL;
908bf7c4fcbSKyle Evans
909bf7c4fcbSKyle Evans need_reinit = 1;
910bf7c4fcbSKyle Evans }
911d3d381b2SKyle Evans
9125fcf252fSNeel Natu if (need_reinit) {
9135fcf252fSNeel Natu error = vm_reinit(ctx);
914a4a838a3SKyle Evans if (error)
915a4a838a3SKyle Evans err(1, "vm_reinit");
9165fcf252fSNeel Natu }
9175fcf252fSNeel Natu
9189b1aa8d6SNeel Natu vm_set_memflags(ctx, memflags);
919b060ba50SNeel Natu error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL);
920a4a838a3SKyle Evans if (error)
921a4a838a3SKyle Evans err(1, "vm_setup_memory");
922c487da1eSNeel Natu
923bf7c4fcbSKyle Evans loader_open(bootfd);
924d3d381b2SKyle Evans func = dlsym(loader_hdl, "loader_main");
925a4a838a3SKyle Evans if (!func)
926a4a838a3SKyle Evans errx(1, "dlsym: %s", dlerror());
9278c96dcc1SMarcel Moolenaar
9286380102cSPeter Grehan tcgetattr(consout_fd, &term);
929c487da1eSNeel Natu oldterm = term;
9306380102cSPeter Grehan cfmakeraw(&term);
9316380102cSPeter Grehan term.c_cflag |= CLOCAL;
9326380102cSPeter Grehan
9336380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &term);
9346380102cSPeter Grehan
935b6afa84bSNeel Natu addenv("smbios.bios.vendor=BHYVE");
936b6afa84bSNeel Natu addenv("boot_serial=1");
937b6afa84bSNeel Natu
938d3d381b2SKyle Evans func(&cb, NULL, USERBOOT_VERSION_5, ndisks);
9398c96dcc1SMarcel Moolenaar
9408c96dcc1SMarcel Moolenaar free(loader);
9418c96dcc1SMarcel Moolenaar return (0);
942c487da1eSNeel Natu }
943