2 * Copyright (c) 1998 Robert Nordier
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
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
20 #include <sys/param.h>
21 #include <sys/reboot.h>
22 #include <sys/diskslice.h>
23 #include <sys/disklabel.h>
24 #include <sys/dirent.h>
25 #include <machine/bootinfo.h>
27 #include <ufs/ffs/fs.h>
28 #include <ufs/ufs/dinode.h>
39 #define RBX_ASKNAME 0x0 /* -a */
40 #define RBX_SINGLE 0x1 /* -s */
41 #define RBX_DFLTROOT 0x5 /* -r */
42 #define RBX_KDB 0x6 /* -d */
43 #define RBX_CONFIG 0xa /* -c */
44 #define RBX_VERBOSE 0xb /* -v */
45 #define RBX_SERIAL 0xc /* -h */
46 #define RBX_CDROM 0xd /* -C */
47 #define RBX_GDB 0xf /* -g */
48 #define RBX_DUAL 0x1d /* -D */
49 #define RBX_PROBEKBD 0x1e /* -P */
51 #define RBX_MASK 0xffff
53 #define PATH_CONFIG "/boot.config"
54 #define PATH_BOOT3 "/boot/loader"
55 #define PATH_KERNEL "/kernel"
63 #define V86_CY(x) ((x) & 1)
64 #define V86_ZR(x) ((x) & 0x40)
76 static const char optstr[NOPT] = "DhaCcdgPrsv";
77 static const unsigned char flags[NOPT] = {
91 static const char *const dev_nm[] = {"wd", " ", "fd", " ", "da"};
103 static char cmd[512];
104 static char kname[1024];
105 static uint32_t opts;
106 static struct bootinfo bootinfo;
108 static uint32_t fs_off;
109 static uint8_t ioctrl = 0x1;
112 static void load(const char *);
113 static int parse(char *);
114 static void readfile(const char *, void *, size_t);
115 static ino_t lookup(const char *);
116 static int fsfind(const char *, ino_t *);
117 static int xfsread(ino_t, void *, size_t);
118 static ssize_t fsread(ino_t, void *, size_t);
119 static int dskread(void *, unsigned, unsigned);
120 static int printf(const char *,...);
121 static void getstr(char *, int);
122 static int putchar(int);
123 static int getchar(void);
124 static void *memcpy(void *, const void *, size_t);
125 static int strcmp(const char *, const char *);
126 static void *malloc(size_t);
127 static uint32_t memsize(int);
128 static uint32_t drvinfo(int);
129 static int drvread(void *, unsigned, unsigned);
130 static int keyhit(unsigned);
131 static int xputc(int);
132 static int xgetc(int);
133 static void putc(int);
134 static int getc(int);
142 dsk.drive = *(uint8_t *)PTOV(ARGS);
143 dsk.type = dsk.drive & DRV_HARD ? MAJ_WD : MAJ_FD;
144 dsk.unit = dsk.drive & DRV_MASK;
145 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
146 bootinfo.bi_version = BOOTINFO_VERSION;
147 bootinfo.bi_size = sizeof(bootinfo);
148 bootinfo.bi_basemem = memsize(MEM_BASE);
149 bootinfo.bi_extmem = memsize(MEM_EXT);
150 bootinfo.bi_memsizes_valid++;
151 for (i = 0; i < N_BIOS_GEOM; i++)
152 bootinfo.bi_bios_geom[i] = drvinfo(i);
154 readfile(PATH_CONFIG, cmd, sizeof(cmd));
156 printf("%s: %s", PATH_CONFIG, cmd);
161 if (autoboot && !*kname) {
163 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
170 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
173 printf(" \n>> FreeBSD/i386 BOOT\n"
174 "Default: %u:%s(%u,%c)%s\n"
176 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
177 'a' + dsk.part, kname);
180 if (!autoboot || keyhit(0x5a))
181 getstr(cmd, sizeof(cmd));
198 load(const char *fname)
211 if (!(ino = lookup(fname))) {
213 printf("No %s\n", fname);
216 if (xfsread(ino, &hdr, sizeof(hdr)))
218 if (N_GETMAGIC(hdr.ex) == ZMAGIC)
220 else if (IS_ELF(hdr.eh))
223 printf("Invalid %s\n", "format");
227 addr = hdr.ex.a_entry & 0xffffff;
230 if (xfsread(ino, p, hdr.ex.a_text))
232 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
233 if (xfsread(ino, p, hdr.ex.a_data))
235 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
236 bootinfo.bi_symtab = VTOP(p);
237 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
238 p += sizeof(hdr.ex.a_syms);
240 if (xfsread(ino, p, hdr.ex.a_syms))
243 if (xfsread(ino, p, sizeof(int)))
248 if (xfsread(ino, p, x))
253 fs_off = hdr.eh.e_phoff;
254 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
255 if (xfsread(ino, ep + j, sizeof(ep[0])))
257 if (ep[j].p_type == PT_LOAD)
260 for (i = 0; i < 2; i++) {
261 p = PTOV(ep[i].p_paddr & 0xffffff);
262 fs_off = ep[i].p_offset;
263 if (xfsread(ino, p, ep[i].p_filesz))
266 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
267 bootinfo.bi_symtab = VTOP(p);
268 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
269 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
270 (hdr.eh.e_shstrndx + 1);
271 if (xfsread(ino, &es, sizeof(es)))
273 for (i = 0; i < 2; i++) {
274 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
275 p += sizeof(es[i].sh_size);
276 fs_off = es[i].sh_offset;
277 if (xfsread(ino, p, es[i].sh_size))
282 addr = hdr.eh.e_entry & 0xffffff;
284 bootinfo.bi_esymtab = VTOP(p);
285 bootinfo.bi_kernelname = VTOP(fname);
286 bootinfo.bi_bios_dev = dsk.drive;
287 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
288 MAKEBOOTDEV(dsk.type, 0, dsk.slice, dsk.unit, dsk.part),
289 0, 0, 0, VTOP(&bootinfo));
298 while ((c = *arg++)) {
301 for (p = arg; *p && *p != '\n' && *p != ' '; p++);
305 while ((c = *arg++)) {
306 for (i = 0; c != optstr[i]; i++)
309 opts ^= 1 << flags[i];
311 if (opts & 1 << RBX_PROBEKBD) {
312 i = *(uint8_t *)PTOV(0x496) & 0x10;
313 printf("Keyboard: %s\n", i ? "yes" : "no");
315 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
316 opts &= ~(1 << RBX_PROBEKBD);
318 ioctrl = opts & 1 << RBX_DUAL ? 0x3 :
319 opts & 1 << RBX_SERIAL ? 0x2 : 0x1;
323 for (q = arg--; *q && *q != '('; q++);
327 if (*arg < '0' || *arg > '9')
334 for (i = 0; arg[0] != dev_nm[i][0] ||
335 arg[1] != dev_nm[i][1]; i++)
340 if (arg[1] != ',' || *arg < '0' || *arg > '9')
342 dsk.unit = *arg - '0';
344 dsk.slice = WHOLE_DISK_SLICE;
346 if (*arg < '0' || *arg > '0' + NDOSPART)
348 if ((dsk.slice = *arg - '0'))
352 if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
354 dsk.part = *arg - 'a';
358 dsk.drive = (dsk.type == MAJ_WD ||
359 dsk.type == MAJ_DA ? DRV_HARD : 0) + drv;
363 if ((i = p - arg - !*(p - 1))) {
364 if (i >= sizeof(kname))
366 memcpy(kname, arg, i + 1);
375 readfile(const char *fname, void *buf, size_t size)
379 if ((ino = lookup(fname)))
380 fsread(ino, buf, size);
384 lookup(const char *path)
386 char name[MAXNAMLEN + 1];
399 for (s = path; *s && *s != '/'; s++);
400 if ((n = s - path) > MAXNAMLEN)
402 ls = *path == '?' && n == 1 && !*s;
403 memcpy(name, path, n);
405 if ((dt = fsfind(name, &ino)) <= 0)
409 return dt == DT_REG ? ino : 0;
413 fsfind(const char *name, ino_t * ino)
421 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
422 for (s = buf; s < buf + DEV_BSIZE;) {
425 printf("%s ", d->d_name);
426 else if (!strcmp(name, d->d_name)) {
438 xfsread(ino_t inode, void *buf, size_t nbyte)
440 if (fsread(inode, buf, nbyte) != nbyte) {
441 printf("Invalid %s\n", "format");
448 fsread(ino_t inode, void *buf, size_t nbyte)
451 static struct dinode din;
453 static ufs_daddr_t *indbuf;
455 static ufs_daddr_t blkmap, indmap;
456 static unsigned fsblks;
458 ufs_daddr_t lbn, addr;
463 blkbuf = malloc(BSIZEMAX);
465 if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
467 memcpy(&fs, blkbuf, sizeof(fs));
468 if (fs.fs_magic != FS_MAGIC) {
472 fsblks = fs.fs_bsize >> DEV_BSHIFT;
477 if (inomap != inode) {
478 if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
481 din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
487 if (nbyte > (n = din.di_size - fs_off))
491 lbn = lblkno(&fs, fs_off);
493 addr = din.di_db[lbn];
495 if (indmap != din.di_ib[0]) {
497 indbuf = malloc(BSIZEMAX);
498 if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
501 indmap = din.di_ib[0];
503 addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
505 n = dblksize(&fs, &din, lbn);
506 if (blkmap != addr) {
507 if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT))
511 off = blkoff(&fs, fs_off);
515 memcpy(s, blkbuf + off, n);
524 dskread(void *buf, unsigned lba, unsigned nblk)
527 struct dos_partition *dp;
533 sec = malloc(DEV_BSIZE);
535 if (drvread(sec, DOSBBSECTOR, 1))
537 dp = (void *)(sec + DOSPARTOFF);
539 if (sl < BASE_SLICE) {
540 for (i = 0; i < NDOSPART; i++)
541 if (dp[i].dp_typ == DOSPTYP_386BSD &&
542 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
544 if (dp[i].dp_flag & 0x80 ||
545 dsk.slice == COMPATIBILITY_SLICE)
548 if (dsk.slice == WHOLE_DISK_SLICE)
551 if (sl != WHOLE_DISK_SLICE) {
552 if (sl != COMPATIBILITY_SLICE)
553 dp += sl - BASE_SLICE;
554 if (dp->dp_typ != DOSPTYP_386BSD) {
555 printf("Invalid %s\n", "slice");
558 dsk.start = dp->dp_start;
560 if (drvread(sec, dsk.start + LABELSECTOR, 1))
562 d = (void *)(sec + LABELOFFSET);
563 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
564 if (dsk.part != RAW_PART) {
565 printf("Invalid %s\n", "label");
570 if (d->d_type == DTYPE_SCSI)
574 if (dsk.part >= d->d_npartitions ||
575 !d->d_partitions[dsk.part].p_size) {
576 printf("Invalid %s\n", "partition");
579 dsk.start = d->d_partitions[dsk.part].p_offset;
582 return drvread(buf, dsk.start + lba, nblk);
586 printf(const char *fmt,...)
588 static const char digits[16] = "0123456789abcdef";
596 while ((c = *fmt++)) {
601 putchar(va_arg(ap, int));
604 for (s = va_arg(ap, char *); *s; s++)
609 r = c == 'u' ? 10U : 16U;
610 u = va_arg(ap, unsigned);
613 *s++ = digits[u % r];
627 getstr(char *str, int size)
634 switch (c = getchar()) {
650 if (s - str < size - 1)
678 memcpy(void *dst, const void *src, size_t size)
683 for (d = dst, s = src; size; size--)
689 strcmp(const char *s1, const char *s2)
691 for (; *s1 == *s2 && *s1; s1++, s2++);
692 return (u_char)*s1 - (u_char)*s2;
698 static uint32_t next;
702 next = roundup2(__base + _end, 0x10000) - __base;
722 v86.edx = DRV_HARD + drive;
726 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
727 (v86.edx & 0xff00) | (v86.ecx & 0x3f);
731 drvread(void *buf, unsigned lba, unsigned nblk)
733 static unsigned c = 0x2d5c7c2f;
735 printf("%c\b", c = c << 8 | c >> 24);
736 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
737 v86.addr = 0x704; /* call to xread in boot1 */
738 v86.es = VTOPSEG(buf);
740 v86.ebx = VTOPOFF(buf);
742 v86.edx = nblk << 8 | dsk.drive;
745 if (V86_CY(v86.efl)) {
746 printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff,
754 keyhit(unsigned ticks)
762 t1 = *(uint32_t *)PTOV(0x46c);
765 if (t1 < t0 || t1 >= t0 + ticks)
784 if (ioctrl & 0x1 && getc(1))
785 return fn ? 1 : getc(0);
786 if (ioctrl & 0x2 && sio_ischar())
787 return fn ? 1 : sio_getc();
797 v86.eax = 0xe00 | (c & 0xff);
808 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);