Index: head/sys/boot/arm/at91/boot2/boot2.c =================================================================== --- head/sys/boot/arm/at91/boot2/boot2.c (revision 294765) +++ head/sys/boot/arm/at91/boot2/boot2.c (revision 294766) @@ -1,396 +1,361 @@ /*- * Copyright (c) 2008 John Hay * Copyright (c) 2006 M Warner Losh * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "lib.h" #include "board.h" #include "paths.h" +#include "rbx.h" -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -/* #define RBX_KDB 0x6 -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -/* #define RBX_SERIAL 0xc -h */ -/* #define RBX_CDROM 0xd -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -/* #define RBX_MUTE 0x10 -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -/* #define RBX_PAUSE 0x14 -p */ -/* #define RBX_QUIET 0x15 -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -/* #define RBX_DUAL 0x1d -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -v, -g */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | \ - OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_GDB)) - #undef PATH_KERNEL #define PATH_KERNEL "/boot/kernel/kernel.gz.tramp" extern uint32_t _end; #define NOPT 6 - -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) static const char optstr[NOPT] = "agnrsv"; static const unsigned char bootflags[NOPT] = { RBX_ASKNAME, RBX_GDB, RBX_NOINTR, RBX_DFLTROOT, RBX_SINGLE, RBX_VERBOSE }; unsigned board_id; /* board type to pass to kernel, if set by board_* code */ unsigned dsk_start; static char cmd[512]; static char kname[1024]; static uint32_t opts; static uint8_t dsk_meta; int main(void); static void load(void); static int parse(void); static int dskread(void *, unsigned, unsigned); #ifdef FIXUP_BOOT_DRV static void fixup_boot_drv(caddr_t, int, int, int); #endif #define UFS_SMALL_CGBASE #include "ufsread.c" #ifdef DEBUG #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__) #else #define DPRINTF(fmt, ...) #endif static inline int xfsread(ufs_ino_t inode, void *buf, size_t nbyte) { if ((size_t)fsread(inode, buf, nbyte) != nbyte) return -1; return 0; } static inline void getstr(int c) { char *s; s = cmd; if (c == 0) c = getc(10000); for (;;) { switch (c) { case 0: break; case '\177': case '\b': if (s > cmd) { s--; printf("\b \b"); } break; case '\n': case '\r': *s = 0; return; default: if (s - cmd < sizeof(cmd) - 1) *s++ = c; xputchar(c); } c = getc(10000); } } int main(void) { int autoboot, c = 0; ufs_ino_t ino; dmadat = (void *)(0x20000000 + (16 << 20)); board_init(); autoboot = 1; /* Process configuration file */ if ((ino = lookup(PATH_CONFIG)) || (ino = lookup(PATH_DOTCONFIG))) fsread(ino, cmd, sizeof(cmd)); if (*cmd) { if (parse()) autoboot = 0; printf("%s: %s\n", PATH_CONFIG, cmd); /* Do not process this command twice */ *cmd = 0; } if (*kname == '\0') strcpy(kname, PATH_KERNEL); /* Present the user with the boot2 prompt. */ for (;;) { printf("\nDefault: %s\nboot: ", kname); if (!autoboot || (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0)) getstr(c); xputchar('\n'); autoboot = 0; c = 0; if (parse()) xputchar('\a'); else load(); } return (1); } static void load(void) { Elf32_Ehdr eh; static Elf32_Phdr ep[2]; caddr_t p; ufs_ino_t ino; uint32_t addr; int i, j; #ifdef FIXUP_BOOT_DRV caddr_t staddr; int klen; staddr = (caddr_t)0xffffffff; klen = 0; #endif if (!(ino = lookup(kname))) { if (!ls) printf("No %s\n", kname); return; } if (xfsread(ino, &eh, sizeof(eh))) return; if (!IS_ELF(eh)) { printf("Invalid %s\n", "format"); return; } fs_off = eh.e_phoff; for (j = i = 0; i < eh.e_phnum && j < 2; i++) { if (xfsread(ino, ep + j, sizeof(ep[0]))) return; if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = (caddr_t)ep[i].p_paddr; fs_off = ep[i].p_offset; #ifdef FIXUP_BOOT_DRV if (staddr == (caddr_t)0xffffffff) staddr = p; klen += ep[i].p_filesz; #endif if (xfsread(ino, p, ep[i].p_filesz)) return; } addr = eh.e_entry; #ifdef FIXUP_BOOT_DRV fixup_boot_drv(staddr, klen, bootslice, bootpart); #endif ((void(*)(int, int, int, int))addr)(opts & RBX_MASK, board_id, 0, 0); } static int parse() { char *arg = cmd; char *ep, *p; int c, i; while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); ep = p; if (*p) *p++ = 0; if (c == '-') { while ((c = *arg++)) { for (i = 0; c != optstr[i]; i++) if (i == NOPT - 1) return -1; opts ^= OPT_SET(bootflags[i]); } } else { arg--; if ((i = ep - arg)) { if ((size_t)i >= sizeof(kname)) return -1; memcpy(kname, arg, i + 1); } } arg = p; } return 0; } static int dskread(void *buf, unsigned lba, unsigned nblk) { struct dos_partition *dp; struct disklabel *d; char *sec; int i; if (!dsk_meta) { sec = dmadat->secbuf; dsk_start = 0; if (drvread(sec, DOSBBSECTOR, 1)) return -1; dp = (void *)(sec + DOSPARTOFF); for (i = 0; i < NDOSPART; i++) { if (dp[i].dp_typ == DOSPTYP_386BSD) break; } if (i == NDOSPART) return -1; /* * Although dp_start is aligned within the disk * partition structure, DOSPARTOFF is 446, which is * only word (2) aligned, not longword (4) aligned. * Cope by using memcpy to fetch the start of this * partition. */ memcpy(&dsk_start, &dp[1].dp_start, 4); if (drvread(sec, dsk_start + LABELSECTOR, 1)) return -1; d = (void *)(sec + LABELOFFSET); if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { printf("Invalid %s\n", "label"); return -1; } if (!d->d_partitions[0].p_size) { printf("Invalid %s\n", "partition"); return -1; } dsk_start += d->d_partitions[0].p_offset; dsk_start -= d->d_partitions[RAW_PART].p_offset; dsk_meta++; } return drvread(buf, dsk_start + lba, nblk); } #ifdef FIXUP_BOOT_DRV /* * fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel * and change it to what was specified on the comandline or /boot.conf * file or to what was encountered on the disk. It will try to handle 3 * different disk layouts, raw (dangerously dedicated), slice only and * slice + partition. It will look for the following strings in the * kernel, but if it is one of the first three, the string in the kernel * must use the correct form to match the actual disk layout: * - ufs:ad0a * - ufs:ad0s1 * - ufs:ad0s1a * - ufs:ROOTDEVNAME * In the case of the first three strings, only the "a" at the end and * the "1" after the "s" will be modified, if they exist. The string * length will not be changed. In the case of the last string, the * whole string will be built up and nul, '\0' terminated. */ static void fixup_boot_drv(caddr_t addr, int klen, int bs, int bp) { const u_int8_t op[] = "ufs:ROOTDEVNAME"; const u_int8_t op2[] = "ufs:ad0"; u_int8_t *p, *ps; DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n", (int)addr, klen, bs, bp); if (bs > 4) return; if (bp > 7) return; ps = memmem(addr, klen, op, sizeof(op)); if (ps != NULL) { p = ps + 4; /* past ufs: */ DPRINTF("Found it at 0x%x\n", (int)ps); p[0] = 'a'; p[1] = 'd'; p[2] = '0'; /* ad0 */ p += 3; if (bs > 0) { /* append slice */ *p++ = 's'; *p++ = bs + '0'; } if (disk_layout != DL_SLICE) { /* append partition */ *p++ = bp + 'a'; } *p = '\0'; } else { ps = memmem(addr, klen, op2, sizeof(op2) - 1); if (ps != NULL) { p = ps + sizeof(op2) - 1; DPRINTF("Found it at 0x%x\n", (int)ps); if (*p == 's') { /* fix slice */ p++; *p++ = bs + '0'; } if (*p == 'a') *p = bp + 'a'; } } if (ps == NULL) { printf("Could not locate \"%s\" to fix kernel boot device, " "check ROOTDEVNAME is set\n", op); return; } DPRINTF("Changed boot device to %s\n", ps); } #endif Index: head/sys/boot/arm/ixp425/boot2/boot2.c =================================================================== --- head/sys/boot/arm/ixp425/boot2/boot2.c (revision 294765) +++ head/sys/boot/arm/ixp425/boot2/boot2.c (revision 294766) @@ -1,481 +1,446 @@ /*- * Copyright (c) 2008 John Hay * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "lib.h" #include "paths.h" +#include "rbx.h" -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -/* #define RBX_KDB 0x6 -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -/* #define RBX_SERIAL 0xc -h */ -/* #define RBX_CDROM 0xd -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -/* #define RBX_MUTE 0x10 -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -/* #define RBX_PAUSE 0x14 -p */ -/* #define RBX_QUIET 0x15 -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -/* #define RBX_DUAL 0x1d -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -v, -g */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | \ - OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_GDB)) - extern uint32_t _end; #define NOPT 6 - -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) static const char optstr[NOPT] = "agnrsv"; static const unsigned char flags[NOPT] = { RBX_ASKNAME, RBX_GDB, RBX_NOINTR, RBX_DFLTROOT, RBX_SINGLE, RBX_VERBOSE }; static unsigned dsk_start; static char cmd[512]; static char kname[1024]; static uint32_t opts; static uint8_t dsk_meta; static int bootslice; static int bootpart; static int disk_layout; #define DL_UNKNOWN 0 #define DL_RAW 1 /* Dangerously dedicated */ #define DL_SLICE 2 /* Use only slices (DOS partitions) */ #define DL_SLICEPART 3 /* Use slices and partitions */ static void load(void); static int parse(void); static int dskread(void *, unsigned, unsigned); static int drvread(void *, unsigned, unsigned); #ifdef FIXUP_BOOT_DRV static void fixup_boot_drv(caddr_t, int, int, int); #endif #include "ufsread.c" #ifdef DEBUG #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__) #else #define DPRINTF(fmt, ...) #endif static inline int xfsread(ufs_ino_t inode, void *buf, size_t nbyte) { if ((size_t)fsread(inode, buf, nbyte) != nbyte) return -1; return 0; } static inline void getstr(int c) { char *s; s = cmd; if (c == 0) c = getc(10000); for (;;) { switch (c) { case 0: break; case '\177': case '\b': if (s > cmd) { s--; printf("\b \b"); } break; case '\n': case '\r': *s = 0; return; default: if (s - cmd < sizeof(cmd) - 1) *s++ = c; xputchar(c); } c = getc(10000); } } int main(void) { const char *bt; int autoboot, c = 0; ufs_ino_t ino; dmadat = (void *)(0x1c0000); p_memset((char *)dmadat, 0, 32 * 1024); bt = board_init(); printf("FreeBSD ARM (%s) boot2 v%d.%d\n", bt, 0, 4); autoboot = 1; /* Process configuration file */ if ((ino = lookup(PATH_CONFIG)) || (ino = lookup(PATH_DOTCONFIG))) fsread(ino, cmd, sizeof(cmd)); if (*cmd) { if (parse()) autoboot = 0; printf("%s: %s\n", PATH_CONFIG, cmd); /* Do not process this command twice */ *cmd = 0; } if (*kname == '\0') strcpy(kname, PATH_KERNEL); /* Present the user with the boot2 prompt. */ for (;;) { printf("\nDefault: %s\nboot: ", kname); if (!autoboot || (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0)) getstr(c); xputchar('\n'); autoboot = 0; c = 0; DPRINTF("cmd is '%s'\n", cmd); if (parse()) xputchar('\a'); else load(); } } static void load(void) { Elf32_Ehdr eh; static Elf32_Phdr ep[2]; caddr_t p; ufs_ino_t ino; uint32_t addr; int i, j; #ifdef FIXUP_BOOT_DRV caddr_t staddr; int klen; staddr = (caddr_t)0xffffffff; klen = 0; #endif if (!(ino = lookup(kname))) { if (!ls) printf("No %s\n", kname); return; } DPRINTF("Found %s\n", kname); if (xfsread(ino, &eh, sizeof(eh))) return; if (!IS_ELF(eh)) { printf("Invalid %s\n", "format"); return; } fs_off = eh.e_phoff; for (j = i = 0; i < eh.e_phnum && j < 2; i++) { if (xfsread(ino, ep + j, sizeof(ep[0]))) return; if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = (caddr_t)(ep[i].p_paddr & 0x0fffffff); fs_off = ep[i].p_offset; #ifdef FIXUP_BOOT_DRV if (staddr == (caddr_t)0xffffffff) staddr = p; klen += ep[i].p_filesz; #endif if (xfsread(ino, p, ep[i].p_filesz)) return; } addr = eh.e_entry & 0x0fffffff; DPRINTF("Entry point %x for %s\n", addr, kname); clr_board(); #ifdef FIXUP_BOOT_DRV fixup_boot_drv(staddr, klen, bootslice, bootpart); #endif ((void(*)(int))addr)(RB_BOOTINFO /* XXX | (opts & RBX_MASK) */); } static int parse() { char *arg = cmd; char *ep, *p; int c, i; while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); ep = p; if (*p) *p++ = 0; if (c == '-') { while ((c = *arg++)) { for (i = 0; c != optstr[i]; i++) if (i == NOPT - 1) return -1; opts ^= OPT_SET(flags[i]); } } else { arg--; /* look for ad0s1a:... | ad0s1:... */ if (strlen(arg) > 6 && arg[0] == 'a' && arg[1] == 'd' && arg[3] == 's' && (arg[5] == ':' || arg[6] == ':')) { /* XXX Should also handle disk. */ bootslice = arg[4] - '0'; if (bootslice < 1 || bootslice > 4) return (-1); bootpart = 0; if (arg[5] != ':') bootpart = arg[5] - 'a'; if (bootpart < 0 || bootpart > 7) return (-1); dsk_meta = 0; if (arg[5] == ':') arg += 6; else arg += 7; /* look for ad0a:... */ } else if (strlen(arg) > 4 && arg[0] == 'a' && arg[1] == 'd' && arg[2] == '0' && arg[4] == ':') { bootslice = 0; bootpart = arg[3] - 'a'; if (bootpart < 0 || bootpart > 7) return (-1); dsk_meta = 0; arg += 5; } if ((i = ep - arg)) { if ((size_t)i >= sizeof(kname)) return -1; memcpy(kname, arg, i + 1); } } arg = p; } return 0; } /* * dskread() will try to handle the disk layouts that are typically * encountered. * - raw or "Dangerously Dedicated" mode. No real slice table, just the * default one that is included with bsdlabel -B. Typically this is * used with ROOTDEVNAME=\"ufs:ad0a\". * - slice only. Only a slice table is installed with no bsd label or * bsd partition table. This is typically used with * ROOTDEVNAME=\"ufs:ad0s1\". * - slice + bsd label + partition table. This is typically done with * with fdisk + bsdlabel and is used with ROOTDEVNAME=\"ufs:ad0s1a\". */ static int dskread(void *buf, unsigned lba, unsigned nblk) { struct dos_partition *dp; struct disklabel *d; char *sec; int i; if (!dsk_meta) { sec = dmadat->secbuf; dsk_start = 0; if (drvread(sec, DOSBBSECTOR, 1)) return -1; dp = (void *)(sec + DOSPARTOFF); if (bootslice != 0) { i = bootslice - 1; if (dp[i].dp_typ != DOSPTYP_386BSD) return -1; } else { for (i = 0; i < NDOSPART; i++) { if ((dp[i].dp_typ == DOSPTYP_386BSD) && (dp[i].dp_flag == 0x80)) break; } } if (i != NDOSPART) { bootslice = i + 1; DPRINTF("Found an active fbsd slice. (%d)\n", i + 1); /* * Although dp_start is aligned within the disk * partition structure, DOSPARTOFF is 446, which * is only word (2) aligned, not longword (4) * aligned. Cope by using memcpy to fetch the * start of this partition. */ memcpy(&dsk_start, &dp[i].dp_start, 4); dsk_start = swap32(dsk_start); DPRINTF("dsk_start %x\n", dsk_start); if ((bootslice == 4) && (dsk_start == 0)) { disk_layout = DL_RAW; bootslice = 0; } } if (drvread(sec, dsk_start + LABELSECTOR, 1)) return -1; d = (void *)(sec + LABELOFFSET); if ((d->d_magic == DISKMAGIC && d->d_magic2 == DISKMAGIC) || (swap32(d->d_magic) == DISKMAGIC && swap32(d->d_magic2) == DISKMAGIC)) { DPRINTF("p_size = %x\n", !d->d_partitions[bootpart].p_size); if (!d->d_partitions[bootpart].p_size) { printf("Invalid partition\n"); return -1; } DPRINTF("p_offset %x, RAW %x\n", swap32(d->d_partitions[bootpart].p_offset), swap32(d->d_partitions[RAW_PART].p_offset)); dsk_start += swap32(d->d_partitions[bootpart].p_offset); dsk_start -= swap32(d->d_partitions[RAW_PART].p_offset); if ((disk_layout == DL_UNKNOWN) && (bootslice == 0)) disk_layout = DL_RAW; else if (disk_layout == DL_UNKNOWN) disk_layout = DL_SLICEPART; } else { disk_layout = DL_SLICE; DPRINTF("Invalid %s\n", "label"); } DPRINTF("bootslice %d, bootpart %d, dsk_start %u\n", bootslice, bootpart, dsk_start); dsk_meta++; } return drvread(buf, dsk_start + lba, nblk); } static int drvread(void *buf, unsigned lba, unsigned nblk) { static unsigned c = 0x2d5c7c2f; printf("%c\b", c = c << 8 | c >> 24); return (avila_read((char *)buf, lba, nblk)); } #ifdef FIXUP_BOOT_DRV /* * fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel * and change it to what was specified on the comandline or /boot.conf * file or to what was encountered on the disk. It will try to handle 3 * different disk layouts, raw (dangerously dedicated), slice only and * slice + partition. It will look for the following strings in the * kernel, but if it is one of the first three, the string in the kernel * must use the correct form to match the actual disk layout: * - ufs:ad0a * - ufs:ad0s1 * - ufs:ad0s1a * - ufs:ROOTDEVNAME * In the case of the first three strings, only the "a" at the end and * the "1" after the "s" will be modified, if they exist. The string * length will not be changed. In the case of the last string, the * whole string will be built up and nul, '\0' terminated. */ static void fixup_boot_drv(caddr_t addr, int klen, int bs, int bp) { const u_int8_t op[] = "ufs:ROOTDEVNAME"; const u_int8_t op2[] = "ufs:ad0"; u_int8_t *p, *ps; DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n", (int)addr, klen, bs, bp); if (bs > 4) return; if (bp > 7) return; ps = memmem(addr, klen, op, sizeof(op)); if (ps != NULL) { p = ps + 4; /* past ufs: */ DPRINTF("Found it at 0x%x\n", (int)ps); p[0] = 'a'; p[1] = 'd'; p[2] = '0'; /* ad0 */ p += 3; if (bs > 0) { /* append slice */ *p++ = 's'; *p++ = bs + '0'; } if (disk_layout != DL_SLICE) { /* append partition */ *p++ = bp + 'a'; } *p = '\0'; } else { ps = memmem(addr, klen, op2, sizeof(op2) - 1); if (ps != NULL) { p = ps + sizeof(op2) - 1; DPRINTF("Found it at 0x%x\n", (int)ps); if (*p == 's') { /* fix slice */ p++; *p++ = bs + '0'; } if (*p == 'a') *p = bp + 'a'; } } if (ps == NULL) { printf("Could not locate \"%s\" to fix kernel boot device, " "check ROOTDEVNAME is set\n", op); return; } DPRINTF("Changed boot device to %s\n", ps); } #endif Index: head/sys/boot/common/rbx.h =================================================================== --- head/sys/boot/common/rbx.h (nonexistent) +++ head/sys/boot/common/rbx.h (revision 294766) @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#ifndef _RBX_H_ +#define _RBX_H_ + +#define RBX_ASKNAME 0x0 /* -a */ +#define RBX_SINGLE 0x1 /* -s */ +/* 0x2 is reserved for log2(RB_NOSYNC). */ +/* 0x3 is reserved for log2(RB_HALT). */ +/* 0x4 is reserved for log2(RB_INITNAME). */ +#define RBX_DFLTROOT 0x5 /* -r */ +#define RBX_KDB 0x6 /* -d */ +/* 0x7 is reserved for log2(RB_RDONLY). */ +/* 0x8 is reserved for log2(RB_DUMP). */ +/* 0x9 is reserved for log2(RB_MINIROOT). */ +#define RBX_CONFIG 0xa /* -c */ +#define RBX_VERBOSE 0xb /* -v */ +#define RBX_SERIAL 0xc /* -h */ +#define RBX_CDROM 0xd /* -C */ +/* 0xe is reserved for log2(RB_POWEROFF). */ +#define RBX_GDB 0xf /* -g */ +#define RBX_MUTE 0x10 /* -m */ +/* 0x11 is reserved for log2(RB_SELFTEST). */ +/* 0x12 is reserved for boot programs. */ +/* 0x13 is reserved for boot programs. */ +#define RBX_PAUSE 0x14 /* -p */ +#define RBX_QUIET 0x15 /* -q */ +#define RBX_NOINTR 0x1c /* -n */ +/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ +#define RBX_DUAL 0x1d /* -D */ +/* 0x1f is reserved for log2(RB_BOOTINFO). */ + +/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ +#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ + OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ + OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ + OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ + OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ + OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) + +#define OPT_SET(opt) (1 << (opt)) +#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) + +extern uint32_t opts; + +#endif /* !_RBX_H_ */ Property changes on: head/sys/boot/common/rbx.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/i386/boot2/boot2.c =================================================================== --- head/sys/boot/i386/boot2/boot2.c (revision 294765) +++ head/sys/boot/i386/boot2/boot2.c (revision 294766) @@ -1,683 +1,646 @@ /*- * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "boot2.h" #include "lib.h" #include "paths.h" +#include "rbx.h" /* Define to 0 to omit serial support */ #ifndef SERIAL #define SERIAL 1 #endif #define IO_KEYBOARD 1 #define IO_SERIAL 2 #if SERIAL #define DO_KBD (ioctrl & IO_KEYBOARD) #define DO_SIO (ioctrl & IO_SERIAL) #else #define DO_KBD (1) #define DO_SIO (0) #endif #define SECOND 18 /* Circa that many ticks in a second. */ -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) - #define ARGS 0x900 #define NOPT 14 #define NDEV 3 #define MEM_BASE 0x12 #define MEM_EXT 0x15 #define DRV_HARD 0x80 #define DRV_MASK 0x7f #define TYPE_AD 0 #define TYPE_DA 1 #define TYPE_MAXHARD TYPE_DA #define TYPE_FD 2 -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - extern uint32_t _end; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ static const unsigned char flags[NOPT] = { RBX_DUAL, RBX_SERIAL, RBX_ASKNAME, RBX_CDROM, RBX_CONFIG, RBX_KDB, RBX_GDB, RBX_MUTE, RBX_NOINTR, RBX_PAUSE, RBX_QUIET, RBX_DFLTROOT, RBX_SINGLE, RBX_VERBOSE }; static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; static struct dsk { unsigned drive; unsigned type; unsigned unit; uint8_t slice; uint8_t part; unsigned start; int init; } dsk; static char cmd[512], cmddup[512], knamebuf[1024]; static const char *kname; -static uint32_t opts; +uint32_t opts; static struct bootinfo bootinfo; #if SERIAL static int comspeed = SIOSPD; static uint8_t ioctrl = IO_KEYBOARD; #endif int main(void); void exit(int); static void load(void); static int parse(void); static int dskread(void *, unsigned, unsigned); static void printf(const char *,...); static void putchar(int); static int drvread(void *, unsigned, unsigned); static int keyhit(unsigned); static int xputc(int); static int xgetc(int); static inline int getc(int); static void memcpy(void *, const void *, int); static void memcpy(void *dst, const void *src, int len) { const char *s = src; char *d = dst; while (len--) *d++ = *s++; } static inline int strcmp(const char *s1, const char *s2) { for (; *s1 == *s2 && *s1; s1++, s2++); return (unsigned char)*s1 - (unsigned char)*s2; } #define UFS_SMALL_CGBASE #include "ufsread.c" static inline int xfsread(ufs_ino_t inode, void *buf, size_t nbyte) { if ((size_t)fsread(inode, buf, nbyte) != nbyte) { printf("Invalid %s\n", "format"); return -1; } return 0; } static inline void getstr(void) { char *s; int c; s = cmd; for (;;) { switch (c = xgetc(0)) { case 0: break; case '\177': case '\b': if (s > cmd) { s--; printf("\b \b"); } break; case '\n': case '\r': *s = 0; return; default: if (s - cmd < sizeof(cmd) - 1) *s++ = c; putchar(c); } } } static inline void putc(int c) { v86.addr = 0x10; v86.eax = 0xe00 | (c & 0xff); v86.ebx = 0x7; v86int(); } int main(void) { uint8_t autoboot; ufs_ino_t ino; size_t nbyte; dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); v86.ctl = V86_FLAGS; v86.efl = PSL_RESERVED_DEFAULT | PSL_I; dsk.drive = *(uint8_t *)PTOV(ARGS); dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; dsk.unit = dsk.drive & DRV_MASK; dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_size = sizeof(bootinfo); /* Process configuration file */ autoboot = 1; if ((ino = lookup(PATH_CONFIG)) || (ino = lookup(PATH_DOTCONFIG))) { nbyte = fsread(ino, cmd, sizeof(cmd) - 1); cmd[nbyte] = '\0'; } if (*cmd) { memcpy(cmddup, cmd, sizeof(cmd)); if (parse()) autoboot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmddup); /* Do not process this command twice */ *cmd = 0; } /* * Try to exec stage 3 boot loader. If interrupted by a keypress, * or in case of failure, try to load a kernel directly instead. */ if (!kname) { kname = PATH_BOOT3; if (autoboot && !keyhit(3*SECOND)) { load(); kname = PATH_KERNEL; } } /* Present the user with the boot2 prompt. */ for (;;) { if (!autoboot || !OPT_CHECK(RBX_QUIET)) printf("\nFreeBSD/x86 boot\n" "Default: %u:%s(%u,%c)%s\n" "boot: ", dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 'a' + dsk.part, kname); if (DO_SIO) sio_flush(); if (!autoboot || keyhit(3*SECOND)) getstr(); else if (!autoboot || !OPT_CHECK(RBX_QUIET)) putchar('\n'); autoboot = 0; if (parse()) putchar('\a'); else load(); } } /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ void exit(int x) { } static void load(void) { union { struct exec ex; Elf32_Ehdr eh; } hdr; static Elf32_Phdr ep[2]; static Elf32_Shdr es[2]; caddr_t p; ufs_ino_t ino; uint32_t addr; int k; uint8_t i, j; if (!(ino = lookup(kname))) { if (!ls) printf("No %s\n", kname); return; } if (xfsread(ino, &hdr, sizeof(hdr))) return; if (N_GETMAGIC(hdr.ex) == ZMAGIC) { addr = hdr.ex.a_entry & 0xffffff; p = PTOV(addr); fs_off = PAGE_SIZE; if (xfsread(ino, p, hdr.ex.a_text)) return; p += roundup2(hdr.ex.a_text, PAGE_SIZE); if (xfsread(ino, p, hdr.ex.a_data)) return; } else if (IS_ELF(hdr.eh)) { fs_off = hdr.eh.e_phoff; for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) { if (xfsread(ino, ep + j, sizeof(ep[0]))) return; if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = PTOV(ep[i].p_paddr & 0xffffff); fs_off = ep[i].p_offset; if (xfsread(ino, p, ep[i].p_filesz)) return; } p += roundup2(ep[1].p_memsz, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { fs_off = hdr.eh.e_shoff + sizeof(es[0]) * (hdr.eh.e_shstrndx + 1); if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { *(Elf32_Word *)p = es[i].sh_size; p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) return; p += es[i].sh_size; } } addr = hdr.eh.e_entry & 0xffffff; bootinfo.bi_esymtab = VTOP(p); } else { printf("Invalid %s\n", "format"); return; } bootinfo.bi_kernelname = VTOP(kname); bootinfo.bi_bios_dev = dsk.drive; __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 0, 0, 0, VTOP(&bootinfo)); } static int parse() { char *arg = cmd; char *ep, *p, *q; const char *cp; unsigned int drv; int c, i, j; size_t k; while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); ep = p; if (*p) *p++ = 0; if (c == '-') { while ((c = *arg++)) { if (c == 'P') { if (*(uint8_t *)PTOV(0x496) & 0x10) { cp = "yes"; } else { opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); cp = "no"; } printf("Keyboard: %s\n", cp); continue; #if SERIAL } else if (c == 'S') { j = 0; while ((unsigned int)(i = *arg++ - '0') <= 9) j = j * 10 + i; if (j > 0 && i == -'0') { comspeed = j; break; } /* Fall through to error below ('S' not in optstr[]). */ #endif } for (i = 0; c != optstr[i]; i++) if (i == NOPT - 1) return -1; opts ^= OPT_SET(flags[i]); } #if SERIAL ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; if (DO_SIO) { if (sio_init(115200 / comspeed) != 0) ioctrl &= ~IO_SERIAL; } #endif } else { for (q = arg--; *q && *q != '('; q++); if (*q) { drv = -1; if (arg[1] == ':') { drv = *arg - '0'; if (drv > 9) return (-1); arg += 2; } if (q - arg != 2) return -1; for (i = 0; arg[0] != dev_nm[i][0] || arg[1] != dev_nm[i][1]; i++) if (i == NDEV - 1) return -1; dsk.type = i; arg += 3; dsk.unit = *arg - '0'; if (arg[1] != ',' || dsk.unit > 9) return -1; arg += 2; dsk.slice = WHOLE_DISK_SLICE; if (arg[1] == ',') { dsk.slice = *arg - '0' + 1; if (dsk.slice > NDOSPART + 1) return -1; arg += 2; } if (arg[1] != ')') return -1; dsk.part = *arg - 'a'; if (dsk.part > 7) return (-1); arg += 2; if (drv == -1) drv = dsk.unit; dsk.drive = (dsk.type <= TYPE_MAXHARD ? DRV_HARD : 0) + drv; dsk_meta = 0; } k = ep - arg; if (k > 0) { if (k >= sizeof(knamebuf)) return -1; memcpy(knamebuf, arg, k + 1); kname = knamebuf; } } arg = p; } return 0; } static int dskread(void *buf, unsigned lba, unsigned nblk) { struct dos_partition *dp; struct disklabel *d; char *sec; unsigned i; uint8_t sl; const char *reason; if (!dsk_meta) { sec = dmadat->secbuf; dsk.start = 0; if (drvread(sec, DOSBBSECTOR, 1)) return -1; dp = (void *)(sec + DOSPARTOFF); sl = dsk.slice; if (sl < BASE_SLICE) { for (i = 0; i < NDOSPART; i++) if (dp[i].dp_typ == DOSPTYP_386BSD && (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { sl = BASE_SLICE + i; if (dp[i].dp_flag & 0x80 || dsk.slice == COMPATIBILITY_SLICE) break; } if (dsk.slice == WHOLE_DISK_SLICE) dsk.slice = sl; } if (sl != WHOLE_DISK_SLICE) { if (sl != COMPATIBILITY_SLICE) dp += sl - BASE_SLICE; if (dp->dp_typ != DOSPTYP_386BSD) { reason = "slice"; goto error; } dsk.start = dp->dp_start; } if (drvread(sec, dsk.start + LABELSECTOR, 1)) return -1; d = (void *)(sec + LABELOFFSET); if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { if (dsk.part != RAW_PART) { reason = "label"; goto error; } } else { if (!dsk.init) { if (d->d_type == DTYPE_SCSI) dsk.type = TYPE_DA; dsk.init++; } if (dsk.part >= d->d_npartitions || !d->d_partitions[dsk.part].p_size) { reason = "partition"; goto error; } dsk.start += d->d_partitions[dsk.part].p_offset; dsk.start -= d->d_partitions[RAW_PART].p_offset; } } return drvread(buf, dsk.start + lba, nblk); error: printf("Invalid %s\n", reason); return -1; } static void printf(const char *fmt,...) { va_list ap; static char buf[10]; char *s; unsigned u; int c; va_start(ap, fmt); while ((c = *fmt++)) { if (c == '%') { c = *fmt++; switch (c) { case 'c': putchar(va_arg(ap, int)); continue; case 's': for (s = va_arg(ap, char *); *s; s++) putchar(*s); continue; case 'u': u = va_arg(ap, unsigned); s = buf; do *s++ = '0' + u % 10U; while (u /= 10U); while (--s >= buf) putchar(*s); continue; } } putchar(c); } va_end(ap); return; } static void putchar(int c) { if (c == '\n') xputc('\r'); xputc(c); } static int drvread(void *buf, unsigned lba, unsigned nblk) { static unsigned c = 0x2d5c7c2f; if (!OPT_CHECK(RBX_QUIET)) { xputc(c = c << 8 | c >> 24); xputc('\b'); } v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.addr = XREADORG; /* call to xread in boot1 */ v86.es = VTOPSEG(buf); v86.eax = lba; v86.ebx = VTOPOFF(buf); v86.ecx = lba >> 16; v86.edx = nblk << 8 | dsk.drive; v86int(); v86.ctl = V86_FLAGS; if (V86_CY(v86.efl)) { printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); return -1; } return 0; } static int keyhit(unsigned ticks) { uint32_t t0, t1; if (OPT_CHECK(RBX_NOINTR)) return 0; t0 = 0; for (;;) { if (xgetc(1)) return 1; t1 = *(uint32_t *)PTOV(0x46c); if (!t0) t0 = t1; if ((uint32_t)(t1 - t0) >= ticks) return 0; } } static int xputc(int c) { if (DO_KBD) putc(c); if (DO_SIO) sio_putc(c); return c; } static int getc(int fn) { v86.addr = 0x16; v86.eax = fn << 8; v86int(); return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); } static int xgetc(int fn) { if (OPT_CHECK(RBX_NOINTR)) return 0; for (;;) { if (DO_KBD && getc(1)) return fn ? 1 : getc(0); if (DO_SIO && sio_ischar()) return fn ? 1 : sio_getc(); if (fn) return 0; } } Index: head/sys/boot/i386/common/rbx.h =================================================================== --- head/sys/boot/i386/common/rbx.h (revision 294765) +++ head/sys/boot/i386/common/rbx.h (nonexistent) @@ -1,61 +0,0 @@ -/*- - * Copyright (c) 1998 Robert Nordier - * All rights reserved. - * - * Redistribution and use in source and binary forms are freely - * permitted provided that the above copyright notice and this - * paragraph and the following disclaimer are duplicated in all - * such forms. - * - * This software is provided "AS IS" and without any express or - * implied warranties, including, without limitation, the implied - * warranties of merchantability and fitness for a particular - * purpose. - * - * $FreeBSD$ - */ - -#ifndef _RBX_H_ -#define _RBX_H_ - -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) - -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - -extern uint32_t opts; - -#endif /* !_RBX_H_ */ Property changes on: head/sys/boot/i386/common/rbx.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/boot/mips/beri/boot2/boot2.c =================================================================== --- head/sys/boot/mips/beri/boot2/boot2.c (revision 294765) +++ head/sys/boot/mips/beri/boot2/boot2.c (revision 294766) @@ -1,698 +1,661 @@ /*- * Copyright (c) 2013-2014 Robert N. M. Watson * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "paths.h" +#include "rbx.h" static int beri_argc; static const char **beri_argv, **beri_envv; static uint64_t beri_memsize; #define IO_KEYBOARD 1 #define IO_SERIAL 2 #define SECOND 1 /* Circa that many ticks in a second. */ -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) - #define ARGS 0x900 #define NOPT 14 #define MEM_BASE 0x12 #define MEM_EXT 0x15 /* * XXXRW: I think this has to do with whether boot2 expects a partition * table? */ #define DRV_HARD 0x80 #define DRV_MASK 0x7f /* Default to using CFI flash. */ #define TYPE_DEFAULT BOOTINFO_DEV_TYPE_SDCARD /* Hard-coded assumption about location of JTAG-loaded kernel. */ #define DRAM_KERNEL_ADDR ((void *)mips_phys_to_cached(0x20000)) - -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) extern uint32_t _end; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ static const unsigned char flags[NOPT] = { RBX_DUAL, RBX_SERIAL, RBX_ASKNAME, RBX_CDROM, RBX_CONFIG, RBX_KDB, RBX_GDB, RBX_MUTE, RBX_NOINTR, RBX_PAUSE, RBX_QUIET, RBX_DFLTROOT, RBX_SINGLE, RBX_VERBOSE }; /* These must match BOOTINFO_DEV_TYPE constants. */ static const char *const dev_nm[] = {"dram", "cfi", "sdcard"}; static const u_int dev_nm_count = sizeof(dev_nm) / sizeof(dev_nm[0]); static struct dmadat __dmadat; static struct dsk { unsigned type; /* BOOTINFO_DEV_TYPE_x object type. */ uintptr_t unitptr; /* Unit number or pointer to object. */ uint8_t slice; uint8_t part; #if 0 unsigned start; int init; #endif } dsk; static char cmd[512], cmddup[512], knamebuf[1024]; static const char *kname; static uint32_t opts; #if 0 static int comspeed = SIOSPD; #endif struct bootinfo bootinfo; static uint8_t ioctrl = IO_KEYBOARD; void exit(int); void putchar(int); static void boot_fromdram(void); static void boot_fromfs(void); static void load(void); static int parse(void); static int dskread(void *, unsigned, unsigned); static int xputc(int); static int xgetc(int); #define UFS_SMALL_CGBASE #include "ufsread.c" static inline int xfsread(ufs_ino_t inode, void *buf, size_t nbyte) { if ((size_t)fsread(inode, buf, nbyte) != nbyte) { printf("Invalid %s\n", "format"); return -1; } return 0; } static inline void getstr(void) { char *s; int c; s = cmd; for (;;) { switch (c = xgetc(0)) { case 0: break; case '\177': case '\b': if (s > cmd) { s--; printf("\b \b"); } break; case '\n': case '\r': putchar('\n'); *s = 0; return; default: if (s - cmd < sizeof(cmd) - 1) *s++ = c; putchar(c); } } } int main(u_int argc, const char *argv[], const char *envv[], uint64_t memsize) { uint8_t autoboot; ufs_ino_t ino; size_t nbyte; /* Arguments from Miniboot. */ beri_argc = argc; beri_argv = argv; beri_envv = envv; beri_memsize = memsize; dmadat = &__dmadat; #if 0 /* XXXRW: more here. */ v86.ctl = V86_FLAGS; v86.efl = PSL_RESERVED_DEFAULT | PSL_I; dsk.drive = *(uint8_t *)PTOV(ARGS); #endif dsk.type = TYPE_DEFAULT; #if 0 dsk.unit = dsk.drive & DRV_MASK; dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; #endif bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_size = sizeof(bootinfo); /* Process configuration file */ autoboot = 1; if ((ino = lookup(PATH_CONFIG)) || (ino = lookup(PATH_DOTCONFIG))) { nbyte = fsread(ino, cmd, sizeof(cmd) - 1); cmd[nbyte] = '\0'; } if (*cmd) { memcpy(cmddup, cmd, sizeof(cmd)); if (parse()) autoboot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmddup); /* Do not process this command twice */ *cmd = 0; } /* * Try to exec stage 3 boot loader. If interrupted by a keypress, * or in case of failure, try to load a kernel directly instead. */ if (!kname) { kname = PATH_BOOT3; if (autoboot && !keyhit(3*SECOND)) { boot_fromfs(); kname = PATH_KERNEL; } } /* Present the user with the boot2 prompt. */ for (;;) { if (!autoboot || !OPT_CHECK(RBX_QUIET)) printf("\nFreeBSD/mips boot\n" "Default: %s%ju:%s\n" "boot: ", dev_nm[dsk.type], dsk.unitptr, kname); #if 0 if (ioctrl & IO_SERIAL) sio_flush(); #endif if (!autoboot || keyhit(3*SECOND)) getstr(); else if (!autoboot || !OPT_CHECK(RBX_QUIET)) putchar('\n'); autoboot = 0; if (parse()) putchar('\a'); else load(); } } /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ void exit(int x) { } static void boot(void *entryp, int argc, const char *argv[], const char *envv[]) { bootinfo.bi_kernelname = (bi_ptr_t)kname; bootinfo.bi_boot2opts = opts & RBX_MASK; bootinfo.bi_boot_dev_type = dsk.type; bootinfo.bi_boot_dev_unitptr = dsk.unitptr; bootinfo.bi_memsize = beri_memsize; #if 0 /* * XXXRW: A possible future way to distinguish Miniboot passing a memory * size vs DTB..? */ if (beri_memsize <= BERI_MEMVSDTB) bootinfo.bi_memsize = beri_memsize; else bootinfo.bi_dtb = beri_memsize; #endif ((void(*)(int, const char **, const char **, void *))entryp)(argc, argv, envv, &bootinfo); } /* * Boot a kernel that has mysteriously (i.e., by JTAG) appeared in DRAM; * assume that it is already properly relocated, etc, and invoke its entry * address without question or concern. */ static void boot_fromdram(void) { void *kaddr = DRAM_KERNEL_ADDR; /* XXXRW: Something better here. */ Elf64_Ehdr *ehp = kaddr; if (!IS_ELF(*ehp)) { printf("Invalid %s\n", "format"); return; } boot((void *)ehp->e_entry, beri_argc, beri_argv, beri_envv); } static void boot_fromfs(void) { union { Elf64_Ehdr eh; } hdr; static Elf64_Phdr ep[2]; #if 0 static Elf64_Shdr es[2]; #endif caddr_t p; ufs_ino_t ino; uint64_t addr; int i, j; if (!(ino = lookup(kname))) { if (!ls) printf("No %s\n", kname); return; } if (xfsread(ino, &hdr, sizeof(hdr))) return; if (IS_ELF(hdr.eh)) { fs_off = hdr.eh.e_phoff; for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { if (xfsread(ino, ep + j, sizeof(ep[0]))) return; if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = (caddr_t)ep[i].p_paddr; fs_off = ep[i].p_offset; if (xfsread(ino, p, ep[i].p_filesz)) return; } p += roundup2(ep[1].p_memsz, PAGE_SIZE); #if 0 bootinfo.bi_symtab = VTOP(p); if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { fs_off = hdr.eh.e_shoff + sizeof(es[0]) * (hdr.eh.e_shstrndx + 1); if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { *(Elf32_Word *)p = es[i].sh_size; p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) return; p += es[i].sh_size; } } #endif addr = hdr.eh.e_entry; #if 0 bootinfo.bi_esymtab = VTOP(p); #endif } else { printf("Invalid %s\n", "format"); return; } boot((void *)addr, beri_argc, beri_argv, beri_envv); } static void load(void) { switch (dsk.type) { case BOOTINFO_DEV_TYPE_DRAM: boot_fromdram(); break; default: boot_fromfs(); break; } } static int parse() { char *arg = cmd; char *ep, *p, *q; char unit; size_t len; const char *cp; #if 0 int c, i, j; #else int c, i; #endif while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); ep = p; if (*p) *p++ = 0; if (c == '-') { while ((c = *arg++)) { if (c == 'P') { cp = "yes"; #if 0 } else { opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); cp = "no"; } #endif printf("Keyboard: %s\n", cp); continue; #if 0 } else if (c == 'S') { j = 0; while ((unsigned int)(i = *arg++ - '0') <= 9) j = j * 10 + i; if (j > 0 && i == -'0') { comspeed = j; break; } /* Fall through to error below ('S' not in optstr[]). */ #endif } for (i = 0; c != optstr[i]; i++) if (i == NOPT - 1) return -1; opts ^= OPT_SET(flags[i]); } ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; #if 0 if (ioctrl & IO_SERIAL) { if (sio_init(115200 / comspeed) != 0) ioctrl &= ~IO_SERIAL; } #endif } else { /*- * Parse a device/kernel name. Format(s): * * path * deviceX:path * * NB: Utterly incomprehensible but space-efficient ARM/i386 * parsing removed in favour of larger but easier-to-read C. This * is still not great, however -- e.g., relating to unit handling. * * TODO: it would be nice if a DRAM pointer could be specified * here. * * XXXRW: Pick up pieces here. */ /* * Search for a parens; if none, then it's just a path. * Otherwise, it's a devicename. */ arg--; q = strsep(&arg, ":"); if (arg != NULL) { len = strlen(q); if (len < 2) { printf("Invalid device: name too short\n"); return (-1); } /* * First, handle one-digit unit. */ unit = q[len-1]; if (unit < '0' || unit > '9') { printf("Invalid device: invalid unit\n", q, unit); return (-1); } unit -= '0'; q[len-1] = '\0'; /* * Next, find matching device. */ for (i = 0; i < dev_nm_count; i++) { if (strcmp(q, dev_nm[i]) == 0) break; } if (i == dev_nm_count) { printf("Invalid device: no driver match\n"); return (-1); } dsk.type = i; dsk.unitptr = unit; /* Someday: also a DRAM pointer? */ } else arg = q; if ((i = ep - arg)) { if ((size_t)i >= sizeof(knamebuf)) return -1; memcpy(knamebuf, arg, i + 1); kname = knamebuf; } } arg = p; } return 0; } static int drvread(void *buf, unsigned lba, unsigned nblk) { /* XXXRW: eventually, we may want to pass 'drive' and 'unit' here. */ switch (dsk.type) { case BOOTINFO_DEV_TYPE_CFI: return (cfi_read(buf, lba, nblk)); case BOOTINFO_DEV_TYPE_SDCARD: return (altera_sdcard_read(buf, lba, nblk)); default: return (-1); } } static int dskread(void *buf, unsigned lba, unsigned nblk) { #if 0 /* * XXXRW: For now, assume no partition table around the file system; it's * just in raw flash. */ struct dos_partition *dp; struct disklabel *d; char *sec; unsigned i; uint8_t sl; if (!dsk_meta) { sec = dmadat->secbuf; dsk.start = 0; if (drvread(sec, DOSBBSECTOR, 1)) return -1; dp = (void *)(sec + DOSPARTOFF); sl = dsk.slice; if (sl < BASE_SLICE) { for (i = 0; i < NDOSPART; i++) if (dp[i].dp_typ == DOSPTYP_386BSD && (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { sl = BASE_SLICE + i; if (dp[i].dp_flag & 0x80 || dsk.slice == COMPATIBILITY_SLICE) break; } if (dsk.slice == WHOLE_DISK_SLICE) dsk.slice = sl; } if (sl != WHOLE_DISK_SLICE) { if (sl != COMPATIBILITY_SLICE) dp += sl - BASE_SLICE; if (dp->dp_typ != DOSPTYP_386BSD) { printf("Invalid %s\n", "slice"); return -1; } dsk.start = le32toh(dp->dp_start); } if (drvread(sec, dsk.start + LABELSECTOR, 1)) return -1; d = (void *)(sec + LABELOFFSET); if (le32toh(d->d_magic) != DISKMAGIC || le32toh(d->d_magic2) != DISKMAGIC) { if (dsk.part != RAW_PART) { printf("Invalid %s\n", "label"); return -1; } } else { if (!dsk.init) { if (le16toh(d->d_type) == DTYPE_SCSI) dsk.type = TYPE_DA; dsk.init++; } if (dsk.part >= le16toh(d->d_npartitions) || !(le32toh(d->d_partitions[dsk.part].p_size))) { printf("Invalid %s\n", "partition"); return -1; } dsk.start += le32toh(d->d_partitions[dsk.part].p_offset); dsk.start -= le32toh(d->d_partitions[RAW_PART].p_offset); } } return drvread(buf, dsk.start + lba, nblk); #else return drvread(buf, lba, nblk); #endif } void putchar(int c) { if (c == '\n') xputc('\r'); xputc(c); } static int xputc(int c) { if (ioctrl & IO_KEYBOARD) putc(c); #if 0 if (ioctrl & IO_SERIAL) sio_putc(c); #endif return c; } static int xgetc(int fn) { if (OPT_CHECK(RBX_NOINTR)) return 0; for (;;) { if (ioctrl & IO_KEYBOARD && keyhit(0)) return fn ? 1 : getc(); #if 0 if (ioctrl & IO_SERIAL && sio_ischar()) return fn ? 1 : sio_getc(); #endif if (fn) return 0; } } Index: head/sys/boot/pc98/boot2/boot2.c =================================================================== --- head/sys/boot/pc98/boot2/boot2.c (revision 294765) +++ head/sys/boot/pc98/boot2/boot2.c (revision 294766) @@ -1,840 +1,803 @@ /*- * Copyright (c) 2008-2009 TAKAHASHI Yoshihiro * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "boot2.h" #include "lib.h" #include "paths.h" +#include "rbx.h" /* Define to 0 to omit serial support */ #ifndef SERIAL #define SERIAL 0 #endif #define IO_KEYBOARD 1 #define IO_SERIAL 2 #if SERIAL #define DO_KBD (ioctrl & IO_KEYBOARD) #define DO_SIO (ioctrl & IO_SERIAL) #else #define DO_KBD (1) #define DO_SIO (0) #endif #define SECOND 1 /* Circa that many ticks in a second. */ -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) - #define ARGS 0x900 #define NOPT 14 #define NDEV 3 #define DRV_DISK 0xf0 #define DRV_UNIT 0x0f #define TYPE_AD 0 #define TYPE_DA 1 #define TYPE_FD 2 - -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) extern uint32_t _end; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ static const unsigned char flags[NOPT] = { RBX_DUAL, RBX_SERIAL, RBX_ASKNAME, RBX_CDROM, RBX_CONFIG, RBX_KDB, RBX_GDB, RBX_MUTE, RBX_NOINTR, RBX_PAUSE, RBX_QUIET, RBX_DFLTROOT, RBX_SINGLE, RBX_VERBOSE }; static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; static const unsigned char dev_daua[NDEV] = {0x80, 0xa0, 0x90}; static struct dsk { unsigned daua; unsigned type; unsigned disk; unsigned unit; unsigned head; unsigned sec; uint8_t slice; uint8_t part; unsigned start; } dsk; static char cmd[512], cmddup[512], knamebuf[1024]; static const char *kname; static uint32_t opts; static struct bootinfo bootinfo; #if SERIAL static int comspeed = SIOSPD; static uint8_t ioctrl = IO_KEYBOARD; #endif int main(void); void exit(int); static void load(void); static int parse(void); static int dskread(void *, unsigned, unsigned); static void printf(const char *,...); static void putchar(int); static int drvread(void *, unsigned); static int keyhit(unsigned); static int xputc(int); static int xgetc(int); static inline int getc(int); static void memcpy(void *, const void *, int); static void memcpy(void *dst, const void *src, int len) { const char *s = src; char *d = dst; while (len--) *d++ = *s++; } static inline int strcmp(const char *s1, const char *s2) { for (; *s1 == *s2 && *s1; s1++, s2++); return (unsigned char)*s1 - (unsigned char)*s2; } #define UFS_SMALL_CGBASE #include "ufsread.c" static inline int xfsread(ufs_ino_t inode, void *buf, size_t nbyte) { if ((size_t)fsread(inode, buf, nbyte) != nbyte) { printf("Invalid %s\n", "format"); return -1; } return 0; } static inline void getstr(void) { char *s; int c; s = cmd; for (;;) { switch (c = xgetc(0)) { case 0: break; case '\177': case '\b': if (s > cmd) { s--; printf("\b \b"); } break; case '\n': case '\r': *s = 0; return; default: if (s - cmd < sizeof(cmd) - 1) *s++ = c; putchar(c); } } } static inline void putc(int c) { v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.addr = PUTCORG; /* call to putc in boot1 */ v86.eax = c; v86int(); v86.ctl = V86_FLAGS; } static inline int is_scsi_hd(void) { if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01) return 1; return 0; } static inline void fix_sector_size(void) { u_char *p; p = (u_char *)PTOV(0x460 + dsk.unit * 4); /* SCSI equipment parameter */ if ((p[0] & 0x1f) == 7) { /* SCSI MO */ if (!(p[3] & 0x30)) { /* 256B / sector */ p[3] |= 0x10; /* forced set 512B / sector */ p[3 + 0xa1000] |= 0x10; } } } static inline uint32_t get_diskinfo(void) { if (dsk.disk == 0x30) { /* 1440KB FD */ /* 80 cylinders, 2 heads, 18 sectors */ return (80 << 16) | (2 << 8) | 18; } else if (dsk.disk == 0x90) { /* 1200KB FD */ /* 80 cylinders, 2 heads, 15 sectors */ return (80 << 16) | (2 << 8) | 15; } else if (dsk.disk == 0x80 || is_scsi_hd()) { /* IDE or SCSI HDD */ v86.addr = 0x1b; v86.eax = 0x8400 | dsk.daua; v86int(); return (v86.ecx << 16) | v86.edx; } /* SCSI MO or CD */ fix_sector_size(); /* SCSI MO */ /* other SCSI devices */ return (65535 << 16) | (8 << 8) | 32; } static void set_dsk(void) { uint32_t di; di = get_diskinfo(); dsk.head = (di >> 8) & 0xff; dsk.sec = di & 0xff; dsk.start = 0; } #ifdef GET_BIOSGEOM static uint32_t bd_getbigeom(int bunit) { int hds = 0; int unit = 0x80; /* IDE HDD */ u_int addr = 0x55d; while (unit < 0xa7) { if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) if (hds++ == bunit) break; if (unit >= 0xA0) { int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F; if (media == 7 && hds++ == bunit) /* SCSI MO */ return(0xFFFE0820); /* C:65535 H:8 S:32 */ } if (++unit == 0x84) { unit = 0xA0; /* SCSI HDD */ addr = 0x482; } } if (unit == 0xa7) return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ v86.addr = 0x1b; v86.eax = 0x8400 | unit; v86int(); if (V86_CY(v86.efl)) return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff); } #endif static int check_slice(void) { struct pc98_partition *dp; char *sec; unsigned i, cyl; sec = dmadat->secbuf; cyl = *(uint16_t *)PTOV(ARGS); set_dsk(); if (dsk.type == TYPE_FD) return (WHOLE_DISK_SLICE); if (drvread(sec, PC98_BBSECTOR)) return (WHOLE_DISK_SLICE); /* Read error */ dp = (void *)(sec + PC98_PARTOFF); for (i = 0; i < PC98_NPARTS; i++) { if (dp[i].dp_mid == DOSMID_386BSD) { if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl) return (BASE_SLICE + i); } } return (WHOLE_DISK_SLICE); } int main(void) { #ifdef GET_BIOSGEOM int i; #endif uint8_t autoboot; ufs_ino_t ino; size_t nbyte; dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); v86.ctl = V86_FLAGS; v86.efl = PSL_RESERVED_DEFAULT | PSL_I; dsk.daua = *(uint8_t *)PTOV(0x584); dsk.disk = dsk.daua & DRV_DISK; dsk.unit = dsk.daua & DRV_UNIT; if (dsk.disk == 0x80) dsk.type = TYPE_AD; else if (dsk.disk == 0xa0) dsk.type = TYPE_DA; else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */ dsk.type = TYPE_FD; dsk.slice = check_slice(); #ifdef GET_BIOSGEOM for (i = 0; i < N_BIOS_GEOM; i++) bootinfo.bi_bios_geom[i] = bd_getbigeom(i); #endif bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_size = sizeof(bootinfo); /* Process configuration file */ autoboot = 1; if ((ino = lookup(PATH_CONFIG)) || (ino = lookup(PATH_DOTCONFIG))) { nbyte = fsread(ino, cmd, sizeof(cmd) - 1); cmd[nbyte] = '\0'; } if (*cmd) { memcpy(cmddup, cmd, sizeof(cmd)); if (parse()) autoboot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmddup); /* Do not process this command twice */ *cmd = 0; } /* * Try to exec stage 3 boot loader. If interrupted by a keypress, * or in case of failure, try to load a kernel directly instead. */ if (!kname) { kname = PATH_BOOT3; if (autoboot && !keyhit(3*SECOND)) { load(); kname = PATH_KERNEL; } } /* Present the user with the boot2 prompt. */ for (;;) { if (!autoboot || !OPT_CHECK(RBX_QUIET)) printf("\nFreeBSD/pc98 boot\n" "Default: %u:%s(%u,%c)%s\n" "boot: ", dsk.unit, dev_nm[dsk.type], dsk.unit, 'a' + dsk.part, kname); if (DO_SIO) sio_flush(); if (!autoboot || keyhit(3*SECOND)) getstr(); else if (!autoboot || !OPT_CHECK(RBX_QUIET)) putchar('\n'); autoboot = 0; if (parse()) putchar('\a'); else load(); } } /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ void exit(int x) { } static void load(void) { union { struct exec ex; Elf32_Ehdr eh; } hdr; static Elf32_Phdr ep[2]; static Elf32_Shdr es[2]; caddr_t p; ufs_ino_t ino; uint32_t addr; int k; uint8_t i, j; if (!(ino = lookup(kname))) { if (!ls) printf("No %s\n", kname); return; } if (xfsread(ino, &hdr, sizeof(hdr))) return; if (N_GETMAGIC(hdr.ex) == ZMAGIC) { addr = hdr.ex.a_entry & 0xffffff; p = PTOV(addr); fs_off = PAGE_SIZE; if (xfsread(ino, p, hdr.ex.a_text)) return; p += roundup2(hdr.ex.a_text, PAGE_SIZE); if (xfsread(ino, p, hdr.ex.a_data)) return; } else if (IS_ELF(hdr.eh)) { fs_off = hdr.eh.e_phoff; for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) { if (xfsread(ino, ep + j, sizeof(ep[0]))) return; if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = PTOV(ep[i].p_paddr & 0xffffff); fs_off = ep[i].p_offset; if (xfsread(ino, p, ep[i].p_filesz)) return; } p += roundup2(ep[1].p_memsz, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { fs_off = hdr.eh.e_shoff + sizeof(es[0]) * (hdr.eh.e_shstrndx + 1); if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { *(Elf32_Word *)p = es[i].sh_size; p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) return; p += es[i].sh_size; } } addr = hdr.eh.e_entry & 0xffffff; bootinfo.bi_esymtab = VTOP(p); } else { printf("Invalid %s\n", "format"); return; } bootinfo.bi_kernelname = VTOP(kname); bootinfo.bi_bios_dev = dsk.daua; __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 0, 0, 0, VTOP(&bootinfo)); } static int parse() { char *arg = cmd; char *ep, *p, *q; const char *cp; unsigned int drv; int c, i, j; size_t k; while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); ep = p; if (*p) *p++ = 0; if (c == '-') { while ((c = *arg++)) { if (c == 'P') { if (*(uint8_t *)PTOV(0x481) & 0x48) { cp = "yes"; } else { opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); cp = "no"; } printf("Keyboard: %s\n", cp); continue; #if SERIAL } else if (c == 'S') { j = 0; while ((unsigned int)(i = *arg++ - '0') <= 9) j = j * 10 + i; if (j > 0 && i == -'0') { comspeed = j; break; } /* Fall through to error below ('S' not in optstr[]). */ #endif } for (i = 0; c != optstr[i]; i++) if (i == NOPT - 1) return -1; opts ^= OPT_SET(flags[i]); } #if SERIAL ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; if (DO_SIO) { if (sio_init(115200 / comspeed) != 0) ioctrl &= ~IO_SERIAL; } #endif } else { for (q = arg--; *q && *q != '('; q++); if (*q) { drv = -1; if (arg[1] == ':') { drv = *arg - '0'; if (drv > 9) return (-1); arg += 2; } if (q - arg != 2) return -1; for (i = 0; arg[0] != dev_nm[i][0] || arg[1] != dev_nm[i][1]; i++) if (i == NDEV - 1) return -1; dsk.type = i; arg += 3; dsk.unit = *arg - '0'; if (arg[1] != ',' || dsk.unit > 9) return -1; arg += 2; dsk.slice = WHOLE_DISK_SLICE; if (arg[1] == ',') { dsk.slice = *arg - '0' + 1; if (dsk.slice > PC98_NPARTS + 1) return -1; arg += 2; } if (arg[1] != ')') return -1; dsk.part = *arg - 'a'; if (dsk.part > 7) return (-1); arg += 2; if (drv == -1) drv = dsk.unit; dsk.disk = dev_daua[dsk.type]; dsk.daua = dsk.disk | dsk.unit; dsk_meta = 0; } k = ep - arg; if (k > 0) { if (k >= sizeof(knamebuf)) return -1; memcpy(knamebuf, arg, k + 1); kname = knamebuf; } } arg = p; } return 0; } static int dskread(void *buf, unsigned lba, unsigned nblk) { struct pc98_partition *dp; struct disklabel *d; char *sec; unsigned i; uint8_t sl; u_char *p; const char *reason; if (!dsk_meta) { sec = dmadat->secbuf; set_dsk(); if (dsk.type == TYPE_FD) goto unsliced; if (drvread(sec, PC98_BBSECTOR)) return -1; dp = (void *)(sec + PC98_PARTOFF); sl = dsk.slice; if (sl < BASE_SLICE) { for (i = 0; i < PC98_NPARTS; i++) if (dp[i].dp_mid == DOSMID_386BSD) { sl = BASE_SLICE + i; break; } dsk.slice = sl; } if (sl != WHOLE_DISK_SLICE) { dp += sl - BASE_SLICE; if (dp->dp_mid != DOSMID_386BSD) { reason = "slice"; goto error; } dsk.start = dp->dp_scyl * dsk.head * dsk.sec + dp->dp_shd * dsk.sec + dp->dp_ssect; } if (drvread(sec, dsk.start + LABELSECTOR)) return -1; d = (void *)(sec + LABELOFFSET); if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { if (dsk.part != RAW_PART) { reason = "label"; goto error; } } else { if (dsk.part >= d->d_npartitions || !d->d_partitions[dsk.part].p_size) { reason = "partition"; goto error; } dsk.start += d->d_partitions[dsk.part].p_offset; dsk.start -= d->d_partitions[RAW_PART].p_offset; } unsliced: ; } for (p = buf; nblk; p += 512, lba++, nblk--) { if ((i = drvread(p, dsk.start + lba))) return i; } return 0; error: printf("Invalid %s\n", reason); return -1; } static void printf(const char *fmt,...) { va_list ap; static char buf[10]; char *s; unsigned u; int c; va_start(ap, fmt); while ((c = *fmt++)) { if (c == '%') { c = *fmt++; switch (c) { case 'c': putchar(va_arg(ap, int)); continue; case 's': for (s = va_arg(ap, char *); *s; s++) putchar(*s); continue; case 'u': u = va_arg(ap, unsigned); s = buf; do *s++ = '0' + u % 10U; while (u /= 10U); while (--s >= buf) putchar(*s); continue; } } putchar(c); } va_end(ap); return; } static void putchar(int c) { if (c == '\n') xputc('\r'); xputc(c); } static int drvread(void *buf, unsigned lba) { static unsigned c = 0x2d5c7c2f; unsigned bpc, x, cyl, head, sec; bpc = dsk.sec * dsk.head; cyl = lba / bpc; x = lba % bpc; head = x / dsk.sec; sec = x % dsk.sec; if (!OPT_CHECK(RBX_QUIET)) { xputc(c = c << 8 | c >> 24); xputc('\b'); } v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.addr = READORG; /* call to read in boot1 */ v86.ecx = cyl; v86.edx = (head << 8) | sec; v86.edi = lba; v86.ebx = 512; v86.es = VTOPSEG(buf); v86.ebp = VTOPOFF(buf); v86int(); v86.ctl = V86_FLAGS; if (V86_CY(v86.efl)) { printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff, cyl, head, sec, lba); return -1; } return 0; } static inline void delay(void) { int i; i = 800; do { outb(0x5f, 0); /* about 600ns */ } while (--i >= 0); } static int keyhit(unsigned sec) { unsigned i; if (OPT_CHECK(RBX_NOINTR)) return 0; for (i = 0; i < sec * 1000; i++) { if (xgetc(1)) return 1; delay(); } return 0; } static int xputc(int c) { if (DO_KBD) putc(c); if (DO_SIO) sio_putc(c); return c; } static int getc(int fn) { v86.addr = 0x18; v86.eax = fn << 8; v86int(); if (fn) return (v86.ebx >> 8) & 0x01; else return v86.eax & 0xff; } static int xgetc(int fn) { if (OPT_CHECK(RBX_NOINTR)) return 0; for (;;) { if (DO_KBD && getc(1)) return fn ? 1 : getc(0); if (DO_SIO && sio_ischar()) return fn ? 1 : sio_getc(); if (fn) return 0; } }