Index: stable/8/sys/boot/arm/at91/boot2/boot2.c =================================================================== --- stable/8/sys/boot/arm/at91/boot2/boot2.c (revision 231287) +++ stable/8/sys/boot/arm/at91/boot2/boot2.c (revision 231288) @@ -1,393 +1,395 @@ /*- * Copyright (c) 2008 John Hay * Copyright (c) 2006 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" #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_CONFIG "/boot.config" +#define PATH_DOTCONFIG "/boot.config" +#define PATH_CONFIG "/boot/config" //#define PATH_KERNEL "/boot/kernel/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 flags[NOPT] = { RBX_ASKNAME, RBX_GDB, RBX_NOINTR, RBX_DFLTROOT, RBX_SINGLE, RBX_VERBOSE }; unsigned dsk_start; static char cmd[512]; static char kname[1024]; static uint32_t opts; static int dsk_meta; static void load(void); static int parse(void); static int xfsread(ino_t, void *, size_t); 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(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; ino_t ino; dmadat = (void *)(0x20000000 + (16 << 20)); board_init(); autoboot = 1; /* Process configuration file */ - if ((ino = lookup(PATH_CONFIG))) + 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(); } } static void load(void) { Elf32_Ehdr eh; static Elf32_Phdr ep[2]; caddr_t p; 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))addr)(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--; 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: stable/8/sys/boot/arm/ixp425/boot2/boot2.c =================================================================== --- stable/8/sys/boot/arm/ixp425/boot2/boot2.c (revision 231287) +++ stable/8/sys/boot/arm/ixp425/boot2/boot2.c (revision 231288) @@ -1,483 +1,485 @@ /*- * 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" #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_CONFIG "/boot.config" +#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 int 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 xfsread(ino_t, void *, size_t); 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(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; 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))) + 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; 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: stable/8/sys/boot/i386/boot2/boot2.c =================================================================== --- stable/8/sys/boot/i386/boot2/boot2.c (revision 231287) +++ stable/8/sys/boot/i386/boot2/boot2.c (revision 231288) @@ -1,648 +1,650 @@ /*- * 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" #define IO_KEYBOARD 1 #define IO_SERIAL 2 #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_CONFIG "/boot.config" +#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]; static const char *kname; static uint32_t opts; static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint8_t ioctrl = IO_KEYBOARD; void exit(int); static void load(void); static int parse(void); static int xfsread(ino_t, void *, size_t); 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(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; ino_t ino; kname = NULL; 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))) + if ((ino = lookup(PATH_CONFIG)) || + (ino = lookup(PATH_DOTCONFIG))) fsread(ino, cmd, sizeof(cmd)); 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 (autoboot && !kname) { kname = PATH_BOOT3; if (!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 (ioctrl & IO_SERIAL) 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; ino_t ino; uint32_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 (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 = 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++) { *(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; 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) sio_init(115200 / comspeed); } 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; } kname = arg; } 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; 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 = 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) { printf("Invalid %s\n", "label"); return -1; } } 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) { printf("Invalid %s\n", "partition"); return -1; } 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); } 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)) printf("%c\b", c = c << 8 | c >> 24); 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 (ioctrl & IO_KEYBOARD) putc(c); if (ioctrl & IO_SERIAL) 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 (ioctrl & IO_KEYBOARD && getc(1)) return fn ? 1 : getc(0); if (ioctrl & IO_SERIAL && sio_ischar()) return fn ? 1 : sio_getc(); if (fn) return 0; } } Index: stable/8/sys/boot/i386/gptboot/gptboot.c =================================================================== --- stable/8/sys/boot/i386/gptboot/gptboot.c (revision 231287) +++ stable/8/sys/boot/i386/gptboot/gptboot.c (revision 231288) @@ -1,435 +1,436 @@ /*- * 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_CONFIG "/boot.config" +#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 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 xfsread(ino_t, void *, size_t); static int dskread(void *, daddr_t, unsigned); static uint32_t memsize(void); #include "ufsread.c" static inline int xfsread(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]; int autoboot, dskupdated; 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'; - ino = lookup(PATH_CONFIG); - if (ino > 0) + if ((ino = lookup(PATH_CONFIG)) || + (ino = lookup(PATH_DOTCONFIG))) fsread(ino, cmd, sizeof(cmd)); 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; 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) sio_init(115200 / comspeed); } 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: stable/8/sys/boot/i386/zfsboot/zfsboot.c =================================================================== --- stable/8/sys/boot/i386/zfsboot/zfsboot.c (revision 231287) +++ stable/8/sys/boot/i386/zfsboot/zfsboot.c (revision 231288) @@ -1,775 +1,777 @@ /*- * 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" /* Hint to loader that we came from ZFS */ #define KARGS_FLAGS_ZFS 0x4 -#define PATH_CONFIG "/boot.config" +#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 #define MAXBDDEV 31 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 kname[1024]; static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint32_t bootdev; 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 */ spa_t *spa; /* * 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 %s\n", "format"); 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.efl & 1) || (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.efl & 1)) { 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.efl & 0x1) && /* 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, spa_t **spap) { #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 MBR and probe each slice in turn for a vdev. */ if (vdev_probe(vdev_read, dsk, spap) == 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, spap) == 0) { /* * We record the first pool we find (we will try * to boot from that one). */ spap = NULL; /* * 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, spap) == 0) { /* * We record the first pool we find (we will try to boot * from that one. */ spap = 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, &spa); /* * 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. */ for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) { 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, NULL); } /* * If we didn't find a pool on the boot drive, default to the * first pool we found, if any. */ if (!spa) { spa = STAILQ_FIRST(&zfs_pools); if (!spa) { printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); for (;;) ; } } zfs_mount_pool(spa); - if (zfs_lookup(spa, PATH_CONFIG, &dn) == 0) { + if (zfs_lookup(spa, PATH_CONFIG, &dn) == 0 || + zfs_lookup(spa, PATH_DOTCONFIG, &dn) == 0) { off = 0; zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); } if (*cmd) { if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmd); if (parse()) autoboot = 0; /* 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" "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(spa, kname, &dn)) { 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); __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), bootdev, KARGS_FLAGS_ZFS, (uint32_t) spa->spa_guid, (uint32_t) (spa->spa_guid >> 32), VTOP(&bootinfo)); } static int parse(void) { char *arg = cmd; char *ep, *p, *q; const char *cp; //unsigned int drv; 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) sio_init(115200 / comspeed); } if (c == '?') { dnode_phys_t dn; if (zfs_lookup(spa, 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 a colon, switch pools. */ q = (char *) strchr(arg, ':'); if (q) { spa_t *newspa; *q++ = 0; newspa = spa_find_by_name(arg); if (newspa) { spa = newspa; zfs_mount_pool(spa); } else { printf("\nCan't find ZFS pool %s\n", arg); 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: stable/8/sys/boot/pc98/boot2/boot2.c =================================================================== --- stable/8/sys/boot/pc98/boot2/boot2.c (revision 231287) +++ stable/8/sys/boot/pc98/boot2/boot2.c (revision 231288) @@ -1,803 +1,805 @@ /*- * 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" #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_CONFIG "/boot.config" +#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; unsigned slice; unsigned part; unsigned start; } dsk; static char cmd[512], cmddup[512]; static const char *kname = NULL; static uint32_t opts; static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint8_t ioctrl = IO_KEYBOARD; void exit(int); static void load(void); static int parse(void); static int xfsread(ino_t, void *, size_t); 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(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.efl & 0x1) 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, DOSBBSECTOR + 1)) return (WHOLE_DISK_SLICE); /* Read error */ dp = (void *)(sec + DOSPARTOFF); for (i = 0; i < NDOSPART; 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; ino_t ino; 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))) + if ((ino = lookup(PATH_CONFIG)) || + (ino = lookup(PATH_DOTCONFIG))) fsread(ino, cmd, sizeof(cmd)); 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 (autoboot && !kname) { kname = PATH_BOOT3; if (!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 (ioctrl & IO_SERIAL) 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; ino_t ino; uint32_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 (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 = 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++) { *(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; 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; } 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) sio_init(115200 / comspeed); } 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.disk = dev_daua[dsk.type]; dsk.daua = dsk.disk | dsk.unit; dsk_meta = 0; } kname = arg; } arg = p; } return 0; } static int dskread(void *buf, unsigned lba, unsigned nblk) { struct pc98_partition *dp; struct disklabel *d; char *sec; unsigned sl, i; u_char *p; if (!dsk_meta) { sec = dmadat->secbuf; set_dsk(); if (dsk.type == TYPE_FD) goto unsliced; 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_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) { printf("Invalid %s\n", "slice"); return -1; } 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) { printf("Invalid %s\n", "label"); return -1; } } else { if (dsk.part >= d->d_npartitions || !d->d_partitions[dsk.part].p_size) { printf("Invalid %s\n", "partition"); return -1; } 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; } 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)) printf("%c\b", c = c << 8 | c >> 24); 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 (ioctrl & IO_KEYBOARD) putc(c); if (ioctrl & IO_SERIAL) 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 (ioctrl & IO_KEYBOARD && getc(1)) return fn ? 1 : getc(0); if (ioctrl & IO_SERIAL && sio_ischar()) return fn ? 1 : sio_getc(); if (fn) return 0; } } Index: stable/8/sys/boot =================================================================== --- stable/8/sys/boot (revision 231287) +++ stable/8/sys/boot (revision 231288) Property changes on: stable/8/sys/boot ___________________________________________________________________ Added: svn:mergeinfo ## -0,0 +0,13 ## Merged /user/peter/kinfo/sys/boot:r185413-185547 Merged /stable/8/sys/sys/boot:r211823 Merged /head/sys/boot:r196118,196121-196122,196129,196132,196135,196141-196142,196149-196150,196152,196159,196162,196174,196176,196179,196193,196196,196200-196201,196203-196206,196224,196226,196228-196230,196234,196246,196256,196260,196263,196267-196269,196274,196276,196289,196291,196293,196295,196297,196299,196301,196303,196307,196309,196316,196318,196326,196332-196334,196342,196352-196353,196358,196364,196366,196368,196370,196372,196376,196378,196380,196386,196388,196390,196395,196397,196403-196404,196410,196412,196415,196417,196419,196423,196435,196455-196458,196460,196464-196466,196470-196471,196481-196482,196487-196498,196501-196505,196507,196509-196510,196512,196516-196520,196524,196529,196531-196536,196543,196547,196551,196553,196556,196559-196560,196567-196569,196579-196580,196592,196608-196610,196615,196633,196635-196637,196640,196643-196644,196648-196649,196653,196655-196657,196659-196660,196662,196678,196689,196692,196702-196705,196707,196714,196717,196721,196730,196733,196738-196739,196745,196762,196769,196771-196772,196777,196785,196796-196798,196809,196811,196822-196824,196826,196829,196835,196837,196840,196844,196863-196865,196871,196879,196885,196887-196889,196891,196893,196897-196898,196900-196901,196903-196904,196907,196919-196921,196927,196932,196941,196943-196944,196947,196949,196953-196954,196964-196966,196978-196980,196982-196983,196985,196987,196993,197009,197011,197017-197019,197021-197022,197025,197030-197031,197039-197040,197043,197046,197048-197049,197062,197070,197073-197080,197082-197085,197099,197104-197105,197107,197109,197128-197133,197150-197156,197164,197167,197172-197174,197176-197177,197185,197190-197191,197193,197195,197201-197203,197208,197210,197212,197214,197218-197219,197223-197225,197227,197235,197240-197243,197257,197260-197263,197269,197286-197289,197293-197294,197306,197316-197317,197323,197325-197328,197331-197332,197334,197341-197342,197348,197350-197351,197364,197372-197373,197379-197381,197383-197384,197386-197391,197395,197397,197399,197401-197403,197405-197407,197410,197413,197415-197416,197420-197421,197424,197426,197428,197433,197435,197438-197439,197442,197444,197449-197450,197455,197458-197469,197475-197476,197478,197490,197493,197496-197497,197501,197504,197512-197515,197518,197525,197535,197540-197541,197553-197556,197558-197559,197561-197573,197579-197581,197583-197592,197600,197603-197606,197608,197611,197624,197627,197636,197640-197641,197643-197645,197647-197650,197654,197657-197663,197680,197682-197683,197687-197688,197692,197695-197696,197709,197711,197720-197721,197726-197727,197729-197730,197735,197761,197772,197783,197789,197791,197795,197803,197814,197816,197824,197831-197832,197837-197838,197841-197843,197850,197856,197860-197861,197863,197868,197896,197898,197910,197914,197928-197930,197932-197934,197942,197945,197948,197950-197952,197955,197961-197963,197975-197977,197997,197999,198020,198043,198049-198050,198075-198076,198079,198097-198099,198111,198126,198134,198149,198151-198153,198170,198174,198185,198194,198196,198198,198201-198203,198212-198213,198218-198219,198223,198230,198233,198237,198242,198250-198252,198257-198260,198262,198271,198277,198279,198289-198291,198295,198301,198303,198306-198307,198318-198322,198327-198328,198331-198333,198338,198341-198343,198346,198353,198356-198358,198366-198367,198369,198372-198374,198377-198378,198381-198382,198384-198385,198389-198391,198393-198394,198400,198407,198411,198417-198423,198426-198429,198431-198432,198438-198439,198444-198445,198452,198464,198467-198468,198472,198475-198476,198479-198483,198486-198488,198499,198502,198505-198508,198519-198520,198522,198525,198537,198539,198541,198546,198554,198581-198583,198587-198588,198590,198593,198617,198621,198623,198670,198678,198684,198691-198692,198694-198697,198700,198703,198705,198708,198717-198719,198723-198725,198731,198733,198748,198752,198774-198776,198782,198786,198813-198814,198816,198818-198819,198822,198832,198845,198849,198851-198854,198857-198858,198862,198865-198868,198896-198897,198899,198904-198905,198911,198923-198924,198927-198928,198931,198940,198945,198947,198950,198952,198964,198967-198968,198973,198976,198988,198990,198993,198996-198997,198999,199002,199007-199012,199014-199018,199020,199035-199037,199043,199050,199053-199054,199057-199062,199065,199067,199069,199073-199074,199084,199086,199108,199114-199116,199132,199135-199137,199151,199153,199156-199157,199169,199173,199176,199178,199184,199186-199187,199192-199193,199208-199210,199215,199219,199223,199225-199230,199232,199237-199241,199253,199258-199260,199262-199263,199268-199269,199273-199274,199278-199281,199284,199287,199321-199322,199332-199333,199337-199338,199355,199365,199369-199374,199398,199413,199418,199437,199442,199459,199477,199491,199502,199518,199522-199523,199525-199529,199533-199535,199543,199548-199553,199556,199558-199561,199563-199566,199574,199576,199579-199580,199602,199608-199613,199616-199617,199645-199646,199661-199668,199670-199680,199714-199715,199717-199718,199727,199734,199747,199749,199761-199764,199798-199799,199807-199808,199814,199816,199821-199822,199827,199829,199846,199852,199866,199875,199883-199888,199893-199897,199899,199904-199906,199941,199946-199949,199959-199960,199968-199969,199972,199974,199997,200001,200003,200008,200014,200018,200026-200028,200033,200036-200037,200045,200051-200053,200055,200058,200060,200064,200069,200082-200084,200086-200089,200091,200102,200107,200109-200111,200117,200121,200124-200126,200129,200158,200162,200171,200180,200182,200196,200200,200207,200215-200219,200223,200227-200228,200230,200239-200243,200246,200251,200253-200255,200257,200264,200268,200272-200273,200275,200280,200287-200288,200291,200295,200304-200310,200346,200352-200353,200357,200359,200375,200395-200397,200414,200422,200444,200447,200459,200471,200473,200481-200482,200484-200485,200514,200519-200536,200538-200541,200543-200545,200548,200551-200555,200557-200558,200572,200584,200591,200594,200602,200605,200607,200609,200613,200615-200617,200631,200635,200637-200639,200644,200652-200653,200655,200657-200658,200666-200669,200671,200693,200696,200723-200724,200726-200727,200739-200740,200753-200754,200756,200758-200759,200761,200764,200770,200776,200796,200798,200801,200803-200804,200808,200810,200814-200817,200820-200827,200829,200845,200847,200853-200854,200856-200857,200865,200871-200880,200884-200889,200891,200898-200899,200904-200908,200910-200918,200920-200926,200930,200933-200935,200938,200940,200942,200944-200948,200950,200955,200965-200966,200969,200972,200976-200977,200987,200991,200993-200995,200999-201000,201003-201005,201008-201009,201021,201023,201028-201029,201031-201032,201044,201052,201071,201126,201131,201134,201138-201139,201143,201145,201148,201151,201196,201199-201200,201209,201217,201222,201234,201236,201254,201261,201264,201269,201282,201284-201285,201318-201319,201325,201339-201340,201342,201345,201347,201349-201352,201371,201373-201374,201395-201396,201406,201408,201410,201415-201416,201430,201438-201439,201442-201443,201446,201449,201523,201532,201543-201545,201566-201567,201620,201644-201645,201680-201681,201684,201688-201690,201701,201703,201709-201710,201714,201742,201756,201758,201766-201769,201773,201790,201793,201797,201801,201813-201814,201818,201822,201848,201853,201879,201882-201883,201890,201895-201896,201898-201899,201901,201905-201917,201921,201924,201932,201941,201953-201955,201966,201976-201979,201984-201986,201990,201993,201995,202000,202003,202006,202010-202011,202019,202023,202027-202041,202044,202046,202054,202056-202057,202061-202066,202085,202089-202092,202097,202105,202116,202119-202121,202123,202127,202129,202143,202150,202156,202161,202163,202166,202170-202173,202175,202181,202187,202243,202267-202273,202286,202290,202293-202294,202341-202342,202364,202376,202387,202406,202418,202441,202448-202449,202454,202468-202469,202516-202518,202520-202521,202523,202526,202528-202529,202534,202552,202558,202567,202587-202588,202608-202609,202611-202612,202671,202678,202692,202697-202699,202708,202717,202723,202732,202736,202767,202771,202773-202774,202782-202783,202785-202786,202789,202796-202797,202806,202809,202812,202821-202822,202826-202827,202830-202834,202839,202849-202850,202863-202865,202867,202870,202881-202882,202889,202894,202897-202898,202900,202903-202905,202908-202909,202915,202917,202919,202931,202934-202935,202939-202940,202954,202964,202967,202971,202973,202975-202977,202983-202986,202996-203001,203007-203011,203024,203030,203033-203034,203043,203049-203052,203054,203058,203061-203062,203070,203072,203075-203076,203078,203080-203083,203085,203087,203090,203094,203106,203108,203112-203116,203119,203123,203128-203130,203132,203134,203137-203146,203148-203152,203156,203158-203160,203164-203165,203175,203177,203179-203180,203185,203261,203272,203289,203303,203319-203320,203334-203335,203341,203347,203350,203352,203354-203355,203358,203360,203367,203376,203384-203386,203401,203408,203410,203414-203415,203421-203422,203426,203430,203444-203445,203449,203451,203453,203455,203463,203474,203476-203478,203483-203484,203489,203499,203503-203504,203506-203511,203524-203525,203528-203530,203533,203535,203546,203548,203556,203572,203622,203629,203637,203673,203678-203680,203682-203683,203685,203691,203693,203695-203697,203708,203716,203724,203727-203729,203731-203732,203743,203745-203746,203750-203751,203754,203763,203776,203783,203785,203788,203796,203801,203810,203813,203818,203822,203826-203831,203833-203834,203838-203839,203843-203849,203866,203870,203873,203875,203882-203885,203896,203899,203903,203905-203906,203913,203924,203930-203931,203933-203936,203940,203944-203945,203959,203968,203985,204009,204019,204031,204040,204042,204050-204052,204054-204056,204060,204067,204071,204073,204076,204081-204082,204093,204096,204101-204102,204105-204106,204108-204109,204111,204127-204131,204135-204137,204140-204147,204149,204151-204153,204155-204159,204164,204173,204175,204179-204180,204182-204185,204195,204197,204199,204205,204208,204210,204212,204216,204218-204220,204222-204223,204225,204228,204230,204235-204236,204242,204248-204250,204253,204256-204257,204264-204265,204268-204271,204274,204278-204279,204281,204283,204296-204297,204303,204305,204309,204313,204315-204317,204319,204326-204328,204348,204351,204353-204354,204356,204361-204363,204365-204368,204370-204374,204376-204378,204384-204385,204397,204402,204408,204410,204412-204413,204415,204420,204425,204430,204436-204437,204462-204476,204497-204498,204509,204518,204521,204533,204539-204542,204545,204557,204576-204579,204581,204589-204590,204611,204617,204632-204633,204635,204638,204641,204644,204646-204648,204656-204657,204662,204666,204670,204675,204689-204690,204692,204694,204719,204753,204764,204773,204776-204778,204788-204789,204804-204807,204809-204810,204826,204830,204838,204874,204877-204878,204901-204905,204907,204913,204916,204920-204923,204941,204955,204957,204965,204972,204975,204978-204979,204981,204983,204989-204990,204992,204997,205003,205005,205010,205013-205015,205024,205026-205036,205038-205040,205042-205043,205047-205049,205061,205064,205066,205069,205072,205074-205075,205077,205079-205080,205082-205083,205091-205093,205095-205097,205102,205104,205115,205120,205126,205132-205134,205140-205141,205158,205160-205161,205163,205167,205172,205197,205210,205214,205222-205223,205231,205234,205236,205251-205255,205258,205263-205264,205268-205269,205276,205279,205297,205299-205300,205316-205327,205332,205334,205345-205347,205356-205358,205360-205361,205363-205364,205370,205385,205399,205402,205409,205411-205413,205422,205428-205429,205431-205435,205444,205448,205452,205454-205455,205488,205495,205497,205502,205506,205516,205527,205534-205536,205550,205557-205558,205562,205564,205566,205569,205572-205573,205576,205604-205605,205626-205629,205637,205647,205649-205653,205661-205663,205665,205675,205678,205680-205682,205694,205698,205712-205713,205720,205723,205726-205727,205734,205778,205789,205791,205801-205805,205838,205845,205847,205851,205858,205860,205863,205865,205869,205884-205886,205904,205919,205932,205941,205944-205950,205959,205967,205986-205987,205993,205998-206001,206015,206017-206021,206023,206026-206029,206032,206049-206051,206053-206054,206061,206063,206081,206086,206089,206093-206094,206097-206098,206109,206112,206117,206128-206130,206137,206140,206151,206160,206170,206174,206206,206210,206236,206264,206268,206281,206358,206360,206364,206367,206369-206372,206384,206388,206395,206398,206400,206403-206405,206409,206415-206421,206426,206428-206431,206433,206436-206437,206443-206454,206456,206459-206461,206469-206470,206474-206477,206480-206482,206486,206488,206534,206540,206544-206547,206551,206553,206563,206582,206584,206595,206604,206614,206617,206623,206625,206629,206632,206637-206639,206648,206650-206652,206659,206662,206665,206667,206671-206672,206684,206688,206690,206695,206705,206712-206718,206721,206746,206749,206758,206761,206763-206768,206770,206792-206797,206801,206803,206814,206818-206819,206829,206834,206836-206838,206840,206844,206859,206876,206878-206880,206891-206892,206894-206895,206897,206900-206903,206909,206916,206922,206989,206992-206993,207001,207007-207008,207016,207020,207027,207068,207071,207077-207080,207082,207089,207094,207099,207116,207130-207131,207134,207139,207152,207170,207176,207178,207181,207191,207194-207195,207197,207207,207221-207223,207240-207243,207248,207251,207268-207269,207275-207278,207281-207282,207285-207287,207303,207305-207306,207322-207323,207329-207331,207334-207335,207337,207344,207349-207350,207355,207359-207360,207362-207366,207369,207375-207377,207379-207380,207391,207404,207409,207411,207426-207428,207430-207433,207441-207442,207445-207446,207463,207468,207473-207475,207480-207481,207484,207490,207499-207500,207511,207532-207533,207536-207537,207543,207545,207554,207569-207570,207572,207579-207580,207585,207600,207602-207603,207605-207606,207620,207622-207626,207628,207630,207635,207638-207639,207643,207645,207651-207652,207659,207662,207670-207671,207673,207676,207680,207683,207687-207688,207692,207696,207709,207729,207745,207748,207750,207761,207763-207764,207768,207785,207832,207847-207848,207851-207852,207877-207878,207885,207908-207911,207920-207922,207924-207926,207929,207933-207934,207936-207938,207956-207958,207963,207966,207970,207979,207983,207985,208006-208019,208022,208026,208030,208036,208047-208048,208050,208052,208081-208084,208097,208100-208103,208117,208119-208120,208129-208131,208142-208143,208147-208150,208152,208159-208160,208162,208164-208168,208172-208173,208183,208212,208234,208249-208250,208253-208254,208265,208276,208279,208282,208285,208293,208300,208309,208312,208340,208348-208350,208356,208362,208364,208369-208375,208379,208388,208390-208393,208405,208410-208414,208422,208436,208438,208441-208443,208452-208455,208458,208468,208472,208474,208479-208480,208488,208507-208509,208512,208514-208515,208532-208533,208542-208543,208548,208553-208556,208563-208567,208581-208582,208587,208589,208601,208603-208605,208607-208608,208610,208616,208621,208632-208634,208638-208639,208642-208644,208650,208659,208669-208672,208682-208683,208689,208696-208697,208699,208703,208711-208712,208717,208722,208731,208742-208744,208746,208752,208761-208762,208770,208773,208775-208777,208787,208794,208796,208800,208806,208808-208809,208813-208814,208816-208820,208822-208823,208833-208837,208839,208841-208842,208849,208852-208857,208861-208864,208866,208870,208874-208879,208883,208887,208891,208895,208897-208898,208901-208902,208905,208907,208912,208915,208917-208918,208920-208922,208925,208927-208928,208934,208946-208947,208951-208953,208969-208970,208982-208983,208989,208991,208994,209013,209016,209022,209026,209029,209050,209053,209055-209056,209059-209060,209062,209064-209065,209068,209070-209071,209085,209092-209101,209104-209106,209114-209116,209119-209120,209138,209144,209154-209155,209169,209174,209178,209186-209189,209191,209193-209194,209196-209198,209204,209208,209212-209213,209218,209222,209230,209237-209238,209241-209244,209247,209252,209256,209258-209261,209268,209275,209289,209313-209314,209318,209325,209328-209330,209338-209341,209361,209367,209369,209407,209425,209442-209445,209447,209450,209452,209454,209460-209463,209466,209470,209482-209483,209490,209492,209494,209499-209500,209502,209512,209523,209536,209540-209541,209548-209549,209577,209590,209592,209595,209597-209599,209602-209603,209605,209607,209609,209611,209616,209622,209639,209644-209646,209648,209650,209662-209664,209669,209682-209683,209685-209688,209695,209697,209702,209710,209714,209718,209721,209723,209731,209737,209740-209744,209746-209747,209761,209763,209769,209789,209793,209797,209802,209805-209812,209814-209816,209818,209836,209839-209841,209844-209845,209853,209859-209860,209862,209865-209866,209872,209883-209884,209887-209888,209892,209902,209907,209917-209918,209928-209930,209934-209935,209944,209946,209948-209950,209955-209957,209959-209963,209965-209968,209977-209978,209980-209982,209987,209994,209996,210003,210005,210007,210009,210011-210015,210018,210026-210030,210032,210034,210038-210039,210041,210046,210055,210066,210083,210096,210098-210100,210102,210104-210105,210107-210111,210113-210114,210117,210124,210126,210129,210135-210137,210142,210149-210150,210152,210154-210155,210157-210159,210161,210165,210168,210176,210178,210184,210201,210203,210227,210244,210248,210257,210259-210261,210263,210267-210271,210275,210282,210286,210292,210294,210311-210312,210317,210327,210350,210357-210358,210369,210371,210383,210393,210398,210401,210409,210422-210423,210427-210428,210431,210443,210446,210451-210452,210454-210455,210457,210460,210469-210470,210493-210496,210498,210500-210501,210505,210514-210522,210524,210529,210532-210534,210537,210543,210549,210553,210556,210569,210571,210575-210577,210595-210596,210599-210600,210604-210606,210611,210614-210615,210621,210623-210627,210630-210631,210638,210644,210661,210665,210686,210698-210699,210703,210714,210746-210747,210774,210777,210779-210780,210782-210783,210786,210792,210795-210796,210804-210805,210810,210819,210833-210834,210837,210839,210845-210848,210864,210866,210900,210904,210910-210911,210913-210914,210918,210921-210926,210931,210935,210939-210940,210942-210943,210947,210968,210976-210977,210986,210999,211005-211006,211021-211022,211030,211046-211053,211059,211063,211068,211071,211073,211083,211087,211089,211091,211103-211105,211111,211115,211117,211149,211151,211153,211157,211159,211167,211191,211193-211194,211197,211201-211202,211213,211215-211218,211229,211236,211249,211270,211280,211283,211285,211292,211295,211301,211314-211317,211327,211333,211335,211339,211345-211347,211396,211400,211424,211433,211435,211440,211445,211447-211449,211451,211453,211455,211462,211464,211476-211482,211497-211498,211502-211504,211509-211511,211513-211514,211518,211530,211546,211553,211555,211566,211568,211594,211596,211598,211606-211608,211610-211611,211613-211618,211648,211670-211671,211684,211716-211717,211721,211738,211741,211744-211747,211751-211753,211762,211764-211768,211789,211802,211804,211809,211811-211814,211818,211820-211821,211830,211839,211854-211855,211861-211862,211868,211874,211888,211893,211900,211904-211910,211913,211920,211922-211927,211929,211931-211932,211937,211941,211944,211946-211948,211950-211951,211953,211958,211967,211969,211991-211992,211994,211996,211998,212004,212008,212026,212028,212043-212045,212047,212054,212058,212061,212063-212066,212069,212071,212075,212081,212093,212096,212098-212100,212102-212105,212109,212113,212116-212117,212119-212124,212126-212136,212145-212146,212148,212152-212153,212155-212158,212160,212165-212167,212172,212174,212180-212185,212209-212210,212213,212216-212217,212224-212225,212240,212242,212248,212251,212256,212265-212266,212278,212281-212285,212292-212293,212302,212305-212307,212321-212322,212324-212326,212331,212338,212342,212347,212357,212359-212360,212362-212363,212365-212368,212370-212371,212378,212380,212382-212385,212387,212403,212407,212409-212410,212413,212420,212436,212439,212443,212456-212457,212465,212478,212494,212499,212501-212502,212506,212532,212543-212544,212549-212550,212553,212560,212568,212589,212593-212594,212605,212609,212611,212616,212618-212621,212628,212632-212634,212647,212650,212654-212655,212657,212661,212663,212676,212694,212699,212702-212707,212709-212714,212721,212723,212725,212729-212730,212732,212754-212756,212758-212759,212761,212763-212764,212770,212772-212777,212780-212784,212790,212799-212802,212806,212809,212821,212824,212830,212833-212834,212842-212845,212850-212851,212853-212855,212861,212868,212873,212896-212897,212902,212906,212926,212950-212951,212957,212964,212968-212969,212971-212972,212974,212980,212989,212991,212993-212994,212998-213000,213028,213047,213055,213062-213070,213072,213077,213080-213081,213089-213090,213092,213101,213103-213105,213133,213135-213136,213140,213147,213150,213156,213158,213162,213164-213166,213174,213188,213197-213199,213225-213226,213228-213230,213236,213239-213240,213246,213254-213255,213258,213265,213268,213271-213272,213278,213280,213283,213286,213301,213303-213307,213316,213321-213323,213325,213328,213333-213335,213340-213342,213345-213346,213354,213359-213361,213364,213377,213379,213382,213384-213385,213408-213411,213423-213427,213431-213439,213441,213443,213448,213452,213455-213456,213461,213464-213465,213468,213474-213475,213480-213481,213484-213486,213489,213495,213508-213509,213522,213527-213528,213535-213537,213543-213544,213575,213578,213587,213634,213648,213651,213664,213673,213696,213702,213704,213707-213708,213710-213712,213716-213717,213729-213730,213735-213738,213742-213743,213747,213755-213756,213762,213772,213778,213781,213783,213787,213791,213796-213797,213802-213809,213812,213814,213832,213836-213837,213839-213842,213844,213846,213852,213856-213857,213861,213864,213868-213869,213871-213873,213876,213878-213880,213882,213893-213894,213896-213898,213908,213910,213912-213913,213916,213929-213932,213937,213986,214016,214021,214026,214048-214049,214053,214056,214062,214069-214070,214077,214087,214089,214095,214099,214102,214106-214107,214116,214118,214125,214130,214133,214136,214144,214149,214158,214160,214162-214163,214181,214203,214210,214216,214219,214221,214224-214229,214236,214245,214250-214251,214255,214257-214258,214262-214264,214279,214288,214292,214302-214303,214325,214333,214346-214347,214349,214352,214373,214378,214380,214386,214390,214406,214418,214425,214427-214429,214444,214446,214448-214449,214457,214493-214495,214511,214513,214515-214516,214526,214528,214542,214563-214566,214575-214576,214584,214601,214605-214606,214608,214610,214672,214675-214676,214681-214682,214686,214708,214726,214748,214754,214761,214765-214766,214774,214782,214798,214800,214804,214809,214830-214831,214835,214840-214844,214846,214848-214849,214851-214852,214854,214876-214877,214879-214880,214894,214896,214898-214899,214903,214913,214918-214919,214928,214933,214938-214939,214953-214954,214965,214988-214989,214992,214998-214999,215001,215013-215014,215017-215020,215025,215034-215035,215039,215068,215085,215093,215095,215100-215102,215104,215110,215118,215128,215131-215135,215152-215153,215166,215183,215194,215198-215199,215207,215212,215234,215238,215241,215244,215254,215258,215260,215280-215285,215289,215295,215297-215298,215300-215302,215304-215305,215307,215309,215321,215325-215330,215334,215338-215339,215348-215350,215353,215355,215377,215391-215393,215395,215397-215398,215401,215410,215418-215420,215423,215427-215428,215431-215432,215434,215449,215451,215453-215454,215459,215468-215472,215508,215522-215525,215540-215541,215544,215548,215552-215553,215559,215574,215576,215597,215605-215606,215610,215641,215649,215663-215665,215673,215675,215677,215679,215681-215683,215686-215687,215699,215703,215706-215708,215711,215713-215714,215716,215720-215722,215725-215726,215732,215734,215741-215742,215748,215750,215753-215754,215758,215764,215768,215779,215782,215790,215796-215797,215800-215802,215804,215810-215813,215819-215821,215838,215843-215844,215846-215850,215864-215865,215868,215905-215906,215911,215913-215914,215918,215923-215924,215936,215942,215951,215960,215962-215964,215966,215968-215969,215973,216012-216013,216016,216022,216041,216045,216049-216050,216057-216060,216072,216083-216085,216088,216090-216091,216098,216101,216103,216105,216107,216109,216111,216114-216115,216120,216132,216149-216150,216158-216159,216171-216173,216176,216188,216192,216194-216195,216227,216231,216235-216238,216241-216242,216249-216255,216266-216269,216277,216280,216284,216298,216309,216330,216335,216340,216355,216362-216365,216368,216371,216373-216376,216378,216382,216385,216391,216394,216397,216408,216438,216454,216461,216463,216466,216475,216480,216486,216495,216502-216505,216510,216513,216521-216524,216546,216548-216551,216557,216565,216572,216590-216591,216615-216616,216620-216621,216623,216628,216631-216634,216673,216679,216691-216693,216700,216703,216749,216753-216754,216758,216760,216762,216764,216766,216774,216784,216790,216793-216794,216796,216799,216801-216803,216812-216813,216824,216828-216829,216833,216835,216843-216848,216855-216856,216859-216861,216873,216875,216891-216894,216897-216898,216919,216925,216931,216940,216944,216952,216960-216963,217009-217010,217013,217017,217023,217040,217058,217061,217063,217066,217075-217079,217109,217113,217118,217121,217127,217129,217131-217132,217150,217169,217176,217195,217200,217202-217203,217221,217226,217237,217239,217242,217245-217248,217250,217252,217262-217263,217265,217274,217291-217292,217295-217296,217303,217305,217318,217331,217335-217336,217349-217351,217353,217374,217379,217381-217382,217384-217385,217412-217415,217417,217424,217432,217444,217453,217463,217477,217498-217499,217509,217511,217514-217515,217519,217524,217531,217535,217539,217542,217548,217558,217561,217563-217564,217578,217583,217587-217588,217590-217591,217593,217604,217633,217637,217649,217683,217688-217689,217702,217705-217707,217709,217727,217743,217747-217748,217756,217766,217773-217774,217794,217800,217805-217806,217819,217823-217824,217832,217857,217868,217874-217875,217877,217880,217883,217888,217896,217902,217911,217916,217924,217946,217991,218005,218007,218014,218019,218026,218028,218030-218031,218038,218056,218059,218078,218100-218101,218114,218117-218118,218140-218141,218149,218152-218153,218155-218156,218165,218167-218168,218178,218180,218189,218207,218229,218270-218272,218278,218289-218290,218327,218329,218360,218368,218386,218390-218391,218422-218423,218457,218468,218475,218478,218497,218527,218529-218530,218548,218550,218555,218559,218567,218581-218583,218587-218588,218596,218605,218609-218610,218612-218613,218616-218618,218621,218627,218629,218646,218654-218655,218658,218666-218668,218670,218685-218688,218691,218710,218713,218716-218720,218737,218741,218744-218745,218757,218760,218786-218789,218791-218792,218794,218811-218812,218820,218825-218828,218830-218835,218838,218842-218843,218863-218864,218868,218879,218909,218913,218918,218926,218930,218946,218964-218966,218968-218970,218972,218974,218976,218985,218988-218989,219004,219026,219036,219041-219042,219046,219048,219059-219060,219089,219092,219102,219124,219127,219135,219157,219178,219186,219206,219221,219225,219240,219242,219257,219271,219276,219285-219290,219292-219293,219299,219311-219312,219316-219317,219320,219335-219341,219352,219364,219384,219388,219392,219395-219396,219399-219400,219404-219405,219407,219421,219430,219436,219452,219460,219483,219525,219531-219533,219543-219548,219558-219559,219561-219562,219567,219570,219577,219579-219580,219608,219636,219701-219703,219712,219753,219763-219764,219775-219776,219779-219780,219782-219783,219785-219787,219791,219804,219827-219828,219845,219848,219865,219883,219925,219930,219938,219944-219946,219949-219951,219960,219968,219970,219973-219974,219983,219986-219989,219999,220009,220014,220028,220030-220031,220038-220040,220046,220062,220100-220103,220106,220114,220124,220126,220147,220152,220156,220158,220173,220184,220194,220198,220203-220204,220206,220209-220211,220227,220231-220232,220247,220249,220251-220252,220254,220264,220280-220281,220299,220301,220303-220304,220317,220328,220368,220375,220385,220389-220390,220392,220403,220410,220412-220413,220416,220424,220430-220431,220437,220447,220451-220454,220456,220460-220463,220506-220507,220530,220535,220546,220558,220560,220563,220565-220566,220568-220569,220576,220585,220591-220592,220594-220595,220602,220610-220611,220614-220616,220618-220619,220621-220622,220633-220636,220643-220645,220648-220649,220652,220657,220659-220662,220667-220668,220674,220676-220677,220683,220685-220694,220700-220702,220704,220710-220711,220715,220719-220721,220723-220732,220735,220739-220740,220743,220745,220751-220752,220762-220764,220767,220777-220778,220785-220786,220789-220791,220793-220794,220796,220800,220810,220812,220814,220822,220829-220832,220836-220837,220846,220866-220867,220873-220874,220876-220877,220886,220891-220895,220897,220900,220905,220911,220914,220917,220920,220925,220928-220929,220931,220938-220941,220943-220945,220950-220951,220967,220977,220979,220985,220987,221014-221016,221018,221023,221032,221040-221041,221066,221073,221077,221081,221096,221101-221102,221112,221121,221127,221138,221173,221177,221179,221182,221187-221190,221201,221205,221209,221218,221220,221231,221263,221270,221324,221326,221335,221341,221343-221344,221346,221388,221393,221407,221409,221423-221426,221428-221429,221433-221434,221436,221439,221445-221447,221452-221453,221462,221464,221467-221468,221473-221474,221477,221504,221509,221516-221517,221519,221521,221527,221537,221548,221550,221552,221555,221557-221558,221560-221561,221563-221568,221571,221579,221585,221593,221601,221605,221634,221644-221645,221647,221652,221656,221658,221692,221695,221712-221714,221731,221740-221741,221750,221784,221788-221789,221794,221803,221809,221812-221813,221817-221818,221836,221843,221883,221891,221955,221957-221958,221960,221972,221974,221981,221984,221992,222002-222003,222018,222032,222039,222043,222050-222051,222055,222065,222075,222085-222086,222093,222102,222107,222135,222142-222143,222201,222216,222218-222219,222221,222223,222225-222227,222230-222231,222233-222234,222243-222244,222246-222247,222252,222254-222255,222257,222267-222269,222272,222279,222281,222283,222285,222289,222291,222298,222304,222306,222317,222328-222329,222341,222343,222389,222430,222438,222454,222464,222473-222474,222509-222510,222513,222516,222518,222520,222540,222542,222551-222552,222559-222560,222578,222581-222582,222586,222588-222589,222592,222603,222642,222651-222652,222660,222663,222666,222670,222696,222701,222703,222718-222719,222722,222742,222750,222756-222757,222760,222786,222790,222795,222802,222805-222806,222808,222828-222829,222834-222835,222840,222897,222929-222930,222951-222952,222967,222973,223026,223049,223080,223091,223097,223182,223198,223223,223235,223288,223309,223312,223332,223341,223347-223349,223358,223373,223377-223379,223405,223436-223437,223441,223446,223467,223472,223477,223486,223489-223490,223505,223511-223513,223515,223518-223519,223521,223530,223534-223538,223543,223566,223587,223594,223597,223604,223608,223610-223611,223622-223623,223625,223648,223657,223660,223663,223666,223672,223688,223699,223718-223721,223727-223728,223732,223736,223747,223753,223755,223773-223774,223795,223800-223801,223840,223862,223874-223876,223884-223888,223911,223913-223914,223938,223944,223949,223952,223957-223962,223966,223971,223981,223984-223986,223988-223989,224020,224024,224039,224041,224077-224084,224086,224095,224107,224117,224121,224140,224156-224157,224174,224177,224180,224228,224231,224239,224251-224252,224270,224283,224493-224494,224496-224498,224506,224516,224522,224526-224527,224531-224532,224554,224571,224579,224581-224583,224603-224606,224613,224637,224682,224689,224728,224733,224743,224761,224777,224791,224814,224855,224898,224905,224915,224986,225000,225009,225014-225015,225037-225038,225040-225041,225048-225049,225057,225076,225079,225088-225089,225104,225122,225140,225163,225166,225177,225194,225199,225201,225223,225229,225234,225339-225340,225350,225354,225372,225380,225400,225405,225414,225440,225448,225469,225474-225475,225483,225505,225516,225518,225530,225533,225537,225556,225570,225575-225576,225586,225662,225675,225686,225695,225708,225777,225789,225791,225793-225794,225837,225839,225869,225878,225885-225891,225894,225899,225901,225931-225932,225942-225943,225946-225947,226022,226026,226040,226060,226081-226082,226095,226104,226113-226114,226116-226118,226120,226123,226146,226149,226163,226171,226173,226175-226176,226185,226208,226219,226221,226224,226247,226253,226265,226270,226346,226350,226364,226367,226381,226398,226404,226406,226442,226451,226453,226476,226478-226481,226483,226506,226512,226514,226522,226526,226534,226549-226553,226568,226617,226620,226642,226676,226678,226680-226681,226686-226688,226695-226696,226699-226701,226707,226709-226710,226713,226724,226732,226740,226743,226746,226748-226749,226770,226803-226807,226814-226816,226820-226821,226863-226864,226866-226867,226871-226872,226880,226882,226887,226903,226947-226950,226967,226971,226985-226987,226995,227000-227001,227006,227042-227043,227055,227058-227059,227061-227062,227069-227070,227075,227085-227089,227091-227095,227098-227099,227104,227108,227110-227111,227284,227286,227290-227291,227311-227312,227318-227319,227322-227324,227341,227347,227367,227383,227392-227394,227396,227401,227409,227431-227432,227442,227447,227452,227460-227461,227463-227464,227481,227485,227489,227493-227494,227502,227505,227507,227509,227512,227517,227527,227529,227532,227535,227537,227539,227541,227543,227550,227562,227576-227578,227582,227587,227590-227591,227593,227610,227635,227637-227639,227654,227657,227674-227675,227685-227688,227690,227695-227696,227743-227744,227760,227781,227796,227816-227817,227827-227829,227835,227837,227842-227843,227848,227850-227851,227854,227908,227912,227914,227916,227954,227960,227992,228005,228016,228022,228024,228026-228027,228084,228086,228089,228103-228104,228185,228195,228198,228200,228207,228209,228211,228217-228222,228233,228260,228263,228265-228268,228286,228290-228293,228297-228298,228317,228324-228327,228331-228333,228335-228336,228343,228360-228362,228368-228369,228376,228381,228392,228426,228430-228433,228436,228438,228440-228443,228445,228461,228470,228476,228479-228480,228483,228491,228493,228496-228497,228502,228560-228561,228568,228593,228640,228709-228711,228715-228718,228723,228726-228727,228738,228746,228757-228758,228802,228808,228819-228820,228825,228827,228838,228847,228849,228851,228858,228866,228916,228940,228947,228957,228960,228962,228967,229067,229085-229086,229185,229353,229390,229395,229400,229414,229416,229420,229429-229430,229462,229465,229476-229477,229479,229519,229598,229614,229622,229665,229671-229672,229692,229700,229714,229727,229753,229802,229886,229898,229956,229965,229971,229980-229981,229984,230000,230032,230050,230064,230090-230091,230100-230101,230109,230200,230256,230313,230316,230323,230325,230327,230329,230345,230459,230496,230531,230544,230588,230592,230602,230627-230628,230630-230634,230662,230664,230775,230783,230785,230790,230877,230897-230898,230915,231177 Merged /stable/9/sys/boot:r229068 Merged /head/tools/regression/netinet/boot:r217113 Merged /user/mav/ata/sys/boot:r189793-190578 Merged /user/thompsa/usb/sys/boot:r187190 Merged /user/luigi/ipfw3-r8/sys/boot:r204833-205453 Merged /user/dfr/xenhvm/6/sys/boot:r189304,189451 Merged /user/dfr/xenhvm/7/sys/boot:r188574-189614 Merged /user/piso/ipfw/sys/boot:r190918,190921,190923,190926 Merged /projects/cambria/sys/boot:r186008-186350 Merged /user/piso/sys/boot:r186543,186723,186725-186726,186742,186770-186771,186774,186777-186779,187984-187985,190555,190572,190589,190592,190614,190625,190830