xref: /illumos-gate/usr/src/boot/userboot/test/test.c (revision 10a869258e300c530ae56b29aa3bf43461ca98ff)
1*10a86925SToomas Soome /*
2*10a86925SToomas Soome  * Copyright (c) 2011 Google, Inc.
3*10a86925SToomas Soome  * All rights reserved.
4*10a86925SToomas Soome  *
5*10a86925SToomas Soome  * Redistribution and use in source and binary forms, with or without
6*10a86925SToomas Soome  * modification, are permitted provided that the following conditions
7*10a86925SToomas Soome  * are met:
8*10a86925SToomas Soome  * 1. Redistributions of source code must retain the above copyright
9*10a86925SToomas Soome  *    notice, this list of conditions and the following disclaimer.
10*10a86925SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11*10a86925SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12*10a86925SToomas Soome  *    documentation and/or other materials provided with the distribution.
13*10a86925SToomas Soome  *
14*10a86925SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*10a86925SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*10a86925SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*10a86925SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*10a86925SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*10a86925SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*10a86925SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*10a86925SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*10a86925SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*10a86925SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*10a86925SToomas Soome  * SUCH DAMAGE.
25*10a86925SToomas Soome  */
26*10a86925SToomas Soome 
27*10a86925SToomas Soome #include <sys/types.h>
28*10a86925SToomas Soome #include <sys/disk.h>
29*10a86925SToomas Soome #include <sys/ioctl.h>
30*10a86925SToomas Soome #include <sys/stat.h>
31*10a86925SToomas Soome #include <sys/filio.h>
32*10a86925SToomas Soome #include <dirent.h>
33*10a86925SToomas Soome #include <dlfcn.h>
34*10a86925SToomas Soome #include <err.h>
35*10a86925SToomas Soome #include <errno.h>
36*10a86925SToomas Soome #include <fcntl.h>
37*10a86925SToomas Soome #include <getopt.h>
38*10a86925SToomas Soome #include <inttypes.h>
39*10a86925SToomas Soome #include <limits.h>
40*10a86925SToomas Soome #include <stdio.h>
41*10a86925SToomas Soome #include <stdlib.h>
42*10a86925SToomas Soome #include <string.h>
43*10a86925SToomas Soome #include <termios.h>
44*10a86925SToomas Soome #include <unistd.h>
45*10a86925SToomas Soome 
46*10a86925SToomas Soome #include <userboot.h>
47*10a86925SToomas Soome 
48*10a86925SToomas Soome int *zfs_debug;
49*10a86925SToomas Soome 
50*10a86925SToomas Soome static int script;
51*10a86925SToomas Soome static char *host_base;
52*10a86925SToomas Soome static struct termios term, oldterm;
53*10a86925SToomas Soome static char *image;
54*10a86925SToomas Soome static size_t image_size;
55*10a86925SToomas Soome 
56*10a86925SToomas Soome uint64_t regs[16];
57*10a86925SToomas Soome uint64_t pc;
58*10a86925SToomas Soome int *disk_fd;
59*10a86925SToomas Soome int disk_index = -1;
60*10a86925SToomas Soome 
61*10a86925SToomas Soome void test_exit(void *arg, int v);
62*10a86925SToomas Soome 
63*10a86925SToomas Soome const char *
64*10a86925SToomas Soome _umem_debug_init(void)
65*10a86925SToomas Soome {
66*10a86925SToomas Soome 	return ("default,verbose"); /* $UMEM_DEBUG setting */
67*10a86925SToomas Soome }
68*10a86925SToomas Soome 
69*10a86925SToomas Soome const char *
70*10a86925SToomas Soome _umem_logging_init(void)
71*10a86925SToomas Soome {
72*10a86925SToomas Soome 	return ("fail,contents"); /* $UMEM_LOGGING setting */
73*10a86925SToomas Soome }
74*10a86925SToomas Soome 
75*10a86925SToomas Soome /*
76*10a86925SToomas Soome  * Console i/o
77*10a86925SToomas Soome  */
78*10a86925SToomas Soome 
79*10a86925SToomas Soome void
80*10a86925SToomas Soome test_putc(void *arg, int ch)
81*10a86925SToomas Soome {
82*10a86925SToomas Soome 	char c = ch;
83*10a86925SToomas Soome 
84*10a86925SToomas Soome 	(void) write(1, &c, 1);
85*10a86925SToomas Soome }
86*10a86925SToomas Soome 
87*10a86925SToomas Soome int
88*10a86925SToomas Soome test_getc(void *arg)
89*10a86925SToomas Soome {
90*10a86925SToomas Soome 	char c;
91*10a86925SToomas Soome 
92*10a86925SToomas Soome 	if (read(script, &c, 1) == 1) {
93*10a86925SToomas Soome 		if (c == '\n')
94*10a86925SToomas Soome 			c = '\r';
95*10a86925SToomas Soome 		return (c);
96*10a86925SToomas Soome 	}
97*10a86925SToomas Soome 	return (-1);
98*10a86925SToomas Soome }
99*10a86925SToomas Soome 
100*10a86925SToomas Soome int
101*10a86925SToomas Soome test_poll(void *arg)
102*10a86925SToomas Soome {
103*10a86925SToomas Soome 	int n;
104*10a86925SToomas Soome 
105*10a86925SToomas Soome 	if (ioctl(script, FIONREAD, &n) >= 0)
106*10a86925SToomas Soome 		return (n > 0);
107*10a86925SToomas Soome 	return (0);
108*10a86925SToomas Soome }
109*10a86925SToomas Soome 
110*10a86925SToomas Soome /*
111*10a86925SToomas Soome  * Host filesystem i/o
112*10a86925SToomas Soome  */
113*10a86925SToomas Soome 
114*10a86925SToomas Soome struct test_file {
115*10a86925SToomas Soome 	char *tf_name;
116*10a86925SToomas Soome 	int tf_isdir;
117*10a86925SToomas Soome 	size_t tf_size;
118*10a86925SToomas Soome 	struct stat tf_stat;
119*10a86925SToomas Soome 	union {
120*10a86925SToomas Soome 		int fd;
121*10a86925SToomas Soome 		DIR *dir;
122*10a86925SToomas Soome 	} tf_u;
123*10a86925SToomas Soome };
124*10a86925SToomas Soome 
125*10a86925SToomas Soome int
126*10a86925SToomas Soome test_open(void *arg, const char *filename, void **h_return)
127*10a86925SToomas Soome {
128*10a86925SToomas Soome 	struct test_file *tf;
129*10a86925SToomas Soome 	char path[PATH_MAX];
130*10a86925SToomas Soome 
131*10a86925SToomas Soome 	if (!host_base)
132*10a86925SToomas Soome 		return (ENOENT);
133*10a86925SToomas Soome 
134*10a86925SToomas Soome 	(void) strlcpy(path, host_base, PATH_MAX);
135*10a86925SToomas Soome 	if (path[strlen(path) - 1] == '/')
136*10a86925SToomas Soome 		path[strlen(path) - 1] = 0;
137*10a86925SToomas Soome 	(void) strlcat(path, filename, PATH_MAX);
138*10a86925SToomas Soome 	tf = malloc(sizeof (struct test_file));
139*10a86925SToomas Soome 	if (stat(path, &tf->tf_stat) < 0) {
140*10a86925SToomas Soome 		free(tf);
141*10a86925SToomas Soome 		return (errno);
142*10a86925SToomas Soome 	}
143*10a86925SToomas Soome 
144*10a86925SToomas Soome 	tf->tf_name = strdup(path);
145*10a86925SToomas Soome 	tf->tf_size = tf->tf_stat.st_size;
146*10a86925SToomas Soome 	if (S_ISDIR(tf->tf_stat.st_mode)) {
147*10a86925SToomas Soome 		tf->tf_isdir = 1;
148*10a86925SToomas Soome 		tf->tf_u.dir = opendir(path);
149*10a86925SToomas Soome 		if (!tf->tf_u.dir)
150*10a86925SToomas Soome 			goto out;
151*10a86925SToomas Soome 		*h_return = tf;
152*10a86925SToomas Soome 		return (0);
153*10a86925SToomas Soome 	}
154*10a86925SToomas Soome 	if (S_ISREG(tf->tf_stat.st_mode)) {
155*10a86925SToomas Soome 		tf->tf_isdir = 0;
156*10a86925SToomas Soome 		tf->tf_u.fd = open(path, O_RDONLY);
157*10a86925SToomas Soome 		if (tf->tf_u.fd < 0)
158*10a86925SToomas Soome 			goto out;
159*10a86925SToomas Soome 		*h_return = tf;
160*10a86925SToomas Soome 		return (0);
161*10a86925SToomas Soome 	}
162*10a86925SToomas Soome 
163*10a86925SToomas Soome out:
164*10a86925SToomas Soome 	free(tf);
165*10a86925SToomas Soome 	return (EINVAL);
166*10a86925SToomas Soome }
167*10a86925SToomas Soome 
168*10a86925SToomas Soome int
169*10a86925SToomas Soome test_close(void *arg, void *h)
170*10a86925SToomas Soome {
171*10a86925SToomas Soome 	struct test_file *tf = h;
172*10a86925SToomas Soome 
173*10a86925SToomas Soome 	if (tf->tf_isdir)
174*10a86925SToomas Soome 		(void) closedir(tf->tf_u.dir);
175*10a86925SToomas Soome 	else
176*10a86925SToomas Soome 		(void) close(tf->tf_u.fd);
177*10a86925SToomas Soome 	free(tf->tf_name);
178*10a86925SToomas Soome 	free(tf);
179*10a86925SToomas Soome 
180*10a86925SToomas Soome 	return (0);
181*10a86925SToomas Soome }
182*10a86925SToomas Soome 
183*10a86925SToomas Soome int
184*10a86925SToomas Soome test_isdir(void *arg, void *h)
185*10a86925SToomas Soome {
186*10a86925SToomas Soome 	struct test_file *tf = h;
187*10a86925SToomas Soome 
188*10a86925SToomas Soome 	return (tf->tf_isdir);
189*10a86925SToomas Soome }
190*10a86925SToomas Soome 
191*10a86925SToomas Soome int
192*10a86925SToomas Soome test_read(void *arg, void *h, void *dst, size_t size, size_t *resid_return)
193*10a86925SToomas Soome {
194*10a86925SToomas Soome 	struct test_file *tf = h;
195*10a86925SToomas Soome 	ssize_t sz;
196*10a86925SToomas Soome 
197*10a86925SToomas Soome 	if (tf->tf_isdir)
198*10a86925SToomas Soome 		return (EINVAL);
199*10a86925SToomas Soome 	sz = read(tf->tf_u.fd, dst, size);
200*10a86925SToomas Soome 	if (sz < 0)
201*10a86925SToomas Soome 		return (EINVAL);
202*10a86925SToomas Soome 	*resid_return = size - sz;
203*10a86925SToomas Soome 	return (0);
204*10a86925SToomas Soome }
205*10a86925SToomas Soome 
206*10a86925SToomas Soome int
207*10a86925SToomas Soome test_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return,
208*10a86925SToomas Soome     size_t *namelen_return, char *name)
209*10a86925SToomas Soome {
210*10a86925SToomas Soome 	struct test_file *tf = h;
211*10a86925SToomas Soome 	struct dirent *dp;
212*10a86925SToomas Soome 	struct stat st;
213*10a86925SToomas Soome 	char path[PATH_MAX];
214*10a86925SToomas Soome 
215*10a86925SToomas Soome 	if (!tf->tf_isdir)
216*10a86925SToomas Soome 		return (EINVAL);
217*10a86925SToomas Soome 
218*10a86925SToomas Soome 	dp = readdir(tf->tf_u.dir);
219*10a86925SToomas Soome 	if (!dp)
220*10a86925SToomas Soome 		return (ENOENT);
221*10a86925SToomas Soome 	(void) snprintf(path, sizeof (path), "%s/%s/%s", host_base, tf->tf_name,
222*10a86925SToomas Soome 	    dp->d_name);
223*10a86925SToomas Soome 	if (lstat(path, &st) < 0) {
224*10a86925SToomas Soome 		return (errno);
225*10a86925SToomas Soome 	} else {
226*10a86925SToomas Soome 		*type_return = (st.st_mode & S_IFMT) >> 12;
227*10a86925SToomas Soome 	}
228*10a86925SToomas Soome 
229*10a86925SToomas Soome 	/*
230*10a86925SToomas Soome 	 * Note: d_namlen is in the range 0..255 and therefore less
231*10a86925SToomas Soome 	 * than PATH_MAX so we don't need to test before copying.
232*10a86925SToomas Soome 	 */
233*10a86925SToomas Soome 	*fileno_return = dp->d_ino;
234*10a86925SToomas Soome 	*namelen_return = strlen(dp->d_name);
235*10a86925SToomas Soome 	(void) strcpy(name, dp->d_name);
236*10a86925SToomas Soome 
237*10a86925SToomas Soome 	return (0);
238*10a86925SToomas Soome }
239*10a86925SToomas Soome 
240*10a86925SToomas Soome int
241*10a86925SToomas Soome test_seek(void *arg, void *h, uint64_t offset, int whence)
242*10a86925SToomas Soome {
243*10a86925SToomas Soome 	struct test_file *tf = h;
244*10a86925SToomas Soome 
245*10a86925SToomas Soome 	if (tf->tf_isdir)
246*10a86925SToomas Soome 		return (EINVAL);
247*10a86925SToomas Soome 	if (lseek(tf->tf_u.fd, offset, whence) < 0)
248*10a86925SToomas Soome 		return (errno);
249*10a86925SToomas Soome 	return (0);
250*10a86925SToomas Soome }
251*10a86925SToomas Soome 
252*10a86925SToomas Soome int
253*10a86925SToomas Soome test_stat(void *arg, void *h, int *mode_return, int *uid_return,
254*10a86925SToomas Soome     int *gid_return, uint64_t *size_return)
255*10a86925SToomas Soome {
256*10a86925SToomas Soome 	struct test_file *tf = h;
257*10a86925SToomas Soome 
258*10a86925SToomas Soome 	*mode_return = tf->tf_stat.st_mode;
259*10a86925SToomas Soome 	*uid_return = tf->tf_stat.st_uid;
260*10a86925SToomas Soome 	*gid_return = tf->tf_stat.st_gid;
261*10a86925SToomas Soome 	*size_return = tf->tf_stat.st_size;
262*10a86925SToomas Soome 	return (0);
263*10a86925SToomas Soome }
264*10a86925SToomas Soome 
265*10a86925SToomas Soome /*
266*10a86925SToomas Soome  * Disk image i/o
267*10a86925SToomas Soome  */
268*10a86925SToomas Soome 
269*10a86925SToomas Soome int
270*10a86925SToomas Soome test_diskwrite(void *arg, int unit, uint64_t offset, void *src, size_t size,
271*10a86925SToomas Soome     size_t *resid_return)
272*10a86925SToomas Soome {
273*10a86925SToomas Soome 	ssize_t n;
274*10a86925SToomas Soome 
275*10a86925SToomas Soome 	if (unit > disk_index || disk_fd[unit] == -1)
276*10a86925SToomas Soome 		return (EIO);
277*10a86925SToomas Soome 	n = pwrite(disk_fd[unit], src, size, offset);
278*10a86925SToomas Soome 	if (n < 0)
279*10a86925SToomas Soome 		return (errno);
280*10a86925SToomas Soome 	*resid_return = size - n;
281*10a86925SToomas Soome 	return (0);
282*10a86925SToomas Soome }
283*10a86925SToomas Soome 
284*10a86925SToomas Soome int
285*10a86925SToomas Soome test_diskread(void *arg, int unit, uint64_t offset, void *dst, size_t size,
286*10a86925SToomas Soome     size_t *resid_return)
287*10a86925SToomas Soome {
288*10a86925SToomas Soome 	ssize_t n;
289*10a86925SToomas Soome 
290*10a86925SToomas Soome 	if (unit > disk_index || disk_fd[unit] == -1)
291*10a86925SToomas Soome 		return (EIO);
292*10a86925SToomas Soome 	n = pread(disk_fd[unit], dst, size, offset);
293*10a86925SToomas Soome 	if (n == 0) {
294*10a86925SToomas Soome 		printf("%s: end of disk (%ju)\n", __func__, (intmax_t)offset);
295*10a86925SToomas Soome 		return (EIO);
296*10a86925SToomas Soome 	}
297*10a86925SToomas Soome 
298*10a86925SToomas Soome 	if (n < 0)
299*10a86925SToomas Soome 		return (errno);
300*10a86925SToomas Soome 	*resid_return = size - n;
301*10a86925SToomas Soome 	return (0);
302*10a86925SToomas Soome }
303*10a86925SToomas Soome 
304*10a86925SToomas Soome int
305*10a86925SToomas Soome test_diskioctl(void *arg, int unit, ulong_t cmd, void *data)
306*10a86925SToomas Soome {
307*10a86925SToomas Soome 	struct stat sb;
308*10a86925SToomas Soome 
309*10a86925SToomas Soome 	if (unit > disk_index || disk_fd[unit] == -1)
310*10a86925SToomas Soome 		return (EBADF);
311*10a86925SToomas Soome 	switch (cmd) {
312*10a86925SToomas Soome 	case DIOCGSECTORSIZE:
313*10a86925SToomas Soome 		*(uint_t *)data = 512;
314*10a86925SToomas Soome 		break;
315*10a86925SToomas Soome 	case DIOCGMEDIASIZE:
316*10a86925SToomas Soome 		if (fstat(disk_fd[unit], &sb) == 0)
317*10a86925SToomas Soome 			*(off_t *)data = sb.st_size;
318*10a86925SToomas Soome 		else
319*10a86925SToomas Soome 			return (ENOTTY);
320*10a86925SToomas Soome 		break;
321*10a86925SToomas Soome 	default:
322*10a86925SToomas Soome 		return (ENOTTY);
323*10a86925SToomas Soome 	}
324*10a86925SToomas Soome 	return (0);
325*10a86925SToomas Soome }
326*10a86925SToomas Soome 
327*10a86925SToomas Soome /*
328*10a86925SToomas Soome  * Guest virtual machine i/o
329*10a86925SToomas Soome  *
330*10a86925SToomas Soome  * Note: guest addresses are kernel virtual
331*10a86925SToomas Soome  */
332*10a86925SToomas Soome 
333*10a86925SToomas Soome int
334*10a86925SToomas Soome test_copyin(void *arg, const void *from, uint64_t to, size_t size)
335*10a86925SToomas Soome {
336*10a86925SToomas Soome 
337*10a86925SToomas Soome 	to &= 0x7fffffff;
338*10a86925SToomas Soome 	if (to > image_size)
339*10a86925SToomas Soome 		return (EFAULT);
340*10a86925SToomas Soome 	if (to + size > image_size)
341*10a86925SToomas Soome 		size = image_size - to;
342*10a86925SToomas Soome 	memcpy(&image[to], from, size);
343*10a86925SToomas Soome 	return (0);
344*10a86925SToomas Soome }
345*10a86925SToomas Soome 
346*10a86925SToomas Soome int
347*10a86925SToomas Soome test_copyout(void *arg, uint64_t from, void *to, size_t size)
348*10a86925SToomas Soome {
349*10a86925SToomas Soome 
350*10a86925SToomas Soome 	from &= 0x7fffffff;
351*10a86925SToomas Soome 	if (from > image_size)
352*10a86925SToomas Soome 		return (EFAULT);
353*10a86925SToomas Soome 	if (from + size > image_size)
354*10a86925SToomas Soome 		size = image_size - from;
355*10a86925SToomas Soome 	memcpy(to, &image[from], size);
356*10a86925SToomas Soome 	return (0);
357*10a86925SToomas Soome }
358*10a86925SToomas Soome 
359*10a86925SToomas Soome void
360*10a86925SToomas Soome test_setreg(void *arg, int r, uint64_t v)
361*10a86925SToomas Soome {
362*10a86925SToomas Soome 
363*10a86925SToomas Soome 	if (r < 0 || r >= 16)
364*10a86925SToomas Soome 		return;
365*10a86925SToomas Soome 	regs[r] = v;
366*10a86925SToomas Soome }
367*10a86925SToomas Soome 
368*10a86925SToomas Soome void
369*10a86925SToomas Soome test_setmsr(void *arg, int r, uint64_t v)
370*10a86925SToomas Soome {
371*10a86925SToomas Soome }
372*10a86925SToomas Soome 
373*10a86925SToomas Soome void
374*10a86925SToomas Soome test_setcr(void *arg, int r, uint64_t v)
375*10a86925SToomas Soome {
376*10a86925SToomas Soome }
377*10a86925SToomas Soome 
378*10a86925SToomas Soome void
379*10a86925SToomas Soome test_setgdt(void *arg, uint64_t v, size_t sz)
380*10a86925SToomas Soome {
381*10a86925SToomas Soome }
382*10a86925SToomas Soome 
383*10a86925SToomas Soome void
384*10a86925SToomas Soome test_exec(void *arg, uint64_t pc)
385*10a86925SToomas Soome {
386*10a86925SToomas Soome 	printf("Execute at 0x%"PRIx64"\n\r", pc);
387*10a86925SToomas Soome 	test_exit(arg, 0);
388*10a86925SToomas Soome }
389*10a86925SToomas Soome 
390*10a86925SToomas Soome /*
391*10a86925SToomas Soome  * Misc
392*10a86925SToomas Soome  */
393*10a86925SToomas Soome 
394*10a86925SToomas Soome void
395*10a86925SToomas Soome test_delay(void *arg, int usec)
396*10a86925SToomas Soome {
397*10a86925SToomas Soome 
398*10a86925SToomas Soome 	(void) usleep(usec);
399*10a86925SToomas Soome }
400*10a86925SToomas Soome 
401*10a86925SToomas Soome void
402*10a86925SToomas Soome test_exit(void *arg, int v)
403*10a86925SToomas Soome {
404*10a86925SToomas Soome 
405*10a86925SToomas Soome 	(void) tcsetattr(0, TCSAFLUSH, &oldterm);
406*10a86925SToomas Soome 	exit(v);
407*10a86925SToomas Soome }
408*10a86925SToomas Soome 
409*10a86925SToomas Soome void
410*10a86925SToomas Soome test_getmem(void *arg, uint64_t *lowmem, uint64_t *highmem)
411*10a86925SToomas Soome {
412*10a86925SToomas Soome 
413*10a86925SToomas Soome 	*lowmem = 128*1024*1024;
414*10a86925SToomas Soome 	*highmem = 0;
415*10a86925SToomas Soome }
416*10a86925SToomas Soome 
417*10a86925SToomas Soome char *
418*10a86925SToomas Soome test_getenv(void *arg, int idx)
419*10a86925SToomas Soome {
420*10a86925SToomas Soome 	extern char **environ;
421*10a86925SToomas Soome 
422*10a86925SToomas Soome 	return (environ[idx]);
423*10a86925SToomas Soome }
424*10a86925SToomas Soome 
425*10a86925SToomas Soome struct loader_callbacks cb = {
426*10a86925SToomas Soome 	.putc = test_putc,
427*10a86925SToomas Soome 	.getc = test_getc,
428*10a86925SToomas Soome 	.poll = test_poll,
429*10a86925SToomas Soome 
430*10a86925SToomas Soome 	.open = test_open,
431*10a86925SToomas Soome 	.close = test_close,
432*10a86925SToomas Soome 	.isdir = test_isdir,
433*10a86925SToomas Soome 	.read = test_read,
434*10a86925SToomas Soome 	.readdir = test_readdir,
435*10a86925SToomas Soome 	.seek = test_seek,
436*10a86925SToomas Soome 	.stat = test_stat,
437*10a86925SToomas Soome 
438*10a86925SToomas Soome 	.diskread = test_diskread,
439*10a86925SToomas Soome 	.diskwrite = test_diskwrite,
440*10a86925SToomas Soome 	.diskioctl = test_diskioctl,
441*10a86925SToomas Soome 
442*10a86925SToomas Soome 	.copyin = test_copyin,
443*10a86925SToomas Soome 	.copyout = test_copyout,
444*10a86925SToomas Soome 	.setreg = test_setreg,
445*10a86925SToomas Soome 	.setmsr = test_setmsr,
446*10a86925SToomas Soome 	.setcr = test_setcr,
447*10a86925SToomas Soome 	.setgdt = test_setgdt,
448*10a86925SToomas Soome 	.exec = test_exec,
449*10a86925SToomas Soome 
450*10a86925SToomas Soome 	.delay = test_delay,
451*10a86925SToomas Soome 	.exit = test_exit,
452*10a86925SToomas Soome 	.getmem = test_getmem,
453*10a86925SToomas Soome 
454*10a86925SToomas Soome 	.getenv = test_getenv,
455*10a86925SToomas Soome };
456*10a86925SToomas Soome 
457*10a86925SToomas Soome void
458*10a86925SToomas Soome usage(void)
459*10a86925SToomas Soome {
460*10a86925SToomas Soome 
461*10a86925SToomas Soome 	printf("usage: [-b <userboot shared object>] [-d <disk image path>] "
462*10a86925SToomas Soome 	    "[-h <host filesystem path>\n");
463*10a86925SToomas Soome 	exit(1);
464*10a86925SToomas Soome }
465*10a86925SToomas Soome 
466*10a86925SToomas Soome int
467*10a86925SToomas Soome main(int argc, char **argv)
468*10a86925SToomas Soome {
469*10a86925SToomas Soome 	void *h;
470*10a86925SToomas Soome 	void (*func)(struct loader_callbacks *, void *, int, int) __NORETURN;
471*10a86925SToomas Soome 	int opt;
472*10a86925SToomas Soome 	const char *userboot_obj = "/boot/userboot.so";
473*10a86925SToomas Soome 	struct winsize ws;
474*10a86925SToomas Soome 	int cols = 80, rows = 24, z = 0;
475*10a86925SToomas Soome 	int oflag = O_RDONLY;
476*10a86925SToomas Soome 	char *buffer = NULL;
477*10a86925SToomas Soome 
478*10a86925SToomas Soome 	if (ioctl(1, TIOCGWINSZ, &ws) != -1) {
479*10a86925SToomas Soome 		if (ws.ws_col)
480*10a86925SToomas Soome 			cols = ws.ws_col;
481*10a86925SToomas Soome 		if (ws.ws_row)
482*10a86925SToomas Soome 			rows = ws.ws_row;
483*10a86925SToomas Soome 	}
484*10a86925SToomas Soome 
485*10a86925SToomas Soome 	(void) clearenv();
486*10a86925SToomas Soome 	if (asprintf(&buffer, "%d", cols) > 0)
487*10a86925SToomas Soome 		(void) setenv("screen-#cols", buffer, 1);
488*10a86925SToomas Soome 	free(buffer);
489*10a86925SToomas Soome 	if (asprintf(&buffer, "%d", rows) > 0)
490*10a86925SToomas Soome 		(void) setenv("screen-#rows", buffer, 1);
491*10a86925SToomas Soome 	free(buffer);
492*10a86925SToomas Soome 	(void) setenv("ISADIR", "amd64", 1);
493*10a86925SToomas Soome 
494*10a86925SToomas Soome 	while ((opt = getopt(argc, argv, "b:d:h:s:wz")) != -1) {
495*10a86925SToomas Soome 		switch (opt) {
496*10a86925SToomas Soome 		case 'b':
497*10a86925SToomas Soome 			userboot_obj = optarg;
498*10a86925SToomas Soome 			break;
499*10a86925SToomas Soome 
500*10a86925SToomas Soome 		case 'd':
501*10a86925SToomas Soome 			disk_index++;
502*10a86925SToomas Soome 			disk_fd = reallocarray(disk_fd, disk_index + 1,
503*10a86925SToomas Soome 			    sizeof (int));
504*10a86925SToomas Soome 			disk_fd[disk_index] = open(optarg, oflag);
505*10a86925SToomas Soome 			if (disk_fd[disk_index] < 0)
506*10a86925SToomas Soome 				err(1, "Can't open disk image '%s'", optarg);
507*10a86925SToomas Soome 			break;
508*10a86925SToomas Soome 
509*10a86925SToomas Soome 		case 'h':
510*10a86925SToomas Soome 			host_base = optarg;
511*10a86925SToomas Soome 			break;
512*10a86925SToomas Soome 
513*10a86925SToomas Soome 		case 's':
514*10a86925SToomas Soome 			if (strcmp(optarg, "-") == 0)
515*10a86925SToomas Soome 				script = 0;
516*10a86925SToomas Soome 			else
517*10a86925SToomas Soome 				script = open(optarg, O_RDONLY);
518*10a86925SToomas Soome 
519*10a86925SToomas Soome 			if (script < 0)
520*10a86925SToomas Soome 				err(1, "Can't open script file '%s'", optarg);
521*10a86925SToomas Soome 			break;
522*10a86925SToomas Soome 
523*10a86925SToomas Soome 		case 'w':
524*10a86925SToomas Soome 			oflag = O_RDWR;
525*10a86925SToomas Soome 			break;
526*10a86925SToomas Soome 
527*10a86925SToomas Soome 		case 'z':
528*10a86925SToomas Soome 			z = 1;
529*10a86925SToomas Soome 			break;
530*10a86925SToomas Soome 
531*10a86925SToomas Soome 		case '?':
532*10a86925SToomas Soome 			usage();
533*10a86925SToomas Soome 		}
534*10a86925SToomas Soome 	}
535*10a86925SToomas Soome 
536*10a86925SToomas Soome 	h = dlopen(userboot_obj, RTLD_LAZY | RTLD_LOCAL);
537*10a86925SToomas Soome 	if (!h) {
538*10a86925SToomas Soome 		printf("%s\n", dlerror());
539*10a86925SToomas Soome 		return (1);
540*10a86925SToomas Soome 	}
541*10a86925SToomas Soome 	func = dlsym(h, "loader_main");
542*10a86925SToomas Soome 	if (!func) {
543*10a86925SToomas Soome 		printf("%s\n", dlerror());
544*10a86925SToomas Soome 		return (1);
545*10a86925SToomas Soome 	}
546*10a86925SToomas Soome 	zfs_debug = dlsym(h, "zfs_debug");
547*10a86925SToomas Soome 	if (zfs_debug != NULL)
548*10a86925SToomas Soome 		*zfs_debug = z;
549*10a86925SToomas Soome 
550*10a86925SToomas Soome 	image_size = 128*1024*1024;
551*10a86925SToomas Soome 	image = malloc(image_size);
552*10a86925SToomas Soome 
553*10a86925SToomas Soome 	(void) tcgetattr(0, &term);
554*10a86925SToomas Soome 	oldterm = term;
555*10a86925SToomas Soome 	term.c_iflag &= ~(ICRNL | INPCK | ISTRIP);
556*10a86925SToomas Soome 	term.c_lflag &= ~(ICANON | ECHO | IEXTEN);
557*10a86925SToomas Soome 	term.c_cflag &= ~(CSIZE | PARENB);
558*10a86925SToomas Soome 	term.c_cflag |= CS8;
559*10a86925SToomas Soome 	term.c_oflag &= ~(OPOST);
560*10a86925SToomas Soome 	term.c_cc[VMIN] = 1;
561*10a86925SToomas Soome 	term.c_cc[VTIME] = 0;
562*10a86925SToomas Soome 	(void) tcsetattr(0, TCSADRAIN, &term);
563*10a86925SToomas Soome 
564*10a86925SToomas Soome 	func(&cb, NULL, USERBOOT_VERSION_3, disk_index + 1);
565*10a86925SToomas Soome }
566