main.c revision 332154
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: stable/11/stand/userboot/userboot/main.c 332154 2018-04-06 21:37:25Z kevans $");
30
31#include <stand.h>
32#include <string.h>
33#include <setjmp.h>
34#include <sys/disk.h>
35
36#include "bootstrap.h"
37#include "disk.h"
38#include "libuserboot.h"
39
40#if defined(USERBOOT_ZFS_SUPPORT)
41#include "../zfs/libzfs.h"
42
43static void userboot_zfs_probe(void);
44static int userboot_zfs_found;
45#endif
46
47/* Minimum version required */
48#define	USERBOOT_VERSION	USERBOOT_VERSION_3
49
50#define	MALLOCSZ		(64*1024*1024)
51
52struct loader_callbacks *callbacks;
53void *callbacks_arg;
54
55extern char bootprog_info[];
56static jmp_buf jb;
57
58struct arch_switch archsw;	/* MI/MD interface boundary */
59
60static void	extract_currdev(void);
61
62void
63delay(int usec)
64{
65
66	CALLBACK(delay, usec);
67}
68
69void
70exit(int v)
71{
72
73	CALLBACK(exit, v);
74	longjmp(jb, 1);
75}
76
77void
78loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
79{
80	static char mallocbuf[MALLOCSZ];
81	char *var;
82	int i;
83
84	if (version < USERBOOT_VERSION)
85		abort();
86
87	callbacks = cb;
88	callbacks_arg = arg;
89	userboot_disk_maxunit = ndisks;
90
91	/*
92	 * initialise the heap as early as possible.  Once this is done,
93	 * alloc() is usable.
94	 */
95	setheap((void *)mallocbuf, (void *)(mallocbuf + sizeof(mallocbuf)));
96
97	/*
98	 * Hook up the console
99	 */
100	cons_probe();
101
102	printf("\n%s", bootprog_info);
103#if 0
104	printf("Memory: %ld k\n", memsize() / 1024);
105#endif
106
107	setenv("LINES", "24", 1);	/* optional */
108
109	/*
110	 * Set custom environment variables
111	 */
112	i = 0;
113	while (1) {
114		var = CALLBACK(getenv, i++);
115		if (var == NULL)
116			break;
117		putenv(var);
118	}
119
120	archsw.arch_autoload = userboot_autoload;
121	archsw.arch_getdev = userboot_getdev;
122	archsw.arch_copyin = userboot_copyin;
123	archsw.arch_copyout = userboot_copyout;
124	archsw.arch_readin = userboot_readin;
125#if defined(USERBOOT_ZFS_SUPPORT)
126	archsw.arch_zfs_probe = userboot_zfs_probe;
127#endif
128
129	/*
130	 * Initialise the block cache. Set the upper limit.
131	 */
132	bcache_init(32768, 512);
133	/*
134	 * March through the device switch probing for things.
135	 */
136	for (i = 0; devsw[i] != NULL; i++)
137		if (devsw[i]->dv_init != NULL)
138			(devsw[i]->dv_init)();
139
140	extract_currdev();
141
142	if (setjmp(jb))
143		return;
144
145	interact();			/* doesn't return */
146
147	exit(0);
148}
149
150/*
151 * Set the 'current device' by (if possible) recovering the boot device as
152 * supplied by the initial bootstrap.
153 */
154static void
155extract_currdev(void)
156{
157	struct disk_devdesc dev;
158
159	//bzero(&dev, sizeof(dev));
160
161#if defined(USERBOOT_ZFS_SUPPORT)
162	CTASSERT(sizeof(struct disk_devdesc) >= sizeof(struct zfs_devdesc));
163	if (userboot_zfs_found) {
164		struct zfs_devdesc zdev;
165
166		/* Leave the pool/root guid's unassigned */
167		bzero(&zdev, sizeof(zdev));
168		zdev.dd.d_dev = &zfs_dev;
169
170		dev = *(struct disk_devdesc *)&zdev;
171		init_zfs_bootenv(zfs_fmtdev(&dev));
172	} else
173#endif
174
175	if (userboot_disk_maxunit > 0) {
176		dev.dd.d_dev = &userboot_disk;
177		dev.dd.d_unit = 0;
178		dev.d_slice = 0;
179		dev.d_partition = 0;
180		/*
181		 * If we cannot auto-detect the partition type then
182		 * access the disk as a raw device.
183		 */
184		if (dev.dd.d_dev->dv_open(NULL, &dev)) {
185			dev.d_slice = -1;
186			dev.d_partition = -1;
187		}
188	} else {
189		dev.dd.d_dev = &host_dev;
190		dev.dd.d_unit = 0;
191	}
192
193	env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(&dev),
194	    userboot_setcurrdev, env_nounset);
195	env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(&dev),
196	    env_noset, env_nounset);
197}
198
199#if defined(USERBOOT_ZFS_SUPPORT)
200static void
201userboot_zfs_probe(void)
202{
203	char devname[32];
204	uint64_t pool_guid;
205	int unit;
206
207	/*
208	 * Open all the disks we can find and see if we can reconstruct
209	 * ZFS pools from them. Record if any were found.
210	 */
211	for (unit = 0; unit < userboot_disk_maxunit; unit++) {
212		sprintf(devname, "disk%d:", unit);
213		pool_guid = 0;
214		zfs_probe_dev(devname, &pool_guid);
215		if (pool_guid != 0)
216			userboot_zfs_found = 1;
217	}
218}
219#endif
220
221COMMAND_SET(quit, "quit", "exit the loader", command_quit);
222
223static int
224command_quit(int argc, char *argv[])
225{
226
227	exit(USERBOOT_EXIT_QUIT);
228	return (CMD_OK);
229}
230
231COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
232
233static int
234command_reboot(int argc, char *argv[])
235{
236
237	exit(USERBOOT_EXIT_REBOOT);
238	return (CMD_OK);
239}
240