diff --git a/sys/boot/i386/boot2/boot2.c b/sys/boot/i386/boot2/boot2.c index df3fe81d17ca..f227233d5675 100644 --- a/sys/boot/i386/boot2/boot2.c +++ b/sys/boot/i386/boot2/boot2.c @@ -1,682 +1,682 @@ /*- * 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_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 V86_CY(x) ((x) & 1) #define V86_ZR(x) ((x) & 0x40) #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; unsigned slice; unsigned part; unsigned start; int init; } dsk; static char cmd[512]; static char kname[1024]; 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 uint32_t memsize(void); static int drvread(void *, unsigned, unsigned); static int keyhit(unsigned); static int xputc(int); static int xgetc(int); static 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; } #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 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) { int autoboot; ino_t ino; dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); v86.ctl = V86_FLAGS; 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); bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ bootinfo.bi_extmem = memsize(); bootinfo.bi_memsizes_valid++; /* Process configuration file */ autoboot = 1; if ((ino = lookup(PATH_CONFIG))) fsread(ino, cmd, sizeof(cmd)); if (*cmd) { if (parse()) autoboot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmd); /* 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*SECOND)) { load(); memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); } } /* Present the user with the boot2 prompt. */ for (;;) { if (!autoboot || !OPT_CHECK(RBX_QUIET)) printf("\nFreeBSD/i386 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(5*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, x; int fmt, 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) 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], 0, dsk.slice, dsk.unit, dsk.part), + 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) 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; } 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; unsigned sl, i; 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; 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 (t1 < t0 || 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 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; } } static int getc(int fn) { v86.addr = 0x16; v86.eax = fn << 8; v86int(); return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); } diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c index df3fe81d17ca..f227233d5675 100644 --- a/sys/boot/i386/gptboot/gptboot.c +++ b/sys/boot/i386/gptboot/gptboot.c @@ -1,682 +1,682 @@ /*- * 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_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 V86_CY(x) ((x) & 1) #define V86_ZR(x) ((x) & 0x40) #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; unsigned slice; unsigned part; unsigned start; int init; } dsk; static char cmd[512]; static char kname[1024]; 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 uint32_t memsize(void); static int drvread(void *, unsigned, unsigned); static int keyhit(unsigned); static int xputc(int); static int xgetc(int); static 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; } #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 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) { int autoboot; ino_t ino; dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); v86.ctl = V86_FLAGS; 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); bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ bootinfo.bi_extmem = memsize(); bootinfo.bi_memsizes_valid++; /* Process configuration file */ autoboot = 1; if ((ino = lookup(PATH_CONFIG))) fsread(ino, cmd, sizeof(cmd)); if (*cmd) { if (parse()) autoboot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmd); /* 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*SECOND)) { load(); memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); } } /* Present the user with the boot2 prompt. */ for (;;) { if (!autoboot || !OPT_CHECK(RBX_QUIET)) printf("\nFreeBSD/i386 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(5*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, x; int fmt, 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) 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], 0, dsk.slice, dsk.unit, dsk.part), + 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) 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; } 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; unsigned sl, i; 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; 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 (t1 < t0 || 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 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; } } static int getc(int fn) { v86.addr = 0x16; v86.eax = fn << 8; v86int(); return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); } diff --git a/sys/boot/i386/libi386/bioscd.c b/sys/boot/i386/libi386/bioscd.c index 42dfbb3b8a0e..93de9586c31f 100644 --- a/sys/boot/i386/libi386/bioscd.c +++ b/sys/boot/i386/libi386/bioscd.c @@ -1,356 +1,356 @@ /*- * Copyright (c) 1998 Michael Smith * Copyright (c) 2001 John H. Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * BIOS CD device handling for CD's that have been booted off of via no * emulation booting as defined in the El Torito standard. * * Ideas and algorithms from: * * - FreeBSD libi386/biosdisk.c * */ #include #include #include #include #include #include #include #include "libi386.h" #define BIOSCD_SECSIZE 2048 #define BUFSIZE (1 * BIOSCD_SECSIZE) #define MAXBCDEV 1 /* Major numbers for devices we frontend for. */ #define ACDMAJOR 117 #define CDMAJOR 15 #ifdef DISK_DEBUG # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else # define DEBUG(fmt, args...) #endif struct specification_packet { u_char sp_size; u_char sp_bootmedia; u_char sp_drive; u_char sp_controller; u_int sp_lba; u_short sp_devicespec; u_short sp_buffersegment; u_short sp_loadsegment; u_short sp_sectorcount; u_short sp_cylsec; u_char sp_head; }; /* * List of BIOS devices, translation from disk unit number to * BIOS unit number. */ static struct bcinfo { int bc_unit; /* BIOS unit number */ struct specification_packet bc_sp; } bcinfo [MAXBCDEV]; static int nbcinfo = 0; static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest); static int bc_init(void); static int bc_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bc_open(struct open_file *f, ...); static int bc_close(struct open_file *f); static void bc_print(int verbose); struct devsw bioscd = { "cd", DEVT_CD, bc_init, bc_strategy, bc_open, bc_close, noioctl, bc_print, NULL }; /* * Translate between BIOS device numbers and our private unit numbers. */ int bc_bios2unit(int biosdev) { int i; DEBUG("looking for bios device 0x%x", biosdev); for (i = 0; i < nbcinfo; i++) { DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit); if (bcinfo[i].bc_unit == biosdev) return(i); } return(-1); } int bc_unit2bios(int unit) { if ((unit >= 0) && (unit < nbcinfo)) return(bcinfo[unit].bc_unit); return(-1); } /* * We can't quiz, we have to be told what device to use, so this functoin * doesn't do anything. Instead, the loader calls bc_add() with the BIOS * device number to add. */ static int bc_init(void) { return (0); } int bc_add(int biosdev) { if (nbcinfo >= MAXBCDEV) return (-1); bcinfo[nbcinfo].bc_unit = biosdev; v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x4b01; v86.edx = biosdev; v86.ds = VTOPSEG(&bcinfo[nbcinfo].bc_sp); v86.esi = VTOPOFF(&bcinfo[nbcinfo].bc_sp); v86int(); if ((v86.eax & 0xff00) != 0) return (-1); printf("BIOS CD is cd%d\n", nbcinfo); nbcinfo++; return(0); } /* * Print information about disks */ static void bc_print(int verbose) { int i; char line[80]; for (i = 0; i < nbcinfo; i++) { sprintf(line, " cd%d: Device 0x%x\n", i, bcinfo[i].bc_sp.sp_devicespec); pager_output(line); } } /* * Attempt to open the disk described by (dev) for use by (f). */ static int bc_open(struct open_file *f, ...) { va_list ap; struct i386_devdesc *dev; va_start(ap, f); dev = va_arg(ap, struct i386_devdesc *); va_end(ap); if (dev->d_unit >= nbcinfo) { DEBUG("attempt to open nonexistent disk"); return(ENXIO); } return(0); } static int bc_close(struct open_file *f) { return(0); } static int bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct i386_devdesc *dev; int unit; int blks; #ifdef BD_SUPPORT_FRAGS char fragbuf[BIOSCD_SECSIZE]; size_t fragsize; fragsize = size % BIOSCD_SECSIZE; #else if (size % BIOSCD_SECSIZE) return (EINVAL); #endif if (rw != F_READ) return(EROFS); dev = (struct i386_devdesc *)devdata; unit = dev->d_unit; blks = size / BIOSCD_SECSIZE; if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0) return (EINVAL); dblk /= (BIOSCD_SECSIZE / DEV_BSIZE); DEBUG("read %d from %d to %p", blks, dblk, buf); if (rsize) *rsize = 0; if (blks && bc_read(unit, dblk, blks, buf)) { DEBUG("read error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS DEBUG("bc_strategy: frag read %d from %d+%d to %p", fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE)); if (fragsize && bc_read(unit, dblk + blks, 1, fragsize)) { DEBUG("frag read error"); return(EIO); } bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize); #endif if (rsize) *rsize = size; return (0); } static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest) { u_int result, retry; static unsigned short packet[8]; int biosdev; #ifdef DISK_DEBUG int error; #endif /* Just in case some idiot actually tries to read -1 blocks... */ if (blks < 0) return (-1); /* If nothing to do, just return succcess. */ if (blks == 0) return (0); biosdev = bc_unit2bios(unit); /* * Loop retrying the operation a couple of times. The BIOS * may also retry. */ for (retry = 0; retry < 3; retry++) { /* If retrying, reset the drive */ if (retry > 0) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0; v86.edx = biosdev; v86int(); } packet[0] = 0x10; packet[1] = blks; packet[2] = VTOPOFF(dest); packet[3] = VTOPSEG(dest); packet[4] = dblk & 0xffff; packet[5] = dblk >> 16; packet[6] = 0; packet[7] = 0; v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x4200; v86.edx = biosdev; v86.ds = VTOPSEG(packet); v86.esi = VTOPOFF(packet); v86int(); result = (v86.efl & PSL_C); if (result == 0) break; } #ifdef DISK_DEBUG error = (v86.eax >> 8) & 0xff; #endif DEBUG("%d sectors from %ld to %p (0x%x) %s", blks, dblk, dest, VTOP(dest), result ? "failed" : "ok"); DEBUG("unit %d status 0x%x", unit, error); /* hexdump(dest, (blks * BIOSCD_SECSIZE)); */ return(0); } /* * Return a suitable dev_t value for (dev). */ int bc_getdev(struct i386_devdesc *dev) { int biosdev, unit; int major; int rootdev; unit = dev->d_unit; biosdev = bc_unit2bios(unit); DEBUG("unit %d BIOS device %d", unit, biosdev); if (biosdev == -1) /* not a BIOS device */ return(-1); /* * XXX: Need to examine device spec here to figure out if SCSI or * ATAPI. No idea on how to figure out device number. All we can * really pass to the kernel is what bus and device on which bus we * were booted from, which dev_t isn't well suited to since those * number don't match to unit numbers very well. We may just need * to engage in a hack where we pass -C to the boot args if we are * the boot device. */ major = ACDMAJOR; unit = 0; /* XXX */ /* XXX: Assume partition 'a'. */ - rootdev = MAKEBOOTDEV(major, 0, 0, unit, 0); + rootdev = MAKEBOOTDEV(major, 0, unit, 0); DEBUG("dev is 0x%x\n", rootdev); return(rootdev); } diff --git a/sys/boot/i386/libi386/biosdisk.c b/sys/boot/i386/libi386/biosdisk.c index b65ddd89c09e..18453e20860b 100644 --- a/sys/boot/i386/libi386/biosdisk.c +++ b/sys/boot/i386/libi386/biosdisk.c @@ -1,1231 +1,1228 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * BIOS disk device handling. * * Ideas and algorithms from: * * - NetBSD libi386/biosdisk.c * - FreeBSD biosboot/disk.c * */ #include #include #include #include #include #include #include #include "libi386.h" #define BIOS_NUMDRIVES 0x475 #define BIOSDISK_SECSIZE 512 #define BUFSIZE (1 * BIOSDISK_SECSIZE) #define MAXBDDEV MAXDEV #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ #define WDMAJOR 0 /* major numbers for devices we frontend for */ #define WFDMAJOR 1 #define FDMAJOR 2 #define DAMAJOR 4 #ifdef DISK_DEBUG # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else # define DEBUG(fmt, args...) #endif struct open_disk { int od_dkunit; /* disk unit number */ int od_unit; /* BIOS unit number */ int od_cyl; /* BIOS geometry */ int od_hds; int od_sec; int od_boff; /* block offset from beginning of BIOS disk */ int od_flags; #define BD_MODEINT13 0x0000 #define BD_MODEEDD1 0x0001 #define BD_MODEEDD3 0x0002 #define BD_MODEMASK 0x0003 #define BD_FLOPPY 0x0004 #define BD_LABELOK 0x0008 #define BD_PARTTABOK 0x0010 struct disklabel od_disklabel; int od_nslices; /* slice count */ struct dos_partition od_slicetab[NEXTDOSPART]; }; /* * List of BIOS devices, translation from disk unit number to * BIOS unit number. */ static struct bdinfo { int bd_unit; /* BIOS unit number */ int bd_flags; int bd_type; /* BIOS 'drive type' (floppy only) */ } bdinfo [MAXBDDEV]; static int nbdinfo = 0; static int bd_getgeom(struct open_disk *od); static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest); static int bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest); static int bd_int13probe(struct bdinfo *bd); static void bd_printslice(struct open_disk *od, struct dos_partition *dp, char *prefix, int verbose); static void bd_printbsdslice(struct open_disk *od, daddr_t offset, char *prefix, int verbose); static int bd_init(void); static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bd_open(struct open_file *f, ...); static int bd_close(struct open_file *f); static void bd_print(int verbose); struct devsw biosdisk = { "disk", DEVT_DISK, bd_init, bd_strategy, bd_open, bd_close, noioctl, bd_print, NULL }; static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev); static void bd_closedisk(struct open_disk *od); static int bd_bestslice(struct open_disk *od); static void bd_checkextended(struct open_disk *od, int slicenum); /* * Translate between BIOS device numbers and our private unit numbers. */ int bd_bios2unit(int biosdev) { int i; DEBUG("looking for bios device 0x%x", biosdev); for (i = 0; i < nbdinfo; i++) { DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); if (bdinfo[i].bd_unit == biosdev) return(i); } return(-1); } int bd_unit2bios(int unit) { if ((unit >= 0) && (unit < nbdinfo)) return(bdinfo[unit].bd_unit); return(-1); } /* * Quiz the BIOS for disk devices, save a little info about them. */ static int bd_init(void) { int base, unit, nfd = 0; /* sequence 0, 0x80 */ for (base = 0; base <= 0x80; base += 0x80) { for (unit = base; (nbdinfo < MAXBDDEV); unit++) { /* check the BIOS equipment list for number of fixed disks */ if((base == 0x80) && (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) break; bdinfo[nbdinfo].bd_unit = unit; bdinfo[nbdinfo].bd_flags = (unit < 0x80) ? BD_FLOPPY : 0; if (!bd_int13probe(&bdinfo[nbdinfo])) break; /* XXX we need "disk aliases" to make this simpler */ printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ? ('A' + unit) : ('C' + unit - 0x80), nbdinfo); nbdinfo++; if (base == 0x80) nfd++; } } return(0); } /* * Try to detect a device supported by the legacy int13 BIOS */ static int bd_int13probe(struct bdinfo *bd) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x800; v86.edx = bd->bd_unit; v86int(); if (!(v86.efl & 0x1) && /* carry clear */ ((v86.edx & 0xff) > ((unsigned)bd->bd_unit & 0x7f))) { /* unit # OK */ if ((v86.ecx & 0x3f) == 0) { /* absurd sector size */ DEBUG("Invalid geometry for unit %d", bd->bd_unit); return(0); /* skip device */ } bd->bd_flags |= BD_MODEINT13; bd->bd_type = v86.ebx & 0xff; /* Determine if we can use EDD with this device. */ v86.eax = 0x4100; v86.edx = bd->bd_unit; v86.ebx = 0x55aa; v86int(); if (!(v86.efl & 0x1) && /* carry clear */ ((v86.ebx & 0xffff) == 0xaa55) && /* signature */ (v86.ecx & 0x1)) { /* packets mode ok */ bd->bd_flags |= BD_MODEEDD1; if((v86.eax & 0xff00) > 0x300) bd->bd_flags |= BD_MODEEDD3; } return(1); } return(0); } /* * Print information about disks */ static void bd_print(int verbose) { int i, j; char line[80]; struct i386_devdesc dev; struct open_disk *od; struct dos_partition *dptr; for (i = 0; i < nbdinfo; i++) { sprintf(line, " disk%d: BIOS drive %c:\n", i, (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit) : ('C' + bdinfo[i].bd_unit - 0x80)); pager_output(line); /* try to open the whole disk */ dev.d_unit = i; dev.d_kind.biosdisk.slice = -1; dev.d_kind.biosdisk.partition = -1; if (!bd_opendisk(&od, &dev)) { /* Do we have a partition table? */ if (od->od_flags & BD_PARTTABOK) { dptr = &od->od_slicetab[0]; /* Check for a "dedicated" disk */ if ((dptr[3].dp_typ == DOSPTYP_386BSD) && (dptr[3].dp_start == 0) && (dptr[3].dp_size == 50000)) { sprintf(line, " disk%d", i); bd_printbsdslice(od, 0, line, verbose); } else { for (j = 0; j < od->od_nslices; j++) { sprintf(line, " disk%ds%d", i, j + 1); bd_printslice(od, &dptr[j], line, verbose); } } } bd_closedisk(od); } } } /* * Print information about slices on a disk. For the size calculations we * assume a 512 byte sector. */ static void bd_printslice(struct open_disk *od, struct dos_partition *dp, char *prefix, int verbose) { char line[80]; switch (dp->dp_typ) { case DOSPTYP_386BSD: bd_printbsdslice(od, (daddr_t)dp->dp_start, prefix, verbose); return; case DOSPTYP_LINSWP: if (verbose) sprintf(line, "%s: Linux swap %.6dMB (%d - %d)\n", prefix, dp->dp_size / 2048, dp->dp_start, dp->dp_start + dp->dp_size); else sprintf(line, "%s: Linux swap\n", prefix); break; case DOSPTYP_LINUX: /* * XXX * read the superblock to confirm this is an ext2fs partition? */ if (verbose) sprintf(line, "%s: ext2fs %.6dMB (%d - %d)\n", prefix, dp->dp_size / 2048, dp->dp_start, dp->dp_start + dp->dp_size); else sprintf(line, "%s: ext2fs\n", prefix); break; case 0x00: /* unused partition */ case DOSPTYP_EXT: return; case 0x01: if (verbose) sprintf(line, "%s: FAT-12 %.6dMB (%d - %d)\n", prefix, dp->dp_size / 2048, dp->dp_start, dp->dp_start + dp->dp_size); else sprintf(line, "%s: FAT-12\n", prefix); break; case 0x04: case 0x06: case 0x0e: if (verbose) sprintf(line, "%s: FAT-16 %.6dMB (%d - %d)\n", prefix, dp->dp_size / 2048, dp->dp_start, dp->dp_start + dp->dp_size); else sprintf(line, "%s: FAT-16\n", prefix); break; case 0x0b: case 0x0c: if (verbose) sprintf(line, "%s: FAT-32 %.6dMB (%d - %d)\n", prefix, dp->dp_size / 2048, dp->dp_start, dp->dp_start + dp->dp_size); else sprintf(line, "%s: FAT-32\n", prefix); break; default: if (verbose) sprintf(line, "%s: Unknown fs: 0x%x %.6dMB (%d - %d)\n", prefix, dp->dp_typ, dp->dp_size / 2048, dp->dp_start, dp->dp_start + dp->dp_size); else sprintf(line, "%s: Unknown fs: 0x%x\n", prefix, dp->dp_typ); } pager_output(line); } /* * Print out each valid partition in the disklabel of a FreeBSD slice. * For size calculations, we assume a 512 byte sector size. */ static void bd_printbsdslice(struct open_disk *od, daddr_t offset, char *prefix, int verbose) { char line[80]; char buf[BIOSDISK_SECSIZE]; struct disklabel *lp; int i; /* read disklabel */ if (bd_read(od, offset + LABELSECTOR, 1, buf)) return; lp =(struct disklabel *)(&buf[0]); if (lp->d_magic != DISKMAGIC) { sprintf(line, "%s: FFS bad disklabel\n", prefix); pager_output(line); return; } /* Print partitions */ for (i = 0; i < lp->d_npartitions; i++) { /* * For each partition, make sure we know what type of fs it is. If * not, then skip it. However, since floppies often have bogus * fstypes, print the 'a' partition on a floppy even if it is marked * unused. */ if ((lp->d_partitions[i].p_fstype == FS_BSDFFS) || (lp->d_partitions[i].p_fstype == FS_SWAP) || (lp->d_partitions[i].p_fstype == FS_VINUM) || ((lp->d_partitions[i].p_fstype == FS_UNUSED) && (od->od_flags & BD_FLOPPY) && (i == 0))) { /* Only print out statistics in verbose mode */ if (verbose) sprintf(line, " %s%c: %s %.6dMB (%d - %d)\n", prefix, 'a' + i, (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" : "FFS", lp->d_partitions[i].p_size / 2048, lp->d_partitions[i].p_offset, lp->d_partitions[i].p_offset + lp->d_partitions[i].p_size); else sprintf(line, " %s%c: %s\n", prefix, 'a' + i, (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" : "FFS"); pager_output(line); } } } /* * Attempt to open the disk described by (dev) for use by (f). * * Note that the philosophy here is "give them exactly what * they ask for". This is necessary because being too "smart" * about what the user might want leads to complications. * (eg. given no slice or partition value, with a disk that is * sliced - are they after the first BSD slice, or the DOS * slice before it?) */ static int bd_open(struct open_file *f, ...) { va_list ap; struct i386_devdesc *dev; struct open_disk *od; int error; va_start(ap, f); dev = va_arg(ap, struct i386_devdesc *); va_end(ap); if ((error = bd_opendisk(&od, dev))) return(error); /* * Save our context */ ((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data = od; DEBUG("open_disk %p, partition at 0x%x", od, od->od_boff); return(0); } static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev) { struct dos_partition *dptr; struct disklabel *lp; struct open_disk *od; int sector, slice, i; int error; char buf[BUFSIZE]; if (dev->d_unit >= nbdinfo) { DEBUG("attempt to open nonexistent disk"); return(ENXIO); } od = (struct open_disk *)malloc(sizeof(struct open_disk)); if (!od) { DEBUG("no memory"); return (ENOMEM); } /* Look up BIOS unit number, intialise open_disk structure */ od->od_dkunit = dev->d_unit; od->od_unit = bdinfo[od->od_dkunit].bd_unit; od->od_flags = bdinfo[od->od_dkunit].bd_flags; od->od_boff = 0; od->od_nslices = 0; error = 0; DEBUG("open '%s', unit 0x%x slice %d partition %c", i386_fmtdev(dev), dev->d_unit, dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a'); /* Get geometry for this open (removable device may have changed) */ if (bd_getgeom(od)) { DEBUG("can't get geometry"); error = ENXIO; goto out; } /* * Following calculations attempt to determine the correct value * for d->od_boff by looking for the slice and partition specified, * or searching for reasonable defaults. */ /* * Find the slice in the DOS slice table. */ if (bd_read(od, 0, 1, buf)) { DEBUG("error reading MBR"); error = EIO; goto out; } /* * Check the slice table magic. */ if (((u_char)buf[0x1fe] != 0x55) || ((u_char)buf[0x1ff] != 0xaa)) { /* If a slice number was explicitly supplied, this is an error */ if (dev->d_kind.biosdisk.slice > 0) { DEBUG("no slice table/MBR (no magic)"); error = ENOENT; goto out; } sector = 0; goto unsliced; /* may be a floppy */ } /* * copy the partition table, then pick up any extended partitions. */ bcopy(buf + DOSPARTOFF, &od->od_slicetab, sizeof(struct dos_partition) * NDOSPART); od->od_nslices = 4; /* extended slices start here */ for (i = 0; i < NDOSPART; i++) bd_checkextended(od, i); od->od_flags |= BD_PARTTABOK; dptr = &od->od_slicetab[0]; /* Is this a request for the whole disk? */ if (dev->d_kind.biosdisk.slice == -1) { sector = 0; goto unsliced; } /* * if a slice number was supplied but not found, this is an error. */ if (dev->d_kind.biosdisk.slice > 0) { slice = dev->d_kind.biosdisk.slice - 1; if (slice >= od->od_nslices) { DEBUG("slice %d not found", slice); error = ENOENT; goto out; } } /* * Check for the historically bogus MBR found on true dedicated disks */ if ((dptr[3].dp_typ == DOSPTYP_386BSD) && (dptr[3].dp_start == 0) && (dptr[3].dp_size == 50000)) { sector = 0; goto unsliced; } /* Try to auto-detect the best slice; this should always give a slice number */ if (dev->d_kind.biosdisk.slice == 0) { slice = bd_bestslice(od); if (slice == -1) { error = ENOENT; goto out; } dev->d_kind.biosdisk.slice = slice; } dptr = &od->od_slicetab[0]; /* * Accept the supplied slice number unequivocally (we may be looking * at a DOS partition). */ dptr += (dev->d_kind.biosdisk.slice - 1); /* we number 1-4, offsets are 0-3 */ sector = dptr->dp_start; DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, dptr->dp_size); /* * If we are looking at a BSD slice, and the partition is < 0, assume the 'a' partition */ if ((dptr->dp_typ == DOSPTYP_386BSD) && (dev->d_kind.biosdisk.partition < 0)) dev->d_kind.biosdisk.partition = 0; unsliced: /* * Now we have the slice offset, look for the partition in the disklabel if we have * a partition to start with. * * XXX we might want to check the label checksum. */ if (dev->d_kind.biosdisk.partition < 0) { od->od_boff = sector; /* no partition, must be after the slice */ DEBUG("opening raw slice"); } else { if (bd_read(od, sector + LABELSECTOR, 1, buf)) { DEBUG("error reading disklabel"); error = EIO; goto out; } DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel); bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel)); lp = &od->od_disklabel; od->od_flags |= BD_LABELOK; if (lp->d_magic != DISKMAGIC) { DEBUG("no disklabel"); error = ENOENT; goto out; } if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) { DEBUG("partition '%c' exceeds partitions in table (a-'%c')", 'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions); error = EPART; goto out; } #ifdef DISK_DEBUG /* Complain if the partition is unused unless this is a floppy. */ if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) && !(od->od_flags & BD_FLOPPY)) DEBUG("warning, partition marked as unused"); #endif od->od_boff = lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset - lp->d_partitions[RAW_PART].p_offset + sector; } out: if (error) { free(od); } else { *odp = od; /* return the open disk */ } return(error); } static void bd_checkextended(struct open_disk *od, int slicenum) { char buf[BIOSDISK_SECSIZE]; struct dos_partition *dp; u_int base; int i, start, end; dp = &od->od_slicetab[slicenum]; start = od->od_nslices; if (dp->dp_size == 0) goto done; if (dp->dp_typ != DOSPTYP_EXT) goto done; if (bd_read(od, (daddr_t)dp->dp_start, 1, buf)) goto done; if (((u_char)buf[0x1fe] != 0x55) || ((u_char)buf[0x1ff] != 0xaa)) { DEBUG("no magic in extended table"); goto done; } base = dp->dp_start; dp = (struct dos_partition *)(&buf[DOSPARTOFF]); for (i = 0; i < NDOSPART; i++, dp++) { if (dp->dp_size == 0) continue; if (od->od_nslices == NEXTDOSPART) goto done; dp->dp_start += base; bcopy(dp, &od->od_slicetab[od->od_nslices], sizeof(*dp)); od->od_nslices++; } end = od->od_nslices; /* * now, recursively check the slices we just added */ for (i = start; i < end; i++) bd_checkextended(od, i); done: return; } /* * Search for a slice with the following preferences: * * 1: Active FreeBSD slice * 2: Non-active FreeBSD slice * 3: Active Linux slice * 4: non-active Linux slice * 5: Active FAT/FAT32 slice * 6: non-active FAT/FAT32 slice */ #define PREF_RAWDISK 0 #define PREF_FBSD_ACT 1 #define PREF_FBSD 2 #define PREF_LINUX_ACT 3 #define PREF_LINUX 4 #define PREF_DOS_ACT 5 #define PREF_DOS 6 #define PREF_NONE 7 /* * slicelimit is in the range 0 .. NDOSPART */ static int bd_bestslice(struct open_disk *od) { struct dos_partition *dp; int pref, preflevel; int i, prefslice; prefslice = 0; preflevel = PREF_NONE; dp = &od->od_slicetab[0]; for (i = 0; i < od->od_nslices; i++, dp++) { switch (dp->dp_typ) { case DOSPTYP_386BSD: /* FreeBSD */ pref = dp->dp_flag & 0x80 ? PREF_FBSD_ACT : PREF_FBSD; break; case DOSPTYP_LINUX: pref = dp->dp_flag & 0x80 ? PREF_LINUX_ACT : PREF_LINUX; break; case 0x01: /* DOS/Windows */ case 0x04: case 0x06: case 0x0b: case 0x0c: case 0x0e: pref = dp->dp_flag & 0x80 ? PREF_DOS_ACT : PREF_DOS; break; default: pref = PREF_NONE; } if (pref < preflevel) { preflevel = pref; prefslice = i + 1; } } return (prefslice); } static int bd_close(struct open_file *f) { struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data); bd_closedisk(od); return(0); } static void bd_closedisk(struct open_disk *od) { DEBUG("open_disk %p", od); #if 0 /* XXX is this required? (especially if disk already open...) */ if (od->od_flags & BD_FLOPPY) delay(3000000); #endif free(od); } static int bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata bcd; struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); bcd.dv_strategy = bd_realstrategy; bcd.dv_devdata = devdata; return(bcache_strategy(&bcd, od->od_unit, rw, dblk+od->od_boff, size, buf, rsize)); } static int bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); int blks; #ifdef BD_SUPPORT_FRAGS char fragbuf[BIOSDISK_SECSIZE]; size_t fragsize; fragsize = size % BIOSDISK_SECSIZE; #else if (size % BIOSDISK_SECSIZE) panic("bd_strategy: %d bytes I/O not multiple of block size", size); #endif DEBUG("open_disk %p", od); switch(rw){ case F_READ: blks = size / BIOSDISK_SECSIZE; DEBUG("read %d from %d to %p", blks, dblk, buf); if (rsize) *rsize = 0; if (blks && bd_read(od, dblk, blks, buf)) { DEBUG("read error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS DEBUG("bd_strategy: frag read %d from %d+%d to %p", fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE)); if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) { DEBUG("frag read error"); return(EIO); } bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize); #endif if (rsize) *rsize = size; return (0); break; case F_WRITE : blks = size / BIOSDISK_SECSIZE; DEBUG("write %d from %d to %p", blks, dblk, buf); if (rsize) *rsize = 0; if (blks && bd_write(od, dblk, blks, buf)) { DEBUG("write error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS if(fragsize) { DEBUG("Attempted to write a frag"); return (EIO); } #endif if (rsize) *rsize = size; return (0); default: /* DO NOTHING */ break; } return EROFS; } /* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ #define FLOPPY_BOUNCEBUF 18 static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) { u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; caddr_t p, xp, bbuf, breg; /* Just in case some idiot actually tries to read -1 blocks... */ if (blks < 0) return (-1); bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ resid = blks; p = dest; /* Decide whether we have to bounce */ if (VTOP(dest) >> 20 != 0 || ((od->od_unit < 0x80) && ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16)))) { /* * There is a 64k physical boundary somewhere in the destination buffer, or the * destination buffer is above first 1MB of physical memory so we have * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we * need to. Use the bottom half unless there is a break there, in which case we * use the top half. */ x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); bbuf = alloca(x * 2 * BIOSDISK_SECSIZE); if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) { breg = bbuf; } else { breg = bbuf + x * BIOSDISK_SECSIZE; } maxfer = x; /* limit transfers to bounce region size */ } else { breg = bbuf = NULL; maxfer = 0; } while (resid > 0) { x = dblk; cyl = x / bpc; /* block # / blocks per cylinder */ x %= bpc; /* block offset into cylinder */ hd = x / od->od_sec; /* offset / blocks per track */ sec = x % od->od_sec; /* offset into track */ /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ x = min(od->od_sec - sec, resid); if (maxfer > 0) x = min(x, maxfer); /* fit bounce buffer */ /* where do we transfer to? */ xp = bbuf == NULL ? p : breg; /* correct sector number for 1-based BIOS numbering */ sec++; /* Loop retrying the operation a couple of times. The BIOS may also retry. */ for (retry = 0; retry < 3; retry++) { /* if retrying, reset the drive */ if (retry > 0) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0; v86.edx = od->od_unit; v86int(); } if(cyl > 1023) { /* use EDD if the disk supports it, otherwise, return error */ if(od->od_flags & BD_MODEEDD1) { static unsigned short packet[8]; packet[0] = 0x10; packet[1] = x; packet[2] = VTOPOFF(xp); packet[3] = VTOPSEG(xp); packet[4] = dblk & 0xffff; packet[5] = dblk >> 16; packet[6] = 0; packet[7] = 0; v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x4200; v86.edx = od->od_unit; v86.ds = VTOPSEG(packet); v86.esi = VTOPOFF(packet); v86int(); result = (v86.efl & 0x1); if(result == 0) break; } else { result = 1; break; } } else { /* Use normal CHS addressing */ v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x200 | x; v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; v86.edx = (hd << 8) | od->od_unit; v86.es = VTOPSEG(xp); v86.ebx = VTOPOFF(xp); v86int(); result = (v86.efl & 0x1); if (result == 0) break; } } DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok"); /* BUG here, cannot use v86 in printf because putchar uses it too */ DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff); if (result) { return(-1); } if (bbuf != NULL) bcopy(breg, p, x * BIOSDISK_SECSIZE); p += (x * BIOSDISK_SECSIZE); dblk += x; resid -= x; } /* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ return(0); } static int bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) { u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; caddr_t p, xp, bbuf, breg; /* Just in case some idiot actually tries to read -1 blocks... */ if (blks < 0) return (-1); bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ resid = blks; p = dest; /* Decide whether we have to bounce */ if (VTOP(dest) >> 20 != 0 || ((od->od_unit < 0x80) && ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16)))) { /* * There is a 64k physical boundary somewhere in the destination buffer, or the * destination buffer is above first 1MB of physical memory so we have * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we * need to. Use the bottom half unless there is a break there, in which case we * use the top half. */ x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); bbuf = alloca(x * 2 * BIOSDISK_SECSIZE); if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) { breg = bbuf; } else { breg = bbuf + x * BIOSDISK_SECSIZE; } maxfer = x; /* limit transfers to bounce region size */ } else { breg = bbuf = NULL; maxfer = 0; } while (resid > 0) { x = dblk; cyl = x / bpc; /* block # / blocks per cylinder */ x %= bpc; /* block offset into cylinder */ hd = x / od->od_sec; /* offset / blocks per track */ sec = x % od->od_sec; /* offset into track */ /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ x = min(od->od_sec - sec, resid); if (maxfer > 0) x = min(x, maxfer); /* fit bounce buffer */ /* where do we transfer to? */ xp = bbuf == NULL ? p : breg; /* correct sector number for 1-based BIOS numbering */ sec++; /* Put your Data In, Put your Data out, Put your Data In, and shake it all about */ if (bbuf != NULL) bcopy(p, breg, x * BIOSDISK_SECSIZE); /* Loop retrying the operation a couple of times. The BIOS may also retry. */ for (retry = 0; retry < 3; retry++) { /* if retrying, reset the drive */ if (retry > 0) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0; v86.edx = od->od_unit; v86int(); } if(cyl > 1023) { /* use EDD if the disk supports it, otherwise, return error */ if(od->od_flags & BD_MODEEDD1) { static unsigned short packet[8]; packet[0] = 0x10; packet[1] = x; packet[2] = VTOPOFF(xp); packet[3] = VTOPSEG(xp); packet[4] = dblk & 0xffff; packet[5] = dblk >> 16; packet[6] = 0; packet[7] = 0; v86.ctl = V86_FLAGS; v86.addr = 0x13; /* Should we Write with verify ?? 0x4302 ? */ v86.eax = 0x4300; v86.edx = od->od_unit; v86.ds = VTOPSEG(packet); v86.esi = VTOPOFF(packet); v86int(); result = (v86.efl & 0x1); if(result == 0) break; } else { result = 1; break; } } else { /* Use normal CHS addressing */ v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x300 | x; v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; v86.edx = (hd << 8) | od->od_unit; v86.es = VTOPSEG(xp); v86.ebx = VTOPOFF(xp); v86int(); result = (v86.efl & 0x1); if (result == 0) break; } } DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok"); /* BUG here, cannot use v86 in printf because putchar uses it too */ DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff); if (result) { return(-1); } p += (x * BIOSDISK_SECSIZE); dblk += x; resid -= x; } /* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ return(0); } static int bd_getgeom(struct open_disk *od) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x800; v86.edx = od->od_unit; v86int(); if ((v86.efl & 0x1) || /* carry set */ ((v86.edx & 0xff) <= (unsigned)(od->od_unit & 0x7f))) /* unit # bad */ return(1); /* convert max cyl # -> # of cylinders */ od->od_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; /* convert max head # -> # of heads */ od->od_hds = ((v86.edx & 0xff00) >> 8) + 1; od->od_sec = v86.ecx & 0x3f; DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec); return(0); } /* * Return the BIOS geometry of a given "fixed drive" in a format * suitable for the legacy bootinfo structure. Since the kernel is * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we * prefer to get the information directly, rather than rely on being * able to put it together from information already maintained for * different purposes and for a probably different number of drives. * * For valid drives, the geometry is expected in the format (31..0) * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are * indicated by returning the geometry of a "1.2M" PC-format floppy * disk. And, incidentally, what is returned is not the geometry as * such but the highest valid cylinder, head, and sector numbers. */ u_int32_t bd_getbigeom(int bunit) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x800; v86.edx = 0x80 + bunit; v86int(); if (v86.efl & 0x1) return 0x4f010f; return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | (v86.edx & 0xff00) | (v86.ecx & 0x3f); } /* * Return a suitable dev_t value for (dev). * * In the case where it looks like (dev) is a SCSI disk, we allow the number of * IDE disks to be specified in $num_ide_disks. There should be a Better Way. */ int bd_getdev(struct i386_devdesc *dev) { struct open_disk *od; int biosdev; int major; int rootdev; char *nip, *cp; int unitofs = 0, i, unit; biosdev = bd_unit2bios(dev->d_unit); DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev); if (biosdev == -1) /* not a BIOS device */ return(-1); if (bd_opendisk(&od, dev) != 0) /* oops, not a viable device */ return(-1); if (biosdev < 0x80) { /* floppy (or emulated floppy) or ATAPI device */ if (bdinfo[dev->d_unit].bd_type == DT_ATAPI) { /* is an ATAPI disk */ major = WFDMAJOR; } else { /* is a floppy disk */ major = FDMAJOR; } } else { /* harddisk */ if ((od->od_flags & BD_LABELOK) && (od->od_disklabel.d_type == DTYPE_SCSI)) { /* label OK, disk labelled as SCSI */ major = DAMAJOR; /* check for unit number correction hint, now deprecated */ if ((nip = getenv("num_ide_disks")) != NULL) { i = strtol(nip, &cp, 0); /* check for parse error */ if ((cp != nip) && (*cp == 0)) unitofs = i; } } else { /* assume an IDE disk */ major = WDMAJOR; } } /* default root disk unit number */ unit = (biosdev & 0x7f) - unitofs; /* XXX a better kludge to set the root disk unit number */ if ((nip = getenv("root_disk_unit")) != NULL) { i = strtol(nip, &cp, 0); /* check for parse error */ if ((cp != nip) && (*cp == 0)) unit = i; } - rootdev = MAKEBOOTDEV(major, - (dev->d_kind.biosdisk.slice + 1) >> 4, /* XXX slices may be wrong here */ - (dev->d_kind.biosdisk.slice + 1) & 0xf, - unit, - dev->d_kind.biosdisk.partition); + rootdev = MAKEBOOTDEV(major, dev->d_kind.biosdisk.slice + 1, unit, + dev->d_kind.biosdisk.partition); DEBUG("dev is 0x%x\n", rootdev); return(rootdev); } diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index 0c0046ff4726..2083456bbbae 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -1,316 +1,315 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include "bootstrap.h" #include "libi386/libi386.h" #include "btxv86.h" #define KARGS_FLAGS_CD 0x1 #define KARGS_FLAGS_PXE 0x2 /* Arguments passed in from the boot1/boot2 loader */ static struct { u_int32_t howto; u_int32_t bootdev; u_int32_t bootflags; u_int32_t pxeinfo; u_int32_t res2; u_int32_t bootinfo; } *kargs; static u_int32_t initial_howto; static u_int32_t initial_bootdev; static struct bootinfo *initial_bootinfo; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); /* from vers.c */ extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; /* XXX debugging */ extern char end[]; static void *heap_top; static void *heap_bottom; int main(void) { int i; /* Pick up arguments */ kargs = (void *)__args; initial_howto = kargs->howto; initial_bootdev = kargs->bootdev; initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; /* * Initialise the heap as early as possible. Once this is done, malloc() is usable. */ bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) heap_top = PTOV(memtop_copyin); memtop_copyin -= 0x300000; heap_bottom = PTOV(memtop_copyin); #else heap_top = (void *)bios_basemem; heap_bottom = (void *)end; #endif setheap(heap_bottom, heap_top); /* * XXX Chicken-and-egg problem; we want to have console output early, but some * console attributes may depend on reading from eg. the boot device, which we * can't do yet. * * We can use printf() etc. once this is done. * If the previous boot stage has requested a serial console, prefer that. */ bi_setboothowto(initial_howto); if (initial_howto & RB_MULTIPLE) { if (initial_howto & RB_SERIAL) setenv("console", "comconsole vidconsole", 1); else setenv("console", "vidconsole comconsole", 1); } else if (initial_howto & RB_SERIAL) setenv("console", "comconsole", 1); else if (initial_howto & RB_MUTE) setenv("console", "nullconsole", 1); cons_probe(); /* * Initialise the block cache */ bcache_init(32, 512); /* 16k cache XXX tune this */ /* * Special handling for PXE and CD booting. */ if (kargs->bootinfo == 0) { /* * We only want the PXE disk to try to init itself in the below * walk through devsw if we actually booted off of PXE. */ if (kargs->bootflags & KARGS_FLAGS_PXE) pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); else if (kargs->bootflags & KARGS_FLAGS_CD) bc_add(initial_bootdev); } /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); if (initial_bootinfo != NULL) { initial_bootinfo->bi_basemem = bios_basemem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024; } /* detect ACPI for future reference */ biosacpi_detect(); /* detect SMBIOS for future reference */ smbios_detect(); printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); extract_currdev(); /* set $currdev and $loaddev */ setenv("LINES", "24", 1); /* optional */ bios_getsmap(); archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; interact(); /* doesn't return */ /* if we ever get here, it is an error */ return (1); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. * * XXX should be extended for netbooting. */ static void extract_currdev(void) { struct i386_devdesc new_currdev; int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.d_dev = &biosdisk; /* new-style boot loaders such as pxeldr and cdldr */ if (kargs->bootinfo == 0) { if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { /* we are booting from a CD with cdboot */ new_currdev.d_dev = &bioscd; new_currdev.d_unit = bc_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.d_dev = &pxedisk; new_currdev.d_unit = 0; } else { /* we don't know what our boot device is */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } else { - new_currdev.d_kind.biosdisk.slice = (B_ADAPTOR(initial_bootdev) << 4) + - B_CONTROLLER(initial_bootdev) - 1; + new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); biosdev = initial_bootinfo->bi_bios_dev; /* * If we are booted by an old bootstrap, we have to guess at the BIOS * unit number. We will lose if there is more than one disk type * and we are not booting from the lowest-numbered disk type * (ie. SCSI when IDE also exists). */ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ } new_currdev.d_type = new_currdev.d_dev->dv_type; /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. */ if ((new_currdev.d_type == biosdisk.dv_type) && ((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting from.\n" "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.d_unit = 0; } env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); delay(1000000); __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, sbrk(0), heap_top); return(CMD_OK); } /* ISA bus access functions for PnP, derived from */ static int isa_inb(int port) { u_char data; if (__builtin_constant_p(port) && (((port) & 0xffff) < 0x100) && ((port) < 0x10000)) { __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); } else { __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); } return(data); } static void isa_outb(int port, int value) { u_char al = value; if (__builtin_constant_p(port) && (((port) & 0xffff) < 0x100) && ((port) < 0x10000)) { __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port))); } else { __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); } } diff --git a/sys/boot/pc98/boot2/boot.c b/sys/boot/pc98/boot2/boot.c index f350b9161457..4bdfbef7b14e 100644 --- a/sys/boot/pc98/boot2/boot.c +++ b/sys/boot/pc98/boot2/boot.c @@ -1,405 +1,405 @@ /* * Mach Operating System * Copyright (c) 1992, 1991 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. * * from: Mach, [92/04/03 16:51:14 rvb] */ /* Copyright 1988, 1989, 1990, 1991, 1992 by Intel Corporation, Santa Clara, California. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies and that both the copyright notice and this permission notice appear in supporting documentation, and that the name of Intel not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "boot.h" #include #include #include #define ouraddr (BOOTSEG << 4) /* XXX */ #define BOOT_CONFIG_SIZE 512 #define BOOT_HELP_SIZE 2048 #define KERNEL_CONFIG_SIZE 512 #define NAMEBUF_LEN 1024 /* oversized to defend against gets() */ static char boot_config[BOOT_CONFIG_SIZE]; static char boot_help[BOOT_HELP_SIZE]; char *name; static char kernel_config[KERNEL_CONFIG_SIZE]; static char kernel_config_namebuf[NAMEBUF_LEN + sizeof "config"]; static char linebuf[NAMEBUF_LEN]; static char namebuf[NAMEBUF_LEN]; struct bootinfo bootinfo; int loadflags; static void getbootdev(char *ptr, int *howto); static void loadprog(void); static void readfile(char *path, char *buf, size_t nbytes); /* NORETURN */ void boot(int drive) { int i, ret; unsigned char disk_equips; /* Pick up the story from the Bios on geometry of disks */ for(ret = 0; ret < 2; ret ++) { if (*(unsigned char*)V(0xA155d) & (1 << ret)) { bootinfo.bi_bios_geom[ret] = get_diskinfo(ret + 0x80); } } bootinfo.bi_basemem = memsize(0); bootinfo.bi_extmem = memsize(1); bootinfo.bi_memsizes_valid = 1; gateA20(); /* set machine type to PC98_SYSTEM_PARAMETER */ machine_check(); /* * The default boot device is the first partition in the * compatibility slice on the boot drive. */ dosdev = drive; maj = (drive&0x70) >> 3; /* a good first bet */ if (maj == 4) { /* da */ disk_equips = *(unsigned char *)V(0xA1482); unit = 0; for (i=0; i<(drive&0x0f); i++) { int media = ((unsigned *)V(0xA1460))[i] & 0x1F; if ((disk_equips >> i) & 1) /* HD */ unit++; else if (media == 7) /* MO */ unit++; } } else { unit = drive & 0x0f; } readfile("boot.config", boot_config, BOOT_CONFIG_SIZE); name = "/boot/loader"; if (boot_config[0] != '\0') { getbootdev(boot_config, &loadflags); printf("boot.config: %s", boot_config); if (openrd() != 0) name = "kernel"; } loadstart: /* print this all each time.. (saves space to do so) */ /* If we have looped, use the previous entries as defaults */ printf("\r \n>> FreeBSD BOOT @ 0x%x: %d/%d k of memory, %s%s console\n" "Boot default: %d:%s(%d,%c)%s\n" "%s\n" "boot: ", ouraddr, bootinfo.bi_basemem, bootinfo.bi_extmem, (loadflags & RB_SERIAL) ? "serial" : "internal", (loadflags & RB_DUAL) ? "/dual" : "", dosdev & 0x0f, devs[maj], unit, 'a' + part, name ? name : "*specify_a_kernel_name*", boot_help); /* * Ignore flags from previous attempted boot, if any. * XXX this is now too strict. Settings given in boot.config should * not be changed. */ loadflags &= (RB_DUAL | RB_SERIAL); /* * Be paranoid and make doubly sure that the input buffer is empty. */ if (loadflags & (RB_DUAL | RB_SERIAL)) init_serial(); if (!gets(linebuf)) putchar('\n'); else getbootdev(linebuf, &loadflags); if (name == NULL) goto loadstart; ret = openrd(); if (ret != 0) { if (ret > 0) printf("Can't find %s\n", name); goto loadstart; } /* if (inode.i_mode&IEXEC) loadflags |= RB_KDB; */ loadprog(); goto loadstart; } static void loadprog(void) { struct exec head; int startaddr; int addr; /* physical address.. not directly useable */ int bootdev; int i; unsigned pad; char *s, *t; read((void *)&head, sizeof(head)); if ( N_BADMAG(head)) { printf("Invalid format!\n"); return; } poff = N_TXTOFF(head); /*if(poff==0) poff = 32;*/ /* * We assume that the entry address is the same as the lowest text * address and that the kernel startup code handles relocation by * this address rounded down to a multiple of 16M. */ startaddr = head.a_entry & 0x00FFFFFF; addr = startaddr; printf("Booting %d:%s(%d,%c)%s @ 0x%x\n" , dosdev & 0x0f , devs[maj] , unit , 'a'+part , name , addr); if(addr < 0x00100000) { /* * Bail out, instead of risking to damage the BIOS * variables, the loader, or the adapter memory area. * We don't support loading below 1 MB any more. */ printf("Start address too low\n"); return; } printf("text=0x%x ", head.a_text); /********************************************************/ /* LOAD THE TEXT SEGMENT */ /********************************************************/ xread((void *)addr, head.a_text); addr += head.a_text; /********************************************************/ /* Load the Initialised data after the text */ /********************************************************/ while (addr & PAGE_MASK) *(char *)addr++ = 0; printf("data=0x%x ", head.a_data); xread((void *)addr, head.a_data); addr += head.a_data; /********************************************************/ /* Skip over the uninitialised data */ /* (but clear it) */ /********************************************************/ printf("bss=0x%x ", head.a_bss); /* * XXX however, we should be checking that we don't load ... into * nonexistent memory. A full symbol table is unlikely to fit on 4MB * machines. */ /* kzip & kernel will zero their own bss */ addr += head.a_bss; /* Pad to a page boundary. */ pad = (unsigned)addr & PAGE_MASK; if (pad != 0) { pad = PAGE_SIZE - pad; addr += pad; } bootinfo.bi_symtab = addr; /********************************************************/ /* Copy the symbol table size */ /********************************************************/ pcpy(&head.a_syms, (void *)addr, sizeof(head.a_syms)); addr += sizeof(head.a_syms); /********************************************************/ /* Load the symbol table */ /********************************************************/ printf("symbols=[+0x%x+0x%x+0x%x", pad, sizeof(head.a_syms), head.a_syms); xread((void *)addr, head.a_syms); addr += head.a_syms; /********************************************************/ /* Load the string table size */ /********************************************************/ read((void *)&i, sizeof(int)); pcpy(&i, (void *)addr, sizeof(int)); i -= sizeof(int); addr += sizeof(int); /********************************************************/ /* Load the string table */ /********************************************************/ printf("+0x%x+0x%x]\n", sizeof(int), i); xread((void *)addr, i); addr += i; bootinfo.bi_esymtab = addr; /* * For backwards compatibility, use the previously-unused adaptor * and controller bitfields to hold the slice number. */ - bootdev = MAKEBOOTDEV(maj, (slice >> 4), slice & 0xf, unit, part); + bootdev = MAKEBOOTDEV(maj, slice, unit, part); bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_kernelname = (u_int32_t)(name + ouraddr); bootinfo.bi_nfs_diskless = 0; bootinfo.bi_size = sizeof(bootinfo); bootinfo.bi_bios_dev = dosdev; /* * Load the kernel config file (if any). Its name is given by * appending ".config" to the kernel name. Build the name inline * because no str*() functions are available. The file has to be * copied to &disklabel for userconfig. It can't be loaded there * directly because the label is used late in readfile() in some * unusual cases. */ s = name; t = kernel_config_namebuf; do ; while ((*t++ = *s++) != '\0'); s = ".config"; --t; do ; while ((*t++ = *s++) != '\0'); readfile(kernel_config_namebuf, kernel_config, KERNEL_CONFIG_SIZE); pcpy(kernel_config, (char *)&disklabel + ouraddr, KERNEL_CONFIG_SIZE); printf("total=0x%x entry point=0x%x\n", addr, startaddr); startprog(startaddr, loadflags | RB_BOOTINFO, bootdev, (unsigned)&bootinfo + ouraddr); } static void readfile(char *path, char *buf, size_t nbytes) { int openstatus; buf[0] = '\0'; name = path; openstatus = openrd(); if (openstatus == 0) { /* XXX no way to determine file size. */ read(buf, nbytes); } buf[nbytes - 1] = '\0'; } static void getbootdev(char *ptr, int *howto) { char c; int f; char *p; /* Copy the flags to save some bytes. */ f = *howto; c = *ptr; for (;;) { nextarg: while (c == ' ' || c == '\n') c = *++ptr; if (c == '-') while ((c = *++ptr) != '\0') { if (c == ' ' || c == '\n') goto nextarg; if (c == 'a') f |= RB_ASKNAME; if (c == 'C') f |= RB_CDROM; if (c == 'D') f ^= RB_DUAL; if (c == 'd') f |= RB_KDB; if (c == 'g') f |= RB_GDB; if (c == 'h') f ^= RB_SERIAL; if (c == 'P') f |= RB_PROBEKBD; if (c == 'r') f |= RB_DFLTROOT; if (c == 's') f |= RB_SINGLE; if (c == 'v') f |= RB_VERBOSE; } if (c == '\0') break; p = name = namebuf; while (c != '\0' && c != ' ' && c != '\n') { *p++ = c; c = *++ptr; } *p = '\0'; } if (f & RB_PROBEKBD) { if (probe_keyboard()) { f |= RB_DUAL | RB_SERIAL; printf("No keyboard found\n"); } else printf("Keyboard found\n"); } if (f & (RB_DUAL | RB_SERIAL)) init_serial(); *howto = f; } diff --git a/sys/boot/pc98/libpc98/bioscd.c b/sys/boot/pc98/libpc98/bioscd.c index 03b38a365f4f..40d455b4a915 100644 --- a/sys/boot/pc98/libpc98/bioscd.c +++ b/sys/boot/pc98/libpc98/bioscd.c @@ -1,344 +1,344 @@ /*- * Copyright (c) 1998 Michael Smith * Copyright (c) 2001 John H. Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * BIOS CD device handling for CD's that have been booted off of via no * emulation booting as defined in the El Torito standard. * * Ideas and algorithms from: * * - FreeBSD libi386/biosdisk.c * */ #include #include #include #include #include #include #include #include "libi386.h" #define BIOSCD_SECSIZE 2048 #define BUFSIZE (1 * BIOSCD_SECSIZE) #define MAXBCDEV 1 /* Major numbers for devices we frontend for. */ #define ACDMAJOR 117 #define CDMAJOR 15 #ifdef DISK_DEBUG # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else # define DEBUG(fmt, args...) #endif struct specification_packet { u_char sp_size; u_char sp_bootmedia; u_char sp_drive; u_char sp_controller; u_int sp_lba; u_short sp_devicespec; u_short sp_buffersegment; u_short sp_loadsegment; u_short sp_sectorcount; u_short sp_cylsec; u_char sp_head; }; /* * List of BIOS devices, translation from disk unit number to * BIOS unit number. */ static struct bcinfo { int bc_unit; /* BIOS unit number */ struct specification_packet bc_sp; } bcinfo [MAXBCDEV]; static int nbcinfo = 0; static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest); static int bc_init(void); static int bc_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bc_open(struct open_file *f, ...); static int bc_close(struct open_file *f); static void bc_print(int verbose); struct devsw bioscd = { "cd", DEVT_CD, bc_init, bc_strategy, bc_open, bc_close, noioctl, bc_print, NULL }; /* * Translate between BIOS device numbers and our private unit numbers. */ int bc_bios2unit(int biosdev) { int i; DEBUG("looking for bios device 0x%x", biosdev); for (i = 0; i < nbcinfo; i++) { DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit); if (bcinfo[i].bc_unit == biosdev) return(i); } return(-1); } int bc_unit2bios(int unit) { if ((unit >= 0) && (unit < nbcinfo)) return(bcinfo[unit].bc_unit); return(-1); } /* * We can't quiz, we have to be told what device to use, so this functoin * doesn't do anything. Instead, the loader calls bc_add() with the BIOS * device number to add. */ static int bc_init(void) { return (0); } int bc_add(int biosdev) { if (nbcinfo >= MAXBCDEV) return (-1); bcinfo[nbcinfo].bc_unit = biosdev; /* SCSI CD-ROM only */ if ((biosdev & 0xf0) != 0xa0) return (-1); if ((((uint32_t *)PTOV(0xA1460))[biosdev & 0x0f] & 0x1f) != 5) return (-1); printf("BIOS CD is cd%d\n", nbcinfo); nbcinfo++; return(0); } /* * Print information about disks */ static void bc_print(int verbose) { int i; char line[80]; for (i = 0; i < nbcinfo; i++) { sprintf(line, " cd%d: Device 0x%x\n", i, bcinfo[i].bc_sp.sp_devicespec); pager_output(line); } } /* * Attempt to open the disk described by (dev) for use by (f). */ static int bc_open(struct open_file *f, ...) { va_list ap; struct i386_devdesc *dev; va_start(ap, f); dev = va_arg(ap, struct i386_devdesc *); va_end(ap); if (dev->d_unit >= nbcinfo) { DEBUG("attempt to open nonexistent disk"); return(ENXIO); } return(0); } static int bc_close(struct open_file *f) { return(0); } static int bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct i386_devdesc *dev; int unit; int blks; #ifdef BD_SUPPORT_FRAGS char fragbuf[BIOSCD_SECSIZE]; size_t fragsize; fragsize = size % BIOSCD_SECSIZE; #else if (size % BIOSCD_SECSIZE) return (EINVAL); #endif if (rw != F_READ) return(EROFS); dev = (struct i386_devdesc *)devdata; unit = dev->d_unit; blks = size / BIOSCD_SECSIZE; if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0) return (EINVAL); dblk /= (BIOSCD_SECSIZE / DEV_BSIZE); DEBUG("read %d from %d to %p", blks, dblk, buf); if (rsize) *rsize = 0; if (blks && bc_read(unit, dblk, blks, buf)) { DEBUG("read error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS DEBUG("bc_strategy: frag read %d from %d+%d to %p", fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE)); if (fragsize && bc_read(unit, dblk + blks, 1, fragsize)) { DEBUG("frag read error"); return(EIO); } bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize); #endif if (rsize) *rsize = size; return (0); } static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest) { u_int result, retry; static unsigned short packet[8]; int biosdev; #ifdef DISK_DEBUG int error; #endif /* Just in case some idiot actually tries to read -1 blocks... */ if (blks < 0) return (-1); /* If nothing to do, just return succcess. */ if (blks == 0) return (0); biosdev = bc_unit2bios(unit); /* * Loop retrying the operation a couple of times. The BIOS * may also retry. */ for (retry = 0; retry < 3; retry++) { /* If retrying, reset the drive */ if (retry > 0) { v86.ctl = V86_FLAGS; v86.addr = 0x1b; v86.eax = 0x0300 | biosdev; v86int(); } v86.ctl = V86_FLAGS; v86.addr = 0x1b; v86.eax = 0x0600 | (biosdev & 0x7f); v86.ebx = blks * BIOSCD_SECSIZE; v86.ecx = dblk & 0xffff; v86.edx = (dblk >> 16) & 0xffff; v86.ebp = VTOPOFF(dest); v86.es = VTOPSEG(dest); v86int(); result = (v86.efl & PSL_C); if (result == 0) break; } #ifdef DISK_DEBUG error = (v86.eax >> 8) & 0xff; #endif DEBUG("%d sectors from %ld to %p (0x%x) %s", blks, dblk, dest, VTOP(dest), result ? "failed" : "ok"); DEBUG("unit %d status 0x%x", unit, error); /* hexdump(dest, (blks * BIOSCD_SECSIZE)); */ return(0); } /* * Return a suitable dev_t value for (dev). */ int bc_getdev(struct i386_devdesc *dev) { int biosdev, unit, device; int major; int rootdev; unit = dev->d_unit; biosdev = bc_unit2bios(unit); DEBUG("unit %d BIOS device %d", unit, biosdev); if (biosdev == -1) /* not a BIOS device */ return(-1); device = biosdev & 0xf0; if (device == 0x80) major = ACDMAJOR; else if (device == 0xa0) major = CDMAJOR; else return (-1); unit = 0; /* XXX */ /* XXX: Assume partition 'a'. */ - rootdev = MAKEBOOTDEV(major, 0, 0, unit, 0); + rootdev = MAKEBOOTDEV(major, 0, unit, 0); DEBUG("dev is 0x%x\n", rootdev); return(rootdev); } diff --git a/sys/boot/pc98/libpc98/biosdisk.c b/sys/boot/pc98/libpc98/biosdisk.c index ef89e1227d76..d23d474d02b1 100644 --- a/sys/boot/pc98/libpc98/biosdisk.c +++ b/sys/boot/pc98/libpc98/biosdisk.c @@ -1,1115 +1,1112 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * BIOS disk device handling. * * Ideas and algorithms from: * * - NetBSD libi386/biosdisk.c * - FreeBSD biosboot/disk.c * */ #include #include #include #include #include #include #include #include "libi386.h" #define BIOS_NUMDRIVES 0x475 #define BIOSDISK_SECSIZE 512 #define BUFSIZE (1 * BIOSDISK_SECSIZE) #define MAXBDDEV MAXDEV #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ #define WDMAJOR 0 /* major numbers for devices we frontend for */ #define WFDMAJOR 1 #define FDMAJOR 2 #define DAMAJOR 4 #ifdef DISK_DEBUG # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else # define DEBUG(fmt, args...) #endif struct open_disk { int od_dkunit; /* disk unit number */ int od_unit; /* BIOS unit number */ int od_cyl; /* BIOS geometry */ int od_hds; int od_sec; int od_boff; /* block offset from beginning of BIOS disk */ int od_flags; #define BD_MODEINT13 0x0000 #define BD_MODEEDD1 0x0001 #define BD_MODEEDD3 0x0002 #define BD_MODEMASK 0x0003 #define BD_FLOPPY 0x0004 #define BD_LABELOK 0x0008 #define BD_PARTTABOK 0x0010 #define BD_OPTICAL 0x0020 struct disklabel od_disklabel; int od_nslices; /* slice count */ struct pc98_partition od_slicetab[NDOSPART]; }; /* * List of BIOS devices, translation from disk unit number to * BIOS unit number. */ static struct bdinfo { int bd_unit; /* BIOS unit number */ int bd_flags; int bd_type; /* BIOS 'drive type' (floppy only) */ int bd_da_unit; /* kernel unit number for da */ } bdinfo [MAXBDDEV]; static int nbdinfo = 0; static int bd_getgeom(struct open_disk *od); static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest); static int bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest); static int bd_int13probe(struct bdinfo *bd); static void bd_printslice(struct open_disk *od, struct pc98_partition *dp, char *prefix, int verbose); static void bd_printbsdslice(struct open_disk *od, daddr_t offset, char *prefix, int verbose); static int bd_init(void); static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bd_open(struct open_file *f, ...); static int bd_close(struct open_file *f); static void bd_print(int verbose); struct devsw biosdisk = { "disk", DEVT_DISK, bd_init, bd_strategy, bd_open, bd_close, noioctl, bd_print, NULL }; static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev); static void bd_closedisk(struct open_disk *od); static int bd_bestslice(struct open_disk *od); static void bd_checkextended(struct open_disk *od, int slicenum); /* * Translate between BIOS device numbers and our private unit numbers. */ int bd_bios2unit(int biosdev) { int i; DEBUG("looking for bios device 0x%x", biosdev); for (i = 0; i < nbdinfo; i++) { DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); if (bdinfo[i].bd_unit == biosdev) return(i); } return(-1); } int bd_unit2bios(int unit) { if ((unit >= 0) && (unit < nbdinfo)) return(bdinfo[unit].bd_unit); return(-1); } /* * Quiz the BIOS for disk devices, save a little info about them. */ static int bd_init(void) { int base, unit; int da_drive=0, n=-0x10; /* sequence 0x90, 0x80, 0xa0 */ for (base = 0x90; base <= 0xa0; base += n, n += 0x30) { for (unit = base; (nbdinfo < MAXBDDEV) || ((unit & 0x0f) < 4); unit++) { bdinfo[nbdinfo].bd_unit = unit; bdinfo[nbdinfo].bd_flags = (unit & 0xf0) == 0x90 ? BD_FLOPPY : 0; if (!bd_int13probe(&bdinfo[nbdinfo])){ if (((unit & 0xf0) == 0x90 && (unit & 0x0f) < 4) || ((unit & 0xf0) == 0xa0 && (unit & 0x0f) < 6)) continue; /* Target IDs are not contiguous. */ else break; } if (bdinfo[nbdinfo].bd_flags & BD_FLOPPY){ /* available 1.44MB access? */ if (*(u_char *)PTOV(0xA15AE) & (1<<(unit & 0xf))) { /* boot media 1.2MB FD? */ if ((*(u_char *)PTOV(0xA1584) & 0xf0) != 0x90) bdinfo[nbdinfo].bd_unit = 0x30 + (unit & 0xf); } } else { if ((unit & 0xF0) == 0xA0) /* SCSI HD or MO */ bdinfo[nbdinfo].bd_da_unit = da_drive++; } /* XXX we need "disk aliases" to make this simpler */ printf("BIOS drive %c: is disk%d\n", 'A' + nbdinfo, nbdinfo); nbdinfo++; } } return(0); } /* * Try to detect a device supported by the legacy int13 BIOS */ static int bd_int13probe(struct bdinfo *bd) { int addr; if (bd->bd_flags & BD_FLOPPY) { addr = 0xa155c; } else { if ((bd->bd_unit & 0xf0) == 0x80) addr = 0xa155d; else addr = 0xa1482; } if ( *(u_char *)PTOV(addr) & (1<<(bd->bd_unit & 0x0f))) { bd->bd_flags |= BD_MODEINT13; return(1); } if ((bd->bd_unit & 0xF0) == 0xA0) { int media = ((unsigned *)PTOV(0xA1460))[bd->bd_unit & 0x0F] & 0x1F; if (media == 7) { /* MO */ bd->bd_flags |= BD_MODEINT13 | BD_OPTICAL; return(1); } } return(0); } /* * Print information about disks */ static void bd_print(int verbose) { int i, j; char line[80]; struct i386_devdesc dev; struct open_disk *od; struct pc98_partition *dptr; for (i = 0; i < nbdinfo; i++) { sprintf(line, " disk%d: BIOS drive %c:\n", i, 'A' + i); pager_output(line); /* try to open the whole disk */ dev.d_unit = i; dev.d_kind.biosdisk.slice = -1; dev.d_kind.biosdisk.partition = -1; if (!bd_opendisk(&od, &dev)) { /* Do we have a partition table? */ if (od->od_flags & BD_PARTTABOK) { dptr = &od->od_slicetab[0]; /* Check for a "dedicated" disk */ for (j = 0; j < od->od_nslices; j++) { switch(dptr[j].dp_mid) { case DOSMID_386BSD: sprintf(line, " disk%ds%d", i, j + 1); bd_printbsdslice(od, dptr[j].dp_scyl * od->od_hds * od->od_sec + dptr[j].dp_shd * od->od_sec + dptr[j].dp_ssect, line, verbose); break; default: break; } } } bd_closedisk(od); } } } /* * Print out each valid partition in the disklabel of a FreeBSD slice. * For size calculations, we assume a 512 byte sector size. */ static void bd_printbsdslice(struct open_disk *od, daddr_t offset, char *prefix, int verbose) { char line[80]; char buf[BIOSDISK_SECSIZE]; struct disklabel *lp; int i; /* read disklabel */ if (bd_read(od, offset + LABELSECTOR, 1, buf)) return; lp =(struct disklabel *)(&buf[0]); if (lp->d_magic != DISKMAGIC) { sprintf(line, "%s: FFS bad disklabel\n", prefix); pager_output(line); return; } /* Print partitions */ for (i = 0; i < lp->d_npartitions; i++) { /* * For each partition, make sure we know what type of fs it is. If * not, then skip it. However, since floppies often have bogus * fstypes, print the 'a' partition on a floppy even if it is marked * unused. */ if ((lp->d_partitions[i].p_fstype == FS_BSDFFS) || (lp->d_partitions[i].p_fstype == FS_SWAP) || (lp->d_partitions[i].p_fstype == FS_VINUM) || ((lp->d_partitions[i].p_fstype == FS_UNUSED) && (od->od_flags & BD_FLOPPY) && (i == 0))) { /* Only print out statistics in verbose mode */ if (verbose) sprintf(line, " %s%c: %s %.6dMB (%d - %d)\n", prefix, 'a' + i, (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" : "FFS", lp->d_partitions[i].p_size / 2048, lp->d_partitions[i].p_offset, lp->d_partitions[i].p_offset + lp->d_partitions[i].p_size); else sprintf(line, " %s%c: %s\n", prefix, 'a' + i, (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" : "FFS"); pager_output(line); } } } /* * Attempt to open the disk described by (dev) for use by (f). * * Note that the philosophy here is "give them exactly what * they ask for". This is necessary because being too "smart" * about what the user might want leads to complications. * (eg. given no slice or partition value, with a disk that is * sliced - are they after the first BSD slice, or the DOS * slice before it?) */ static int bd_open(struct open_file *f, ...) { va_list ap; struct i386_devdesc *dev; struct open_disk *od; int error; va_start(ap, f); dev = va_arg(ap, struct i386_devdesc *); va_end(ap); if ((error = bd_opendisk(&od, dev))) return(error); /* * Save our context */ ((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data = od; DEBUG("open_disk %p, partition at 0x%x", od, od->od_boff); return(0); } static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev) { struct pc98_partition *dptr; struct disklabel *lp; struct open_disk *od; int sector, slice, i; int error; char buf[BUFSIZE]; if (dev->d_unit >= nbdinfo) { DEBUG("attempt to open nonexistent disk"); return(ENXIO); } od = (struct open_disk *)malloc(sizeof(struct open_disk)); if (!od) { DEBUG("no memory"); return (ENOMEM); } /* Look up BIOS unit number, intialise open_disk structure */ od->od_dkunit = dev->d_unit; od->od_unit = bdinfo[od->od_dkunit].bd_unit; od->od_flags = bdinfo[od->od_dkunit].bd_flags; od->od_boff = 0; od->od_nslices = 0; error = 0; DEBUG("open '%s', unit 0x%x slice %d partition %c", i386_fmtdev(dev), dev->d_unit, dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a'); /* Get geometry for this open (removable device may have changed) */ if (bd_getgeom(od)) { DEBUG("can't get geometry"); error = ENXIO; goto out; } /* * Following calculations attempt to determine the correct value * for d->od_boff by looking for the slice and partition specified, * or searching for reasonable defaults. */ /* * Find the slice in the DOS slice table. */ if (od->od_flags & BD_FLOPPY) { sector = 0; goto unsliced; } if (bd_read(od, 0, 1, buf)) { DEBUG("error reading MBR"); error = EIO; goto out; } /* * Check the slice table magic. */ if (((u_char)buf[0x1fe] != 0x55) || ((u_char)buf[0x1ff] != 0xaa)) { /* If a slice number was explicitly supplied, this is an error */ if (dev->d_kind.biosdisk.slice > 0) { DEBUG("no slice table/MBR (no magic)"); error = ENOENT; goto out; } sector = 0; goto unsliced; /* may be a floppy */ } if (bd_read(od, 1, 1, buf)) { DEBUG("error reading MBR"); error = EIO; goto out; } /* * copy the partition table, then pick up any extended partitions. */ bcopy(buf + DOSPARTOFF, &od->od_slicetab, sizeof(struct pc98_partition) * NDOSPART); od->od_nslices = NDOSPART; /* extended slices start here */ od->od_flags |= BD_PARTTABOK; dptr = &od->od_slicetab[0]; /* Is this a request for the whole disk? */ if (dev->d_kind.biosdisk.slice == -1) { sector = 0; goto unsliced; } /* * if a slice number was supplied but not found, this is an error. */ if (dev->d_kind.biosdisk.slice > 0) { slice = dev->d_kind.biosdisk.slice - 1; if (slice >= od->od_nslices) { DEBUG("slice %d not found", slice); error = ENOENT; goto out; } } /* Try to auto-detect the best slice; this should always give a slice number */ if (dev->d_kind.biosdisk.slice == 0) { slice = bd_bestslice(od); if (slice == -1) { error = ENOENT; goto out; } dev->d_kind.biosdisk.slice = slice; } dptr = &od->od_slicetab[0]; /* * Accept the supplied slice number unequivocally (we may be looking * at a DOS partition). */ dptr += (dev->d_kind.biosdisk.slice - 1); /* we number 1-4, offsets are 0-3 */ sector = dptr->dp_scyl * od->od_hds * od->od_sec + dptr->dp_shd * od->od_sec + dptr->dp_ssect; { int end = dptr->dp_ecyl * od->od_hds * od->od_sec + dptr->dp_ehd * od->od_sec + dptr->dp_esect; DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, end-sector); } /* * If we are looking at a BSD slice, and the partition is < 0, assume the 'a' partition */ if ((dptr->dp_mid == DOSMID_386BSD) && (dev->d_kind.biosdisk.partition < 0)) dev->d_kind.biosdisk.partition = 0; unsliced: /* * Now we have the slice offset, look for the partition in the disklabel if we have * a partition to start with. * * XXX we might want to check the label checksum. */ if (dev->d_kind.biosdisk.partition < 0) { od->od_boff = sector; /* no partition, must be after the slice */ DEBUG("opening raw slice"); } else { if (bd_read(od, sector + LABELSECTOR, 1, buf)) { DEBUG("error reading disklabel"); error = EIO; goto out; } DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel); bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel)); lp = &od->od_disklabel; od->od_flags |= BD_LABELOK; if (lp->d_magic != DISKMAGIC) { DEBUG("no disklabel"); error = ENOENT; goto out; } if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) { DEBUG("partition '%c' exceeds partitions in table (a-'%c')", 'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions); error = EPART; goto out; } #ifdef DISK_DEBUG /* Complain if the partition is unused unless this is a floppy. */ if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) && !(od->od_flags & BD_FLOPPY)) DEBUG("warning, partition marked as unused"); #endif od->od_boff = lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset - lp->d_partitions[RAW_PART].p_offset + sector; } out: if (error) { free(od); } else { *odp = od; /* return the open disk */ } return(error); } /* * Search for a slice with the following preferences: * * 1: Active FreeBSD slice * 2: Non-active FreeBSD slice * 3: Active Linux slice * 4: non-active Linux slice * 5: Active FAT/FAT32 slice * 6: non-active FAT/FAT32 slice */ #define PREF_RAWDISK 0 #define PREF_FBSD_ACT 1 #define PREF_FBSD 2 #define PREF_LINUX_ACT 3 #define PREF_LINUX 4 #define PREF_DOS_ACT 5 #define PREF_DOS 6 #define PREF_NONE 7 /* * slicelimit is in the range 0 .. NDOSPART */ static int bd_bestslice(struct open_disk *od) { struct pc98_partition *dp; int pref, preflevel; int i, prefslice; prefslice = 0; preflevel = PREF_NONE; dp = &od->od_slicetab[0]; for (i = 0; i < od->od_nslices; i++, dp++) { switch(dp->dp_mid & 0x7f) { case DOSMID_386BSD & 0x7f: /* FreeBSD */ if ((dp->dp_mid & 0x80) && (preflevel > PREF_FBSD_ACT)) { pref = i; preflevel = PREF_FBSD_ACT; } else if (preflevel > PREF_FBSD) { pref = i; preflevel = PREF_FBSD; } break; case 0x11: /* DOS/Windows */ case 0x20: case 0x21: case 0x22: case 0x23: case 0x63: if ((dp->dp_mid & 0x80) && (preflevel > PREF_DOS_ACT)) { pref = i; preflevel = PREF_DOS_ACT; } else if (preflevel > PREF_DOS) { pref = i; preflevel = PREF_DOS; } break; } } return (prefslice); } static int bd_close(struct open_file *f) { struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data); bd_closedisk(od); return(0); } static void bd_closedisk(struct open_disk *od) { DEBUG("open_disk %p", od); #if 0 /* XXX is this required? (especially if disk already open...) */ if (od->od_flags & BD_FLOPPY) delay(3000000); #endif free(od); } static int bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata bcd; struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); bcd.dv_strategy = bd_realstrategy; bcd.dv_devdata = devdata; return(bcache_strategy(&bcd, od->od_unit, rw, dblk+od->od_boff, size, buf, rsize)); } static int bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); int blks; #ifdef BD_SUPPORT_FRAGS char fragbuf[BIOSDISK_SECSIZE]; size_t fragsize; fragsize = size % BIOSDISK_SECSIZE; #else if (size % BIOSDISK_SECSIZE) panic("bd_strategy: %d bytes I/O not multiple of block size", size); #endif DEBUG("open_disk %p", od); switch(rw){ case F_READ: blks = size / BIOSDISK_SECSIZE; DEBUG("read %d from %d to %p", blks, dblk, buf); if (rsize) *rsize = 0; if (blks && bd_read(od, dblk, blks, buf)) { DEBUG("read error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS DEBUG("bd_strategy: frag read %d from %d+%d to %p", fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE)); if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) { DEBUG("frag read error"); return(EIO); } bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize); #endif if (rsize) *rsize = size; return (0); break; case F_WRITE : blks = size / BIOSDISK_SECSIZE; DEBUG("write %d from %d to %p", blks, dblk, buf); if (rsize) *rsize = 0; if (blks && bd_write(od, dblk, blks, buf)) { DEBUG("write error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS if(fragsize) { DEBUG("Attempted to write a frag"); return (EIO); } #endif if (rsize) *rsize = size; return (0); default: /* DO NOTHING */ break; } return EROFS; } /* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ #define FLOPPY_BOUNCEBUF 18 static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) { u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; caddr_t p, xp, bbuf, breg; /* Just in case some idiot actually tries to read -1 blocks... */ if (blks < 0) return (-1); bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ resid = blks; p = dest; /* Decide whether we have to bounce */ if (VTOP(dest) >> 20 != 0 || ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) { /* * There is a 64k physical boundary somewhere in the destination buffer, or the * destination buffer is above first 1MB of physical memory so we have * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we * need to. Use the bottom half unless there is a break there, in which case we * use the top half. */ x = min(od->od_sec, (unsigned)blks); bbuf = alloca(x * 2 * BIOSDISK_SECSIZE); if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) { breg = bbuf; } else { breg = bbuf + x * BIOSDISK_SECSIZE; } maxfer = x; /* limit transfers to bounce region size */ } else { breg = bbuf = NULL; maxfer = 0; } while (resid > 0) { x = dblk; cyl = x / bpc; /* block # / blocks per cylinder */ x %= bpc; /* block offset into cylinder */ hd = x / od->od_sec; /* offset / blocks per track */ sec = x % od->od_sec; /* offset into track */ /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ x = min(od->od_sec - sec, resid); if (maxfer > 0) x = min(x, maxfer); /* fit bounce buffer */ /* where do we transfer to? */ xp = bbuf == NULL ? p : breg; /* correct sector number for 1-based BIOS numbering */ if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90) sec++; /* Loop retrying the operation a couple of times. The BIOS may also retry. */ for (retry = 0; retry < 3; retry++) { /* if retrying, reset the drive */ if (retry > 0) { v86.ctl = V86_FLAGS; v86.addr = 0x1b; v86.eax = 0x0300 | od->od_unit; v86int(); } v86.ctl = V86_FLAGS; v86.addr = 0x1b; if (od->od_flags & BD_FLOPPY) { v86.eax = 0xd600 | od->od_unit; v86.ecx = 0x0200 | (cyl & 0xff); } else { v86.eax = 0x0600 | od->od_unit; v86.ecx = cyl; } if (od->od_flags & BD_OPTICAL) { v86.eax &= 0xFF7F; v86.ecx = dblk & 0xFFFF; v86.edx = dblk >> 16; } else { v86.edx = (hd << 8) | sec; } v86.ebx = x * BIOSDISK_SECSIZE; v86.es = VTOPSEG(xp); v86.ebp = VTOPOFF(xp); v86int(); result = (v86.efl & 0x1); if (result == 0) break; } DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, od->od_flags & BD_FLOPPY ? sec - 1 : sec, p, VTOP(p), result ? "failed" : "ok"); /* BUG here, cannot use v86 in printf because putchar uses it too */ DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit, od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec, (v86.eax >> 8) & 0xff); if (result) { return(-1); } if (bbuf != NULL) bcopy(breg, p, x * BIOSDISK_SECSIZE); p += (x * BIOSDISK_SECSIZE); dblk += x; resid -= x; } /* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ return(0); } static int bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) { u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; caddr_t p, xp, bbuf, breg; /* Just in case some idiot actually tries to read -1 blocks... */ if (blks < 0) return (-1); bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ resid = blks; p = dest; /* Decide whether we have to bounce */ if (VTOP(dest) >> 20 != 0 || ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) { /* * There is a 64k physical boundary somewhere in the destination buffer, or the * destination buffer is above first 1MB of physical memory so we have * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we * need to. Use the bottom half unless there is a break there, in which case we * use the top half. */ x = min(od->od_sec, (unsigned)blks); bbuf = alloca(x * 2 * BIOSDISK_SECSIZE); if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) { breg = bbuf; } else { breg = bbuf + x * BIOSDISK_SECSIZE; } maxfer = x; /* limit transfers to bounce region size */ } else { breg = bbuf = NULL; maxfer = 0; } while (resid > 0) { x = dblk; cyl = x / bpc; /* block # / blocks per cylinder */ x %= bpc; /* block offset into cylinder */ hd = x / od->od_sec; /* offset / blocks per track */ sec = x % od->od_sec; /* offset into track */ /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ x = min(od->od_sec - sec, resid); if (maxfer > 0) x = min(x, maxfer); /* fit bounce buffer */ /* where do we transfer to? */ xp = bbuf == NULL ? p : breg; /* correct sector number for 1-based BIOS numbering */ if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90) sec++; /* Put your Data In, Put your Data out, Put your Data In, and shake it all about */ if (bbuf != NULL) bcopy(p, breg, x * BIOSDISK_SECSIZE); p += (x * BIOSDISK_SECSIZE); dblk += x; resid -= x; /* Loop retrying the operation a couple of times. The BIOS may also retry. */ for (retry = 0; retry < 3; retry++) { /* if retrying, reset the drive */ if (retry > 0) { v86.ctl = V86_FLAGS; v86.addr = 0x1b; v86.eax = 0x0300 | od->od_unit; v86int(); } v86.ctl = V86_FLAGS; v86.addr = 0x1b; if (od->od_flags & BD_FLOPPY) { v86.eax = 0xd500 | od->od_unit; v86.ecx = 0x0200 | (cyl & 0xff); } else { v86.eax = 0x0500 | od->od_unit; v86.ecx = cyl; } v86.edx = (hd << 8) | sec; v86.ebx = x * BIOSDISK_SECSIZE; v86.es = VTOPSEG(xp); v86.ebp = VTOPOFF(xp); v86int(); result = (v86.efl & 0x1); if (result == 0) break; } DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, od->od_flags & BD_FLOPPY ? sec - 1 : sec, p, VTOP(p), result ? "failed" : "ok"); /* BUG here, cannot use v86 in printf because putchar uses it too */ DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit, od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec, (v86.eax >> 8) & 0xff); if (result) { return(-1); } } /* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ return(0); } static int bd_getgeom(struct open_disk *od) { if (od->od_flags & BD_FLOPPY) { od->od_cyl = 79; od->od_hds = 2; od->od_sec = (od->od_unit & 0xf0) == 0x30 ? 18 : 15; } else if (od->od_flags & BD_OPTICAL) { od->od_cyl = 0xFFFE; od->od_hds = 8; od->od_sec = 32; } else { v86.ctl = V86_FLAGS; v86.addr = 0x1b; v86.eax = 0x8400 | od->od_unit; v86int(); od->od_cyl = v86.ecx; od->od_hds = (v86.edx >> 8) & 0xff; od->od_sec = v86.edx & 0xff; if (v86.efl & 0x1) return(1); } DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec); return(0); } /* * Return the BIOS geometry of a given "fixed drive" in a format * suitable for the legacy bootinfo structure. Since the kernel is * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we * prefer to get the information directly, rather than rely on being * able to put it together from information already maintained for * different purposes and for a probably different number of drives. * * For valid drives, the geometry is expected in the format (31..0) * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are * indicated by returning the geometry of a "1.2M" PC-format floppy * disk. And, incidentally, what is returned is not the geometry as * such but the highest valid cylinder, head, and sector numbers. */ u_int32_t bd_getbigeom(int bunit) { int hds = 0; int unit = 0x80; /* IDE HDD */ u_int addr = 0xA155d; while (unit < 0xa7) { if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) if (hds++ == bunit) break; if (unit >= 0xA0) { int media = ((unsigned *)PTOV(0xA1460))[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 = 0xA1482; } } if (unit == 0xa7) return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ v86.ctl = V86_FLAGS; 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); } /* * Return a suitable dev_t value for (dev). * * In the case where it looks like (dev) is a SCSI disk, we allow the number of * IDE disks to be specified in $num_ide_disks. There should be a Better Way. */ int bd_getdev(struct i386_devdesc *dev) { struct open_disk *od; int biosdev; int major; int rootdev; char *nip, *cp; int unitofs = 0, i, unit; biosdev = bd_unit2bios(dev->d_unit); DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev); if (biosdev == -1) /* not a BIOS device */ return(-1); if (bd_opendisk(&od, dev) != 0) /* oops, not a viable device */ return(-1); if ((biosdev & 0xf0) == 0x90 || (biosdev & 0xf0) == 0x30) { /* floppy (or emulated floppy) or ATAPI device */ if (bdinfo[dev->d_unit].bd_type == DT_ATAPI) { /* is an ATAPI disk */ major = WFDMAJOR; } else { /* is a floppy disk */ major = FDMAJOR; } } else { /* harddisk */ if ((od->od_flags & BD_LABELOK) && (od->od_disklabel.d_type == DTYPE_SCSI)) { /* label OK, disk labelled as SCSI */ major = DAMAJOR; /* check for unit number correction hint, now deprecated */ if ((nip = getenv("num_ide_disks")) != NULL) { i = strtol(nip, &cp, 0); /* check for parse error */ if ((cp != nip) && (*cp == 0)) unitofs = i; } } else { /* assume an IDE disk */ major = WDMAJOR; } } /* default root disk unit number */ if ((biosdev & 0xf0) == 0xa0) unit = bdinfo[dev->d_unit].bd_da_unit; else unit = biosdev & 0xf; /* XXX a better kludge to set the root disk unit number */ if ((nip = getenv("root_disk_unit")) != NULL) { i = strtol(nip, &cp, 0); /* check for parse error */ if ((cp != nip) && (*cp == 0)) unit = i; } - rootdev = MAKEBOOTDEV(major, - (dev->d_kind.biosdisk.slice + 1) >> 4, /* XXX slices may be wrong here */ - (dev->d_kind.biosdisk.slice + 1) & 0xf, - unit, - dev->d_kind.biosdisk.partition); + rootdev = MAKEBOOTDEV(major, dev->d_kind.biosdisk.slice + 1, unit, + dev->d_kind.biosdisk.partition); DEBUG("dev is 0x%x\n", rootdev); return(rootdev); } diff --git a/sys/i386/include/bootinfo.h b/sys/i386/include/bootinfo.h index 475a09e08883..09b4e2cc351c 100644 --- a/sys/i386/include/bootinfo.h +++ b/sys/i386/include/bootinfo.h @@ -1,118 +1,112 @@ /*- * Copyright (C) 1994 by Rodney W. Grimes, Milwaukie, Oregon 97222 * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer as * the first lines of this file unmodified. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Rodney W. Grimes. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL RODNEY W. GRIMES BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE_BOOTINFO_H_ #define _MACHINE_BOOTINFO_H_ /* Only change the version number if you break compatibility. */ #define BOOTINFO_VERSION 1 #define N_BIOS_GEOM 8 /* * A zero bootinfo field often means that there is no info available. * Flags are used to indicate the validity of fields where zero is a * normal value. */ struct bootinfo { u_int32_t bi_version; u_int32_t bi_kernelname; /* represents a char * */ u_int32_t bi_nfs_diskless; /* struct nfs_diskless * */ /* End of fields that are always present. */ #define bi_endcommon bi_n_bios_used u_int32_t bi_n_bios_used; u_int32_t bi_bios_geom[N_BIOS_GEOM]; u_int32_t bi_size; u_int8_t bi_memsizes_valid; u_int8_t bi_bios_dev; /* bootdev BIOS unit number */ u_int8_t bi_pad[2]; u_int32_t bi_basemem; u_int32_t bi_extmem; u_int32_t bi_symtab; /* struct symtab * */ u_int32_t bi_esymtab; /* struct symtab * */ /* Items below only from advanced bootloader */ u_int32_t bi_kernend; /* end of kernel space */ u_int32_t bi_envp; /* environment */ u_int32_t bi_modulep; /* preloaded modules */ }; #ifdef _KERNEL extern struct bootinfo bootinfo; #endif /* * Constants for converting boot-style device number to type, * adaptor (uba, mba, etc), unit number and partition number. * Type (== major device number) is in the low byte * for backward compatibility. Except for that of the "magic * number", each mask applies to the shifted value. * Format: - * (4) (4) (4) (4) (8) (8) + * (4) (8) (4) (8) (8) * -------------------------------- - * |MA | AD| CT| UN| PART | TYPE | + * |MA | SLICE | UN| PART | TYPE | * -------------------------------- */ -#define B_ADAPTORSHIFT 24 -#define B_ADAPTORMASK 0x0f -#define B_ADAPTOR(val) (((val) >> B_ADAPTORSHIFT) & B_ADAPTORMASK) -#define B_CONTROLLERSHIFT 20 -#define B_CONTROLLERMASK 0xf -#define B_CONTROLLER(val) (((val)>>B_CONTROLLERSHIFT) & B_CONTROLLERMASK) #define B_SLICESHIFT 20 #define B_SLICEMASK 0xff #define B_SLICE(val) (((val)>>B_SLICESHIFT) & B_SLICEMASK) #define B_UNITSHIFT 16 #define B_UNITMASK 0xf #define B_UNIT(val) (((val) >> B_UNITSHIFT) & B_UNITMASK) #define B_PARTITIONSHIFT 8 #define B_PARTITIONMASK 0xff #define B_PARTITION(val) (((val) >> B_PARTITIONSHIFT) & B_PARTITIONMASK) #define B_TYPESHIFT 0 #define B_TYPEMASK 0xff #define B_TYPE(val) (((val) >> B_TYPESHIFT) & B_TYPEMASK) #define B_MAGICMASK 0xf0000000 #define B_DEVMAGIC 0xa0000000 -#define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \ - (((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \ - ((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \ - ((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC) +#define MAKEBOOTDEV(type, slice, unit, partition) \ + (((type) << B_TYPESHIFT) | ((slice) << B_SLICESHIFT) | \ + ((unit) << B_UNITSHIFT) | ((partition) << B_PARTITIONSHIFT) | \ + B_DEVMAGIC) #define BASE_SLICE 2 #define COMPATIBILITY_SLICE 0 #define MAX_SLICES 32 #define WHOLE_DISK_SLICE 1 #endif /* !_MACHINE_BOOTINFO_H_ */