xref: /freebsd-src/usr.sbin/bhyveload/bhyveload.c (revision c3e9ce3312e8bd27c01e00889f1a07bc630e26fc)
1c487da1eSNeel Natu /*-
2c487da1eSNeel Natu  * Copyright (c) 2011 NetApp, Inc.
3c487da1eSNeel Natu  * All rights reserved.
4c487da1eSNeel Natu  *
5c487da1eSNeel Natu  * Redistribution and use in source and binary forms, with or without
6c487da1eSNeel Natu  * modification, are permitted provided that the following conditions
7c487da1eSNeel Natu  * are met:
8c487da1eSNeel Natu  * 1. Redistributions of source code must retain the above copyright
9c487da1eSNeel Natu  *    notice, this list of conditions and the following disclaimer.
10c487da1eSNeel Natu  * 2. Redistributions in binary form must reproduce the above copyright
11c487da1eSNeel Natu  *    notice, this list of conditions and the following disclaimer in the
12c487da1eSNeel Natu  *    documentation and/or other materials provided with the distribution.
13c487da1eSNeel Natu  *
14c487da1eSNeel Natu  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15c487da1eSNeel Natu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c487da1eSNeel Natu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c487da1eSNeel Natu  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18c487da1eSNeel Natu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c487da1eSNeel Natu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c487da1eSNeel Natu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c487da1eSNeel Natu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c487da1eSNeel Natu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c487da1eSNeel Natu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c487da1eSNeel Natu  * SUCH DAMAGE.
25c487da1eSNeel Natu  *
26c487da1eSNeel Natu  * $FreeBSD$
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  * $FreeBSD$
55c487da1eSNeel Natu  */
56c487da1eSNeel Natu 
57c487da1eSNeel Natu #include <sys/cdefs.h>
58c487da1eSNeel Natu __FBSDID("$FreeBSD$");
59c487da1eSNeel Natu 
60c487da1eSNeel Natu #include <sys/ioctl.h>
61c487da1eSNeel Natu #include <sys/stat.h>
62c487da1eSNeel Natu 
63c487da1eSNeel Natu #include <machine/specialreg.h>
64c487da1eSNeel Natu #include <machine/vmm.h>
65c487da1eSNeel Natu 
66c487da1eSNeel Natu #include <dirent.h>
67c487da1eSNeel Natu #include <dlfcn.h>
68c487da1eSNeel Natu #include <errno.h>
69c487da1eSNeel Natu #include <fcntl.h>
70c487da1eSNeel Natu #include <getopt.h>
71c487da1eSNeel Natu #include <limits.h>
72c487da1eSNeel Natu #include <stdio.h>
73c487da1eSNeel Natu #include <stdlib.h>
74c487da1eSNeel Natu #include <string.h>
75c487da1eSNeel Natu #include <termios.h>
76c487da1eSNeel Natu #include <unistd.h>
77c487da1eSNeel Natu 
78c487da1eSNeel Natu #include <vmmapi.h>
79c487da1eSNeel Natu 
80c487da1eSNeel Natu #include "userboot.h"
81c487da1eSNeel Natu 
82c487da1eSNeel Natu #define	MB	(1024 * 1024UL)
83c487da1eSNeel Natu #define	GB	(1024 * 1024 * 1024UL)
84c487da1eSNeel Natu #define	BSP	0
85c487da1eSNeel Natu 
86c487da1eSNeel Natu static char *host_base = "/";
87c487da1eSNeel Natu static struct termios term, oldterm;
88c487da1eSNeel Natu static int disk_fd = -1;
89c487da1eSNeel Natu 
90c487da1eSNeel Natu static char *vmname, *progname, *membase;
91c487da1eSNeel Natu static uint64_t lowmem, highmem;
92c487da1eSNeel Natu static struct vmctx *ctx;
93c487da1eSNeel Natu 
94c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp;
95c487da1eSNeel Natu 
96c487da1eSNeel Natu static void cb_exit(void *arg, int v);
97c487da1eSNeel Natu 
98c487da1eSNeel Natu /*
99c487da1eSNeel Natu  * Console i/o callbacks
100c487da1eSNeel Natu  */
101c487da1eSNeel Natu 
102c487da1eSNeel Natu static void
103c487da1eSNeel Natu cb_putc(void *arg, int ch)
104c487da1eSNeel Natu {
105c487da1eSNeel Natu 	char c = ch;
106c487da1eSNeel Natu 
107c487da1eSNeel Natu 	write(1, &c, 1);
108c487da1eSNeel Natu }
109c487da1eSNeel Natu 
110c487da1eSNeel Natu static int
111c487da1eSNeel Natu cb_getc(void *arg)
112c487da1eSNeel Natu {
113c487da1eSNeel Natu 	char c;
114c487da1eSNeel Natu 
115c487da1eSNeel Natu 	if (read(0, &c, 1) == 1)
116c487da1eSNeel Natu 		return (c);
117c487da1eSNeel Natu 	return (-1);
118c487da1eSNeel Natu }
119c487da1eSNeel Natu 
120c487da1eSNeel Natu static int
121c487da1eSNeel Natu cb_poll(void *arg)
122c487da1eSNeel Natu {
123c487da1eSNeel Natu 	int n;
124c487da1eSNeel Natu 
125c487da1eSNeel Natu 	if (ioctl(0, FIONREAD, &n) >= 0)
126c487da1eSNeel Natu 		return (n > 0);
127c487da1eSNeel Natu 	return (0);
128c487da1eSNeel Natu }
129c487da1eSNeel Natu 
130c487da1eSNeel Natu /*
131c487da1eSNeel Natu  * Host filesystem i/o callbacks
132c487da1eSNeel Natu  */
133c487da1eSNeel Natu 
134c487da1eSNeel Natu struct cb_file {
135c487da1eSNeel Natu 	int cf_isdir;
136c487da1eSNeel Natu 	size_t cf_size;
137c487da1eSNeel Natu 	struct stat cf_stat;
138c487da1eSNeel Natu 	union {
139c487da1eSNeel Natu 		int fd;
140c487da1eSNeel Natu 		DIR *dir;
141c487da1eSNeel Natu 	} cf_u;
142c487da1eSNeel Natu };
143c487da1eSNeel Natu 
144c487da1eSNeel Natu static int
145c487da1eSNeel Natu cb_open(void *arg, const char *filename, void **hp)
146c487da1eSNeel Natu {
147c487da1eSNeel Natu 	struct stat st;
148c487da1eSNeel Natu 	struct cb_file *cf;
149c487da1eSNeel Natu 	char path[PATH_MAX];
150c487da1eSNeel Natu 
151c487da1eSNeel Natu 	if (!host_base)
152c487da1eSNeel Natu 		return (ENOENT);
153c487da1eSNeel Natu 
154c487da1eSNeel Natu 	strlcpy(path, host_base, PATH_MAX);
155c487da1eSNeel Natu 	if (path[strlen(path) - 1] == '/')
156c487da1eSNeel Natu 		path[strlen(path) - 1] = 0;
157c487da1eSNeel Natu 	strlcat(path, filename, PATH_MAX);
158c487da1eSNeel Natu 	cf = malloc(sizeof(struct cb_file));
159c487da1eSNeel Natu 	if (stat(path, &cf->cf_stat) < 0) {
160c487da1eSNeel Natu 		free(cf);
161c487da1eSNeel Natu 		return (errno);
162c487da1eSNeel Natu 	}
163c487da1eSNeel Natu 
164c487da1eSNeel Natu 	cf->cf_size = st.st_size;
165c487da1eSNeel Natu 	if (S_ISDIR(cf->cf_stat.st_mode)) {
166c487da1eSNeel Natu 		cf->cf_isdir = 1;
167c487da1eSNeel Natu 		cf->cf_u.dir = opendir(path);
168c487da1eSNeel Natu 		if (!cf->cf_u.dir)
169c487da1eSNeel Natu 			goto out;
170c487da1eSNeel Natu 		*hp = cf;
171c487da1eSNeel Natu 		return (0);
172c487da1eSNeel Natu 	}
173c487da1eSNeel Natu 	if (S_ISREG(cf->cf_stat.st_mode)) {
174c487da1eSNeel Natu 		cf->cf_isdir = 0;
175c487da1eSNeel Natu 		cf->cf_u.fd = open(path, O_RDONLY);
176c487da1eSNeel Natu 		if (cf->cf_u.fd < 0)
177c487da1eSNeel Natu 			goto out;
178c487da1eSNeel Natu 		*hp = cf;
179c487da1eSNeel Natu 		return (0);
180c487da1eSNeel Natu 	}
181c487da1eSNeel Natu 
182c487da1eSNeel Natu out:
183c487da1eSNeel Natu 	free(cf);
184c487da1eSNeel Natu 	return (EINVAL);
185c487da1eSNeel Natu }
186c487da1eSNeel Natu 
187c487da1eSNeel Natu static int
188c487da1eSNeel Natu cb_close(void *arg, void *h)
189c487da1eSNeel Natu {
190c487da1eSNeel Natu 	struct cb_file *cf = h;
191c487da1eSNeel Natu 
192c487da1eSNeel Natu 	if (cf->cf_isdir)
193c487da1eSNeel Natu 		closedir(cf->cf_u.dir);
194c487da1eSNeel Natu 	else
195c487da1eSNeel Natu 		close(cf->cf_u.fd);
196c487da1eSNeel Natu 	free(cf);
197c487da1eSNeel Natu 
198c487da1eSNeel Natu 	return (0);
199c487da1eSNeel Natu }
200c487da1eSNeel Natu 
201c487da1eSNeel Natu static int
202c487da1eSNeel Natu cb_isdir(void *arg, void *h)
203c487da1eSNeel Natu {
204c487da1eSNeel Natu 	struct cb_file *cf = h;
205c487da1eSNeel Natu 
206c487da1eSNeel Natu 	return (cf->cf_isdir);
207c487da1eSNeel Natu }
208c487da1eSNeel Natu 
209c487da1eSNeel Natu static int
210c487da1eSNeel Natu cb_read(void *arg, void *h, void *buf, size_t size, size_t *resid)
211c487da1eSNeel Natu {
212c487da1eSNeel Natu 	struct cb_file *cf = h;
213c487da1eSNeel Natu 	ssize_t sz;
214c487da1eSNeel Natu 
215c487da1eSNeel Natu 	if (cf->cf_isdir)
216c487da1eSNeel Natu 		return (EINVAL);
217c487da1eSNeel Natu 	sz = read(cf->cf_u.fd, buf, size);
218c487da1eSNeel Natu 	if (sz < 0)
219c487da1eSNeel Natu 		return (EINVAL);
220c487da1eSNeel Natu 	*resid = size - sz;
221c487da1eSNeel Natu 	return (0);
222c487da1eSNeel Natu }
223c487da1eSNeel Natu 
224c487da1eSNeel Natu static int
225c487da1eSNeel Natu cb_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return,
226c487da1eSNeel Natu 	   size_t *namelen_return, char *name)
227c487da1eSNeel Natu {
228c487da1eSNeel Natu 	struct cb_file *cf = h;
229c487da1eSNeel Natu 	struct dirent *dp;
230c487da1eSNeel Natu 
231c487da1eSNeel Natu 	if (!cf->cf_isdir)
232c487da1eSNeel Natu 		return (EINVAL);
233c487da1eSNeel Natu 
234c487da1eSNeel Natu 	dp = readdir(cf->cf_u.dir);
235c487da1eSNeel Natu 	if (!dp)
236c487da1eSNeel Natu 		return (ENOENT);
237c487da1eSNeel Natu 
238c487da1eSNeel Natu 	/*
239c487da1eSNeel Natu 	 * Note: d_namlen is in the range 0..255 and therefore less
240c487da1eSNeel Natu 	 * than PATH_MAX so we don't need to test before copying.
241c487da1eSNeel Natu 	 */
242c487da1eSNeel Natu 	*fileno_return = dp->d_fileno;
243c487da1eSNeel Natu 	*type_return = dp->d_type;
244c487da1eSNeel Natu 	*namelen_return = dp->d_namlen;
245c487da1eSNeel Natu 	memcpy(name, dp->d_name, dp->d_namlen);
246c487da1eSNeel Natu 	name[dp->d_namlen] = 0;
247c487da1eSNeel Natu 
248c487da1eSNeel Natu 	return (0);
249c487da1eSNeel Natu }
250c487da1eSNeel Natu 
251c487da1eSNeel Natu static int
252c487da1eSNeel Natu cb_seek(void *arg, void *h, uint64_t offset, int whence)
253c487da1eSNeel Natu {
254c487da1eSNeel Natu 	struct cb_file *cf = h;
255c487da1eSNeel Natu 
256c487da1eSNeel Natu 	if (cf->cf_isdir)
257c487da1eSNeel Natu 		return (EINVAL);
258c487da1eSNeel Natu 	if (lseek(cf->cf_u.fd, offset, whence) < 0)
259c487da1eSNeel Natu 		return (errno);
260c487da1eSNeel Natu 	return (0);
261c487da1eSNeel Natu }
262c487da1eSNeel Natu 
263c487da1eSNeel Natu static int
264c487da1eSNeel Natu cb_stat(void *arg, void *h, int *mode, int *uid, int *gid, uint64_t *size)
265c487da1eSNeel Natu {
266c487da1eSNeel Natu 	struct cb_file *cf = h;
267c487da1eSNeel Natu 
268c487da1eSNeel Natu 	*mode = cf->cf_stat.st_mode;
269c487da1eSNeel Natu 	*uid = cf->cf_stat.st_uid;
270c487da1eSNeel Natu 	*gid = cf->cf_stat.st_gid;
271c487da1eSNeel Natu 	*size = cf->cf_stat.st_size;
272c487da1eSNeel Natu 	return (0);
273c487da1eSNeel Natu }
274c487da1eSNeel Natu 
275c487da1eSNeel Natu /*
276c487da1eSNeel Natu  * Disk image i/o callbacks
277c487da1eSNeel Natu  */
278c487da1eSNeel Natu 
279c487da1eSNeel Natu static int
280c487da1eSNeel Natu cb_diskread(void *arg, int unit, uint64_t from, void *to, size_t size,
281c487da1eSNeel Natu 	    size_t *resid)
282c487da1eSNeel Natu {
283c487da1eSNeel Natu 	ssize_t n;
284c487da1eSNeel Natu 
285c487da1eSNeel Natu 	if (unit != 0 || disk_fd == -1)
286c487da1eSNeel Natu 		return (EIO);
287c487da1eSNeel Natu 	n = pread(disk_fd, to, size, from);
288c487da1eSNeel Natu 	if (n < 0)
289c487da1eSNeel Natu 		return (errno);
290c487da1eSNeel Natu 	*resid = size - n;
291c487da1eSNeel Natu 	return (0);
292c487da1eSNeel Natu }
293c487da1eSNeel Natu 
294c487da1eSNeel Natu /*
295c487da1eSNeel Natu  * Guest virtual machine i/o callbacks
296c487da1eSNeel Natu  */
297c487da1eSNeel Natu static int
298c487da1eSNeel Natu cb_copyin(void *arg, const void *from, uint64_t to, size_t size)
299c487da1eSNeel Natu {
300c487da1eSNeel Natu 
301c487da1eSNeel Natu 	to &= 0x7fffffff;
302c487da1eSNeel Natu 	if (to > lowmem)
303c487da1eSNeel Natu 		return (EFAULT);
304c487da1eSNeel Natu 	if (to + size > lowmem)
305c487da1eSNeel Natu 		size = lowmem - to;
306c487da1eSNeel Natu 
307c487da1eSNeel Natu 	memcpy(&membase[to], from, size);
308c487da1eSNeel Natu 
309c487da1eSNeel Natu 	return (0);
310c487da1eSNeel Natu }
311c487da1eSNeel Natu 
312c487da1eSNeel Natu static int
313c487da1eSNeel Natu cb_copyout(void *arg, uint64_t from, void *to, size_t size)
314c487da1eSNeel Natu {
315c487da1eSNeel Natu 
316c487da1eSNeel Natu 	from &= 0x7fffffff;
317c487da1eSNeel Natu 	if (from > lowmem)
318c487da1eSNeel Natu 		return (EFAULT);
319c487da1eSNeel Natu 	if (from + size > lowmem)
320c487da1eSNeel Natu 		size = lowmem - from;
321c487da1eSNeel Natu 
322c487da1eSNeel Natu 	memcpy(to, &membase[from], size);
323c487da1eSNeel Natu 
324c487da1eSNeel Natu 	return (0);
325c487da1eSNeel Natu }
326c487da1eSNeel Natu 
327c487da1eSNeel Natu static void
328c487da1eSNeel Natu cb_setreg(void *arg, int r, uint64_t v)
329c487da1eSNeel Natu {
330c487da1eSNeel Natu 	int error;
331c487da1eSNeel Natu 	enum vm_reg_name vmreg;
332c487da1eSNeel Natu 
333c487da1eSNeel Natu 	vmreg = VM_REG_LAST;
334c487da1eSNeel Natu 
335c487da1eSNeel Natu 	switch (r) {
336c487da1eSNeel Natu 	case 4:
337c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_RSP;
338c487da1eSNeel Natu 		rsp = v;
339c487da1eSNeel Natu 		break;
340c487da1eSNeel Natu 	default:
341c487da1eSNeel Natu 		break;
342c487da1eSNeel Natu 	}
343c487da1eSNeel Natu 
344c487da1eSNeel Natu 	if (vmreg == VM_REG_LAST) {
345c487da1eSNeel Natu 		printf("test_setreg(%d): not implemented\n", r);
346c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
347c487da1eSNeel Natu 	}
348c487da1eSNeel Natu 
349c487da1eSNeel Natu 	error = vm_set_register(ctx, BSP, vmreg, v);
350c487da1eSNeel Natu 	if (error) {
351c487da1eSNeel Natu 		perror("vm_set_register");
352c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
353c487da1eSNeel Natu 	}
354c487da1eSNeel Natu }
355c487da1eSNeel Natu 
356c487da1eSNeel Natu static void
357c487da1eSNeel Natu cb_setmsr(void *arg, int r, uint64_t v)
358c487da1eSNeel Natu {
359c487da1eSNeel Natu 	int error;
360c487da1eSNeel Natu 	enum vm_reg_name vmreg;
361c487da1eSNeel Natu 
362c487da1eSNeel Natu 	vmreg = VM_REG_LAST;
363c487da1eSNeel Natu 
364c487da1eSNeel Natu 	switch (r) {
365c487da1eSNeel Natu 	case MSR_EFER:
366c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_EFER;
367c487da1eSNeel Natu 		break;
368c487da1eSNeel Natu 	default:
369c487da1eSNeel Natu 		break;
370c487da1eSNeel Natu 	}
371c487da1eSNeel Natu 
372c487da1eSNeel Natu 	if (vmreg == VM_REG_LAST) {
373c487da1eSNeel Natu 		printf("test_setmsr(%d): not implemented\n", r);
374c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
375c487da1eSNeel Natu 	}
376c487da1eSNeel Natu 
377c487da1eSNeel Natu 	error = vm_set_register(ctx, BSP, vmreg, v);
378c487da1eSNeel Natu 	if (error) {
379c487da1eSNeel Natu 		perror("vm_set_msr");
380c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
381c487da1eSNeel Natu 	}
382c487da1eSNeel Natu }
383c487da1eSNeel Natu 
384c487da1eSNeel Natu static void
385c487da1eSNeel Natu cb_setcr(void *arg, int r, uint64_t v)
386c487da1eSNeel Natu {
387c487da1eSNeel Natu 	int error;
388c487da1eSNeel Natu 	enum vm_reg_name vmreg;
389c487da1eSNeel Natu 
390c487da1eSNeel Natu 	vmreg = VM_REG_LAST;
391c487da1eSNeel Natu 
392c487da1eSNeel Natu 	switch (r) {
393c487da1eSNeel Natu 	case 0:
394c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_CR0;
395c487da1eSNeel Natu 		break;
396c487da1eSNeel Natu 	case 3:
397c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_CR3;
398c487da1eSNeel Natu 		cr3 = v;
399c487da1eSNeel Natu 		break;
400c487da1eSNeel Natu 	case 4:
401c487da1eSNeel Natu 		vmreg = VM_REG_GUEST_CR4;
402c487da1eSNeel Natu 		break;
403c487da1eSNeel Natu 	default:
404c487da1eSNeel Natu 		break;
405c487da1eSNeel Natu 	}
406c487da1eSNeel Natu 
407c487da1eSNeel Natu 	if (vmreg == VM_REG_LAST) {
408c487da1eSNeel Natu 		printf("test_setcr(%d): not implemented\n", r);
409c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
410c487da1eSNeel Natu 	}
411c487da1eSNeel Natu 
412c487da1eSNeel Natu 	error = vm_set_register(ctx, BSP, vmreg, v);
413c487da1eSNeel Natu 	if (error) {
414c487da1eSNeel Natu 		perror("vm_set_cr");
415c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
416c487da1eSNeel Natu 	}
417c487da1eSNeel Natu }
418c487da1eSNeel Natu 
419c487da1eSNeel Natu static void
420c487da1eSNeel Natu cb_setgdt(void *arg, uint64_t base, size_t size)
421c487da1eSNeel Natu {
422c487da1eSNeel Natu 	int error;
423c487da1eSNeel Natu 
424c487da1eSNeel Natu 	error = vm_set_desc(ctx, BSP, VM_REG_GUEST_GDTR, base, size - 1, 0);
425c487da1eSNeel Natu 	if (error != 0) {
426c487da1eSNeel Natu 		perror("vm_set_desc(gdt)");
427c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
428c487da1eSNeel Natu 	}
429c487da1eSNeel Natu 
430c487da1eSNeel Natu 	gdtbase = base;
431c487da1eSNeel Natu }
432c487da1eSNeel Natu 
433c487da1eSNeel Natu static void
434c487da1eSNeel Natu cb_exec(void *arg, uint64_t rip)
435c487da1eSNeel Natu {
436c487da1eSNeel Natu 	int error;
437c487da1eSNeel Natu 
438c487da1eSNeel Natu 	error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, rsp);
439c487da1eSNeel Natu 	if (error) {
440c487da1eSNeel Natu 		perror("vm_setup_freebsd_registers");
441c487da1eSNeel Natu 		cb_exit(NULL, USERBOOT_EXIT_QUIT);
442c487da1eSNeel Natu 	}
443c487da1eSNeel Natu 
444c487da1eSNeel Natu 	cb_exit(NULL, 0);
445c487da1eSNeel Natu }
446c487da1eSNeel Natu 
447c487da1eSNeel Natu /*
448c487da1eSNeel Natu  * Misc
449c487da1eSNeel Natu  */
450c487da1eSNeel Natu 
451c487da1eSNeel Natu static void
452c487da1eSNeel Natu cb_delay(void *arg, int usec)
453c487da1eSNeel Natu {
454c487da1eSNeel Natu 
455c487da1eSNeel Natu 	usleep(usec);
456c487da1eSNeel Natu }
457c487da1eSNeel Natu 
458c487da1eSNeel Natu static void
459c487da1eSNeel Natu cb_exit(void *arg, int v)
460c487da1eSNeel Natu {
461c487da1eSNeel Natu 
462c487da1eSNeel Natu 	tcsetattr(0, TCSAFLUSH, &oldterm);
463c487da1eSNeel Natu 	exit(v);
464c487da1eSNeel Natu }
465c487da1eSNeel Natu 
466c487da1eSNeel Natu static void
467c487da1eSNeel Natu cb_getmem(void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem)
468c487da1eSNeel Natu {
469c487da1eSNeel Natu 
470c487da1eSNeel Natu 	*ret_lowmem = lowmem;
471c487da1eSNeel Natu 	*ret_highmem = highmem;
472c487da1eSNeel Natu }
473c487da1eSNeel Natu 
474*c3e9ce33SNeel Natu static const char *
475*c3e9ce33SNeel Natu cb_getenv(void *arg, int num)
476*c3e9ce33SNeel Natu {
477*c3e9ce33SNeel Natu 	int max;
478*c3e9ce33SNeel Natu 
479*c3e9ce33SNeel Natu 	static const char * var[] = {
480*c3e9ce33SNeel Natu 		"smbios.bios.vendor=BHYVE",
481*c3e9ce33SNeel Natu 		"boot_serial=1",
482*c3e9ce33SNeel Natu 		NULL
483*c3e9ce33SNeel Natu 	};
484*c3e9ce33SNeel Natu 
485*c3e9ce33SNeel Natu 	max = sizeof(var) / sizeof(var[0]);
486*c3e9ce33SNeel Natu 
487*c3e9ce33SNeel Natu 	if (num < max)
488*c3e9ce33SNeel Natu 		return (var[num]);
489*c3e9ce33SNeel Natu 	else
490*c3e9ce33SNeel Natu 		return (NULL);
491*c3e9ce33SNeel Natu }
492*c3e9ce33SNeel Natu 
493c487da1eSNeel Natu static struct loader_callbacks_v1 cb = {
494c487da1eSNeel Natu 	.getc = cb_getc,
495c487da1eSNeel Natu 	.putc = cb_putc,
496c487da1eSNeel Natu 	.poll = cb_poll,
497c487da1eSNeel Natu 
498c487da1eSNeel Natu 	.open = cb_open,
499c487da1eSNeel Natu 	.close = cb_close,
500c487da1eSNeel Natu 	.isdir = cb_isdir,
501c487da1eSNeel Natu 	.read = cb_read,
502c487da1eSNeel Natu 	.readdir = cb_readdir,
503c487da1eSNeel Natu 	.seek = cb_seek,
504c487da1eSNeel Natu 	.stat = cb_stat,
505c487da1eSNeel Natu 
506c487da1eSNeel Natu 	.diskread = cb_diskread,
507c487da1eSNeel Natu 
508c487da1eSNeel Natu 	.copyin = cb_copyin,
509c487da1eSNeel Natu 	.copyout = cb_copyout,
510c487da1eSNeel Natu 	.setreg = cb_setreg,
511c487da1eSNeel Natu 	.setmsr = cb_setmsr,
512c487da1eSNeel Natu 	.setcr = cb_setcr,
513c487da1eSNeel Natu 	.setgdt = cb_setgdt,
514c487da1eSNeel Natu 	.exec = cb_exec,
515c487da1eSNeel Natu 
516c487da1eSNeel Natu 	.delay = cb_delay,
517c487da1eSNeel Natu 	.exit = cb_exit,
518c487da1eSNeel Natu 	.getmem = cb_getmem,
519*c3e9ce33SNeel Natu 
520*c3e9ce33SNeel Natu 	.getenv = cb_getenv,
521c487da1eSNeel Natu };
522c487da1eSNeel Natu 
523c487da1eSNeel Natu static void
524c487da1eSNeel Natu usage(void)
525c487da1eSNeel Natu {
526c487da1eSNeel Natu 
527c487da1eSNeel Natu 	printf("usage: %s [-d <disk image path>] [-h <host filesystem path>] "
528c487da1eSNeel Natu 	       "[-m <lowmem>][-M <highmem>] "
529c487da1eSNeel Natu 	       "<vmname>\n", progname);
530c487da1eSNeel Natu 	exit(1);
531c487da1eSNeel Natu }
532c487da1eSNeel Natu 
533c487da1eSNeel Natu int
534c487da1eSNeel Natu main(int argc, char** argv)
535c487da1eSNeel Natu {
536c487da1eSNeel Natu 	void *h;
537c487da1eSNeel Natu 	void (*func)(struct loader_callbacks_v1 *, void *, int, int);
538c487da1eSNeel Natu 	int opt, error;
539c487da1eSNeel Natu 	char *disk_image;
540c487da1eSNeel Natu 
541c487da1eSNeel Natu 	progname = argv[0];
542c487da1eSNeel Natu 
543c487da1eSNeel Natu 	lowmem = 768 * MB;
544c487da1eSNeel Natu 	highmem = 0;
545c487da1eSNeel Natu 	disk_image = NULL;
546c487da1eSNeel Natu 
547c487da1eSNeel Natu 	while ((opt = getopt(argc, argv, "d:h:m:M:")) != -1) {
548c487da1eSNeel Natu 		switch (opt) {
549c487da1eSNeel Natu 		case 'd':
550c487da1eSNeel Natu 			disk_image = optarg;
551c487da1eSNeel Natu 			break;
552c487da1eSNeel Natu 
553c487da1eSNeel Natu 		case 'h':
554c487da1eSNeel Natu 			host_base = optarg;
555c487da1eSNeel Natu 			break;
556c487da1eSNeel Natu 
557c487da1eSNeel Natu 		case 'm':
558c487da1eSNeel Natu 			lowmem = strtoul(optarg, NULL, 0) * MB;
559c487da1eSNeel Natu 			break;
560c487da1eSNeel Natu 
561c487da1eSNeel Natu 		case 'M':
562c487da1eSNeel Natu 			highmem = strtoul(optarg, NULL, 0) * MB;
563c487da1eSNeel Natu 			break;
564c487da1eSNeel Natu 
565c487da1eSNeel Natu 		case '?':
566c487da1eSNeel Natu 			usage();
567c487da1eSNeel Natu 		}
568c487da1eSNeel Natu 	}
569c487da1eSNeel Natu 
570c487da1eSNeel Natu 	argc -= optind;
571c487da1eSNeel Natu 	argv += optind;
572c487da1eSNeel Natu 
573c487da1eSNeel Natu 	if (argc != 1)
574c487da1eSNeel Natu 		usage();
575c487da1eSNeel Natu 
576c487da1eSNeel Natu 	vmname = argv[0];
577c487da1eSNeel Natu 
578c487da1eSNeel Natu 	error = vm_create(vmname);
579c487da1eSNeel Natu 	if (error != 0 && errno != EEXIST) {
580c487da1eSNeel Natu 		perror("vm_create");
581c487da1eSNeel Natu 		exit(1);
582c487da1eSNeel Natu 
583c487da1eSNeel Natu 	}
584c487da1eSNeel Natu 
585c487da1eSNeel Natu 	ctx = vm_open(vmname);
586c487da1eSNeel Natu 	if (ctx == NULL) {
587c487da1eSNeel Natu 		perror("vm_open");
588c487da1eSNeel Natu 		exit(1);
589c487da1eSNeel Natu 	}
590c487da1eSNeel Natu 
591c487da1eSNeel Natu 	error = vm_setup_memory(ctx, 0, lowmem, &membase);
592c487da1eSNeel Natu 	if (error) {
593c487da1eSNeel Natu 		perror("vm_setup_memory(lowmem)");
594c487da1eSNeel Natu 		exit(1);
595c487da1eSNeel Natu 	}
596c487da1eSNeel Natu 
597c487da1eSNeel Natu 	if (highmem != 0) {
598c487da1eSNeel Natu 		error = vm_setup_memory(ctx, 4 * GB, highmem, NULL);
599c487da1eSNeel Natu 		if (error) {
600c487da1eSNeel Natu 			perror("vm_setup_memory(highmem)");
601c487da1eSNeel Natu 			exit(1);
602c487da1eSNeel Natu 		}
603c487da1eSNeel Natu 	}
604c487da1eSNeel Natu 
605c487da1eSNeel Natu 	tcgetattr(0, &term);
606c487da1eSNeel Natu 	oldterm = term;
607c487da1eSNeel Natu 	term.c_lflag &= ~(ICANON|ECHO);
608c487da1eSNeel Natu 	term.c_iflag &= ~ICRNL;
609c487da1eSNeel Natu 	tcsetattr(0, TCSAFLUSH, &term);
61038f1b189SPeter Grehan 	h = dlopen("/boot/userboot.so", RTLD_LOCAL);
611c487da1eSNeel Natu 	if (!h) {
612c487da1eSNeel Natu 		printf("%s\n", dlerror());
613c487da1eSNeel Natu 		return (1);
614c487da1eSNeel Natu 	}
615c487da1eSNeel Natu 	func = dlsym(h, "loader_main");
616c487da1eSNeel Natu 	if (!func) {
617c487da1eSNeel Natu 		printf("%s\n", dlerror());
618c487da1eSNeel Natu 		return (1);
619c487da1eSNeel Natu 	}
620c487da1eSNeel Natu 
621c487da1eSNeel Natu 	if (disk_image) {
622c487da1eSNeel Natu 		disk_fd = open(disk_image, O_RDONLY);
623c487da1eSNeel Natu 	}
624*c3e9ce33SNeel Natu 	func(&cb, NULL, USERBOOT_VERSION_3, disk_fd >= 0);
625c487da1eSNeel Natu }
626