1 /* $OpenBSD: ofdev.c,v 1.18 2011/04/10 09:58:19 miod 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 <lib/libkern/libkern.h> 39 #include <sys/disklabel.h> 40 #include <netinet/in.h> 41 42 #include <lib/libsa/stand.h> 43 #include <lib/libsa/ufs.h> 44 #include <lib/libsa/cd9660.h> 45 #include <lib/libsa/nfs.h> 46 #include <hfs.h> 47 48 #include <macppc/stand/ofdev.h> 49 50 extern char bootdev[]; 51 52 /* 53 * this function is passed [device specifier]:[kernel] 54 * however a device specifier may contain a ':' 55 */ 56 char namebuf[256]; 57 static char * 58 filename(char *str) 59 { 60 char *cp; 61 char savec; 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, daddr32_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 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 size_t read; 163 int part_cnt; 164 int i; 165 char *s; 166 167 if ((strategy(devp, F_READ, 1, DEV_BSIZE, buf, &read) != 0) || 168 (read != DEV_BSIZE)) 169 return ERDLAB; 170 171 part = (struct part_map_entry *)buf; 172 173 /* if first partition is not valid, assume not HFS/DPME partitioned */ 174 if (part->pmSig != PART_ENTRY_MAGIC) 175 return ERDLAB; 176 177 part_cnt = part->pmMapBlkCnt; 178 179 /* first search for "OpenBSD" partition type 180 * standard bsd disklabel lives inside at offset 0 181 * otherwise, we should fake a bsd partition 182 * with first HFS partition starting at 'i' 183 * ? will this cause problems with booting bsd.rd from hfs 184 */ 185 for (i = 0; i < part_cnt; i++) { 186 /* read the appropriate block */ 187 if ((strategy(devp, F_READ, 1+i, DEV_BSIZE, buf, &read) != 0) 188 || (read != DEV_BSIZE)) 189 return ERDLAB; 190 191 part = (struct part_map_entry *)buf; 192 /* toupper the string, in case caps are different... */ 193 for (s = part->pmPartType; *s; s++) 194 if ((*s >= 'a') && (*s <= 'z')) 195 *s = (*s - 'a' + 'A'); 196 197 if (0 == strcmp(part->pmPartType, PART_TYPE_OPENBSD)) { 198 /* FOUND OUR PARTITION!!! */ 199 if(strategy(devp, F_READ, part->pmPyPartStart, 200 DEV_BSIZE, buf, &read) == 0 201 && read == DEV_BSIZE) 202 { 203 if (!getdisklabel(buf, lp)) 204 return 0; 205 206 /* If we have an OpenBSD region 207 * but no valid parition table, 208 * we cannot load a kernel from 209 * it, punt. 210 * should not have more than one 211 * OpenBSD of DPME type. 212 */ 213 return ERDLAB; 214 } 215 } 216 } 217 return ERDLAB; 218 } 219 220 /* 221 * Find a valid disklabel. 222 */ 223 static int 224 search_label(devp, off, buf, lp, off0) 225 struct of_dev *devp; 226 u_long off; 227 char *buf; 228 struct disklabel *lp; 229 u_long off0; 230 { 231 size_t read; 232 struct dos_partition *p; 233 int i; 234 u_long poff; 235 static int recursion; 236 237 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) || 238 read != DEV_BSIZE) 239 return ERDLAB; 240 241 if (buf[510] != 0x55 || buf[511] != 0xaa) 242 return ERDLAB; 243 244 if (recursion++ <= 1) 245 off0 += off; 246 for (p = (struct dos_partition *)(buf + DOSPARTOFF), i = 4; 247 --i >= 0; p++) { 248 if (p->dp_typ == DOSPTYP_OPENBSD) { 249 poff = get_long(&p->dp_start) + off0; 250 if (strategy(devp, F_READ, poff + LABELSECTOR, 251 DEV_BSIZE, buf, &read) == 0 252 && read == DEV_BSIZE) { 253 if (!getdisklabel(buf, lp)) { 254 recursion--; 255 return 0; 256 } 257 } 258 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 259 || read != DEV_BSIZE) { 260 recursion--; 261 return ERDLAB; 262 } 263 } else if (p->dp_typ == DOSPTYP_EXTEND) { 264 poff = get_long(&p->dp_start); 265 if (!search_label(devp, poff, buf, lp, off0)) { 266 recursion--; 267 return 0; 268 } 269 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 270 || read != DEV_BSIZE) { 271 recursion--; 272 return ERDLAB; 273 } 274 } 275 } 276 recursion--; 277 return ERDLAB; 278 } 279 280 int 281 devopen(struct open_file *of, const char *name, char **file) 282 { 283 char *cp; 284 char fname[256]; 285 char buf[DEV_BSIZE]; 286 struct disklabel label; 287 int handle, part; 288 size_t read; 289 int error = 0; 290 291 if (ofdev.handle != -1) 292 panic("devopen"); 293 if (of->f_flags != F_READ) 294 return EPERM; 295 296 strlcpy(fname, name, sizeof fname); 297 cp = filename(fname); 298 if (cp == NULL) 299 return ENOENT; 300 strlcpy(buf, cp, sizeof buf); 301 strlcpy(opened_name, fname, sizeof opened_name); 302 303 strlcat(opened_name, ":", sizeof opened_name); 304 if (*buf != '/') 305 strlcat(opened_name, "/", sizeof opened_name); 306 307 strlcat(opened_name, buf, sizeof opened_name); 308 *file = opened_name + strlen(fname) + 1; 309 310 if ((handle = OF_finddevice(fname)) == -1) 311 return ENOENT; 312 if (OF_getprop(handle, "name", buf, sizeof buf) < 0) 313 return ENXIO; 314 if (OF_getprop(handle, "device_type", buf, sizeof buf) < 0) 315 return ENXIO; 316 if (!strcmp(buf, "block")) 317 /* 318 * For block devices, indicate raw partition 319 * (:0 in OpenFirmware) 320 */ 321 strlcat(fname, ":0", sizeof fname); 322 if ((handle = OF_open(fname)) == -1) 323 return ENXIO; 324 bzero(&ofdev, sizeof ofdev); 325 ofdev.handle = handle; 326 ofdev.dmabuf = NULL; 327 OF_call_method("dma-alloc", handle, 1, 1, MAXPHYS, &ofdev.dmabuf); 328 if (!strcmp(buf, "block")) { 329 ofdev.type = OFDEV_DISK; 330 ofdev.bsize = DEV_BSIZE; 331 /* First try to find a disklabel without MBR partitions */ 332 if (strategy(&ofdev, F_READ, 333 LABELSECTOR, DEV_BSIZE, buf, &read) != 0 || 334 read != DEV_BSIZE || 335 getdisklabel(buf, &label)) { 336 /* Else try MBR partitions */ 337 error = read_mac_label(&ofdev, buf, &label); 338 if (error == ERDLAB) 339 error = search_label(&ofdev, 0, buf, &label, 0); 340 341 if (error && error != ERDLAB) 342 goto bad; 343 } 344 345 if (error == ERDLAB) { 346 /* No label, just use complete disk */ 347 ofdev.partoff = 0; 348 } else { 349 part = 0; /* how to pass this parameter */ 350 ofdev.partoff = label.d_partitions[part].p_offset; 351 } 352 353 of->f_dev = devsw; 354 of->f_devdata = &ofdev; 355 bcopy(&file_system_ufs, file_system, sizeof file_system[0]); 356 bcopy(&file_system_cd9660, file_system + 1, 357 sizeof file_system[0]); 358 bcopy(&file_system_hfs, file_system + 2, 359 sizeof file_system[0]); 360 nfsys = 3; 361 return 0; 362 } 363 if (!strcmp(buf, "network")) { 364 ofdev.type = OFDEV_NET; 365 of->f_dev = devsw; 366 of->f_devdata = &ofdev; 367 bcopy(&file_system_nfs, file_system, sizeof file_system[0]); 368 nfsys = 1; 369 if (error = net_open(&ofdev)) 370 goto bad; 371 return 0; 372 } 373 error = EFTYPE; 374 bad: 375 OF_close(handle); 376 ofdev.handle = -1; 377 return error; 378 } 379