Annotation of sys/arch/macppc/stand/ofdev.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ofdev.c,v 1.14 2007/06/14 03:27:16 drahn Exp $ */
! 2: /* $NetBSD: ofdev.c,v 1.1 1997/04/16 20:29:20 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1995, 1996 Wolfgang Solfrank.
! 6: * Copyright (C) 1995, 1996 TooLs GmbH.
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by TooLs GmbH.
! 20: * 4. The name of TooLs GmbH may not be used to endorse or promote products
! 21: * derived from this software without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 26: * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 27: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 33: */
! 34: /*
! 35: * Device I/O routines using Open Firmware
! 36: */
! 37: #include <sys/param.h>
! 38: #include <sys/disklabel.h>
! 39: #include <netinet/in.h>
! 40:
! 41: #include <lib/libsa/stand.h>
! 42: #include <lib/libsa/ufs.h>
! 43: #include <lib/libsa/cd9660.h>
! 44: #include <lib/libsa/nfs.h>
! 45: #include <hfs.h>
! 46:
! 47: #include <macppc/stand/ofdev.h>
! 48:
! 49: extern char bootdev[];
! 50:
! 51: /*
! 52: * this function is passed [device specifier]:[kernel]
! 53: * however a device specifier may contain a ':'
! 54: */
! 55: char namebuf[256];
! 56: static char *
! 57: filename(char *str)
! 58: {
! 59: char *cp, *lp;
! 60: char savec;
! 61: int dhandle;
! 62:
! 63: cp = strrchr(str, ':');
! 64: if (cp == NULL)
! 65: return NULL;
! 66:
! 67: savec = *cp;
! 68: *cp = 0;
! 69: strlcpy(namebuf, cp+1, sizeof namebuf);
! 70: return namebuf;
! 71: }
! 72:
! 73: static int
! 74: strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
! 75: size_t *rsize)
! 76: {
! 77: struct of_dev *dev = devdata;
! 78: u_quad_t pos;
! 79: int n;
! 80:
! 81: if (rw != F_READ)
! 82: return EPERM;
! 83: if (dev->type != OFDEV_DISK)
! 84: panic("strategy");
! 85:
! 86: pos = (u_quad_t)(blk + dev->partoff) * dev->bsize;
! 87:
! 88: for (;;) {
! 89: if (OF_seek(dev->handle, pos) < 0)
! 90: break;
! 91: n = OF_read(dev->handle, buf, size);
! 92: if (n == -2)
! 93: continue;
! 94: if (n < 0)
! 95: break;
! 96: *rsize = n;
! 97: return 0;
! 98: }
! 99: return EIO;
! 100: }
! 101:
! 102: static int
! 103: devclose(struct open_file *of)
! 104: {
! 105: struct of_dev *op = of->f_devdata;
! 106:
! 107: if (op->type == OFDEV_NET)
! 108: net_close(op);
! 109: if (op->dmabuf)
! 110: OF_call_method("dma-free", op->handle, 2, 0,
! 111: op->dmabuf, MAXPHYS);
! 112:
! 113: OF_close(op->handle);
! 114: op->handle = -1;
! 115: }
! 116:
! 117: static struct devsw devsw[1] = {
! 118: "OpenFirmware",
! 119: strategy,
! 120: (int (*)(struct open_file *, ...))nodev,
! 121: devclose,
! 122: noioctl
! 123: };
! 124: int ndevs = sizeof devsw / sizeof devsw[0];
! 125:
! 126: static struct fs_ops file_system_ufs = {
! 127: ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat
! 128: };
! 129: static struct fs_ops file_system_cd9660 = {
! 130: cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
! 131: cd9660_stat
! 132: };
! 133: static struct fs_ops file_system_hfs = {
! 134: hfs_open, hfs_close, hfs_read, hfs_write, hfs_seek, hfs_stat
! 135: };
! 136: static struct fs_ops file_system_nfs = {
! 137: nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat
! 138: };
! 139:
! 140: struct fs_ops file_system[3];
! 141: int nfsys;
! 142:
! 143: static struct of_dev ofdev = {
! 144: -1,
! 145: };
! 146:
! 147: char opened_name[256];
! 148:
! 149: static u_long
! 150: get_long(p)
! 151: const void *p;
! 152: {
! 153: const unsigned char *cp = p;
! 154:
! 155: return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24);
! 156: }
! 157:
! 158: int
! 159: read_mac_label(struct of_dev *devp, char *buf, struct disklabel *lp)
! 160: {
! 161: struct part_map_entry *part;
! 162: struct buf *bp;
! 163: int err;
! 164: size_t read;
! 165: int part_cnt;
! 166: int i;
! 167: char *s;
! 168:
! 169: if ((strategy(devp, F_READ, 1, DEV_BSIZE, buf, &read) != 0) ||
! 170: (read != DEV_BSIZE))
! 171: return ERDLAB;
! 172:
! 173: part = (struct part_map_entry *)buf;
! 174:
! 175: /* if first partition is not valid, assume not HFS/DPME partitioned */
! 176: if (part->pmSig != PART_ENTRY_MAGIC)
! 177: return ERDLAB;
! 178:
! 179: part_cnt = part->pmMapBlkCnt;
! 180:
! 181: /* first search for "OpenBSD" partition type
! 182: * standard bsd disklabel lives inside at offset 0
! 183: * otherwise, we should fake a bsd partition
! 184: * with first HFS partition starting at 'i'
! 185: * ? will this cause problems with booting bsd.rd from hfs
! 186: */
! 187: for (i = 0; i < part_cnt; i++) {
! 188: /* read the appropriate block */
! 189: if ((strategy(devp, F_READ, 1+i, DEV_BSIZE, buf, &read) != 0)
! 190: || (read != DEV_BSIZE))
! 191: return ERDLAB;
! 192:
! 193: part = (struct part_map_entry *)buf;
! 194: /* toupper the string, in case caps are different... */
! 195: for (s = part->pmPartType; *s; s++)
! 196: if ((*s >= 'a') && (*s <= 'z'))
! 197: *s = (*s - 'a' + 'A');
! 198:
! 199: if (0 == strcmp(part->pmPartType, PART_TYPE_OPENBSD)) {
! 200: /* FOUND OUR PARTITION!!! */
! 201: if(strategy(devp, F_READ, part->pmPyPartStart,
! 202: DEV_BSIZE, buf, &read) == 0
! 203: && read == DEV_BSIZE)
! 204: {
! 205: if (!getdisklabel(buf, lp))
! 206: return 0;
! 207:
! 208: /* If we have an OpenBSD region
! 209: * but no valid parition table,
! 210: * we cannot load a kernel from
! 211: * it, punt.
! 212: * should not have more than one
! 213: * OpenBSD of DPME type.
! 214: */
! 215: return ERDLAB;
! 216: }
! 217: }
! 218: }
! 219: return ERDLAB;
! 220: }
! 221:
! 222: /*
! 223: * Find a valid disklabel.
! 224: */
! 225: static int
! 226: search_label(devp, off, buf, lp, off0)
! 227: struct of_dev *devp;
! 228: u_long off;
! 229: char *buf;
! 230: struct disklabel *lp;
! 231: u_long off0;
! 232: {
! 233: size_t read;
! 234: struct dos_partition *p;
! 235: int i;
! 236: u_long poff;
! 237: static int recursion;
! 238:
! 239: if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) ||
! 240: read != DEV_BSIZE)
! 241: return ERDLAB;
! 242:
! 243: if (buf[510] != 0x55 || buf[511] != 0xaa)
! 244: return ERDLAB;
! 245:
! 246: if (recursion++ <= 1)
! 247: off0 += off;
! 248: for (p = (struct dos_partition *)(buf + DOSPARTOFF), i = 4;
! 249: --i >= 0; p++) {
! 250: if (p->dp_typ == DOSPTYP_OPENBSD) {
! 251: poff = get_long(&p->dp_start) + off0;
! 252: if (strategy(devp, F_READ, poff + LABELSECTOR,
! 253: DEV_BSIZE, buf, &read) == 0
! 254: && read == DEV_BSIZE) {
! 255: if (!getdisklabel(buf, lp)) {
! 256: recursion--;
! 257: return 0;
! 258: }
! 259: }
! 260: if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read)
! 261: || read != DEV_BSIZE) {
! 262: recursion--;
! 263: return ERDLAB;
! 264: }
! 265: } else if (p->dp_typ == DOSPTYP_EXTEND) {
! 266: poff = get_long(&p->dp_start);
! 267: if (!search_label(devp, poff, buf, lp, off0)) {
! 268: recursion--;
! 269: return 0;
! 270: }
! 271: if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read)
! 272: || read != DEV_BSIZE) {
! 273: recursion--;
! 274: return ERDLAB;
! 275: }
! 276: }
! 277: }
! 278: recursion--;
! 279: return ERDLAB;
! 280: }
! 281:
! 282: int
! 283: devopen(struct open_file *of, const char *name, char **file)
! 284: {
! 285: char *cp;
! 286: char fname[256];
! 287: char devname[256];
! 288: char buf[DEV_BSIZE];
! 289: struct disklabel label;
! 290: int handle, part;
! 291: size_t read;
! 292: int error = 0;
! 293:
! 294: if (ofdev.handle != -1)
! 295: panic("devopen");
! 296: if (of->f_flags != F_READ)
! 297: return EPERM;
! 298:
! 299: strlcpy(fname, name, sizeof fname);
! 300: cp = filename(fname);
! 301: if (cp == NULL)
! 302: return ENOENT;
! 303: strlcpy(buf, cp, sizeof buf);
! 304: strlcpy(opened_name, fname, sizeof opened_name);
! 305:
! 306: strlcat(opened_name, ":", sizeof opened_name);
! 307: if (*buf != '/')
! 308: strlcat(opened_name, "/", sizeof opened_name);
! 309:
! 310: strlcat(opened_name, buf, sizeof opened_name);
! 311: *file = opened_name + strlen(fname) + 1;
! 312:
! 313: if ((handle = OF_finddevice(fname)) == -1)
! 314: return ENOENT;
! 315: if (OF_getprop(handle, "name", buf, sizeof buf) < 0)
! 316: return ENXIO;
! 317: if (OF_getprop(handle, "device_type", buf, sizeof buf) < 0)
! 318: return ENXIO;
! 319: if (!strcmp(buf, "block"))
! 320: /*
! 321: * For block devices, indicate raw partition
! 322: * (:0 in OpenFirmware)
! 323: */
! 324: strlcat(fname, ":0", sizeof fname);
! 325: if ((handle = OF_open(fname)) == -1)
! 326: return ENXIO;
! 327: bzero(&ofdev, sizeof ofdev);
! 328: ofdev.handle = handle;
! 329: ofdev.dmabuf = NULL;
! 330: OF_call_method("dma-alloc", handle, 1, 1, MAXPHYS, &ofdev.dmabuf);
! 331: if (!strcmp(buf, "block")) {
! 332: ofdev.type = OFDEV_DISK;
! 333: ofdev.bsize = DEV_BSIZE;
! 334: /* First try to find a disklabel without MBR partitions */
! 335: if (strategy(&ofdev, F_READ,
! 336: LABELSECTOR, DEV_BSIZE, buf, &read) != 0 ||
! 337: read != DEV_BSIZE ||
! 338: getdisklabel(buf, &label)) {
! 339: /* Else try MBR partitions */
! 340: error = read_mac_label(&ofdev, buf, &label);
! 341: if (error == ERDLAB)
! 342: error = search_label(&ofdev, 0, buf, &label, 0);
! 343:
! 344: if (error && error != ERDLAB)
! 345: goto bad;
! 346: }
! 347:
! 348: if (error == ERDLAB) {
! 349: /* No label, just use complete disk */
! 350: ofdev.partoff = 0;
! 351: } else {
! 352: part = 0; /* how to pass this parameter */
! 353: ofdev.partoff = label.d_partitions[part].p_offset;
! 354: }
! 355:
! 356: of->f_dev = devsw;
! 357: of->f_devdata = &ofdev;
! 358: bcopy(&file_system_ufs, file_system, sizeof file_system[0]);
! 359: bcopy(&file_system_cd9660, file_system + 1,
! 360: sizeof file_system[0]);
! 361: bcopy(&file_system_hfs, file_system + 2,
! 362: sizeof file_system[0]);
! 363: nfsys = 3;
! 364: return 0;
! 365: }
! 366: if (!strcmp(buf, "network")) {
! 367: ofdev.type = OFDEV_NET;
! 368: of->f_dev = devsw;
! 369: of->f_devdata = &ofdev;
! 370: bcopy(&file_system_nfs, file_system, sizeof file_system[0]);
! 371: nfsys = 1;
! 372: if (error = net_open(&ofdev))
! 373: goto bad;
! 374: return 0;
! 375: }
! 376: error = EFTYPE;
! 377: bad:
! 378: OF_close(handle);
! 379: ofdev.handle = -1;
! 380: return error;
! 381: }
CVSweb