]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - sys/boot/i386/gptboot/gptboot.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / sys / boot / i386 / gptboot / gptboot.c
1 /*-
2  * Copyright (c) 1998 Robert Nordier
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are freely
6  * permitted provided that the above copyright notice and this
7  * paragraph and the following disclaimer are duplicated in all
8  * such forms.
9  *
10  * This software is provided "AS IS" and without any express or
11  * implied warranties, including, without limitation, the implied
12  * warranties of merchantability and fitness for a particular
13  * purpose.
14  */
15
16 #include <sys/cdefs.h>
17 __FBSDID("$FreeBSD$");
18
19 #include <sys/param.h>
20 #include <sys/gpt.h>
21 #include <sys/dirent.h>
22 #include <sys/reboot.h>
23
24 #include <machine/bootinfo.h>
25 #include <machine/elf.h>
26 #include <machine/psl.h>
27
28 #include <stdarg.h>
29
30 #include <a.out.h>
31
32 #include <btxv86.h>
33
34 #include "lib.h"
35 #include "rbx.h"
36 #include "drv.h"
37 #include "util.h"
38 #include "cons.h"
39 #include "gpt.h"
40 #include "paths.h"
41
42 #define ARGS            0x900
43 #define NOPT            14
44 #define NDEV            3
45 #define MEM_BASE        0x12
46 #define MEM_EXT         0x15
47
48 #define DRV_HARD        0x80
49 #define DRV_MASK        0x7f
50
51 #define TYPE_AD         0
52 #define TYPE_DA         1
53 #define TYPE_MAXHARD    TYPE_DA
54 #define TYPE_FD         2
55
56 extern uint32_t _end;
57
58 static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS;
59 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
60 static const unsigned char flags[NOPT] = {
61         RBX_DUAL,
62         RBX_SERIAL,
63         RBX_ASKNAME,
64         RBX_CDROM,
65         RBX_CONFIG,
66         RBX_KDB,
67         RBX_GDB,
68         RBX_MUTE,
69         RBX_NOINTR,
70         RBX_PAUSE,
71         RBX_QUIET,
72         RBX_DFLTROOT,
73         RBX_SINGLE,
74         RBX_VERBOSE
75 };
76 uint32_t opts;
77
78 static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
79 static const unsigned char dev_maj[NDEV] = {30, 4, 2};
80
81 static struct dsk dsk;
82 static char kname[1024];
83 static int comspeed = SIOSPD;
84 static struct bootinfo bootinfo;
85
86 void exit(int);
87 static void load(void);
88 static int parse(char *, int *);
89 static int dskread(void *, daddr_t, unsigned);
90 static uint32_t memsize(void);
91
92 #include "ufsread.c"
93
94 static inline int
95 xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
96 {
97
98         if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
99                 printf("Invalid %s\n", "format");
100                 return (-1);
101         }
102         return (0);
103 }
104
105 static inline uint32_t
106 memsize(void)
107 {
108
109         v86.addr = MEM_EXT;
110         v86.eax = 0x8800;
111         v86int();
112         return (v86.eax);
113 }
114
115 static int
116 gptinit(void)
117 {
118
119         if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) {
120                 printf("%s: unable to load GPT\n", BOOTPROG);
121                 return (-1);
122         }
123         if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) {
124                 printf("%s: no UFS partition was found\n", BOOTPROG);
125                 return (-1);
126         }
127         dsk_meta = 0;
128         return (0);
129 }
130
131 int
132 main(void)
133 {
134         char cmd[512], cmdtmp[512];
135         ssize_t sz;
136         int autoboot, dskupdated;
137         ufs_ino_t ino;
138
139         dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
140         v86.ctl = V86_FLAGS;
141         v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
142         dsk.drive = *(uint8_t *)PTOV(ARGS);
143         dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
144         dsk.unit = dsk.drive & DRV_MASK;
145         dsk.part = -1;
146         dsk.start = 0;
147         bootinfo.bi_version = BOOTINFO_VERSION;
148         bootinfo.bi_size = sizeof(bootinfo);
149         bootinfo.bi_basemem = 0;        /* XXX will be filled by loader or kernel */
150         bootinfo.bi_extmem = memsize();
151         bootinfo.bi_memsizes_valid++;
152
153         /* Process configuration file */
154
155         if (gptinit() != 0)
156                 return (-1);
157
158         autoboot = 1;
159         *cmd = '\0';
160
161         for (;;) {
162                 *kname = '\0';
163                 if ((ino = lookup(PATH_CONFIG)) ||
164                     (ino = lookup(PATH_DOTCONFIG))) {
165                         sz = fsread(ino, cmd, sizeof(cmd) - 1);
166                         cmd[(sz < 0) ? 0 : sz] = '\0';
167                 }
168                 if (*cmd != '\0') {
169                         memcpy(cmdtmp, cmd, sizeof(cmdtmp));
170                         if (parse(cmdtmp, &dskupdated))
171                                 break;
172                         if (dskupdated && gptinit() != 0)
173                                 break;
174                         if (!OPT_CHECK(RBX_QUIET))
175                                 printf("%s: %s", PATH_CONFIG, cmd);
176                         *cmd = '\0';
177                 }
178
179                 if (autoboot && keyhit(3)) {
180                         if (*kname == '\0')
181                                 memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER));
182                         break;
183                 }
184                 autoboot = 0;
185
186                 /*
187                  * Try to exec stage 3 boot loader. If interrupted by a
188                  * keypress, or in case of failure, try to load a kernel
189                  * directly instead.
190                  */
191                 if (*kname != '\0')
192                         load();
193                 memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER));
194                 load();
195                 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
196                 load();
197                 gptbootfailed(&dsk);
198                 if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1)
199                         break;
200                 dsk_meta = 0;
201         }
202
203         /* Present the user with the boot2 prompt. */
204
205         for (;;) {
206                 if (!OPT_CHECK(RBX_QUIET)) {
207                         printf("\nFreeBSD/x86 boot\n"
208                             "Default: %u:%s(%up%u)%s\n"
209                             "boot: ",
210                             dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
211                             dsk.part, kname);
212                 }
213                 if (ioctrl & IO_SERIAL)
214                         sio_flush();
215                 *cmd = '\0';
216                 if (keyhit(0))
217                         getstr(cmd, sizeof(cmd));
218                 else if (!OPT_CHECK(RBX_QUIET))
219                         putchar('\n');
220                 if (parse(cmd, &dskupdated)) {
221                         putchar('\a');
222                         continue;
223                 }
224                 if (dskupdated && gptinit() != 0)
225                         continue;
226                 load();
227         }
228         /* NOTREACHED */
229 }
230
231 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
232 void
233 exit(int x)
234 {
235 }
236
237 static void
238 load(void)
239 {
240     union {
241         struct exec ex;
242         Elf32_Ehdr eh;
243     } hdr;
244     static Elf32_Phdr ep[2];
245     static Elf32_Shdr es[2];
246     caddr_t p;
247     ufs_ino_t ino;
248     uint32_t addr, x;
249     int fmt, i, j;
250
251     if (!(ino = lookup(kname))) {
252         if (!ls) {
253             printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG,
254                 kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
255                 dsk.part);
256         }
257         return;
258     }
259     if (xfsread(ino, &hdr, sizeof(hdr)))
260         return;
261     if (N_GETMAGIC(hdr.ex) == ZMAGIC)
262         fmt = 0;
263     else if (IS_ELF(hdr.eh))
264         fmt = 1;
265     else {
266         printf("Invalid %s\n", "format");
267         return;
268     }
269     if (fmt == 0) {
270         addr = hdr.ex.a_entry & 0xffffff;
271         p = PTOV(addr);
272         fs_off = PAGE_SIZE;
273         if (xfsread(ino, p, hdr.ex.a_text))
274             return;
275         p += roundup2(hdr.ex.a_text, PAGE_SIZE);
276         if (xfsread(ino, p, hdr.ex.a_data))
277             return;
278         p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
279         bootinfo.bi_symtab = VTOP(p);
280         memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
281         p += sizeof(hdr.ex.a_syms);
282         if (hdr.ex.a_syms) {
283             if (xfsread(ino, p, hdr.ex.a_syms))
284                 return;
285             p += hdr.ex.a_syms;
286             if (xfsread(ino, p, sizeof(int)))
287                 return;
288             x = *(uint32_t *)p;
289             p += sizeof(int);
290             x -= sizeof(int);
291             if (xfsread(ino, p, x))
292                 return;
293             p += x;
294         }
295     } else {
296         fs_off = hdr.eh.e_phoff;
297         for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
298             if (xfsread(ino, ep + j, sizeof(ep[0])))
299                 return;
300             if (ep[j].p_type == PT_LOAD)
301                 j++;
302         }
303         for (i = 0; i < 2; i++) {
304             p = PTOV(ep[i].p_paddr & 0xffffff);
305             fs_off = ep[i].p_offset;
306             if (xfsread(ino, p, ep[i].p_filesz))
307                 return;
308         }
309         p += roundup2(ep[1].p_memsz, PAGE_SIZE);
310         bootinfo.bi_symtab = VTOP(p);
311         if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
312             fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
313                 (hdr.eh.e_shstrndx + 1);
314             if (xfsread(ino, &es, sizeof(es)))
315                 return;
316             for (i = 0; i < 2; i++) {
317                 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
318                 p += sizeof(es[i].sh_size);
319                 fs_off = es[i].sh_offset;
320                 if (xfsread(ino, p, es[i].sh_size))
321                     return;
322                 p += es[i].sh_size;
323             }
324         }
325         addr = hdr.eh.e_entry & 0xffffff;
326     }
327     bootinfo.bi_esymtab = VTOP(p);
328     bootinfo.bi_kernelname = VTOP(kname);
329     bootinfo.bi_bios_dev = dsk.drive;
330     __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
331            MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
332            0, 0, 0, VTOP(&bootinfo));
333 }
334
335 static int
336 parse(char *cmdstr, int *dskupdated)
337 {
338     char *arg = cmdstr;
339     char *ep, *p, *q;
340     const char *cp;
341     unsigned int drv;
342     int c, i, j;
343
344     *dskupdated = 0;
345     while ((c = *arg++)) {
346         if (c == ' ' || c == '\t' || c == '\n')
347             continue;
348         for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
349         ep = p;
350         if (*p)
351             *p++ = 0;
352         if (c == '-') {
353             while ((c = *arg++)) {
354                 if (c == 'P') {
355                     if (*(uint8_t *)PTOV(0x496) & 0x10) {
356                         cp = "yes";
357                     } else {
358                         opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL);
359                         cp = "no";
360                     }
361                     printf("Keyboard: %s\n", cp);
362                     continue;
363                 } else if (c == 'S') {
364                     j = 0;
365                     while ((unsigned int)(i = *arg++ - '0') <= 9)
366                         j = j * 10 + i;
367                     if (j > 0 && i == -'0') {
368                         comspeed = j;
369                         break;
370                     }
371                     /* Fall through to error below ('S' not in optstr[]). */
372                 }
373                 for (i = 0; c != optstr[i]; i++)
374                     if (i == NOPT - 1)
375                         return -1;
376                 opts ^= OPT_SET(flags[i]);
377             }
378             ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
379                      OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
380             if (ioctrl & IO_SERIAL) {
381                 if (sio_init(115200 / comspeed) != 0)
382                     ioctrl &= ~IO_SERIAL;
383             }
384         } else {
385             for (q = arg--; *q && *q != '('; q++);
386             if (*q) {
387                 drv = -1;
388                 if (arg[1] == ':') {
389                     drv = *arg - '0';
390                     if (drv > 9)
391                         return (-1);
392                     arg += 2;
393                 }
394                 if (q - arg != 2)
395                     return -1;
396                 for (i = 0; arg[0] != dev_nm[i][0] ||
397                             arg[1] != dev_nm[i][1]; i++)
398                     if (i == NDEV - 1)
399                         return -1;
400                 dsk.type = i;
401                 arg += 3;
402                 dsk.unit = *arg - '0';
403                 if (arg[1] != 'p' || dsk.unit > 9)
404                     return -1;
405                 arg += 2;
406                 dsk.part = *arg - '0';
407                 if (dsk.part < 1 || dsk.part > 9)
408                     return -1;
409                 arg++;
410                 if (arg[0] != ')')
411                     return -1;
412                 arg++;
413                 if (drv == -1)
414                     drv = dsk.unit;
415                 dsk.drive = (dsk.type <= TYPE_MAXHARD
416                              ? DRV_HARD : 0) + drv;
417                 *dskupdated = 1;
418             }
419             if ((i = ep - arg)) {
420                 if ((size_t)i >= sizeof(kname))
421                     return -1;
422                 memcpy(kname, arg, i + 1);
423             }
424         }
425         arg = p;
426     }
427     return 0;
428 }
429
430 static int
431 dskread(void *buf, daddr_t lba, unsigned nblk)
432 {
433
434         return drvread(&dsk, buf, lba + dsk.start, nblk);
435 }