]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/userboot/userboot/main.c
Adjust ENA driver files to latest ena-com changes
[FreeBSD/FreeBSD.git] / stand / userboot / userboot / main.c
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$");
30
31 #include <stand.h>
32 #include <string.h>
33 #include <setjmp.h>
34 #include <sys/disk.h>
35 #include <sys/zfs_bootenv.h>
36
37 #include "bootstrap.h"
38 #include "disk.h"
39 #include "libuserboot.h"
40
41 #if defined(USERBOOT_ZFS_SUPPORT)
42 #include "libzfs.h"
43
44 static void userboot_zfs_probe(void);
45 static int userboot_zfs_found;
46 #endif
47
48 /* Minimum version required */
49 #define USERBOOT_VERSION        USERBOOT_VERSION_3
50
51 #define LOADER_PATH             "/boot/loader"
52 #define INTERP_MARKER           "$Interpreter:"
53
54 #define MALLOCSZ                (64*1024*1024)
55
56 struct loader_callbacks *callbacks;
57 void *callbacks_arg;
58
59 static jmp_buf jb;
60
61 struct arch_switch archsw;      /* MI/MD interface boundary */
62
63 static void     extract_currdev(void);
64 static void     check_interpreter(void);
65
66 void
67 delay(int usec)
68 {
69
70         CALLBACK(delay, usec);
71 }
72
73 void
74 exit(int v)
75 {
76
77         CALLBACK(exit, v);
78         longjmp(jb, 1);
79 }
80
81 static void
82 check_interpreter(void)
83 {
84         struct stat st;
85         size_t marklen, rdsize;
86         const char *guest_interp, *my_interp;
87         char *buf;
88         int fd;
89
90         /*
91          * If we can't stat(2) or open(2) LOADER_PATH, then we'll fail by
92          * simply letting us roll on with whatever interpreter we were compiled
93          * with.  This is likely not going to be an issue in reality.
94          */
95         buf =  NULL;
96         if (stat(LOADER_PATH, &st) != 0)
97                 return;
98         if ((fd = open(LOADER_PATH, O_RDONLY)) < 0)
99                 return;
100
101         rdsize = st.st_size;
102         buf = malloc(rdsize);
103         if (buf == NULL)
104                 goto out;
105         if (read(fd, buf, rdsize) < rdsize)
106                 goto out;
107
108         marklen = strlen(INTERP_MARKER);
109         my_interp = bootprog_interp + marklen;
110
111         /*
112          * Here we make the assumption that a loader binary without the
113          * interpreter marker is a 4th one.  All loader binaries going forward
114          * should have this properly specified, so our assumption should always
115          * be a good one.
116          */
117         if ((guest_interp = memmem(buf, rdsize, INTERP_MARKER,
118             marklen)) != NULL)
119                 guest_interp += marklen;
120         else
121                 guest_interp = "4th";
122
123         /*
124          * The guest interpreter may not have a version of loader that
125          * specifies the interpreter installed.  If that's the case, we'll
126          * assume it's legacy (4th) and request a swap to that if we're
127          * a Lua-userboot.
128          */
129         if (strcmp(my_interp, guest_interp) != 0)
130                 CALLBACK(swap_interpreter, guest_interp);
131 out:
132         free(buf);
133         close(fd);
134         return;
135 }
136
137 void
138 loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
139 {
140         static char mallocbuf[MALLOCSZ];
141         char *var;
142         int i;
143
144         if (version < USERBOOT_VERSION)
145                 abort();
146
147         callbacks = cb;
148         callbacks_arg = arg;
149         userboot_disk_maxunit = ndisks;
150
151         /*
152          * initialise the heap as early as possible.  Once this is done,
153          * alloc() is usable.
154          */
155         setheap((void *)mallocbuf, (void *)(mallocbuf + sizeof(mallocbuf)));
156
157         /*
158          * Hook up the console
159          */
160         cons_probe();
161
162         printf("\n%s", bootprog_info);
163 #if 0
164         printf("Memory: %ld k\n", memsize() / 1024);
165 #endif
166
167         setenv("LINES", "24", 1);       /* optional */
168
169         /*
170          * Set custom environment variables
171          */
172         i = 0;
173         while (1) {
174                 var = CALLBACK(getenv, i++);
175                 if (var == NULL)
176                         break;
177                 putenv(var);
178         }
179
180         archsw.arch_autoload = userboot_autoload;
181         archsw.arch_getdev = userboot_getdev;
182         archsw.arch_copyin = userboot_copyin;
183         archsw.arch_copyout = userboot_copyout;
184         archsw.arch_readin = userboot_readin;
185 #if defined(USERBOOT_ZFS_SUPPORT)
186         archsw.arch_zfs_probe = userboot_zfs_probe;
187 #endif
188
189         /*
190          * Initialise the block cache. Set the upper limit.
191          */
192         bcache_init(32768, 512);
193         /*
194          * March through the device switch probing for things.
195          */
196         for (i = 0; devsw[i] != NULL; i++)
197                 if (devsw[i]->dv_init != NULL)
198                         (devsw[i]->dv_init)();
199
200         extract_currdev();
201
202         /*
203          * Checking the interpreter isn't worth the overhead unless we
204          * actually have the swap_interpreter callback, so we actually version
205          * check here rather than later on.
206          */
207         if (version >= USERBOOT_VERSION_5)
208                 check_interpreter();
209
210         if (setjmp(jb))
211                 return;
212
213         interact();                     /* doesn't return */
214
215         exit(0);
216 }
217
218 static void
219 set_currdev(const char *devname)
220 {
221
222         env_setenv("currdev", EV_VOLATILE, devname,
223             userboot_setcurrdev, env_nounset);
224         env_setenv("loaddev", EV_VOLATILE, devname,
225             env_noset, env_nounset);
226 }
227
228 /*
229  * Set the 'current device' by (if possible) recovering the boot device as 
230  * supplied by the initial bootstrap.
231  */
232 static void
233 extract_currdev(void)
234 {
235         struct disk_devdesc dev;
236         struct devdesc *dd;
237 #if defined(USERBOOT_ZFS_SUPPORT)
238         struct zfs_devdesc zdev;
239         char *buf = NULL;
240
241         if (userboot_zfs_found) {
242         
243                 /* Leave the pool/root guid's unassigned */
244                 bzero(&zdev, sizeof(zdev));
245                 zdev.dd.d_dev = &zfs_dev;
246                 
247                 init_zfs_boot_options(zfs_fmtdev(&zdev));
248                 dd = &zdev.dd;
249         } else
250 #endif
251
252         if (userboot_disk_maxunit > 0) {
253                 dev.dd.d_dev = &userboot_disk;
254                 dev.dd.d_unit = 0;
255                 dev.d_slice = D_SLICEWILD;
256                 dev.d_partition = D_PARTWILD;
257                 /*
258                  * If we cannot auto-detect the partition type then
259                  * access the disk as a raw device.
260                  */
261                 if (dev.dd.d_dev->dv_open(NULL, &dev)) {
262                         dev.d_slice = D_SLICENONE;
263                         dev.d_partition = D_PARTNONE;
264                 }
265                 dd = &dev.dd;
266         } else {
267                 dev.dd.d_dev = &host_dev;
268                 dev.dd.d_unit = 0;
269                 dd = &dev.dd;
270         }
271
272         set_currdev(userboot_fmtdev(dd));
273
274 #if defined(USERBOOT_ZFS_SUPPORT)
275         if (userboot_zfs_found) {
276                 buf = malloc(VDEV_PAD_SIZE);
277                 if (buf != NULL) {
278                         if (zfs_get_bootonce(&zdev, OS_BOOTONCE, buf,
279                             VDEV_PAD_SIZE) == 0) {
280                                 printf("zfs bootonce: %s\n", buf);
281                                 set_currdev(buf);
282                                 setenv("zfs-bootonce", buf, 1);
283                         }
284                         free(buf);
285                         (void) zfs_attach_nvstore(&zdev);
286                 }
287         }
288 #endif
289 }
290
291 #if defined(USERBOOT_ZFS_SUPPORT)
292 static void
293 userboot_zfs_probe(void)
294 {
295         char devname[32];
296         uint64_t pool_guid;
297         int unit;
298
299         /*
300          * Open all the disks we can find and see if we can reconstruct
301          * ZFS pools from them. Record if any were found.
302          */
303         for (unit = 0; unit < userboot_disk_maxunit; unit++) {
304                 sprintf(devname, "disk%d:", unit);
305                 pool_guid = 0;
306                 zfs_probe_dev(devname, &pool_guid);
307                 if (pool_guid != 0)
308                         userboot_zfs_found = 1;
309         }
310 }
311 #endif
312
313 COMMAND_SET(quit, "quit", "exit the loader", command_quit);
314
315 static int
316 command_quit(int argc, char *argv[])
317 {
318
319         exit(USERBOOT_EXIT_QUIT);
320         return (CMD_OK);
321 }
322
323 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
324
325 static int
326 command_reboot(int argc, char *argv[])
327 {
328
329         exit(USERBOOT_EXIT_REBOOT);
330         return (CMD_OK);
331 }