Deleted Added
full compact
gptboot.c (104620) gptboot.c (104635)
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/*
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/*
17 * $FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 104620 2002-10-07 13:11:28Z phk $
17 * $FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 104635 2002-10-07 21:36:06Z phk $
18 */
19
20#include <sys/param.h>
21#include <sys/reboot.h>
22#include <sys/diskslice.h>
23#include <sys/disklabel.h>
24#include <sys/diskmbr.h>
25#include <sys/dirent.h>
26#include <machine/bootinfo.h>
27#include <machine/elf.h>
28
29#include <stdarg.h>
30
31#include <a.out.h>
32
33#include <btxv86.h>
34
35#include "boot2.h"
36#include "lib.h"
37
38#define IO_KEYBOARD 1
39#define IO_SERIAL 2
40
41#define SECOND 18 /* Circa that many ticks in a second. */
42
43#define RBX_ASKNAME 0x0 /* -a */
44#define RBX_SINGLE 0x1 /* -s */
45#define RBX_DFLTROOT 0x5 /* -r */
46#define RBX_KDB 0x6 /* -d */
47#define RBX_CONFIG 0xa /* -c */
48#define RBX_VERBOSE 0xb /* -v */
49#define RBX_SERIAL 0xc /* -h */
50#define RBX_CDROM 0xd /* -C */
51#define RBX_GDB 0xf /* -g */
52#define RBX_MUTE 0x10 /* -m */
53#define RBX_PAUSE 0x12 /* -p */
54#define RBX_DUAL 0x1d /* -D */
55#define RBX_PROBEKBD 0x1e /* -P */
56#define RBX_NOINTR 0x1f /* -n */
57
58#define RBX_MASK 0x2005ffff
59
60#define PATH_CONFIG "/boot.config"
61#define PATH_BOOT3 "/boot/loader"
62#define PATH_KERNEL "/kernel"
63
64#define ARGS 0x900
65#define NOPT 14
66#define NDEV 5
67#define MEM_BASE 0x12
68#define MEM_EXT 0x15
69#define V86_CY(x) ((x) & 1)
70#define V86_ZR(x) ((x) & 0x40)
71
72#define DRV_HARD 0x80
73#define DRV_MASK 0x7f
74
75#define TYPE_AD 0
76#define TYPE_WD 1
77#define TYPE_DA 2
78#define TYPE_MAXHARD TYPE_DA
79#define TYPE_WFD 3
80#define TYPE_FD 4
81
82extern uint32_t _end;
83
84static const char optstr[NOPT] = "DhaCcdgmnPprsv";
85static const unsigned char flags[NOPT] = {
86 RBX_DUAL,
87 RBX_SERIAL,
88 RBX_ASKNAME,
89 RBX_CDROM,
90 RBX_CONFIG,
91 RBX_KDB,
92 RBX_GDB,
93 RBX_MUTE,
94 RBX_NOINTR,
95 RBX_PROBEKBD,
96 RBX_PAUSE,
97 RBX_DFLTROOT,
98 RBX_SINGLE,
99 RBX_VERBOSE
100};
101
102static const char *const dev_nm[NDEV] = {"ad", "wd", "da", " ", "fd"};
103static const unsigned char dev_maj[NDEV] = {30, 0, 4, 1, 2};
104
105static struct dsk {
106 unsigned drive;
107 unsigned type;
108 unsigned unit;
109 unsigned slice;
110 unsigned part;
111 unsigned start;
112 int init;
113} dsk;
114static char cmd[512];
115static char kname[1024];
116static uint32_t opts = RB_BOOTINFO;
117static struct bootinfo bootinfo;
118static uint8_t ioctrl = IO_KEYBOARD;
119
120void exit(int);
121static void load(const char *);
122static int parse(char *);
123static int xfsread(ino_t, void *, size_t);
124static int dskread(void *, unsigned, unsigned);
125static int printf(const char *,...);
126static int putchar(int);
127static uint32_t memsize(int);
128static int drvread(void *, unsigned, unsigned);
129static int keyhit(unsigned);
130static int xputc(int);
131static int xgetc(int);
132static int getc(int);
133
134#if 1
135#define memcpy __builtin_memcpy
136#else
137static void memcpy(char *, const char *, int);
138static void
139memcpy(char *dst, const char *src, int len)
140{
141 while (len--)
142 *dst++ = *src++;
143}
144#endif
145
146static inline int
147strcmp(const char *s1, const char *s2)
148{
149 for (; *s1 == *s2 && *s1; s1++, s2++);
150 return (u_char)*s1 - (u_char)*s2;
151}
152
153#include "ufsread.c"
154
155static int
156xfsread(ino_t inode, void *buf, size_t nbyte)
157{
158 if (fsread(inode, buf, nbyte) != nbyte) {
159 printf("Invalid %s\n", "format");
160 return -1;
161 }
162 return 0;
163}
164
165static inline void
166getstr(char *str, int size)
167{
168 char *s;
169 int c;
170
171 s = str;
172 for (;;) {
173 switch (c = xgetc(0)) {
174 case 0:
175 break;
176 case '\177':
177 c = '\b';
178 case '\b':
179 if (s > str) {
180 s--;
181 putchar('\b');
182 putchar(' ');
183 } else
184 c = 0;
185 break;
186 case '\n':
187 case '\r':
188 *s = 0;
189 return;
190 default:
191 if (s - str < size - 1)
192 *s++ = c;
193 }
194 if (c)
195 putchar(c);
196 }
197}
198
199static inline uint32_t
200drvinfo(int drive)
201{
202 v86.addr = 0x13;
203 v86.eax = 0x800;
204 v86.edx = DRV_HARD + drive;
205 v86int();
206 if (V86_CY(v86.efl))
207 return 0x4f010f;
208 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
209 (v86.edx & 0xff00) | (v86.ecx & 0x3f);
210}
211
212static inline void
213putc(int c)
214{
215 v86.addr = 0x10;
216 v86.eax = 0xe00 | (c & 0xff);
217 v86.ebx = 0x7;
218 v86int();
219}
220
221int
222main(void)
223{
224 int autoboot, i;
225 ino_t ino;
226
227 dmadat = (void *)(roundup2(__base + _end, 0x10000) - __base);
228 v86.ctl = V86_FLAGS;
229 dsk.drive = *(uint8_t *)PTOV(ARGS);
230 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
231 dsk.unit = dsk.drive & DRV_MASK;
232 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
233 bootinfo.bi_version = BOOTINFO_VERSION;
234 bootinfo.bi_size = sizeof(bootinfo);
235 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */
236 bootinfo.bi_extmem = memsize(MEM_EXT);
237 bootinfo.bi_memsizes_valid++;
238 for (i = 0; i < N_BIOS_GEOM; i++)
239 bootinfo.bi_bios_geom[i] = drvinfo(i);
240
241 /* Process configuration file */
242
243 autoboot = 1;
244
245 if ((ino = lookup(PATH_CONFIG)))
246 fsread(ino, cmd, sizeof(cmd));
247
248 if (*cmd) {
249 printf("%s: %s", PATH_CONFIG, cmd);
250 if (parse(cmd))
251 autoboot = 0;
252 /* Do not process this command twice */
253 *cmd = 0;
254 }
255
256 /*
257 * Try to exec stage 3 boot loader. If interrupted by a keypress,
258 * or in case of failure, try to load a kernel directly instead.
259 */
260
261 if (autoboot && !*kname) {
262 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
263 if (!keyhit(3*SECOND)) {
264 load(kname);
265 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
266 }
267 }
268
269 /* Present the user with the boot2 prompt. */
270
271 for (;;) {
18 */
19
20#include <sys/param.h>
21#include <sys/reboot.h>
22#include <sys/diskslice.h>
23#include <sys/disklabel.h>
24#include <sys/diskmbr.h>
25#include <sys/dirent.h>
26#include <machine/bootinfo.h>
27#include <machine/elf.h>
28
29#include <stdarg.h>
30
31#include <a.out.h>
32
33#include <btxv86.h>
34
35#include "boot2.h"
36#include "lib.h"
37
38#define IO_KEYBOARD 1
39#define IO_SERIAL 2
40
41#define SECOND 18 /* Circa that many ticks in a second. */
42
43#define RBX_ASKNAME 0x0 /* -a */
44#define RBX_SINGLE 0x1 /* -s */
45#define RBX_DFLTROOT 0x5 /* -r */
46#define RBX_KDB 0x6 /* -d */
47#define RBX_CONFIG 0xa /* -c */
48#define RBX_VERBOSE 0xb /* -v */
49#define RBX_SERIAL 0xc /* -h */
50#define RBX_CDROM 0xd /* -C */
51#define RBX_GDB 0xf /* -g */
52#define RBX_MUTE 0x10 /* -m */
53#define RBX_PAUSE 0x12 /* -p */
54#define RBX_DUAL 0x1d /* -D */
55#define RBX_PROBEKBD 0x1e /* -P */
56#define RBX_NOINTR 0x1f /* -n */
57
58#define RBX_MASK 0x2005ffff
59
60#define PATH_CONFIG "/boot.config"
61#define PATH_BOOT3 "/boot/loader"
62#define PATH_KERNEL "/kernel"
63
64#define ARGS 0x900
65#define NOPT 14
66#define NDEV 5
67#define MEM_BASE 0x12
68#define MEM_EXT 0x15
69#define V86_CY(x) ((x) & 1)
70#define V86_ZR(x) ((x) & 0x40)
71
72#define DRV_HARD 0x80
73#define DRV_MASK 0x7f
74
75#define TYPE_AD 0
76#define TYPE_WD 1
77#define TYPE_DA 2
78#define TYPE_MAXHARD TYPE_DA
79#define TYPE_WFD 3
80#define TYPE_FD 4
81
82extern uint32_t _end;
83
84static const char optstr[NOPT] = "DhaCcdgmnPprsv";
85static const unsigned char flags[NOPT] = {
86 RBX_DUAL,
87 RBX_SERIAL,
88 RBX_ASKNAME,
89 RBX_CDROM,
90 RBX_CONFIG,
91 RBX_KDB,
92 RBX_GDB,
93 RBX_MUTE,
94 RBX_NOINTR,
95 RBX_PROBEKBD,
96 RBX_PAUSE,
97 RBX_DFLTROOT,
98 RBX_SINGLE,
99 RBX_VERBOSE
100};
101
102static const char *const dev_nm[NDEV] = {"ad", "wd", "da", " ", "fd"};
103static const unsigned char dev_maj[NDEV] = {30, 0, 4, 1, 2};
104
105static struct dsk {
106 unsigned drive;
107 unsigned type;
108 unsigned unit;
109 unsigned slice;
110 unsigned part;
111 unsigned start;
112 int init;
113} dsk;
114static char cmd[512];
115static char kname[1024];
116static uint32_t opts = RB_BOOTINFO;
117static struct bootinfo bootinfo;
118static uint8_t ioctrl = IO_KEYBOARD;
119
120void exit(int);
121static void load(const char *);
122static int parse(char *);
123static int xfsread(ino_t, void *, size_t);
124static int dskread(void *, unsigned, unsigned);
125static int printf(const char *,...);
126static int putchar(int);
127static uint32_t memsize(int);
128static int drvread(void *, unsigned, unsigned);
129static int keyhit(unsigned);
130static int xputc(int);
131static int xgetc(int);
132static int getc(int);
133
134#if 1
135#define memcpy __builtin_memcpy
136#else
137static void memcpy(char *, const char *, int);
138static void
139memcpy(char *dst, const char *src, int len)
140{
141 while (len--)
142 *dst++ = *src++;
143}
144#endif
145
146static inline int
147strcmp(const char *s1, const char *s2)
148{
149 for (; *s1 == *s2 && *s1; s1++, s2++);
150 return (u_char)*s1 - (u_char)*s2;
151}
152
153#include "ufsread.c"
154
155static int
156xfsread(ino_t inode, void *buf, size_t nbyte)
157{
158 if (fsread(inode, buf, nbyte) != nbyte) {
159 printf("Invalid %s\n", "format");
160 return -1;
161 }
162 return 0;
163}
164
165static inline void
166getstr(char *str, int size)
167{
168 char *s;
169 int c;
170
171 s = str;
172 for (;;) {
173 switch (c = xgetc(0)) {
174 case 0:
175 break;
176 case '\177':
177 c = '\b';
178 case '\b':
179 if (s > str) {
180 s--;
181 putchar('\b');
182 putchar(' ');
183 } else
184 c = 0;
185 break;
186 case '\n':
187 case '\r':
188 *s = 0;
189 return;
190 default:
191 if (s - str < size - 1)
192 *s++ = c;
193 }
194 if (c)
195 putchar(c);
196 }
197}
198
199static inline uint32_t
200drvinfo(int drive)
201{
202 v86.addr = 0x13;
203 v86.eax = 0x800;
204 v86.edx = DRV_HARD + drive;
205 v86int();
206 if (V86_CY(v86.efl))
207 return 0x4f010f;
208 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
209 (v86.edx & 0xff00) | (v86.ecx & 0x3f);
210}
211
212static inline void
213putc(int c)
214{
215 v86.addr = 0x10;
216 v86.eax = 0xe00 | (c & 0xff);
217 v86.ebx = 0x7;
218 v86int();
219}
220
221int
222main(void)
223{
224 int autoboot, i;
225 ino_t ino;
226
227 dmadat = (void *)(roundup2(__base + _end, 0x10000) - __base);
228 v86.ctl = V86_FLAGS;
229 dsk.drive = *(uint8_t *)PTOV(ARGS);
230 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
231 dsk.unit = dsk.drive & DRV_MASK;
232 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
233 bootinfo.bi_version = BOOTINFO_VERSION;
234 bootinfo.bi_size = sizeof(bootinfo);
235 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */
236 bootinfo.bi_extmem = memsize(MEM_EXT);
237 bootinfo.bi_memsizes_valid++;
238 for (i = 0; i < N_BIOS_GEOM; i++)
239 bootinfo.bi_bios_geom[i] = drvinfo(i);
240
241 /* Process configuration file */
242
243 autoboot = 1;
244
245 if ((ino = lookup(PATH_CONFIG)))
246 fsread(ino, cmd, sizeof(cmd));
247
248 if (*cmd) {
249 printf("%s: %s", PATH_CONFIG, cmd);
250 if (parse(cmd))
251 autoboot = 0;
252 /* Do not process this command twice */
253 *cmd = 0;
254 }
255
256 /*
257 * Try to exec stage 3 boot loader. If interrupted by a keypress,
258 * or in case of failure, try to load a kernel directly instead.
259 */
260
261 if (autoboot && !*kname) {
262 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
263 if (!keyhit(3*SECOND)) {
264 load(kname);
265 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
266 }
267 }
268
269 /* Present the user with the boot2 prompt. */
270
271 for (;;) {
272 printf(" \n>> FreeBSD/i386 BOOT\n"
272#ifdef UFS1_ONLY
273 printf(" \n>> FreeBSD/i386/UFS1 BOOT\n"
274#else
275 printf(" \n>> FreeBSD/i386/UFS[12] BOOT\n"
276#endif
273 "Default: %u:%s(%u,%c)%s\n"
274 "boot: ",
275 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
276 'a' + dsk.part, kname);
277 if (ioctrl & IO_SERIAL)
278 sio_flush();
279 if (!autoboot || keyhit(5*SECOND))
280 getstr(cmd, sizeof(cmd));
281 else
282 putchar('\n');
283 autoboot = 0;
284 if (parse(cmd))
285 putchar('\a');
286 else
287 load(kname);
288 }
289}
290
291/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
292void
293exit(int x)
294{
295}
296
297static void
298load(const char *fname)
299{
300 union {
301 struct exec ex;
302 Elf32_Ehdr eh;
303 } hdr;
304 Elf32_Phdr ep[2];
305 Elf32_Shdr es[2];
306 caddr_t p;
307 ino_t ino;
308 uint32_t addr, x;
309 int fmt, i, j;
310
311 if (!(ino = lookup(fname))) {
312 if (!ls)
313 printf("No %s\n", fname);
314 return;
315 }
316 if (xfsread(ino, &hdr, sizeof(hdr)))
317 return;
318 if (N_GETMAGIC(hdr.ex) == ZMAGIC)
319 fmt = 0;
320 else if (IS_ELF(hdr.eh))
321 fmt = 1;
322 else {
323 printf("Invalid %s\n", "format");
324 return;
325 }
326 if (fmt == 0) {
327 addr = hdr.ex.a_entry & 0xffffff;
328 p = PTOV(addr);
329 fs_off = PAGE_SIZE;
330 if (xfsread(ino, p, hdr.ex.a_text))
331 return;
332 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
333 if (xfsread(ino, p, hdr.ex.a_data))
334 return;
335 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
336 bootinfo.bi_symtab = VTOP(p);
337 memcpy(p, (char *)&hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
338 p += sizeof(hdr.ex.a_syms);
339 if (hdr.ex.a_syms) {
340 if (xfsread(ino, p, hdr.ex.a_syms))
341 return;
342 p += hdr.ex.a_syms;
343 if (xfsread(ino, p, sizeof(int)))
344 return;
345 x = *(uint32_t *)p;
346 p += sizeof(int);
347 x -= sizeof(int);
348 if (xfsread(ino, p, x))
349 return;
350 p += x;
351 }
352 } else {
353 fs_off = hdr.eh.e_phoff;
354 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
355 if (xfsread(ino, ep + j, sizeof(ep[0])))
356 return;
357 if (ep[j].p_type == PT_LOAD)
358 j++;
359 }
360 for (i = 0; i < 2; i++) {
361 p = PTOV(ep[i].p_paddr & 0xffffff);
362 fs_off = ep[i].p_offset;
363 if (xfsread(ino, p, ep[i].p_filesz))
364 return;
365 }
366 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
367 bootinfo.bi_symtab = VTOP(p);
368 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
369 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
370 (hdr.eh.e_shstrndx + 1);
371 if (xfsread(ino, &es, sizeof(es)))
372 return;
373 for (i = 0; i < 2; i++) {
374 memcpy(p, (char *)&es[i].sh_size, sizeof(es[i].sh_size));
375 p += sizeof(es[i].sh_size);
376 fs_off = es[i].sh_offset;
377 if (xfsread(ino, p, es[i].sh_size))
378 return;
379 p += es[i].sh_size;
380 }
381 }
382 addr = hdr.eh.e_entry & 0xffffff;
383 }
384 bootinfo.bi_esymtab = VTOP(p);
385 bootinfo.bi_kernelname = VTOP(fname);
386 bootinfo.bi_bios_dev = dsk.drive;
387 __exec((caddr_t)addr, opts & RBX_MASK,
388 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
389 0, 0, 0, VTOP(&bootinfo));
390}
391
392static int
393parse(char *arg)
394{
395 char *p, *q;
396 int drv, c, i;
397
398 while ((c = *arg++)) {
399 if (c == ' ' || c == '\t' || c == '\n')
400 continue;
401 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
402 if (*p)
403 *p++ = 0;
404 if (c == '-') {
405 while ((c = *arg++)) {
406 for (i = 0; c != optstr[i]; i++)
407 if (i == NOPT - 1)
408 return -1;
409 opts ^= 1 << flags[i];
410 }
411 if (opts & 1 << RBX_PROBEKBD) {
412 i = *(uint8_t *)PTOV(0x496) & 0x10;
413 /* printf("Keyboard: %s\n", i ? "yes" : "no"); */
414 if (!i)
415 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
416 opts &= ~(1 << RBX_PROBEKBD);
417 }
418 ioctrl = opts & 1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) :
419 opts & 1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD;
420 if (ioctrl & IO_SERIAL)
421 sio_init();
422 } else {
423 for (q = arg--; *q && *q != '('; q++);
424 if (*q) {
425 drv = -1;
426 if (arg[1] == ':') {
427 if (*arg < '0' || *arg > '9')
428 return -1;
429 drv = *arg - '0';
430 arg += 2;
431 }
432 if (q - arg != 2)
433 return -1;
434 for (i = 0; arg[0] != dev_nm[i][0] ||
435 arg[1] != dev_nm[i][1]; i++)
436 if (i == NDEV - 1)
437 return -1;
438 dsk.type = i;
439 arg += 3;
440 if (arg[1] != ',' || *arg < '0' || *arg > '9')
441 return -1;
442 dsk.unit = *arg - '0';
443 arg += 2;
444 dsk.slice = WHOLE_DISK_SLICE;
445 if (arg[1] == ',') {
446 if (*arg < '0' || *arg > '0' + NDOSPART)
447 return -1;
448 if ((dsk.slice = *arg - '0'))
449 dsk.slice++;
450 arg += 2;
451 }
452 if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
453 return -1;
454 dsk.part = *arg - 'a';
455 arg += 2;
456 if (drv == -1)
457 drv = dsk.unit;
458 dsk.drive = (dsk.type <= TYPE_MAXHARD
459 ? DRV_HARD : 0) + drv;
460 dsk_meta = 0;
461 fsread(0, NULL, 0);
462 }
463 if ((i = p - arg - !*(p - 1))) {
464 if (i >= sizeof(kname))
465 return -1;
466 memcpy(kname, arg, i + 1);
467 }
468 }
469 arg = p;
470 }
471 return 0;
472}
473
474static int
475dskread(void *buf, unsigned lba, unsigned nblk)
476{
477 struct dos_partition *dp;
478 struct disklabel *d;
479 char *sec;
480 unsigned sl, i;
481
482 if (!dsk_meta) {
483 sec = dmadat->secbuf;
484 dsk.start = 0;
485 if (drvread(sec, DOSBBSECTOR, 1))
486 return -1;
487 dp = (void *)(sec + DOSPARTOFF);
488 sl = dsk.slice;
489 if (sl < BASE_SLICE) {
490 for (i = 0; i < NDOSPART; i++)
491 if (dp[i].dp_typ == DOSPTYP_386BSD &&
492 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
493 sl = BASE_SLICE + i;
494 if (dp[i].dp_flag & 0x80 ||
495 dsk.slice == COMPATIBILITY_SLICE)
496 break;
497 }
498 if (dsk.slice == WHOLE_DISK_SLICE)
499 dsk.slice = sl;
500 }
501 if (sl != WHOLE_DISK_SLICE) {
502 if (sl != COMPATIBILITY_SLICE)
503 dp += sl - BASE_SLICE;
504 if (dp->dp_typ != DOSPTYP_386BSD) {
505 printf("Invalid %s\n", "slice");
506 return -1;
507 }
508 dsk.start = dp->dp_start;
509 }
510 if (drvread(sec, dsk.start + LABELSECTOR, 1))
511 return -1;
512 d = (void *)(sec + LABELOFFSET);
513 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
514 if (dsk.part != RAW_PART) {
515 printf("Invalid %s\n", "label");
516 return -1;
517 }
518 } else {
519 if (!dsk.init) {
520 if (d->d_type == DTYPE_SCSI)
521 dsk.type = TYPE_DA;
522 dsk.init++;
523 }
524 if (dsk.part >= d->d_npartitions ||
525 !d->d_partitions[dsk.part].p_size) {
526 printf("Invalid %s\n", "partition");
527 return -1;
528 }
529 dsk.start += d->d_partitions[dsk.part].p_offset;
530 dsk.start -= d->d_partitions[RAW_PART].p_offset;
531 }
532 }
533 return drvread(buf, dsk.start + lba, nblk);
534}
535
536static int
537printf(const char *fmt,...)
538{
539 static const char digits[16] = "0123456789abcdef";
540 va_list ap;
541 char buf[10];
542 char *s;
543 unsigned r, u;
544 int c;
545
546 va_start(ap, fmt);
547 while ((c = *fmt++)) {
548 if (c == '%') {
549 c = *fmt++;
550 switch (c) {
551 case 'c':
552 putchar(va_arg(ap, int));
553 continue;
554 case 's':
555 for (s = va_arg(ap, char *); *s; s++)
556 putchar(*s);
557 continue;
558 case 'u':
559 case 'x':
560 r = c == 'u' ? 10U : 16U;
561 u = va_arg(ap, unsigned);
562 s = buf;
563 do
564 *s++ = digits[u % r];
565 while (u /= r);
566 while (--s >= buf)
567 putchar(*s);
568 continue;
569 }
570 }
571 putchar(c);
572 }
573 va_end(ap);
574 return 0;
575}
576
577static int
578putchar(int c)
579{
580 if (c == '\n')
581 xputc('\r');
582 return xputc(c);
583}
584
585static uint32_t
586memsize(int type)
587{
588 v86.addr = type;
589 v86.eax = 0x8800;
590 v86int();
591 return v86.eax;
592}
593
594static int
595drvread(void *buf, unsigned lba, unsigned nblk)
596{
597 static unsigned c = 0x2d5c7c2f;
598
599 printf("%c\b", c = c << 8 | c >> 24);
600 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
601 v86.addr = XREADORG; /* call to xread in boot1 */
602 v86.es = VTOPSEG(buf);
603 v86.eax = lba;
604 v86.ebx = VTOPOFF(buf);
605 v86.ecx = lba >> 16;
606 v86.edx = nblk << 8 | dsk.drive;
607 v86int();
608 v86.ctl = V86_FLAGS;
609 if (V86_CY(v86.efl)) {
610 printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff,
611 lba);
612 return -1;
613 }
614 return 0;
615}
616
617static int
618keyhit(unsigned ticks)
619{
620 uint32_t t0, t1;
621
622 if (opts & 1 << RBX_NOINTR)
623 return 0;
624 t0 = 0;
625 for (;;) {
626 if (xgetc(1))
627 return 1;
628 t1 = *(uint32_t *)PTOV(0x46c);
629 if (!t0)
630 t0 = t1;
631 if (t1 < t0 || t1 >= t0 + ticks)
632 return 0;
633 }
634}
635
636static int
637xputc(int c)
638{
639 if (ioctrl & IO_KEYBOARD)
640 putc(c);
641 if (ioctrl & IO_SERIAL)
642 sio_putc(c);
643 return c;
644}
645
646static int
647xgetc(int fn)
648{
649 if (opts & 1 << RBX_NOINTR)
650 return 0;
651 for (;;) {
652 if (ioctrl & IO_KEYBOARD && getc(1))
653 return fn ? 1 : getc(0);
654 if (ioctrl & IO_SERIAL && sio_ischar())
655 return fn ? 1 : sio_getc();
656 if (fn)
657 return 0;
658 }
659}
660
661static int
662getc(int fn)
663{
664 v86.addr = 0x16;
665 v86.eax = fn << 8;
666 v86int();
667 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
668}
277 "Default: %u:%s(%u,%c)%s\n"
278 "boot: ",
279 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
280 'a' + dsk.part, kname);
281 if (ioctrl & IO_SERIAL)
282 sio_flush();
283 if (!autoboot || keyhit(5*SECOND))
284 getstr(cmd, sizeof(cmd));
285 else
286 putchar('\n');
287 autoboot = 0;
288 if (parse(cmd))
289 putchar('\a');
290 else
291 load(kname);
292 }
293}
294
295/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
296void
297exit(int x)
298{
299}
300
301static void
302load(const char *fname)
303{
304 union {
305 struct exec ex;
306 Elf32_Ehdr eh;
307 } hdr;
308 Elf32_Phdr ep[2];
309 Elf32_Shdr es[2];
310 caddr_t p;
311 ino_t ino;
312 uint32_t addr, x;
313 int fmt, i, j;
314
315 if (!(ino = lookup(fname))) {
316 if (!ls)
317 printf("No %s\n", fname);
318 return;
319 }
320 if (xfsread(ino, &hdr, sizeof(hdr)))
321 return;
322 if (N_GETMAGIC(hdr.ex) == ZMAGIC)
323 fmt = 0;
324 else if (IS_ELF(hdr.eh))
325 fmt = 1;
326 else {
327 printf("Invalid %s\n", "format");
328 return;
329 }
330 if (fmt == 0) {
331 addr = hdr.ex.a_entry & 0xffffff;
332 p = PTOV(addr);
333 fs_off = PAGE_SIZE;
334 if (xfsread(ino, p, hdr.ex.a_text))
335 return;
336 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
337 if (xfsread(ino, p, hdr.ex.a_data))
338 return;
339 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
340 bootinfo.bi_symtab = VTOP(p);
341 memcpy(p, (char *)&hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
342 p += sizeof(hdr.ex.a_syms);
343 if (hdr.ex.a_syms) {
344 if (xfsread(ino, p, hdr.ex.a_syms))
345 return;
346 p += hdr.ex.a_syms;
347 if (xfsread(ino, p, sizeof(int)))
348 return;
349 x = *(uint32_t *)p;
350 p += sizeof(int);
351 x -= sizeof(int);
352 if (xfsread(ino, p, x))
353 return;
354 p += x;
355 }
356 } else {
357 fs_off = hdr.eh.e_phoff;
358 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
359 if (xfsread(ino, ep + j, sizeof(ep[0])))
360 return;
361 if (ep[j].p_type == PT_LOAD)
362 j++;
363 }
364 for (i = 0; i < 2; i++) {
365 p = PTOV(ep[i].p_paddr & 0xffffff);
366 fs_off = ep[i].p_offset;
367 if (xfsread(ino, p, ep[i].p_filesz))
368 return;
369 }
370 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
371 bootinfo.bi_symtab = VTOP(p);
372 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
373 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
374 (hdr.eh.e_shstrndx + 1);
375 if (xfsread(ino, &es, sizeof(es)))
376 return;
377 for (i = 0; i < 2; i++) {
378 memcpy(p, (char *)&es[i].sh_size, sizeof(es[i].sh_size));
379 p += sizeof(es[i].sh_size);
380 fs_off = es[i].sh_offset;
381 if (xfsread(ino, p, es[i].sh_size))
382 return;
383 p += es[i].sh_size;
384 }
385 }
386 addr = hdr.eh.e_entry & 0xffffff;
387 }
388 bootinfo.bi_esymtab = VTOP(p);
389 bootinfo.bi_kernelname = VTOP(fname);
390 bootinfo.bi_bios_dev = dsk.drive;
391 __exec((caddr_t)addr, opts & RBX_MASK,
392 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
393 0, 0, 0, VTOP(&bootinfo));
394}
395
396static int
397parse(char *arg)
398{
399 char *p, *q;
400 int drv, c, i;
401
402 while ((c = *arg++)) {
403 if (c == ' ' || c == '\t' || c == '\n')
404 continue;
405 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
406 if (*p)
407 *p++ = 0;
408 if (c == '-') {
409 while ((c = *arg++)) {
410 for (i = 0; c != optstr[i]; i++)
411 if (i == NOPT - 1)
412 return -1;
413 opts ^= 1 << flags[i];
414 }
415 if (opts & 1 << RBX_PROBEKBD) {
416 i = *(uint8_t *)PTOV(0x496) & 0x10;
417 /* printf("Keyboard: %s\n", i ? "yes" : "no"); */
418 if (!i)
419 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
420 opts &= ~(1 << RBX_PROBEKBD);
421 }
422 ioctrl = opts & 1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) :
423 opts & 1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD;
424 if (ioctrl & IO_SERIAL)
425 sio_init();
426 } else {
427 for (q = arg--; *q && *q != '('; q++);
428 if (*q) {
429 drv = -1;
430 if (arg[1] == ':') {
431 if (*arg < '0' || *arg > '9')
432 return -1;
433 drv = *arg - '0';
434 arg += 2;
435 }
436 if (q - arg != 2)
437 return -1;
438 for (i = 0; arg[0] != dev_nm[i][0] ||
439 arg[1] != dev_nm[i][1]; i++)
440 if (i == NDEV - 1)
441 return -1;
442 dsk.type = i;
443 arg += 3;
444 if (arg[1] != ',' || *arg < '0' || *arg > '9')
445 return -1;
446 dsk.unit = *arg - '0';
447 arg += 2;
448 dsk.slice = WHOLE_DISK_SLICE;
449 if (arg[1] == ',') {
450 if (*arg < '0' || *arg > '0' + NDOSPART)
451 return -1;
452 if ((dsk.slice = *arg - '0'))
453 dsk.slice++;
454 arg += 2;
455 }
456 if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
457 return -1;
458 dsk.part = *arg - 'a';
459 arg += 2;
460 if (drv == -1)
461 drv = dsk.unit;
462 dsk.drive = (dsk.type <= TYPE_MAXHARD
463 ? DRV_HARD : 0) + drv;
464 dsk_meta = 0;
465 fsread(0, NULL, 0);
466 }
467 if ((i = p - arg - !*(p - 1))) {
468 if (i >= sizeof(kname))
469 return -1;
470 memcpy(kname, arg, i + 1);
471 }
472 }
473 arg = p;
474 }
475 return 0;
476}
477
478static int
479dskread(void *buf, unsigned lba, unsigned nblk)
480{
481 struct dos_partition *dp;
482 struct disklabel *d;
483 char *sec;
484 unsigned sl, i;
485
486 if (!dsk_meta) {
487 sec = dmadat->secbuf;
488 dsk.start = 0;
489 if (drvread(sec, DOSBBSECTOR, 1))
490 return -1;
491 dp = (void *)(sec + DOSPARTOFF);
492 sl = dsk.slice;
493 if (sl < BASE_SLICE) {
494 for (i = 0; i < NDOSPART; i++)
495 if (dp[i].dp_typ == DOSPTYP_386BSD &&
496 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
497 sl = BASE_SLICE + i;
498 if (dp[i].dp_flag & 0x80 ||
499 dsk.slice == COMPATIBILITY_SLICE)
500 break;
501 }
502 if (dsk.slice == WHOLE_DISK_SLICE)
503 dsk.slice = sl;
504 }
505 if (sl != WHOLE_DISK_SLICE) {
506 if (sl != COMPATIBILITY_SLICE)
507 dp += sl - BASE_SLICE;
508 if (dp->dp_typ != DOSPTYP_386BSD) {
509 printf("Invalid %s\n", "slice");
510 return -1;
511 }
512 dsk.start = dp->dp_start;
513 }
514 if (drvread(sec, dsk.start + LABELSECTOR, 1))
515 return -1;
516 d = (void *)(sec + LABELOFFSET);
517 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
518 if (dsk.part != RAW_PART) {
519 printf("Invalid %s\n", "label");
520 return -1;
521 }
522 } else {
523 if (!dsk.init) {
524 if (d->d_type == DTYPE_SCSI)
525 dsk.type = TYPE_DA;
526 dsk.init++;
527 }
528 if (dsk.part >= d->d_npartitions ||
529 !d->d_partitions[dsk.part].p_size) {
530 printf("Invalid %s\n", "partition");
531 return -1;
532 }
533 dsk.start += d->d_partitions[dsk.part].p_offset;
534 dsk.start -= d->d_partitions[RAW_PART].p_offset;
535 }
536 }
537 return drvread(buf, dsk.start + lba, nblk);
538}
539
540static int
541printf(const char *fmt,...)
542{
543 static const char digits[16] = "0123456789abcdef";
544 va_list ap;
545 char buf[10];
546 char *s;
547 unsigned r, u;
548 int c;
549
550 va_start(ap, fmt);
551 while ((c = *fmt++)) {
552 if (c == '%') {
553 c = *fmt++;
554 switch (c) {
555 case 'c':
556 putchar(va_arg(ap, int));
557 continue;
558 case 's':
559 for (s = va_arg(ap, char *); *s; s++)
560 putchar(*s);
561 continue;
562 case 'u':
563 case 'x':
564 r = c == 'u' ? 10U : 16U;
565 u = va_arg(ap, unsigned);
566 s = buf;
567 do
568 *s++ = digits[u % r];
569 while (u /= r);
570 while (--s >= buf)
571 putchar(*s);
572 continue;
573 }
574 }
575 putchar(c);
576 }
577 va_end(ap);
578 return 0;
579}
580
581static int
582putchar(int c)
583{
584 if (c == '\n')
585 xputc('\r');
586 return xputc(c);
587}
588
589static uint32_t
590memsize(int type)
591{
592 v86.addr = type;
593 v86.eax = 0x8800;
594 v86int();
595 return v86.eax;
596}
597
598static int
599drvread(void *buf, unsigned lba, unsigned nblk)
600{
601 static unsigned c = 0x2d5c7c2f;
602
603 printf("%c\b", c = c << 8 | c >> 24);
604 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
605 v86.addr = XREADORG; /* call to xread in boot1 */
606 v86.es = VTOPSEG(buf);
607 v86.eax = lba;
608 v86.ebx = VTOPOFF(buf);
609 v86.ecx = lba >> 16;
610 v86.edx = nblk << 8 | dsk.drive;
611 v86int();
612 v86.ctl = V86_FLAGS;
613 if (V86_CY(v86.efl)) {
614 printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff,
615 lba);
616 return -1;
617 }
618 return 0;
619}
620
621static int
622keyhit(unsigned ticks)
623{
624 uint32_t t0, t1;
625
626 if (opts & 1 << RBX_NOINTR)
627 return 0;
628 t0 = 0;
629 for (;;) {
630 if (xgetc(1))
631 return 1;
632 t1 = *(uint32_t *)PTOV(0x46c);
633 if (!t0)
634 t0 = t1;
635 if (t1 < t0 || t1 >= t0 + ticks)
636 return 0;
637 }
638}
639
640static int
641xputc(int c)
642{
643 if (ioctrl & IO_KEYBOARD)
644 putc(c);
645 if (ioctrl & IO_SERIAL)
646 sio_putc(c);
647 return c;
648}
649
650static int
651xgetc(int fn)
652{
653 if (opts & 1 << RBX_NOINTR)
654 return 0;
655 for (;;) {
656 if (ioctrl & IO_KEYBOARD && getc(1))
657 return fn ? 1 : getc(0);
658 if (ioctrl & IO_SERIAL && sio_ischar())
659 return fn ? 1 : sio_getc();
660 if (fn)
661 return 0;
662 }
663}
664
665static int
666getc(int fn)
667{
668 v86.addr = 0x16;
669 v86.eax = fn << 8;
670 v86int();
671 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
672}