Index: head/sys/boot/arm/at91/boot2/boot2.c =================================================================== --- head/sys/boot/arm/at91/boot2/boot2.c (revision 294764) +++ head/sys/boot/arm/at91/boot2/boot2.c (revision 294765) @@ -1,397 +1,396 @@ /*- * Copyright (c) 2008 John Hay - * Copyright (c) 2006 Warner Losh + * 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" #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)) -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -//#define PATH_KERNEL "/boot/kernel/kernel" +#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 294764) +++ head/sys/boot/arm/ixp425/boot2/boot2.c (revision 294765) @@ -1,484 +1,481 @@ /*- * 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" #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)) - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_KERNEL "/boot/kernel/kernel" 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/paths.h =================================================================== --- head/sys/boot/common/paths.h (nonexistent) +++ head/sys/boot/common/paths.h (revision 294765) @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2016 M. Warner Losh + * All rights reserved. + * + * 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 AUTHORS 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 AUTHORS 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. + * + * $FreeBSD$ + */ + +#ifndef _PATHS_H_ +#define _PATHS_H_ + +#define PATH_DOTCONFIG "/boot.config" +#define PATH_CONFIG "/boot/config" +#define PATH_BOOT3 "/boot/loader" +#define PATH_LOADER "/boot/loader" +#define PATH_LOADER_EFI "/boot/loader.efi" +#define PATH_KERNEL "/boot/kernel/kernel" + +#endif /* _PATHS_H_ */ Property changes on: head/sys/boot/common/paths.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/efi/boot1/boot1.c =================================================================== --- head/sys/boot/efi/boot1/boot1.c (revision 294764) +++ head/sys/boot/efi/boot1/boot1.c (revision 294765) @@ -1,361 +1,360 @@ /*- * Copyright (c) 1998 Robert Nordier * All rights reserved. * Copyright (c) 2001 Robert Drehmel * All rights reserved. * Copyright (c) 2014 Nathan Whitehorn * All rights reserved. * Copyright (c) 2015 Eric McCorkle * 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 "boot_module.h" +#include "paths.h" -#define _PATH_LOADER "/boot/loader.efi" - static const boot_module_t *boot_modules[] = { #ifdef EFI_ZFS_BOOT &zfs_module, #endif #ifdef EFI_UFS_BOOT &ufs_module #endif }; #define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) /* The initial number of handles used to query EFI for partitions. */ #define NUM_HANDLES_INIT 24 void putchar(int c); EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); static void try_load(const boot_module_t* mod); static EFI_STATUS probe_handle(EFI_HANDLE h); EFI_SYSTEM_TABLE *systab; EFI_BOOT_SERVICES *bs; static EFI_HANDLE *image; static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; /* * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from * EFI methods. */ void * Malloc(size_t len, const char *file __unused, int line __unused) { void *out; if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) return (out); return (NULL); } void Free(void *buf, const char *file __unused, int line __unused) { (void)bs->FreePool(buf); } /* * This function only returns if it fails to load the kernel. If it * succeeds, it simply boots the kernel. */ void try_load(const boot_module_t *mod) { size_t bufsize; void *buf; dev_info_t *dev; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; - status = mod->load(_PATH_LOADER, &dev, &buf, &bufsize); + status = mod->load(PATH_LOADER_EFI, &dev, &buf, &bufsize); if (status == EFI_NOT_FOUND) return; if (status != EFI_SUCCESS) { - printf("%s failed to load %s (%lu)\n", mod->name, _PATH_LOADER, - EFI_ERROR_CODE(status)); + printf("%s failed to load %s (%lu)\n", mod->name, + PATH_LOADER_EFI, EFI_ERROR_CODE(status)); return; } if ((status = bs->LoadImage(TRUE, image, dev->devpath, buf, bufsize, &loaderhandle)) != EFI_SUCCESS) { printf("Failed to load image provided by %s, size: %zu, (%lu)\n", mod->name, bufsize, EFI_ERROR_CODE(status)); return; } if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, (VOID**)&loaded_image)) != EFI_SUCCESS) { printf("Failed to query LoadedImage provided by %s (%lu)\n", mod->name, EFI_ERROR_CODE(status)); return; } loaded_image->DeviceHandle = dev->devhandle; if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != EFI_SUCCESS) { printf("Failed to start image provided by %s (%lu)\n", mod->name, EFI_ERROR_CODE(status)); return; } } EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) { EFI_HANDLE *handles; EFI_STATUS status; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; /* Basic initialization*/ systab = Xsystab; image = Ximage; bs = Xsystab->BootServices; /* Set up the console, so printf works. */ status = bs->LocateProtocol(&ConsoleControlGUID, NULL, (VOID **)&ConsoleControl); if (status == EFI_SUCCESS) (void)ConsoleControl->SetMode(ConsoleControl, EfiConsoleControlScreenText); /* * Reset the console and find the best text mode. */ conout = systab->ConOut; conout->Reset(conout, TRUE); max_dim = best_mode = 0; for (i = 0; ; i++) { status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) break; if (cols * rows > max_dim) { max_dim = cols * rows; best_mode = i; } } if (max_dim > 0) conout->SetMode(conout, best_mode); conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); printf("\n>> FreeBSD EFI boot block\n"); - printf(" Loader path: %s\n\n", _PATH_LOADER); + printf(" Loader path: %s\n\n", PATH_LOADER_EFI); printf(" Initializing modules:"); for (i = 0; i < NUM_BOOT_MODULES; i++) { if (boot_modules[i] == NULL) continue; printf(" %s", boot_modules[i]->name); if (boot_modules[i]->init != NULL) boot_modules[i]->init(); } putchar('\n'); /* Get all the device handles */ hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) != EFI_SUCCESS) panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, EFI_ERROR_CODE(status)); status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, &hsize, handles); switch (status) { case EFI_SUCCESS: break; case EFI_BUFFER_TOO_SMALL: (void)bs->FreePool(handles); if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles) != EFI_SUCCESS)) { panic("Failed to allocate %zu handles (%lu)", hsize / sizeof(*handles), EFI_ERROR_CODE(status)); } status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, &hsize, handles); if (status != EFI_SUCCESS) panic("Failed to get device handles (%lu)\n", EFI_ERROR_CODE(status)); break; default: panic("Failed to get device handles (%lu)", EFI_ERROR_CODE(status)); } /* Scan all partitions, probing with all modules. */ nhandles = hsize / sizeof(*handles); printf(" Probing %zu block devices...", nhandles); for (i = 0; i < nhandles; i++) { status = probe_handle(handles[i]); switch (status) { case EFI_UNSUPPORTED: printf("."); break; case EFI_SUCCESS: printf("+"); break; default: printf("x"); break; } } printf(" done\n"); /* Status summary. */ for (i = 0; i < NUM_BOOT_MODULES; i++) { if (boot_modules[i] != NULL) { printf(" "); boot_modules[i]->status(); } } /* Select a partition to boot by trying each module in order. */ for (i = 0; i < NUM_BOOT_MODULES; i++) if (boot_modules[i] != NULL) try_load(boot_modules[i]); /* If we get here, we're out of luck... */ panic("No bootable partitions found!"); } static EFI_STATUS probe_handle(EFI_HANDLE h) { dev_info_t *devinfo; EFI_BLOCK_IO *blkio; EFI_DEVICE_PATH *devpath; EFI_STATUS status; UINTN i; /* Figure out if we're dealing with an actual partition. */ status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); if (status == EFI_UNSUPPORTED) return (status); if (status != EFI_SUCCESS) { DPRINTF("\nFailed to query DevicePath (%lu)\n", EFI_ERROR_CODE(status)); return (status); } while (!IsDevicePathEnd(NextDevicePathNode(devpath))) devpath = NextDevicePathNode(devpath); status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); if (status == EFI_UNSUPPORTED) return (status); if (status != EFI_SUCCESS) { DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", EFI_ERROR_CODE(status)); return (status); } if (!blkio->Media->LogicalPartition) return (EFI_UNSUPPORTED); /* Run through each module, see if it can load this partition */ for (i = 0; i < NUM_BOOT_MODULES; i++) { if (boot_modules[i] == NULL) continue; if ((status = bs->AllocatePool(EfiLoaderData, sizeof(*devinfo), (void **)&devinfo)) != EFI_SUCCESS) { DPRINTF("\nFailed to allocate devinfo (%lu)\n", EFI_ERROR_CODE(status)); continue; } devinfo->dev = blkio; devinfo->devpath = devpath; devinfo->devhandle = h; devinfo->devdata = NULL; devinfo->next = NULL; status = boot_modules[i]->probe(devinfo); if (status == EFI_SUCCESS) return (EFI_SUCCESS); (void)bs->FreePool(devinfo); } return (EFI_UNSUPPORTED); } void add_device(dev_info_t **devinfop, dev_info_t *devinfo) { dev_info_t *dev; if (*devinfop == NULL) { *devinfop = devinfo; return; } for (dev = *devinfop; dev->next != NULL; dev = dev->next) ; dev->next = devinfo; } void panic(const char *fmt, ...) { va_list ap; printf("panic: "); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); while (1) {} } void putchar(int c) { CHAR16 buf[2]; if (c == '\n') { buf[0] = '\r'; buf[1] = 0; systab->ConOut->OutputString(systab->ConOut, buf); } buf[0] = c; buf[1] = 0; systab->ConOut->OutputString(systab->ConOut, buf); } Index: head/sys/boot/i386/boot2/boot2.c =================================================================== --- head/sys/boot/i386/boot2/boot2.c (revision 294764) +++ head/sys/boot/i386/boot2/boot2.c (revision 294765) @@ -1,687 +1,683 @@ /*- * 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" /* 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 PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" #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; 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/gptboot/gptboot.c =================================================================== --- head/sys/boot/i386/gptboot/gptboot.c (revision 294764) +++ head/sys/boot/i386/gptboot/gptboot.c (revision 294765) @@ -1,439 +1,435 @@ /*- * 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 "lib.h" #include "rbx.h" #include "drv.h" #include "util.h" #include "cons.h" #include "gpt.h" - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" +#include "paths.h" #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 extern uint32_t _end; static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; 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 }; uint32_t opts; static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; static struct dsk dsk; static char kname[1024]; static int comspeed = SIOSPD; static struct bootinfo bootinfo; void exit(int); static void load(void); static int parse(char *, int *); static int dskread(void *, daddr_t, unsigned); static uint32_t memsize(void); #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 uint32_t memsize(void) { v86.addr = MEM_EXT; v86.eax = 0x8800; v86int(); return (v86.eax); } static int gptinit(void) { if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) { printf("%s: unable to load GPT\n", BOOTPROG); return (-1); } if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) { printf("%s: no UFS partition was found\n", BOOTPROG); return (-1); } dsk_meta = 0; return (0); } int main(void) { char cmd[512], cmdtmp[512]; ssize_t sz; int autoboot, dskupdated; ufs_ino_t ino; 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.part = -1; dsk.start = 0; bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_size = sizeof(bootinfo); bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ bootinfo.bi_extmem = memsize(); bootinfo.bi_memsizes_valid++; /* Process configuration file */ if (gptinit() != 0) return (-1); autoboot = 1; *cmd = '\0'; for (;;) { *kname = '\0'; if ((ino = lookup(PATH_CONFIG)) || (ino = lookup(PATH_DOTCONFIG))) { sz = fsread(ino, cmd, sizeof(cmd) - 1); cmd[(sz < 0) ? 0 : sz] = '\0'; } if (*cmd != '\0') { memcpy(cmdtmp, cmd, sizeof(cmdtmp)); if (parse(cmdtmp, &dskupdated)) break; if (dskupdated && gptinit() != 0) break; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmd); *cmd = '\0'; } if (autoboot && keyhit(3)) { if (*kname == '\0') memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); break; } autoboot = 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 != '\0') load(); memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); load(); memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); load(); gptbootfailed(&dsk); if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1) break; dsk_meta = 0; } /* Present the user with the boot2 prompt. */ for (;;) { if (!OPT_CHECK(RBX_QUIET)) { printf("\nFreeBSD/x86 boot\n" "Default: %u:%s(%up%u)%s\n" "boot: ", dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, dsk.part, kname); } if (ioctrl & IO_SERIAL) sio_flush(); *cmd = '\0'; if (keyhit(0)) getstr(cmd, sizeof(cmd)); else if (!OPT_CHECK(RBX_QUIET)) putchar('\n'); if (parse(cmd, &dskupdated)) { putchar('\a'); continue; } if (dskupdated && gptinit() != 0) continue; load(); } /* NOTREACHED */ } /* 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, x; int fmt, i, j; if (!(ino = lookup(kname))) { if (!ls) { printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, dsk.part); } return; } if (xfsread(ino, &hdr, sizeof(hdr))) return; if (N_GETMAGIC(hdr.ex) == ZMAGIC) fmt = 0; else if (IS_ELF(hdr.eh)) fmt = 1; else { printf("Invalid %s\n", "format"); return; } if (fmt == 0) { 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; p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { if (xfsread(ino, p, hdr.ex.a_syms)) return; p += hdr.ex.a_syms; if (xfsread(ino, p, sizeof(int))) return; x = *(uint32_t *)p; p += sizeof(int); x -= sizeof(int); if (xfsread(ino, p, x)) return; p += x; } } else { 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 = 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++) { memcpy(p, &es[i].sh_size, sizeof(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); 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.part + 1, dsk.unit, 0xff), 0, 0, 0, VTOP(&bootinfo)); } static int parse(char *cmdstr, int *dskupdated) { char *arg = cmdstr; char *ep, *p, *q; const char *cp; unsigned int drv; int c, i, j; *dskupdated = 0; 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; } 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[]). */ } 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 (ioctrl & IO_SERIAL) { if (sio_init(115200 / comspeed) != 0) ioctrl &= ~IO_SERIAL; } } 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] != 'p' || dsk.unit > 9) return -1; arg += 2; dsk.part = *arg - '0'; if (dsk.part < 1 || dsk.part > 9) return -1; arg++; if (arg[0] != ')') return -1; arg++; if (drv == -1) drv = dsk.unit; dsk.drive = (dsk.type <= TYPE_MAXHARD ? DRV_HARD : 0) + drv; *dskupdated = 1; } 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, daddr_t lba, unsigned nblk) { return drvread(&dsk, buf, lba + dsk.start, nblk); } Index: head/sys/boot/i386/zfsboot/zfsboot.c =================================================================== --- head/sys/boot/i386/zfsboot/zfsboot.c (revision 294764) +++ head/sys/boot/i386/zfsboot/zfsboot.c (revision 294765) @@ -1,836 +1,832 @@ /*- * 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 #ifdef GPT #include #endif #include #include #include #include #include #include #include #include #include #include "lib.h" #include "rbx.h" #include "drv.h" #include "util.h" #include "cons.h" #include "bootargs.h" +#include "paths.h" #include "libzfs.h" - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/zfsloader" -#define PATH_KERNEL "/boot/kernel/kernel" #define ARGS 0x900 #define NOPT 14 #define NDEV 3 #define BIOS_NUMDRIVES 0x475 #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 extern uint32_t _end; #ifdef GPT static const uuid_t freebsd_zfs_uuid = GPT_ENT_TYPE_FREEBSD_ZFS; #endif 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 }; uint32_t opts; static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; static char cmd[512]; static char cmddup[512]; static char kname[1024]; static char rootname[256]; static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint32_t bootdev; static struct zfs_boot_args zfsargs; static struct zfsmount zfsmount; vm_offset_t high_heap_base; uint32_t bios_basemem, bios_extmem, high_heap_size; static struct bios_smap smap; /* * The minimum amount of memory to reserve in bios_extmem for the heap. */ #define HEAP_MIN (3 * 1024 * 1024) static char *heap_next; static char *heap_end; /* Buffers that must not span a 64k boundary. */ #define READ_BUF_SIZE 8192 struct dmadat { char rdbuf[READ_BUF_SIZE]; /* for reading large things */ char secbuf[READ_BUF_SIZE]; /* for MBR/disklabel */ }; static struct dmadat *dmadat; void exit(int); static void load(void); static int parse(void); static void bios_getmem(void); static void * malloc(size_t n) { char *p = heap_next; if (p + n > heap_end) { printf("malloc failure\n"); for (;;) ; return 0; } heap_next += n; return p; } static char * strdup(const char *s) { char *p = malloc(strlen(s) + 1); strcpy(p, s); return p; } #include "zfsimpl.c" /* * Read from a dnode (which must be from a ZPL filesystem). */ static int zfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t size) { const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus; size_t n; int rc; n = size; if (*offp + n > zp->zp_size) n = zp->zp_size - *offp; rc = dnode_read(spa, dnode, *offp, start, n); if (rc) return (-1); *offp += n; return (n); } /* * Current ZFS pool */ static spa_t *spa; static spa_t *primary_spa; static vdev_t *primary_vdev; /* * A wrapper for dskread that doesn't have to worry about whether the * buffer pointer crosses a 64k boundary. */ static int vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) { char *p; daddr_t lba; unsigned int nb; struct dsk *dsk = (struct dsk *) priv; if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) return -1; p = buf; lba = off / DEV_BSIZE; lba += dsk->start; while (bytes > 0) { nb = bytes / DEV_BSIZE; if (nb > READ_BUF_SIZE / DEV_BSIZE) nb = READ_BUF_SIZE / DEV_BSIZE; if (drvread(dsk, dmadat->rdbuf, lba, nb)) return -1; memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE); p += nb * DEV_BSIZE; lba += nb; bytes -= nb * DEV_BSIZE; } return 0; } static int xfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte) { if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) { printf("Invalid format\n"); return -1; } return 0; } static void bios_getmem(void) { uint64_t size; /* Parse system memory map */ v86.ebx = 0; do { v86.ctl = V86_FLAGS; v86.addr = 0x15; /* int 0x15 function 0xe820*/ v86.eax = 0xe820; v86.ecx = sizeof(struct bios_smap); v86.edx = SMAP_SIG; v86.es = VTOPSEG(&smap); v86.edi = VTOPOFF(&smap); v86int(); if (V86_CY(v86.efl) || (v86.eax != SMAP_SIG)) break; /* look for a low-memory segment that's large enough */ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && (smap.length >= (512 * 1024))) bios_basemem = smap.length; /* look for the first segment in 'extended' memory */ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) { bios_extmem = smap.length; } /* * Look for the largest segment in 'extended' memory beyond * 1MB but below 4GB. */ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && (smap.base < 0x100000000ull)) { size = smap.length; /* * If this segment crosses the 4GB boundary, truncate it. */ if (smap.base + size > 0x100000000ull) size = 0x100000000ull - smap.base; if (size > high_heap_size) { high_heap_size = size; high_heap_base = smap.base; } } } while (v86.ebx != 0); /* Fall back to the old compatibility function for base memory */ if (bios_basemem == 0) { v86.ctl = 0; v86.addr = 0x12; /* int 0x12 */ v86int(); bios_basemem = (v86.eax & 0xffff) * 1024; } /* Fall back through several compatibility functions for extended memory */ if (bios_extmem == 0) { v86.ctl = V86_FLAGS; v86.addr = 0x15; /* int 0x15 function 0xe801*/ v86.eax = 0xe801; v86int(); if (!V86_CY(v86.efl)) { bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; } } if (bios_extmem == 0) { v86.ctl = 0; v86.addr = 0x15; /* int 0x15 function 0x88*/ v86.eax = 0x8800; v86int(); bios_extmem = (v86.eax & 0xffff) * 1024; } /* * If we have extended memory and did not find a suitable heap * region in the SMAP, use the last 3MB of 'extended' memory as a * high heap candidate. */ if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { high_heap_size = HEAP_MIN; high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; } } /* * Try to detect a device supported by the legacy int13 BIOS */ static int int13probe(int drive) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x800; v86.edx = drive; v86int(); if (!V86_CY(v86.efl) && /* carry clear */ ((v86.edx & 0xff) != (drive & DRV_MASK))) { /* unit # OK */ if ((v86.ecx & 0x3f) == 0) { /* absurd sector size */ return(0); /* skip device */ } return (1); } return(0); } /* * We call this when we find a ZFS vdev - ZFS consumes the dsk * structure so we must make a new one. */ static struct dsk * copy_dsk(struct dsk *dsk) { struct dsk *newdsk; newdsk = malloc(sizeof(struct dsk)); *newdsk = *dsk; return (newdsk); } static void probe_drive(struct dsk *dsk) { #ifdef GPT struct gpt_hdr hdr; struct gpt_ent *ent; daddr_t slba, elba; unsigned part, entries_per_sec; #endif struct dos_partition *dp; char *sec; unsigned i; /* * If we find a vdev on the whole disk, stop here. Otherwise dig * out the partition table and probe each slice/partition * in turn for a vdev. */ if (vdev_probe(vdev_read, dsk, NULL) == 0) return; sec = dmadat->secbuf; dsk->start = 0; #ifdef GPT /* * First check for GPT. */ if (drvread(dsk, sec, 1, 1)) { return; } memcpy(&hdr, sec, sizeof(hdr)); if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { goto trymbr; } /* * Probe all GPT partitions for the presense of ZFS pools. We * return the spa_t for the first we find (if requested). This * will have the effect of booting from the first pool on the * disk. */ entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; slba = hdr.hdr_lba_table; elba = slba + hdr.hdr_entries / entries_per_sec; while (slba < elba) { dsk->start = 0; if (drvread(dsk, sec, slba, 1)) return; for (part = 0; part < entries_per_sec; part++) { ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); if (memcmp(&ent->ent_type, &freebsd_zfs_uuid, sizeof(uuid_t)) == 0) { dsk->start = ent->ent_lba_start; if (vdev_probe(vdev_read, dsk, NULL) == 0) { /* * This slice had a vdev. We need a new dsk * structure now since the vdev now owns this one. */ dsk = copy_dsk(dsk); } } } slba++; } return; trymbr: #endif if (drvread(dsk, sec, DOSBBSECTOR, 1)) return; dp = (void *)(sec + DOSPARTOFF); for (i = 0; i < NDOSPART; i++) { if (!dp[i].dp_typ) continue; dsk->start = dp[i].dp_start; if (vdev_probe(vdev_read, dsk, NULL) == 0) { /* * This slice had a vdev. We need a new dsk structure now * since the vdev now owns this one. */ dsk = copy_dsk(dsk); } } } int main(void) { int autoboot, i; dnode_phys_t dn; off_t off; struct dsk *dsk; dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); bios_getmem(); if (high_heap_size > 0) { heap_end = PTOV(high_heap_base + high_heap_size); heap_next = PTOV(high_heap_base); } else { heap_next = (char *) dmadat + sizeof(*dmadat); heap_end = (char *) PTOV(bios_basemem); } dsk = malloc(sizeof(struct dsk)); 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; dsk->part = 0; dsk->start = 0; dsk->init = 0; bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_size = sizeof(bootinfo); bootinfo.bi_basemem = bios_basemem / 1024; bootinfo.bi_extmem = bios_extmem / 1024; bootinfo.bi_memsizes_valid++; bootinfo.bi_bios_dev = dsk->drive; bootdev = MAKEBOOTDEV(dev_maj[dsk->type], dsk->slice, dsk->unit, dsk->part), /* Process configuration file */ autoboot = 1; zfs_init(); /* * Probe the boot drive first - we will try to boot from whatever * pool we find on that drive. */ probe_drive(dsk); /* * Probe the rest of the drives that the bios knows about. This * will find any other available pools and it may fill in missing * vdevs for the boot pool. */ #ifndef VIRTUALBOX for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) #else for (i = 0; i < MAXBDDEV; i++) #endif { if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS)) continue; if (!int13probe(i | DRV_HARD)) break; dsk = malloc(sizeof(struct dsk)); dsk->drive = i | DRV_HARD; dsk->type = dsk->drive & TYPE_AD; dsk->unit = i; dsk->slice = 0; dsk->part = 0; dsk->start = 0; dsk->init = 0; probe_drive(dsk); } /* * The first discovered pool, if any, is the pool. */ spa = spa_get_primary(); if (!spa) { printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); for (;;) ; } primary_spa = spa; primary_vdev = spa_get_primary_vdev(spa); if (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0) { printf("%s: failed to mount default pool %s\n", BOOTPROG, spa->spa_name); autoboot = 0; } else if (zfs_lookup(&zfsmount, PATH_CONFIG, &dn) == 0 || zfs_lookup(&zfsmount, PATH_DOTCONFIG, &dn) == 0) { off = 0; zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); } if (*cmd) { /* * Note that parse() is destructive to cmd[] and we also want * to honor RBX_QUIET option that could be present in cmd[]. */ memcpy(cmddup, cmd, sizeof(cmd)); if (parse()) autoboot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s\n", 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 (autoboot && !*kname) { memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); if (!keyhit(3)) { load(); memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); } } /* Present the user with the boot2 prompt. */ for (;;) { if (!autoboot || !OPT_CHECK(RBX_QUIET)) { printf("\nFreeBSD/x86 boot\n"); if (zfs_rlookup(spa, zfsmount.rootobj, rootname) != 0) printf("Default: %s/<0x%llx>:%s\n" "boot: ", spa->spa_name, zfsmount.rootobj, kname); else if (rootname[0] != '\0') printf("Default: %s/%s:%s\n" "boot: ", spa->spa_name, rootname, kname); else printf("Default: %s:%s\n" "boot: ", spa->spa_name, kname); } if (ioctrl & IO_SERIAL) sio_flush(); if (!autoboot || keyhit(5)) getstr(cmd, sizeof(cmd)); 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; dnode_phys_t dn; off_t off; uint32_t addr, x; int fmt, i, j; if (zfs_lookup(&zfsmount, kname, &dn)) { printf("\nCan't find %s\n", kname); return; } off = 0; if (xfsread(&dn, &off, &hdr, sizeof(hdr))) return; if (N_GETMAGIC(hdr.ex) == ZMAGIC) fmt = 0; else if (IS_ELF(hdr.eh)) fmt = 1; else { printf("Invalid %s\n", "format"); return; } if (fmt == 0) { addr = hdr.ex.a_entry & 0xffffff; p = PTOV(addr); off = PAGE_SIZE; if (xfsread(&dn, &off, p, hdr.ex.a_text)) return; p += roundup2(hdr.ex.a_text, PAGE_SIZE); if (xfsread(&dn, &off, p, hdr.ex.a_data)) return; p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { if (xfsread(&dn, &off, p, hdr.ex.a_syms)) return; p += hdr.ex.a_syms; if (xfsread(&dn, &off, p, sizeof(int))) return; x = *(uint32_t *)p; p += sizeof(int); x -= sizeof(int); if (xfsread(&dn, &off, p, x)) return; p += x; } } else { off = hdr.eh.e_phoff; for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { if (xfsread(&dn, &off, 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); off = ep[i].p_offset; if (xfsread(&dn, &off, 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) { off = hdr.eh.e_shoff + sizeof(es[0]) * (hdr.eh.e_shstrndx + 1); if (xfsread(&dn, &off, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); p += sizeof(es[i].sh_size); off = es[i].sh_offset; if (xfsread(&dn, &off, p, es[i].sh_size)) return; p += es[i].sh_size; } } addr = hdr.eh.e_entry & 0xffffff; } bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(kname); zfsargs.size = sizeof(zfsargs); zfsargs.pool = zfsmount.spa->spa_guid; zfsargs.root = zfsmount.rootobj; zfsargs.primary_pool = primary_spa->spa_guid; if (primary_vdev != NULL) zfsargs.primary_vdev = primary_vdev->v_guid; else printf("failed to detect primary vdev\n"); __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), bootdev, KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, (uint32_t) spa->spa_guid, (uint32_t) (spa->spa_guid >> 32), VTOP(&bootinfo), zfsargs); } static int zfs_mount_ds(char *dsname) { uint64_t newroot; spa_t *newspa; char *q; q = strchr(dsname, '/'); if (q) *q++ = '\0'; newspa = spa_find_by_name(dsname); if (newspa == NULL) { printf("\nCan't find ZFS pool %s\n", dsname); return -1; } if (zfs_spa_init(newspa)) return -1; newroot = 0; if (q) { if (zfs_lookup_dataset(newspa, q, &newroot)) { printf("\nCan't find dataset %s in ZFS pool %s\n", q, newspa->spa_name); return -1; } } if (zfs_mount(newspa, newroot, &zfsmount)) { printf("\nCan't mount ZFS dataset\n"); return -1; } spa = newspa; return (0); } static int parse(void) { char *arg = cmd; char *ep, *p, *q; const char *cp; int c, i, j; 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; } 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[]). */ } 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 (ioctrl & IO_SERIAL) { if (sio_init(115200 / comspeed) != 0) ioctrl &= ~IO_SERIAL; } } if (c == '?') { dnode_phys_t dn; if (zfs_lookup(&zfsmount, arg, &dn) == 0) { zap_list(spa, &dn); } return -1; } else { arg--; /* * Report pool status if the comment is 'status'. Lets * hope no-one wants to load /status as a kernel. */ if (!strcmp(arg, "status")) { spa_all_status(); return -1; } /* * If there is "zfs:" prefix simply ignore it. */ if (strncmp(arg, "zfs:", 4) == 0) arg += 4; /* * If there is a colon, switch pools. */ q = strchr(arg, ':'); if (q) { *q++ = '\0'; if (zfs_mount_ds(arg) != 0) return -1; arg = q; } if ((i = ep - arg)) { if ((size_t)i >= sizeof(kname)) return -1; memcpy(kname, arg, i + 1); } } arg = p; } return 0; } Index: head/sys/boot/mips/beri/boot2/boot2.c =================================================================== --- head/sys/boot/mips/beri/boot2/boot2.c (revision 294764) +++ head/sys/boot/mips/beri/boot2/boot2.c (revision 294765) @@ -1,701 +1,698 @@ /*- * 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" + 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 PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" #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 294764) +++ head/sys/boot/pc98/boot2/boot2.c (revision 294765) @@ -1,844 +1,840 @@ /*- * 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" /* 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 PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" #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; } } Index: head/sys/boot/powerpc/boot1.chrp/boot1.c =================================================================== --- head/sys/boot/powerpc/boot1.chrp/boot1.c (revision 294764) +++ head/sys/boot/powerpc/boot1.chrp/boot1.c (revision 294765) @@ -1,767 +1,766 @@ /*- * Copyright (c) 1998 Robert Nordier * All rights reserved. * Copyright (c) 2001 Robert Drehmel * 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 -#define _PATH_LOADER "/boot/loader" -#define _PATH_KERNEL "/boot/kernel/kernel" +#include "paths.h" #define BSIZEMAX 16384 typedef int putc_func_t(char c, void *arg); typedef int32_t ofwh_t; struct sp_data { char *sp_buf; u_int sp_len; u_int sp_size; }; static const char digits[] = "0123456789abcdef"; static char bootpath[128]; static char bootargs[128]; static ofwh_t bootdev; static struct fs fs; static char blkbuf[BSIZEMAX]; static unsigned int fsblks; static uint32_t fs_off; int main(int ac, char **av); static void exit(int) __dead2; static void load(const char *); static int dskread(void *, u_int64_t, int); static void usage(void); static void bcopy(const void *src, void *dst, size_t len); static void bzero(void *b, size_t len); static int domount(const char *device, int quiet); static void panic(const char *fmt, ...) __dead2; static int printf(const char *fmt, ...); static int putchar(char c, void *arg); static int vprintf(const char *fmt, va_list ap); static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); static int __putc(char c, void *arg); static int __puts(const char *s, putc_func_t *putc, void *arg); static int __sputc(char c, void *arg); static char *__uitoa(char *buf, u_int val, int base); static char *__ultoa(char *buf, u_long val, int base); void __syncicache(void *, int); /* * Open Firmware interface functions */ typedef u_int32_t ofwcell_t; typedef u_int32_t u_ofwh_t; typedef int (*ofwfp_t)(void *); ofwfp_t ofw; /* the prom Open Firmware entry */ ofwh_t chosenh; void ofw_init(void *, int, int (*)(void *), char *, int); static ofwh_t ofw_finddevice(const char *); static ofwh_t ofw_open(const char *); static int ofw_close(ofwh_t); static int ofw_getprop(ofwh_t, const char *, void *, size_t); static int ofw_setprop(ofwh_t, const char *, void *, size_t); static int ofw_read(ofwh_t, void *, size_t); static int ofw_write(ofwh_t, const void *, size_t); static int ofw_claim(void *virt, size_t len, u_int align); static int ofw_seek(ofwh_t, u_int64_t); static void ofw_exit(void) __dead2; ofwh_t bootdevh; ofwh_t stdinh, stdouth; __asm(" \n\ .data \n\ .align 4 \n\ stack: \n\ .space 16384 \n\ \n\ .text \n\ .globl _start \n\ _start: \n\ lis %r1,stack@ha \n\ addi %r1,%r1,stack@l \n\ addi %r1,%r1,8192 \n\ \n\ b ofw_init \n\ "); void ofw_init(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl) { char *av[16]; char *p; int ac; ofw = openfirm; chosenh = ofw_finddevice("/chosen"); ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs)); ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); bootargs[sizeof(bootargs) - 1] = '\0'; bootpath[sizeof(bootpath) - 1] = '\0'; p = bootpath; while (*p != '\0') { if (*p == ':') { *(++p) = '\0'; break; } p++; } ac = 0; p = bootargs; for (;;) { while (*p == ' ' && *p != '\0') p++; if (*p == '\0' || ac >= 16) break; av[ac++] = p; while (*p != ' ' && *p != '\0') p++; if (*p != '\0') *p++ = '\0'; } exit(main(ac, av)); } static ofwh_t ofw_finddevice(const char *name) { ofwcell_t args[] = { (ofwcell_t)"finddevice", 1, 1, (ofwcell_t)name, 0 }; if ((*ofw)(args)) { printf("ofw_finddevice: name=\"%s\"\n", name); return (1); } return (args[4]); } static int ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"getprop", 4, 1, (u_ofwh_t)ofwh, (ofwcell_t)name, (ofwcell_t)buf, len, 0 }; if ((*ofw)(args)) { printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", ofwh, buf, len); return (1); } return (0); } static int ofw_setprop(ofwh_t ofwh, const char *name, void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"setprop", 4, 1, (u_ofwh_t)ofwh, (ofwcell_t)name, (ofwcell_t)buf, len, 0 }; if ((*ofw)(args)) { printf("ofw_setprop: ofwh=0x%x buf=%p len=%u\n", ofwh, buf, len); return (1); } return (0); } static ofwh_t ofw_open(const char *path) { ofwcell_t args[] = { (ofwcell_t)"open", 1, 1, (ofwcell_t)path, 0 }; if ((*ofw)(args)) { printf("ofw_open: path=\"%s\"\n", path); return (-1); } return (args[4]); } static int ofw_close(ofwh_t devh) { ofwcell_t args[] = { (ofwcell_t)"close", 1, 0, (u_ofwh_t)devh }; if ((*ofw)(args)) { printf("ofw_close: devh=0x%x\n", devh); return (1); } return (0); } static int ofw_claim(void *virt, size_t len, u_int align) { ofwcell_t args[] = { (ofwcell_t)"claim", 3, 1, (ofwcell_t)virt, len, align, 0, 0 }; if ((*ofw)(args)) { printf("ofw_claim: virt=%p len=%u\n", virt, len); return (1); } return (0); } static int ofw_read(ofwh_t devh, void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"read", 3, 1, (u_ofwh_t)devh, (ofwcell_t)buf, len, 0 }; if ((*ofw)(args)) { printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); return (1); } return (0); } static int ofw_write(ofwh_t devh, const void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"write", 3, 1, (u_ofwh_t)devh, (ofwcell_t)buf, len, 0 }; if ((*ofw)(args)) { printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); return (1); } return (0); } static int ofw_seek(ofwh_t devh, u_int64_t off) { ofwcell_t args[] = { (ofwcell_t)"seek", 3, 1, (u_ofwh_t)devh, off >> 32, off, 0 }; if ((*ofw)(args)) { printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); return (1); } return (0); } static void ofw_exit(void) { ofwcell_t args[3]; args[0] = (ofwcell_t)"exit"; args[1] = 0; args[2] = 0; for (;;) (*ofw)(args); } static void bcopy(const void *src, void *dst, size_t len) { const char *s = src; char *d = dst; while (len-- != 0) *d++ = *s++; } static void memcpy(void *dst, const void *src, size_t len) { bcopy(src, dst, len); } static void bzero(void *b, size_t len) { char *p = b; while (len-- != 0) *p++ = 0; } static int strcmp(const char *s1, const char *s2) { for (; *s1 == *s2 && *s1; s1++, s2++) ; return ((u_char)*s1 - (u_char)*s2); } #include "ufsread.c" int main(int ac, char **av) { const char *path; char bootpath_full[255]; int i, len; - path = _PATH_LOADER; + path = PATH_LOADER; for (i = 0; i < ac; i++) { switch (av[i][0]) { case '-': switch (av[i][1]) { default: usage(); } break; default: path = av[i]; break; } } printf(" \n>> FreeBSD/powerpc Open Firmware boot block\n" " Boot path: %s\n" " Boot loader: %s\n", bootpath, path); len = 0; while (bootpath[len] != '\0') len++; memcpy(bootpath_full,bootpath,len+1); if (bootpath_full[len-1] == ':') { for (i = 0; i < 16; i++) { if (i < 10) { bootpath_full[len] = i + '0'; bootpath_full[len+1] = '\0'; } else { bootpath_full[len] = '1'; bootpath_full[len+1] = i - 10 + '0'; bootpath_full[len+2] = '\0'; } if (domount(bootpath_full,1) >= 0) break; if (bootdev > 0) ofw_close(bootdev); } if (i >= 16) panic("domount"); } else { if (domount(bootpath_full,0) == -1) panic("domount"); } printf(" Boot volume: %s\n",bootpath_full); ofw_setprop(chosenh, "bootargs", bootpath_full, len+2); load(path); return (1); } static void usage(void) { printf("usage: boot device [/path/to/loader]\n"); exit(1); } static void exit(int code) { ofw_exit(); } static struct dmadat __dmadat; static int domount(const char *device, int quiet) { dmadat = &__dmadat; if ((bootdev = ofw_open(device)) == -1) { printf("domount: can't open device\n"); return (-1); } if (fsread(0, NULL, 0)) { if (!quiet) printf("domount: can't read superblock\n"); return (-1); } return (0); } static void load(const char *fname) { Elf32_Ehdr eh; Elf32_Phdr ph; caddr_t p; ufs_ino_t ino; int i; if ((ino = lookup(fname)) == 0) { printf("File %s not found\n", fname); return; } if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { printf("Can't read elf header\n"); return; } if (!IS_ELF(eh)) { printf("Not an ELF file\n"); return; } for (i = 0; i < eh.e_phnum; i++) { fs_off = eh.e_phoff + i * eh.e_phentsize; if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { printf("Can't read program header %d\n", i); return; } if (ph.p_type != PT_LOAD) continue; fs_off = ph.p_offset; p = (caddr_t)ph.p_vaddr; ofw_claim(p,(ph.p_filesz > ph.p_memsz) ? ph.p_filesz : ph.p_memsz,0); if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { printf("Can't read content of section %d\n", i); return; } if (ph.p_filesz != ph.p_memsz) bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); __syncicache(p, ph.p_memsz); } ofw_close(bootdev); (*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0, ofw,NULL,0); } static int dskread(void *buf, u_int64_t lba, int nblk) { /* * The Open Firmware should open the correct partition for us. * That means, if we read from offset zero on an open instance handle, * we should read from offset zero of that partition. */ ofw_seek(bootdev, lba * DEV_BSIZE); ofw_read(bootdev, buf, nblk * DEV_BSIZE); return (0); } static void panic(const char *fmt, ...) { char buf[128]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof buf, fmt, ap); printf("panic: %s\n", buf); va_end(ap); exit(1); } static int printf(const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = vprintf(fmt, ap); va_end(ap); return (ret); } static int putchar(char c, void *arg) { char buf; if (c == '\n') { buf = '\r'; ofw_write(stdouth, &buf, 1); } buf = c; ofw_write(stdouth, &buf, 1); return (1); } static int vprintf(const char *fmt, va_list ap) { int ret; ret = __printf(fmt, putchar, 0, ap); return (ret); } static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) { struct sp_data sp; int ret; sp.sp_buf = str; sp.sp_len = 0; sp.sp_size = sz; ret = __printf(fmt, __sputc, &sp, ap); return (ret); } static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) { char buf[(sizeof(long) * 8) + 1]; char *nbuf; u_long ul; u_int ui; int lflag; int sflag; char *s; int pad; int ret; int c; nbuf = &buf[sizeof buf - 1]; ret = 0; while ((c = *fmt++) != 0) { if (c != '%') { ret += putc(c, arg); continue; } lflag = 0; sflag = 0; pad = 0; reswitch: c = *fmt++; switch (c) { case '#': sflag = 1; goto reswitch; case '%': ret += putc('%', arg); break; case 'c': c = va_arg(ap, int); ret += putc(c, arg); break; case 'd': if (lflag == 0) { ui = (u_int)va_arg(ap, int); if (ui < (int)ui) { ui = -ui; ret += putc('-', arg); } s = __uitoa(nbuf, ui, 10); } else { ul = (u_long)va_arg(ap, long); if (ul < (long)ul) { ul = -ul; ret += putc('-', arg); } s = __ultoa(nbuf, ul, 10); } ret += __puts(s, putc, arg); break; case 'l': lflag = 1; goto reswitch; case 'o': if (lflag == 0) { ui = (u_int)va_arg(ap, u_int); s = __uitoa(nbuf, ui, 8); } else { ul = (u_long)va_arg(ap, u_long); s = __ultoa(nbuf, ul, 8); } ret += __puts(s, putc, arg); break; case 'p': ul = (u_long)va_arg(ap, void *); s = __ultoa(nbuf, ul, 16); ret += __puts("0x", putc, arg); ret += __puts(s, putc, arg); break; case 's': s = va_arg(ap, char *); ret += __puts(s, putc, arg); break; case 'u': if (lflag == 0) { ui = va_arg(ap, u_int); s = __uitoa(nbuf, ui, 10); } else { ul = va_arg(ap, u_long); s = __ultoa(nbuf, ul, 10); } ret += __puts(s, putc, arg); break; case 'x': if (lflag == 0) { ui = va_arg(ap, u_int); s = __uitoa(nbuf, ui, 16); } else { ul = va_arg(ap, u_long); s = __ultoa(nbuf, ul, 16); } if (sflag) ret += __puts("0x", putc, arg); ret += __puts(s, putc, arg); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': pad = pad * 10 + c - '0'; goto reswitch; default: break; } } return (ret); } static int __sputc(char c, void *arg) { struct sp_data *sp; sp = arg; if (sp->sp_len < sp->sp_size) sp->sp_buf[sp->sp_len++] = c; sp->sp_buf[sp->sp_len] = '\0'; return (1); } static int __puts(const char *s, putc_func_t *putc, void *arg) { const char *p; int ret; ret = 0; for (p = s; *p != '\0'; p++) ret += putc(*p, arg); return (ret); } static char * __uitoa(char *buf, u_int ui, int base) { char *p; p = buf; *p = '\0'; do *--p = digits[ui % base]; while ((ui /= base) != 0); return (p); } static char * __ultoa(char *buf, u_long ul, int base) { char *p; p = buf; *p = '\0'; do *--p = digits[ul % base]; while ((ul /= base) != 0); return (p); } Index: head/sys/boot/sparc64/boot1/boot1.c =================================================================== --- head/sys/boot/sparc64/boot1/boot1.c (revision 294764) +++ head/sys/boot/sparc64/boot1/boot1.c (revision 294765) @@ -1,751 +1,751 @@ /*- * Copyright (c) 1998 Robert Nordier * All rights reserved. * Copyright (c) 2001 Robert Drehmel * 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 -#define _PATH_LOADER "/boot/loader" -#define _PATH_KERNEL "/boot/kernel/kernel" +#include "paths.h" + #define READ_BUF_SIZE 8192 typedef int putc_func_t(char c, void *arg); typedef int32_t ofwh_t; struct sp_data { char *sp_buf; u_int sp_len; u_int sp_size; }; static const char digits[] = "0123456789abcdef"; static char bootpath[128]; static char bootargs[128]; static ofwh_t bootdev; static uint32_t fs_off; int main(int ac, char **av); static void exit(int) __dead2; static void usage(void); #ifdef ZFSBOOT static void loadzfs(void); static int zbread(char *buf, off_t off, size_t bytes); #else static void load(const char *); #endif static void bcopy(const void *src, void *dst, size_t len); static void bzero(void *b, size_t len); static int domount(const char *device); static int dskread(void *buf, u_int64_t lba, int nblk); static void panic(const char *fmt, ...) __dead2; static int printf(const char *fmt, ...); static int putchar(char c, void *arg); static int vprintf(const char *fmt, va_list ap); static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); static int __puts(const char *s, putc_func_t *putc, void *arg); static int __sputc(char c, void *arg); static char *__uitoa(char *buf, u_int val, int base); static char *__ultoa(char *buf, u_long val, int base); /* * Open Firmware interface functions */ typedef u_int64_t ofwcell_t; typedef u_int32_t u_ofwh_t; typedef int (*ofwfp_t)(ofwcell_t []); static ofwfp_t ofw; /* the PROM Open Firmware entry */ void ofw_init(int, int, int, int, ofwfp_t); static ofwh_t ofw_finddevice(const char *); static ofwh_t ofw_open(const char *); static int ofw_getprop(ofwh_t, const char *, void *, size_t); static int ofw_read(ofwh_t, void *, size_t); static int ofw_write(ofwh_t, const void *, size_t); static int ofw_seek(ofwh_t, u_int64_t); static void ofw_exit(void) __dead2; static ofwh_t stdinh, stdouth; /* * This has to stay here, as the PROM seems to ignore the * entry point specified in the a.out header. (or elftoaout is broken) */ void ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr) { ofwh_t chosenh; char *av[16]; char *p; int ac; ofw = ofwaddr; chosenh = ofw_finddevice("/chosen"); ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs)); ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); bootargs[sizeof(bootargs) - 1] = '\0'; bootpath[sizeof(bootpath) - 1] = '\0'; ac = 0; p = bootargs; for (;;) { while (*p == ' ' && *p != '\0') p++; if (*p == '\0' || ac >= 16) break; av[ac++] = p; while (*p != ' ' && *p != '\0') p++; if (*p != '\0') *p++ = '\0'; } exit(main(ac, av)); } static ofwh_t ofw_finddevice(const char *name) { ofwcell_t args[] = { (ofwcell_t)"finddevice", 1, 1, (ofwcell_t)name, 0 }; if ((*ofw)(args)) { printf("ofw_finddevice: name=\"%s\"\n", name); return (1); } return (args[4]); } static int ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"getprop", 4, 1, (u_ofwh_t)ofwh, (ofwcell_t)name, (ofwcell_t)buf, len, 0 }; if ((*ofw)(args)) { printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", ofwh, buf, len); return (1); } return (0); } static ofwh_t ofw_open(const char *path) { ofwcell_t args[] = { (ofwcell_t)"open", 1, 1, (ofwcell_t)path, 0 }; if ((*ofw)(args)) { printf("ofw_open: path=\"%s\"\n", path); return (-1); } return (args[4]); } static int ofw_close(ofwh_t devh) { ofwcell_t args[] = { (ofwcell_t)"close", 1, 0, (u_ofwh_t)devh }; if ((*ofw)(args)) { printf("ofw_close: devh=0x%x\n", devh); return (1); } return (0); } static int ofw_read(ofwh_t devh, void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"read", 3, 1, (u_ofwh_t)devh, (ofwcell_t)buf, len, 0 }; if ((*ofw)(args)) { printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); return (1); } return (0); } static int ofw_write(ofwh_t devh, const void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"write", 3, 1, (u_ofwh_t)devh, (ofwcell_t)buf, len, 0 }; if ((*ofw)(args)) { printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); return (1); } return (0); } static int ofw_seek(ofwh_t devh, u_int64_t off) { ofwcell_t args[] = { (ofwcell_t)"seek", 3, 1, (u_ofwh_t)devh, off >> 32, off, 0 }; if ((*ofw)(args)) { printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); return (1); } return (0); } static void ofw_exit(void) { ofwcell_t args[3]; args[0] = (ofwcell_t)"exit"; args[1] = 0; args[2] = 0; for (;;) (*ofw)(args); } static void bcopy(const void *src, void *dst, size_t len) { const char *s = src; char *d = dst; while (len-- != 0) *d++ = *s++; } static void memcpy(void *dst, const void *src, size_t len) { bcopy(src, dst, len); } static void bzero(void *b, size_t len) { char *p = b; while (len-- != 0) *p++ = 0; } static int strcmp(const char *s1, const char *s2) { for (; *s1 == *s2 && *s1; s1++, s2++) ; return ((u_char)*s1 - (u_char)*s2); } int main(int ac, char **av) { const char *path; int i; - path = _PATH_LOADER; + path = PATH_LOADER; for (i = 0; i < ac; i++) { switch (av[i][0]) { case '-': switch (av[i][1]) { default: usage(); } break; default: path = av[i]; break; } } #ifdef ZFSBOOT printf(" \n>> FreeBSD/sparc64 ZFS boot block\n Boot path: %s\n", bootpath); #else printf(" \n>> FreeBSD/sparc64 boot block\n Boot path: %s\n" " Boot loader: %s\n", bootpath, path); #endif if (domount(bootpath) == -1) panic("domount"); #ifdef ZFSBOOT loadzfs(); #else load(path); #endif return (1); } static void usage(void) { printf("usage: boot device [/path/to/loader]\n"); exit(1); } static void exit(int code) { ofw_exit(); } #ifdef ZFSBOOT #define VDEV_BOOT_OFFSET (2 * 256 * 1024) static char zbuf[READ_BUF_SIZE]; static int zbread(char *buf, off_t off, size_t bytes) { size_t len; off_t poff; off_t soff; char *p; unsigned int nb; unsigned int lb; p = buf; soff = VDEV_BOOT_OFFSET + off; lb = (soff + bytes + DEV_BSIZE - 1) / DEV_BSIZE; poff = soff; while (poff < soff + bytes) { nb = lb - poff / DEV_BSIZE; if (nb > READ_BUF_SIZE / DEV_BSIZE) nb = READ_BUF_SIZE / DEV_BSIZE; if (dskread(zbuf, poff / DEV_BSIZE, nb)) break; if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes) len = soff + bytes - poff; else len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff; memcpy(p, zbuf + poff % DEV_BSIZE, len); p += len; poff += len; } return (poff - soff); } static void loadzfs(void) { Elf64_Ehdr eh; Elf64_Phdr ph; caddr_t p; int i; if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) { printf("Can't read elf header\n"); return; } if (!IS_ELF(eh)) { printf("Not an ELF file\n"); return; } for (i = 0; i < eh.e_phnum; i++) { fs_off = eh.e_phoff + i * eh.e_phentsize; if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) { printf("Can't read program header %d\n", i); return; } if (ph.p_type != PT_LOAD) continue; fs_off = ph.p_offset; p = (caddr_t)ph.p_vaddr; if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) { printf("Can't read content of section %d\n", i); return; } if (ph.p_filesz != ph.p_memsz) bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); } ofw_close(bootdev); (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); } #else #include "ufsread.c" static struct dmadat __dmadat; static void load(const char *fname) { Elf64_Ehdr eh; Elf64_Phdr ph; caddr_t p; ufs_ino_t ino; int i; if ((ino = lookup(fname)) == 0) { printf("File %s not found\n", fname); return; } if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { printf("Can't read elf header\n"); return; } if (!IS_ELF(eh)) { printf("Not an ELF file\n"); return; } for (i = 0; i < eh.e_phnum; i++) { fs_off = eh.e_phoff + i * eh.e_phentsize; if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { printf("Can't read program header %d\n", i); return; } if (ph.p_type != PT_LOAD) continue; fs_off = ph.p_offset; p = (caddr_t)ph.p_vaddr; if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { printf("Can't read content of section %d\n", i); return; } if (ph.p_filesz != ph.p_memsz) bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); } ofw_close(bootdev); (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); } #endif /* ZFSBOOT */ static int domount(const char *device) { if ((bootdev = ofw_open(device)) == -1) { printf("domount: can't open device\n"); return (-1); } #ifndef ZFSBOOT dmadat = &__dmadat; if (fsread(0, NULL, 0)) { printf("domount: can't read superblock\n"); return (-1); } #endif return (0); } static int dskread(void *buf, u_int64_t lba, int nblk) { /* * The Open Firmware should open the correct partition for us. * That means, if we read from offset zero on an open instance handle, * we should read from offset zero of that partition. */ ofw_seek(bootdev, lba * DEV_BSIZE); ofw_read(bootdev, buf, nblk * DEV_BSIZE); return (0); } static void panic(const char *fmt, ...) { char buf[128]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof buf, fmt, ap); printf("panic: %s\n", buf); va_end(ap); exit(1); } static int printf(const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = vprintf(fmt, ap); va_end(ap); return (ret); } static int putchar(char c, void *arg) { char buf; if (c == '\n') { buf = '\r'; ofw_write(stdouth, &buf, 1); } buf = c; ofw_write(stdouth, &buf, 1); return (1); } static int vprintf(const char *fmt, va_list ap) { int ret; ret = __printf(fmt, putchar, 0, ap); return (ret); } static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) { struct sp_data sp; int ret; sp.sp_buf = str; sp.sp_len = 0; sp.sp_size = sz; ret = __printf(fmt, __sputc, &sp, ap); return (ret); } static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) { char buf[(sizeof(long) * 8) + 1]; char *nbuf; u_long ul; u_int ui; int lflag; int sflag; char *s; int pad; int ret; int c; nbuf = &buf[sizeof buf - 1]; ret = 0; while ((c = *fmt++) != 0) { if (c != '%') { ret += putc(c, arg); continue; } lflag = 0; sflag = 0; pad = 0; reswitch: c = *fmt++; switch (c) { case '#': sflag = 1; goto reswitch; case '%': ret += putc('%', arg); break; case 'c': c = va_arg(ap, int); ret += putc(c, arg); break; case 'd': if (lflag == 0) { ui = (u_int)va_arg(ap, int); if (ui < (int)ui) { ui = -ui; ret += putc('-', arg); } s = __uitoa(nbuf, ui, 10); } else { ul = (u_long)va_arg(ap, long); if (ul < (long)ul) { ul = -ul; ret += putc('-', arg); } s = __ultoa(nbuf, ul, 10); } ret += __puts(s, putc, arg); break; case 'l': lflag = 1; goto reswitch; case 'o': if (lflag == 0) { ui = (u_int)va_arg(ap, u_int); s = __uitoa(nbuf, ui, 8); } else { ul = (u_long)va_arg(ap, u_long); s = __ultoa(nbuf, ul, 8); } ret += __puts(s, putc, arg); break; case 'p': ul = (u_long)va_arg(ap, void *); s = __ultoa(nbuf, ul, 16); ret += __puts("0x", putc, arg); ret += __puts(s, putc, arg); break; case 's': s = va_arg(ap, char *); ret += __puts(s, putc, arg); break; case 'u': if (lflag == 0) { ui = va_arg(ap, u_int); s = __uitoa(nbuf, ui, 10); } else { ul = va_arg(ap, u_long); s = __ultoa(nbuf, ul, 10); } ret += __puts(s, putc, arg); break; case 'x': if (lflag == 0) { ui = va_arg(ap, u_int); s = __uitoa(nbuf, ui, 16); } else { ul = va_arg(ap, u_long); s = __ultoa(nbuf, ul, 16); } if (sflag) ret += __puts("0x", putc, arg); ret += __puts(s, putc, arg); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': pad = pad * 10 + c - '0'; goto reswitch; default: break; } } return (ret); } static int __sputc(char c, void *arg) { struct sp_data *sp; sp = arg; if (sp->sp_len < sp->sp_size) sp->sp_buf[sp->sp_len++] = c; sp->sp_buf[sp->sp_len] = '\0'; return (1); } static int __puts(const char *s, putc_func_t *putc, void *arg) { const char *p; int ret; ret = 0; for (p = s; *p != '\0'; p++) ret += putc(*p, arg); return (ret); } static char * __uitoa(char *buf, u_int ui, int base) { char *p; p = buf; *p = '\0'; do *--p = digits[ui % base]; while ((ui /= base) != 0); return (p); } static char * __ultoa(char *buf, u_long ul, int base) { char *p; p = buf; *p = '\0'; do *--p = digits[ul % base]; while ((ul /= base) != 0); return (p); }