Index: stable/11/stand/pc98/boot2/boot2.c =================================================================== --- stable/11/stand/pc98/boot2/boot2.c (revision 333048) +++ stable/11/stand/pc98/boot2/boot2.c (revision 333049) @@ -1,803 +1,814 @@ /*- * Copyright (c) 2008-2009 TAKAHASHI Yoshihiro * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "boot2.h" #include "lib.h" #include "paths.h" #include "rbx.h" /* Define to 0 to omit serial support */ #ifndef SERIAL #define SERIAL 0 #endif #define IO_KEYBOARD 1 #define IO_SERIAL 2 #if SERIAL #define DO_KBD (ioctrl & IO_KEYBOARD) #define DO_SIO (ioctrl & IO_SERIAL) #else #define DO_KBD (1) #define DO_SIO (0) #endif #define SECOND 1 /* Circa that many ticks in a second. */ #define ARGS 0x900 #define NOPT 14 #define NDEV 3 #define DRV_DISK 0xf0 #define DRV_UNIT 0x0f #define TYPE_AD 0 #define TYPE_DA 1 #define TYPE_FD 2 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 + RBX_DUAL, + RBX_SERIAL, + RBX_ASKNAME, + RBX_CDROM, + RBX_CONFIG, + RBX_KDB, + RBX_GDB, + RBX_MUTE, + RBX_NOINTR, + RBX_PAUSE, + RBX_QUIET, + RBX_DFLTROOT, + RBX_SINGLE, + RBX_VERBOSE }; static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; static const unsigned char dev_daua[NDEV] = {0x80, 0xa0, 0x90}; static struct dsk { - unsigned daua; - unsigned type; - unsigned disk; - unsigned unit; - unsigned head; - unsigned sec; - uint8_t slice; - uint8_t part; - unsigned start; + unsigned daua; + unsigned type; + unsigned disk; + unsigned unit; + unsigned head; + unsigned sec; + uint8_t slice; + uint8_t part; + unsigned start; } dsk; static char cmd[512], cmddup[512], knamebuf[1024]; static const char *kname; uint32_t opts; static struct bootinfo bootinfo; #if SERIAL static int comspeed = SIOSPD; static uint8_t ioctrl = IO_KEYBOARD; #endif int main(void); void exit(int); static void load(void); static int parse(void); static int dskread(void *, unsigned, unsigned); static void printf(const char *,...); static void putchar(int); static int drvread(void *, unsigned); static int keyhit(unsigned); static int xputc(int); static int xgetc(int); static inline int getc(int); static void memcpy(void *, const void *, int); static void memcpy(void *dst, const void *src, int len) { - const char *s = src; - char *d = dst; + const char *s = src; + char *d = dst; - while (len--) - *d++ = *s++; + 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; + + for (; *s1 == *s2 && *s1; s1++, s2++); + return ((unsigned char)*s1 - (unsigned char)*s2); } #define UFS_SMALL_CGBASE #include "ufsread.c" static inline int xfsread(ufs_ino_t inode, void *buf, size_t nbyte) { - if ((size_t)fsread(inode, buf, nbyte) != nbyte) { - printf("Invalid %s\n", "format"); - return -1; - } - return 0; + + if ((size_t)fsread(inode, buf, nbyte) != nbyte) { + printf("Invalid %s\n", "format"); + return (-1); + } + return (0); } static inline void getstr(void) { - char *s; - int c; + 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); + s = cmd; + for (;;) { + switch (c = xgetc(0)) { + case 0: + break; + case '\177': + case '\b': + if (s > cmd) { + s--; + printf("\b \b"); + } + break; + case '\n': + case '\r': + *s = 0; + return; + default: + if (s - cmd < sizeof(cmd) - 1) + *s++ = c; + putchar(c); + } } - } } static inline void putc(int c) { - v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; - v86.addr = PUTCORG; /* call to putc in boot1 */ - v86.eax = c; - v86int(); - v86.ctl = V86_FLAGS; + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.addr = PUTCORG; /* call to putc in boot1 */ + v86.eax = c; + v86int(); + v86.ctl = V86_FLAGS; } static inline int is_scsi_hd(void) { if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01) return 1; return 0; } static inline void fix_sector_size(void) { u_char *p; p = (u_char *)PTOV(0x460 + dsk.unit * 4); /* SCSI equipment parameter */ if ((p[0] & 0x1f) == 7) { /* SCSI MO */ if (!(p[3] & 0x30)) { /* 256B / sector */ p[3] |= 0x10; /* forced set 512B / sector */ p[3 + 0xa1000] |= 0x10; } } } static inline uint32_t get_diskinfo(void) { if (dsk.disk == 0x30) { /* 1440KB FD */ /* 80 cylinders, 2 heads, 18 sectors */ return (80 << 16) | (2 << 8) | 18; } else if (dsk.disk == 0x90) { /* 1200KB FD */ /* 80 cylinders, 2 heads, 15 sectors */ return (80 << 16) | (2 << 8) | 15; } else if (dsk.disk == 0x80 || is_scsi_hd()) { /* IDE or SCSI HDD */ v86.addr = 0x1b; v86.eax = 0x8400 | dsk.daua; v86int(); return (v86.ecx << 16) | v86.edx; } /* SCSI MO or CD */ fix_sector_size(); /* SCSI MO */ /* other SCSI devices */ return (65535 << 16) | (8 << 8) | 32; } static void set_dsk(void) { uint32_t di; di = get_diskinfo(); dsk.head = (di >> 8) & 0xff; dsk.sec = di & 0xff; dsk.start = 0; } #ifdef GET_BIOSGEOM static uint32_t bd_getbigeom(int bunit) { int hds = 0; int unit = 0x80; /* IDE HDD */ u_int addr = 0x55d; while (unit < 0xa7) { if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) if (hds++ == bunit) break; if (unit >= 0xA0) { int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F; if (media == 7 && hds++ == bunit) /* SCSI MO */ return(0xFFFE0820); /* C:65535 H:8 S:32 */ } if (++unit == 0x84) { unit = 0xA0; /* SCSI HDD */ addr = 0x482; } } if (unit == 0xa7) return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ v86.addr = 0x1b; v86.eax = 0x8400 | unit; v86int(); if (V86_CY(v86.efl)) return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff); } #endif static int check_slice(void) { struct pc98_partition *dp; char *sec; unsigned i, cyl; sec = dmadat->secbuf; cyl = *(uint16_t *)PTOV(ARGS); set_dsk(); if (dsk.type == TYPE_FD) return (WHOLE_DISK_SLICE); if (drvread(sec, PC98_BBSECTOR)) return (WHOLE_DISK_SLICE); /* Read error */ dp = (void *)(sec + PC98_PARTOFF); for (i = 0; i < PC98_NPARTS; i++) { if (dp[i].dp_mid == DOSMID_386BSD) { if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl) return (BASE_SLICE + i); } } return (WHOLE_DISK_SLICE); } int main(void) { #ifdef GET_BIOSGEOM - int i; + int i; #endif - uint8_t autoboot; - ufs_ino_t ino; - size_t nbyte; + uint8_t autoboot; + ufs_ino_t ino; + size_t nbyte; - dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); - v86.ctl = V86_FLAGS; - v86.efl = PSL_RESERVED_DEFAULT | PSL_I; - dsk.daua = *(uint8_t *)PTOV(0x584); - dsk.disk = dsk.daua & DRV_DISK; - dsk.unit = dsk.daua & DRV_UNIT; - if (dsk.disk == 0x80) - dsk.type = TYPE_AD; - else if (dsk.disk == 0xa0) - dsk.type = TYPE_DA; - else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */ - dsk.type = TYPE_FD; - dsk.slice = check_slice(); + dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); + v86.ctl = V86_FLAGS; + v86.efl = PSL_RESERVED_DEFAULT | PSL_I; + dsk.daua = *(uint8_t *)PTOV(0x584); + dsk.disk = dsk.daua & DRV_DISK; + dsk.unit = dsk.daua & DRV_UNIT; + if (dsk.disk == 0x80) + dsk.type = TYPE_AD; + else if (dsk.disk == 0xa0) + dsk.type = TYPE_DA; + else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */ + dsk.type = TYPE_FD; + dsk.slice = check_slice(); #ifdef GET_BIOSGEOM - for (i = 0; i < N_BIOS_GEOM; i++) - bootinfo.bi_bios_geom[i] = bd_getbigeom(i); + for (i = 0; i < N_BIOS_GEOM; i++) + bootinfo.bi_bios_geom[i] = bd_getbigeom(i); #endif - bootinfo.bi_version = BOOTINFO_VERSION; - bootinfo.bi_size = sizeof(bootinfo); + bootinfo.bi_version = BOOTINFO_VERSION; + bootinfo.bi_size = sizeof(bootinfo); - /* Process configuration file */ + /* Process configuration file */ - autoboot = 1; + autoboot = 1; - if ((ino = lookup(PATH_CONFIG)) || - (ino = lookup(PATH_DOTCONFIG))) { - nbyte = fsread(ino, cmd, sizeof(cmd) - 1); - cmd[nbyte] = '\0'; - } + if ((ino = lookup(PATH_CONFIG)) || + (ino = lookup(PATH_DOTCONFIG))) { + nbyte = fsread(ino, cmd, sizeof(cmd) - 1); + cmd[nbyte] = '\0'; + } - if (*cmd) { - memcpy(cmddup, cmd, sizeof(cmd)); - if (parse()) - autoboot = 0; - if (!OPT_CHECK(RBX_QUIET)) - printf("%s: %s", PATH_CONFIG, cmddup); - /* Do not process this command twice */ - *cmd = 0; - } + if (*cmd) { + memcpy(cmddup, cmd, sizeof(cmd)); + if (parse()) + autoboot = 0; + if (!OPT_CHECK(RBX_QUIET)) + printf("%s: %s", PATH_CONFIG, cmddup); + /* Do not process this command twice */ + *cmd = 0; + } - /* - * Try to exec stage 3 boot loader. If interrupted by a keypress, - * or in case of failure, try to load a kernel directly instead. - */ + /* + * Try to exec stage 3 boot loader. If interrupted by a keypress, + * or in case of failure, try to load a kernel directly instead. + */ - if (!kname) { - kname = PATH_LOADER; - if (autoboot && !keyhit(3*SECOND)) { - load(); - kname = PATH_KERNEL; + if (!kname) { + kname = PATH_LOADER; + if (autoboot && !keyhit(3*SECOND)) { + load(); + kname = PATH_KERNEL; + } } - } - /* Present the user with the boot2 prompt. */ + /* Present the user with the boot2 prompt. */ - for (;;) { - if (!autoboot || !OPT_CHECK(RBX_QUIET)) - printf("\nFreeBSD/pc98 boot\n" - "Default: %u:%s(%u,%c)%s\n" - "boot: ", - dsk.unit, dev_nm[dsk.type], dsk.unit, - 'a' + dsk.part, kname); - if (DO_SIO) - sio_flush(); - if (!autoboot || keyhit(3*SECOND)) - getstr(); - else if (!autoboot || !OPT_CHECK(RBX_QUIET)) - putchar('\n'); - autoboot = 0; - if (parse()) - putchar('\a'); - else - load(); - } + for (;;) { + if (!autoboot || !OPT_CHECK(RBX_QUIET)) + printf("\nFreeBSD/pc98 boot\n" + "Default: %u:%s(%u,%c)%s\n" + "boot: ", + dsk.unit, dev_nm[dsk.type], dsk.unit, + 'a' + dsk.part, kname); + if (DO_SIO) + sio_flush(); + if (!autoboot || keyhit(3*SECOND)) + getstr(); + else if (!autoboot || !OPT_CHECK(RBX_QUIET)) + putchar('\n'); + autoboot = 0; + if (parse()) + putchar('\a'); + else + load(); + } } /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ void exit(int x) { + } static void load(void) { - union { - struct exec ex; - Elf32_Ehdr eh; - } hdr; - static Elf32_Phdr ep[2]; - static Elf32_Shdr es[2]; - caddr_t p; - ufs_ino_t ino; - uint32_t addr; - int k; - uint8_t i, j; + union { + struct exec ex; + Elf32_Ehdr eh; + } hdr; + static Elf32_Phdr ep[2]; + static Elf32_Shdr es[2]; + caddr_t p; + ufs_ino_t ino; + uint32_t addr; + int k; + uint8_t i, j; - if (!(ino = lookup(kname))) { - if (!ls) - printf("No %s\n", kname); - return; - } - if (xfsread(ino, &hdr, sizeof(hdr))) - return; - - if (N_GETMAGIC(hdr.ex) == ZMAGIC) { - addr = hdr.ex.a_entry & 0xffffff; - p = PTOV(addr); - fs_off = PAGE_SIZE; - if (xfsread(ino, p, hdr.ex.a_text)) - return; - p += roundup2(hdr.ex.a_text, PAGE_SIZE); - if (xfsread(ino, p, hdr.ex.a_data)) - return; - } else if (IS_ELF(hdr.eh)) { - fs_off = hdr.eh.e_phoff; - for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) { - if (xfsread(ino, ep + j, sizeof(ep[0]))) + if (!(ino = lookup(kname))) { + if (!ls) + printf("No %s\n", kname); 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)) + if (xfsread(ino, &hdr, sizeof(hdr))) 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))) + + if (N_GETMAGIC(hdr.ex) == ZMAGIC) { + addr = hdr.ex.a_entry & 0xffffff; + p = PTOV(addr); + fs_off = PAGE_SIZE; + if (xfsread(ino, p, hdr.ex.a_text)) + return; + p += roundup2(hdr.ex.a_text, PAGE_SIZE); + if (xfsread(ino, p, hdr.ex.a_data)) + return; + } else if (IS_ELF(hdr.eh)) { + fs_off = hdr.eh.e_phoff; + for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) { + if (xfsread(ino, ep + j, sizeof(ep[0]))) + return; + if (ep[j].p_type == PT_LOAD) + j++; + } + for (i = 0; i < 2; i++) { + p = PTOV(ep[i].p_paddr & 0xffffff); + fs_off = ep[i].p_offset; + if (xfsread(ino, p, ep[i].p_filesz)) + return; + } + p += roundup2(ep[1].p_memsz, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { + fs_off = hdr.eh.e_shoff + sizeof(es[0]) * + (hdr.eh.e_shstrndx + 1); + if (xfsread(ino, &es, sizeof(es))) + return; + for (i = 0; i < 2; i++) { + *(Elf32_Word *)p = es[i].sh_size; + p += sizeof(es[i].sh_size); + fs_off = es[i].sh_offset; + if (xfsread(ino, p, es[i].sh_size)) + return; + p += es[i].sh_size; + } + } + addr = hdr.eh.e_entry & 0xffffff; + bootinfo.bi_esymtab = VTOP(p); + } else { + printf("Invalid %s\n", "format"); return; - for (i = 0; i < 2; i++) { - *(Elf32_Word *)p = es[i].sh_size; - p += sizeof(es[i].sh_size); - fs_off = es[i].sh_offset; - if (xfsread(ino, p, es[i].sh_size)) - return; - p += es[i].sh_size; - } } - addr = hdr.eh.e_entry & 0xffffff; - bootinfo.bi_esymtab = VTOP(p); - } else { - printf("Invalid %s\n", "format"); - return; - } - bootinfo.bi_kernelname = VTOP(kname); - bootinfo.bi_bios_dev = dsk.daua; - __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), - MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), - 0, 0, 0, VTOP(&bootinfo)); + bootinfo.bi_kernelname = VTOP(kname); + bootinfo.bi_bios_dev = dsk.daua; + __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), + 0, 0, 0, VTOP(&bootinfo)); } static int parse() { - char *arg = cmd; - char *ep, *p, *q; - const char *cp; - unsigned int drv; - int c, i, j; - size_t k; + char *arg = cmd; + char *ep, *p, *q; + const char *cp; + unsigned int drv; + int c, i, j; + size_t k; - while ((c = *arg++)) { - if (c == ' ' || c == '\t' || c == '\n') - continue; - for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); - ep = p; - if (*p) - *p++ = 0; - if (c == '-') { - while ((c = *arg++)) { - if (c == 'P') { - if (*(uint8_t *)PTOV(0x481) & 0x48) { - cp = "yes"; - } else { - opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); - cp = "no"; - } - printf("Keyboard: %s\n", cp); - continue; + while ((c = *arg++)) { + if (c == ' ' || c == '\t' || c == '\n') + continue; + for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); + ep = p; + if (*p) + *p++ = 0; + if (c == '-') { + while ((c = *arg++)) { + if (c == 'P') { + if (*(uint8_t *)PTOV(0x481) & 0x48) { + cp = "yes"; + } else { + opts |= OPT_SET(RBX_DUAL) | + OPT_SET(RBX_SERIAL); + cp = "no"; + } + printf("Keyboard: %s\n", cp); + continue; #if SERIAL - } else if (c == 'S') { - j = 0; - while ((unsigned int)(i = *arg++ - '0') <= 9) - j = j * 10 + i; - if (j > 0 && i == -'0') { - comspeed = j; - break; - } - /* Fall through to error below ('S' not in optstr[]). */ + } else if (c == 'S') { + j = 0; + while ((unsigned int)(i = *arg++ - '0') <= 9) + j = j * 10 + i; + if (j > 0 && i == -'0') { + comspeed = j; + break; + } + /* + * Fall through to error below + * ('S' not in optstr[]). + */ #endif - } - for (i = 0; c != optstr[i]; i++) - if (i == NOPT - 1) - return -1; - opts ^= OPT_SET(flags[i]); - } + } + for (i = 0; c != optstr[i]; i++) + if (i == NOPT - 1) + return (-1); + opts ^= OPT_SET(flags[i]); + } #if SERIAL - ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : - OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; - if (DO_SIO) { - if (sio_init(115200 / comspeed) != 0) - ioctrl &= ~IO_SERIAL; - } + ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : + OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; + if (DO_SIO) { + if (sio_init(115200 / comspeed) != 0) + ioctrl &= ~IO_SERIAL; + } #endif - } else { - for (q = arg--; *q && *q != '('; q++); - if (*q) { - drv = -1; - if (arg[1] == ':') { - drv = *arg - '0'; - if (drv > 9) - return (-1); - arg += 2; + } else { + for (q = arg--; *q && *q != '('; q++); + if (*q) { + drv = -1; + if (arg[1] == ':') { + drv = *arg - '0'; + if (drv > 9) + return (-1); + arg += 2; + } + if (q - arg != 2) + return (-1); + for (i = 0; arg[0] != dev_nm[i][0] || + arg[1] != dev_nm[i][1]; i++) + if (i == NDEV - 1) + return (-1); + dsk.type = i; + arg += 3; + dsk.unit = *arg - '0'; + if (arg[1] != ',' || dsk.unit > 9) + return (-1); + arg += 2; + dsk.slice = WHOLE_DISK_SLICE; + if (arg[1] == ',') { + dsk.slice = *arg - '0' + 1; + if (dsk.slice > PC98_NPARTS + 1) + return (-1); + arg += 2; + } + if (arg[1] != ')') + return (-1); + dsk.part = *arg - 'a'; + if (dsk.part > 7) + return (-1); + arg += 2; + if (drv == -1) + drv = dsk.unit; + dsk.disk = dev_daua[dsk.type]; + dsk.daua = dsk.disk | dsk.unit; + dsk_meta = 0; + } + k = ep - arg; + if (k > 0) { + if (k >= sizeof(knamebuf)) + return (-1); + memcpy(knamebuf, arg, k + 1); + kname = knamebuf; + } } - if (q - arg != 2) - return -1; - for (i = 0; arg[0] != dev_nm[i][0] || - arg[1] != dev_nm[i][1]; i++) - if (i == NDEV - 1) - return -1; - dsk.type = i; - arg += 3; - dsk.unit = *arg - '0'; - if (arg[1] != ',' || dsk.unit > 9) - return -1; - arg += 2; - dsk.slice = WHOLE_DISK_SLICE; - if (arg[1] == ',') { - dsk.slice = *arg - '0' + 1; - if (dsk.slice > PC98_NPARTS + 1) - return -1; - arg += 2; - } - if (arg[1] != ')') - return -1; - dsk.part = *arg - 'a'; - if (dsk.part > 7) - return (-1); - arg += 2; - if (drv == -1) - drv = dsk.unit; - dsk.disk = dev_daua[dsk.type]; - dsk.daua = dsk.disk | dsk.unit; - dsk_meta = 0; - } - k = ep - arg; - if (k > 0) { - if (k >= sizeof(knamebuf)) - return -1; - memcpy(knamebuf, arg, k + 1); - kname = knamebuf; - } + arg = p; } - arg = p; - } - return 0; + return (0); } static int dskread(void *buf, unsigned lba, unsigned nblk) { - struct pc98_partition *dp; - struct disklabel *d; - char *sec; - unsigned i; - uint8_t sl; - u_char *p; - const char *reason; + struct pc98_partition *dp; + struct disklabel *d; + char *sec; + unsigned i; + uint8_t sl; + u_char *p; + const char *reason; - if (!dsk_meta) { - sec = dmadat->secbuf; - set_dsk(); - if (dsk.type == TYPE_FD) - goto unsliced; - if (drvread(sec, PC98_BBSECTOR)) - return -1; - dp = (void *)(sec + PC98_PARTOFF); - sl = dsk.slice; - if (sl < BASE_SLICE) { - for (i = 0; i < PC98_NPARTS; i++) - if (dp[i].dp_mid == DOSMID_386BSD) { - sl = BASE_SLICE + i; - break; + if (!dsk_meta) { + sec = dmadat->secbuf; + set_dsk(); + if (dsk.type == TYPE_FD) + goto unsliced; + if (drvread(sec, PC98_BBSECTOR)) + return -1; + dp = (void *)(sec + PC98_PARTOFF); + sl = dsk.slice; + if (sl < BASE_SLICE) { + for (i = 0; i < PC98_NPARTS; i++) + if (dp[i].dp_mid == DOSMID_386BSD) { + sl = BASE_SLICE + i; + break; + } + dsk.slice = sl; } - dsk.slice = sl; + if (sl != WHOLE_DISK_SLICE) { + dp += sl - BASE_SLICE; + if (dp->dp_mid != DOSMID_386BSD) { + reason = "slice"; + goto error; + } + dsk.start = dp->dp_scyl * dsk.head * dsk.sec + + dp->dp_shd * dsk.sec + dp->dp_ssect; + } + if (drvread(sec, dsk.start + LABELSECTOR)) + return -1; + d = (void *)(sec + LABELOFFSET); + if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { + if (dsk.part != RAW_PART) { + reason = "label"; + goto error; + } + } else { + if (dsk.part >= d->d_npartitions || + !d->d_partitions[dsk.part].p_size) { + reason = "partition"; + goto error; + } + dsk.start += d->d_partitions[dsk.part].p_offset; + dsk.start -= d->d_partitions[RAW_PART].p_offset; + } + unsliced: ; } - if (sl != WHOLE_DISK_SLICE) { - dp += sl - BASE_SLICE; - if (dp->dp_mid != DOSMID_386BSD) { - reason = "slice"; - goto error; - } - dsk.start = dp->dp_scyl * dsk.head * dsk.sec + - dp->dp_shd * dsk.sec + dp->dp_ssect; + for (p = buf; nblk; p += 512, lba++, nblk--) { + if ((i = drvread(p, dsk.start + lba))) + return (i); } - if (drvread(sec, dsk.start + LABELSECTOR)) - return -1; - d = (void *)(sec + LABELOFFSET); - if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { - if (dsk.part != RAW_PART) { - reason = "label"; - goto error; - } - } else { - if (dsk.part >= d->d_npartitions || - !d->d_partitions[dsk.part].p_size) { - reason = "partition"; - goto error; - } - dsk.start += d->d_partitions[dsk.part].p_offset; - dsk.start -= d->d_partitions[RAW_PART].p_offset; - } - unsliced: ; - } - for (p = buf; nblk; p += 512, lba++, nblk--) { - if ((i = drvread(p, dsk.start + lba))) - return i; - } - return 0; + return (0); error: - printf("Invalid %s\n", reason); - return -1; + printf("Invalid %s\n", reason); + return (-1); } static void printf(const char *fmt,...) { - va_list ap; - static char buf[10]; - char *s; - unsigned u; - int c; + va_list ap; + static char buf[10]; + char *s; + unsigned u; + int c; - va_start(ap, fmt); - while ((c = *fmt++)) { - if (c == '%') { - c = *fmt++; - switch (c) { - case 'c': - putchar(va_arg(ap, int)); - continue; - case 's': - for (s = va_arg(ap, char *); *s; s++) - putchar(*s); - continue; - case 'u': - u = va_arg(ap, unsigned); - s = buf; - do - *s++ = '0' + u % 10U; - while (u /= 10U); - while (--s >= buf) - putchar(*s); - continue; - } + 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); } - putchar(c); - } - va_end(ap); - return; + va_end(ap); + return; } static void putchar(int c) { - if (c == '\n') - xputc('\r'); - xputc(c); + + if (c == '\n') + xputc('\r'); + xputc(c); } static int drvread(void *buf, unsigned lba) { - static unsigned c = 0x2d5c7c2f; - unsigned bpc, x, cyl, head, sec; + static unsigned c = 0x2d5c7c2f; + unsigned bpc, x, cyl, head, sec; - bpc = dsk.sec * dsk.head; - cyl = lba / bpc; - x = lba % bpc; - head = x / dsk.sec; - sec = x % dsk.sec; - - if (!OPT_CHECK(RBX_QUIET)) { - xputc(c = c << 8 | c >> 24); - xputc('\b'); - } - v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; - v86.addr = READORG; /* call to read in boot1 */ - v86.ecx = cyl; - v86.edx = (head << 8) | sec; - v86.edi = lba; - v86.ebx = 512; - v86.es = VTOPSEG(buf); - v86.ebp = VTOPOFF(buf); - v86int(); - v86.ctl = V86_FLAGS; - if (V86_CY(v86.efl)) { - printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff, - cyl, head, sec, lba); - return -1; - } - return 0; + bpc = dsk.sec * dsk.head; + cyl = lba / bpc; + x = lba % bpc; + head = x / dsk.sec; + sec = x % dsk.sec; + + if (!OPT_CHECK(RBX_QUIET)) { + xputc(c = c << 8 | c >> 24); + xputc('\b'); + } + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.addr = READORG; /* call to read in boot1 */ + v86.ecx = cyl; + v86.edx = (head << 8) | sec; + v86.edi = lba; + v86.ebx = 512; + v86.es = VTOPSEG(buf); + v86.ebp = VTOPOFF(buf); + v86int(); + v86.ctl = V86_FLAGS; + if (V86_CY(v86.efl)) { + printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff, + cyl, head, sec, lba); + return (-1); + } + return (0); } static inline void delay(void) { - int i; + int i; - i = 800; - do { - outb(0x5f, 0); /* about 600ns */ - } while (--i >= 0); + i = 800; + do { + outb(0x5f, 0); /* about 600ns */ + } while (--i >= 0); } static int keyhit(unsigned sec) { - unsigned i; + unsigned i; - if (OPT_CHECK(RBX_NOINTR)) - return 0; - for (i = 0; i < sec * 1000; i++) { - if (xgetc(1)) - return 1; - delay(); - } - return 0; + if (OPT_CHECK(RBX_NOINTR)) + return (0); + for (i = 0; i < sec * 1000; i++) { + if (xgetc(1)) + return (1); + delay(); + } + return (0); } static int xputc(int c) { - if (DO_KBD) - putc(c); - if (DO_SIO) - sio_putc(c); - return c; + + if (DO_KBD) + putc(c); + if (DO_SIO) + sio_putc(c); + return (c); } static int getc(int fn) { - v86.addr = 0x18; - v86.eax = fn << 8; - v86int(); - if (fn) - return (v86.ebx >> 8) & 0x01; - else - return v86.eax & 0xff; + + v86.addr = 0x18; + v86.eax = fn << 8; + v86int(); + if (fn) + return ((v86.ebx >> 8) & 0x01); + else + return (v86.eax & 0xff); } static int xgetc(int fn) { - if (OPT_CHECK(RBX_NOINTR)) - return 0; - for (;;) { - if (DO_KBD && getc(1)) - return fn ? 1 : getc(0); - if (DO_SIO && sio_ischar()) - return fn ? 1 : sio_getc(); - if (fn) - return 0; - } + + if (OPT_CHECK(RBX_NOINTR)) + return (0); + for (;;) { + if (DO_KBD && getc(1)) + return (fn ? 1 : getc(0)); + if (DO_SIO && sio_ischar()) + return (fn ? 1 : sio_getc()); + if (fn) + return (0); + } } Index: stable/11/stand/pc98/libpc98/bioscd.c =================================================================== --- stable/11/stand/pc98/libpc98/bioscd.c (revision 333048) +++ stable/11/stand/pc98/libpc98/bioscd.c (revision 333049) @@ -1,420 +1,420 @@ /*- * 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 "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; int bc_open; /* reference counter */ void *bc_bcache; /* buffer cache data */ } bcinfo [MAXBCDEV]; static int nbcinfo = 0; #define BC(dev) (bcinfo[(dev)->dd.d_unit]) 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); + size_t size, char *buf, size_t *rsize); static int bc_realstrategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + 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 int 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++; bcache_add_dev(nbcinfo); /* register cd device in bcache */ return(0); } /* * Print information about disks */ static int bc_print(int verbose) { char line[80]; int i, ret = 0; if (nbcinfo == 0) return (0); printf("%s devices:", bioscd.dv_name); if ((ret = pager_output("\n")) != 0) return (ret); for (i = 0; i < nbcinfo; i++) { sprintf(line, " cd%d: Device 0x%x\n", i, bcinfo[i].bc_sp.sp_devicespec); if ((ret = pager_output(line)) != 0) break; } return (ret); } /* * 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->dd.d_unit >= nbcinfo) { DEBUG("attempt to open nonexistent disk"); return(ENXIO); } BC(dev).bc_open++; if (BC(dev).bc_bcache == NULL) BC(dev).bc_bcache = bcache_allocate(); return(0); } static int bc_close(struct open_file *f) { struct i386_devdesc *dev; dev = (struct i386_devdesc *)f->f_devdata; BC(dev).bc_open--; if (BC(dev).bc_open == 0) { bcache_free(BC(dev).bc_bcache); BC(dev).bc_bcache = NULL; } return(0); } static int bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata bcd; struct i386_devdesc *dev; dev = (struct i386_devdesc *)devdata; bcd.dv_strategy = bc_realstrategy; bcd.dv_devdata = devdata; bcd.dv_cache = BC(dev).bc_bcache; return (bcache_strategy(&bcd, rw, dblk, size, buf, rsize)); } static int bc_realstrategy(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->dd.d_unit; blks = size / BIOSCD_SECSIZE; if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0) return (EINVAL); dblk /= (BIOSCD_SECSIZE / DEV_BSIZE); DEBUG("read %d from %lld 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("frag read %d from %lld+%d to %p", fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE)); if (fragsize && bc_read(unit, dblk + blks, 1, fragbuf)) { DEBUG("frag read error"); return(EIO); } bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize); #endif if (rsize) *rsize = size; return (0); } /* Max number of sectors to bounce-buffer at a time. */ #define CD_BOUNCEBUF 8 static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest) { u_int maxfer, resid, result, retry, x; caddr_t bbuf, p, xp; 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); /* Decide whether we have to bounce */ if (VTOP(dest) >> 20 != 0) { /* * The destination buffer is above first 1MB of * physical memory so we have to arrange a suitable * bounce buffer. */ x = min(CD_BOUNCEBUF, (unsigned)blks); bbuf = alloca(x * BIOSCD_SECSIZE); maxfer = x; } else { bbuf = NULL; maxfer = 0; } biosdev = bc_unit2bios(unit); resid = blks; p = dest; while (resid > 0) { if (bbuf) xp = bbuf; else xp = p; x = resid; if (maxfer > 0) x = min(x, maxfer); /* * 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 = x * BIOSCD_SECSIZE; v86.ecx = dblk & 0xffff; v86.edx = (dblk >> 16) & 0xffff; v86.ebp = VTOPOFF(xp); v86.es = VTOPSEG(xp); v86int(); result = V86_CY(v86.efl); if (result == 0) break; } #ifdef DISK_DEBUG error = (v86.eax >> 8) & 0xff; #endif DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p, VTOP(p), result ? "failed" : "ok"); DEBUG("unit %d status 0x%x", unit, error); if (bbuf != NULL) bcopy(bbuf, p, x * BIOSCD_SECSIZE); p += (x * BIOSCD_SECSIZE); dblk += x; resid -= x; } /* 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->dd.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, unit, 0); DEBUG("dev is 0x%x\n", rootdev); return(rootdev); } Index: stable/11/stand/pc98/libpc98/biosdisk.c =================================================================== --- stable/11/stand/pc98/libpc98/biosdisk.c (revision 333048) +++ stable/11/stand/pc98/libpc98/biosdisk.c (revision 333049) @@ -1,1120 +1,1130 @@ /*- * 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 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[PC98_NPARTS]; }; /* * 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 */ - int bd_open; /* reference counter */ - void *bd_bcache; /* buffer cache data */ + 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 */ + int bd_open; /* reference counter */ + void *bd_bcache; /* buffer cache data */ } bdinfo [MAXBDDEV]; static int nbdinfo = 0; #define BD(dev) (bdinfo[(dev)->dd.d_unit]) -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_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 int bd_int13probe(struct bdinfo *bd); +static int bd_printslice(struct open_disk *od, struct pc98_partition *dp, + char *prefix, int verbose); +static int bd_printbsdslice(struct open_disk *od, daddr_t offset, + char *prefix, int verbose); -static int bd_printslice(struct open_disk *od, struct pc98_partition *dp, - char *prefix, int verbose); -static int 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 int bd_print(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 int bd_print(int verbose); - struct devsw biosdisk = { - "disk", - DEVT_DISK, - bd_init, - bd_strategy, - bd_open, - bd_close, - noioctl, - bd_print, - NULL + "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_open_pc98(struct open_disk *od, struct i386_devdesc *dev); 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 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); + + 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) +bd_init(void) { - int base, unit; - int da_drive=0, n=-0x10; + 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_open = 0; - bdinfo[nbdinfo].bd_bcache = NULL; - bdinfo[nbdinfo].bd_unit = unit; - bdinfo[nbdinfo].bd_flags = (unit & 0xf0) == 0x90 ? BD_FLOPPY : 0; + /* 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_open = 0; + bdinfo[nbdinfo].bd_bcache = NULL; + 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)) + /* Target IDs are not contiguous. */ + continue; + else + break; + } - 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); + 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++; } - } - 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++; } - } - bcache_add_dev(nbdinfo); - return(0); + bcache_add_dev(nbdinfo); + return(0); } /* * Try to detect a device supported by the legacy int13 BIOS */ static int bd_int13probe(struct bdinfo *bd) { - int addr; + 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 (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); + if (media == 7) { /* MO */ + bd->bd_flags |= BD_MODEINT13 | BD_OPTICAL; + return(1); + } } - } - return(0); + return (0); } /* * Print information about disks */ static int bd_print(int verbose) { - int i, j, ret = 0; - char line[80]; - struct i386_devdesc dev; - struct open_disk *od; - struct pc98_partition *dptr; + int i, j, ret = 0; + char line[80]; + struct i386_devdesc dev; + struct open_disk *od; + struct pc98_partition *dptr; - if (nbdinfo == 0) - return (0); + if (nbdinfo == 0) + return (0); - printf("%s devices:", biosdisk.dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); + printf("%s devices:", biosdisk.dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); - for (i = 0; i < nbdinfo; i++) { - snprintf(line, sizeof(line), " disk%d: BIOS drive %c:\n", - i, 'A' + i); - if ((ret = pager_output(line)) != 0) - break; + for (i = 0; i < nbdinfo; i++) { + snprintf(line, sizeof(line), " disk%d: BIOS drive %c:\n", + i, 'A' + i); + if ((ret = pager_output(line)) != 0) + break; - /* try to open the whole disk */ - dev.dd.d_unit = i; - dev.d_kind.biosdisk.slice = -1; - dev.d_kind.biosdisk.partition = -1; - - if (!bd_opendisk(&od, &dev)) { + /* try to open the whole disk */ + dev.dd.d_unit = i; + dev.d_kind.biosdisk.slice = -1; + dev.d_kind.biosdisk.partition = -1; - /* Do we have a partition table? */ - if (od->od_flags & BD_PARTTABOK) { - dptr = &od->od_slicetab[0]; + if (!bd_opendisk(&od, &dev)) { - /* Check for a "dedicated" disk */ - for (j = 0; j < od->od_nslices; j++) { - snprintf(line, sizeof(line), " disk%ds%d", i, j + 1); - if ((ret = bd_printslice(od, &dptr[j], line, verbose)) != 0) - break; + /* 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++) { + snprintf(line, sizeof(line), + " disk%ds%d", i, j + 1); + if ((ret = bd_printslice(od, &dptr[j], + line, verbose)) != 0) + break; + } + } + bd_closedisk(od); + if (ret != 0) + break; } - } - bd_closedisk(od); - if (ret != 0) - break; } - } - return (ret); + return (ret); } /* Given a size in 512 byte sectors, convert it to a human-readable number. */ static char * display_size(uint64_t size) { - static char buf[80]; - char unit; + static char buf[80]; + char unit; - size /= 2; - unit = 'K'; - if (size >= 10485760000LL) { - size /= 1073741824; - unit = 'T'; - } else if (size >= 10240000) { - size /= 1048576; - unit = 'G'; - } else if (size >= 10000) { - size /= 1024; - unit = 'M'; - } - sprintf(buf, "%6ld%cB", (long)size, unit); - return (buf); + size /= 2; + unit = 'K'; + if (size >= 10485760000LL) { + size /= 1073741824; + unit = 'T'; + } else if (size >= 10240000) { + size /= 1048576; + unit = 'G'; + } else if (size >= 10000) { + size /= 1024; + unit = 'M'; + } + sprintf(buf, "%6ld%cB", (long)size, unit); + return (buf); } /* * Print information about slices on a disk. For the size calculations we * assume a 512 byte sector. */ static int bd_printslice(struct open_disk *od, struct pc98_partition *dp, char *prefix, int verbose) { int cylsecs, start, size; char stats[80]; char line[80]; cylsecs = od->od_hds * od->od_sec; start = dp->dp_scyl * cylsecs + dp->dp_shd * od->od_sec + dp->dp_ssect; size = (dp->dp_ecyl - dp->dp_scyl + 1) * cylsecs; if (verbose) sprintf(stats, " %s (%d - %d)", display_size(size), start, start + size); else stats[0] = '\0'; switch(dp->dp_mid & PC98_MID_MASK) { case PC98_MID_386BSD: return (bd_printbsdslice(od, start, prefix, verbose)); case 0x00: /* unused partition */ return (0); case 0x01: sprintf(line, "%s: FAT-12%s\n", prefix, stats); break; case 0x11: case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: sprintf(line, "%s: FAT-16%s\n", prefix, stats); break; default: sprintf(line, "%s: Unknown fs: 0x%x %s\n", prefix, dp->dp_mid, stats); } return (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 int 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 (0); lp =(struct disklabel *)(&buf[0]); if (lp->d_magic != DISKMAGIC) { sprintf(line, "%s: FFS bad disklabel\n", prefix); return (pager_output(line)); } /* 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 %s (%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 ", display_size(lp->d_partitions[i].p_size), 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"); if (pager_output(line)) return (1); } } return (0); } /* * 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); BD(dev).bd_open++; if (BD(dev).bd_bcache == NULL) BD(dev).bd_bcache = bcache_allocate(); /* * 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 open_disk *od; int error; if (dev->dd.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->dd.d_unit; od->od_unit = bdinfo[od->od_dkunit].bd_unit; od->od_flags = bdinfo[od->od_dkunit].bd_flags; od->od_boff = 0; error = 0; DEBUG("open '%s', unit 0x%x slice %d partition %d", i386_fmtdev(dev), dev->dd.d_unit, dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition); /* Get geometry for this open (removable device may have changed) */ if (bd_getgeom(od)) { DEBUG("can't get geometry"); error = ENXIO; goto out; } /* Determine disk layout. */ error = bd_open_pc98(od, dev); out: if (error) { free(od); } else { *odp = od; /* return the open disk */ } return(error); } static int bd_open_pc98(struct open_disk *od, struct i386_devdesc *dev) { struct pc98_partition *dptr; struct disklabel *lp; int sector, slice, i; char buf[BUFSIZE]; /* * 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. */ od->od_nslices = 0; if (od->od_flags & BD_FLOPPY) { sector = 0; goto unsliced; } if (bd_read(od, 0, 1, buf)) { DEBUG("error reading MBR"); return (EIO); } /* * 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)"); return (ENOENT); } sector = 0; goto unsliced; /* may be a floppy */ } if (bd_read(od, 1, 1, buf)) { DEBUG("error reading MBR"); return (EIO); } /* * copy the partition table, then pick up any extended partitions. */ bcopy(buf + PC98_PARTOFF, &od->od_slicetab, sizeof(struct pc98_partition) * PC98_NPARTS); od->od_nslices = PC98_NPARTS; /* 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); return (ENOENT); } } /* 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) { return (ENOENT); } 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"); return (EIO); } 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"); return (ENOENT); } 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); return (EPART); } #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; } return (0); } /* * 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 .. PC98_NPARTS */ 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 & PC98_MID_MASK) { case PC98_MID_386BSD: /* FreeBSD */ if ((dp->dp_mid & PC98_MID_BOOTABLE) && (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 & PC98_MID_BOOTABLE) && (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 i386_devdesc *dev = f->f_devdata; struct open_disk *od = (struct open_disk *)(dev->d_kind.biosdisk.data); BD(dev).bd_open--; if (BD(dev).bd_open == 0) { bcache_free(BD(dev).bd_bcache); BD(dev).bd_bcache = NULL; } 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 i386_devdesc *dev = devdata; struct open_disk *od = (struct open_disk *)(dev->d_kind.biosdisk.data); bcd.dv_strategy = bd_realstrategy; bcd.dv_devdata = devdata; bcd.dv_cache = BD(dev).bd_bcache; return(bcache_strategy(&bcd, 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) +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); blks = size / BIOSDISK_SECSIZE; if (rsize) *rsize = 0; switch(rw){ case F_READ: DEBUG("read %d from %d to %p", blks, dblk, buf); 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 break; case F_WRITE : DEBUG("write %d from %d to %p", blks, dblk, buf); 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 break; default: /* DO NOTHING */ return (EROFS); } if (rsize) *rsize = size; return (0); } /* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ #define FLOPPY_BOUNCEBUF 18 static int bd_chs_io(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest, int write) { u_int x, bpc, cyl, hd, sec; bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ 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 */ v86.ctl = V86_FLAGS; v86.addr = 0x1b; if (write) v86.eax = 0x0500 | od->od_unit; else v86.eax = 0x0600 | od->od_unit; if (od->od_flags & BD_FLOPPY) { v86.eax |= 0xd000; v86.ecx = 0x0200 | (cyl & 0xff); v86.edx = (hd << 8) | (sec + 1); } else if (od->od_flags & BD_OPTICAL) { v86.eax &= 0xFF7F; v86.ecx = dblk & 0xFFFF; v86.edx = dblk >> 16; } else { v86.ecx = cyl; v86.edx = (hd << 8) | sec; } v86.ebx = blks * BIOSDISK_SECSIZE; v86.es = VTOPSEG(dest); v86.ebp = VTOPOFF(dest); v86int(); return (V86_CY(v86.efl)); } static int bd_io(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest, int write) { u_int x, sec, result, resid, retry, maxfer; caddr_t p, xp, bbuf, breg; /* Just in case some idiot actually tries to read/write -1 blocks... */ if (blks < 0) return (-1); 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) { /* * Play it safe and don't cross track boundaries. * (XXX this is probably unnecessary) */ sec = dblk % od->od_sec; /* offset into track */ 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; /* * Put your Data In, Put your Data out, * Put your Data In, and shake it all about */ if (write && 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 = 0x1b; v86.eax = 0x0300 | od->od_unit; v86int(); } result = bd_chs_io(od, dblk, x, xp, write); if (result == 0) break; } if (write) DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x, p, VTOP(p), dblk, result ? "failed" : "ok"); else DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x, dblk, p, VTOP(p), result ? "failed" : "ok"); if (result) { return(-1); } if (!write && 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_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) { return (bd_io(od, dblk, blks, dest, 0)); } static int bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) { return (bd_io(od, dblk, blks, dest, 1)); } 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_CY(v86.efl)) 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_CY(v86.efl)) 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->dd.d_unit); DEBUG("unit %d BIOS device %d", dev->dd.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->dd.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->dd.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, unit, dev->d_kind.biosdisk.partition); DEBUG("dev is 0x%x\n", rootdev); return(rootdev); }