1 /* $OpenBSD: ofdev.c,v 1.15 2008/05/25 16:55:31 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 <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; 60 char savec; 61 62 cp = strrchr(str, ':'); 63 if (cp == NULL) 64 return NULL; 65 66 savec = *cp; 67 *cp = 0; 68 strlcpy(namebuf, cp+1, sizeof namebuf); 69 return namebuf; 70 } 71 72 static int 73 strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 74 size_t *rsize) 75 { 76 struct of_dev *dev = devdata; 77 u_quad_t pos; 78 int n; 79 80 if (rw != F_READ) 81 return EPERM; 82 if (dev->type != OFDEV_DISK) 83 panic("strategy"); 84 85 pos = (u_quad_t)(blk + dev->partoff) * dev->bsize; 86 87 for (;;) { 88 if (OF_seek(dev->handle, pos) < 0) 89 break; 90 n = OF_read(dev->handle, buf, size); 91 if (n == -2) 92 continue; 93 if (n < 0) 94 break; 95 *rsize = n; 96 return 0; 97 } 98 return EIO; 99 } 100 101 static int 102 devclose(struct open_file *of) 103 { 104 struct of_dev *op = of->f_devdata; 105 106 if (op->type == OFDEV_NET) 107 net_close(op); 108 if (op->dmabuf) 109 OF_call_method("dma-free", op->handle, 2, 0, 110 op->dmabuf, MAXPHYS); 111 112 OF_close(op->handle); 113 op->handle = -1; 114 } 115 116 static struct devsw devsw[1] = { 117 "OpenFirmware", 118 strategy, 119 (int (*)(struct open_file *, ...))nodev, 120 devclose, 121 noioctl 122 }; 123 int ndevs = sizeof devsw / sizeof devsw[0]; 124 125 static struct fs_ops file_system_ufs = { 126 ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat 127 }; 128 static struct fs_ops file_system_cd9660 = { 129 cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek, 130 cd9660_stat 131 }; 132 static struct fs_ops file_system_hfs = { 133 hfs_open, hfs_close, hfs_read, hfs_write, hfs_seek, hfs_stat 134 }; 135 static struct fs_ops file_system_nfs = { 136 nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat 137 }; 138 139 struct fs_ops file_system[3]; 140 int nfsys; 141 142 static struct of_dev ofdev = { 143 -1, 144 }; 145 146 char opened_name[256]; 147 148 static u_long 149 get_long(p) 150 const void *p; 151 { 152 const unsigned char *cp = p; 153 154 return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24); 155 } 156 157 int 158 read_mac_label(struct of_dev *devp, char *buf, struct disklabel *lp) 159 { 160 struct part_map_entry *part; 161 size_t read; 162 int part_cnt; 163 int i; 164 char *s; 165 166 if ((strategy(devp, F_READ, 1, DEV_BSIZE, buf, &read) != 0) || 167 (read != DEV_BSIZE)) 168 return ERDLAB; 169 170 part = (struct part_map_entry *)buf; 171 172 /* if first partition is not valid, assume not HFS/DPME partitioned */ 173 if (part->pmSig != PART_ENTRY_MAGIC) 174 return ERDLAB; 175 176 part_cnt = part->pmMapBlkCnt; 177 178 /* first search for "OpenBSD" partition type 179 * standard bsd disklabel lives inside at offset 0 180 * otherwise, we should fake a bsd partition 181 * with first HFS partition starting at 'i' 182 * ? will this cause problems with booting bsd.rd from hfs 183 */ 184 for (i = 0; i < part_cnt; i++) { 185 /* read the appropriate block */ 186 if ((strategy(devp, F_READ, 1+i, DEV_BSIZE, buf, &read) != 0) 187 || (read != DEV_BSIZE)) 188 return ERDLAB; 189 190 part = (struct part_map_entry *)buf; 191 /* toupper the string, in case caps are different... */ 192 for (s = part->pmPartType; *s; s++) 193 if ((*s >= 'a') && (*s <= 'z')) 194 *s = (*s - 'a' + 'A'); 195 196 if (0 == strcmp(part->pmPartType, PART_TYPE_OPENBSD)) { 197 /* FOUND OUR PARTITION!!! */ 198 if(strategy(devp, F_READ, part->pmPyPartStart, 199 DEV_BSIZE, buf, &read) == 0 200 && read == DEV_BSIZE) 201 { 202 if (!getdisklabel(buf, lp)) 203 return 0; 204 205 /* If we have an OpenBSD region 206 * but no valid parition table, 207 * we cannot load a kernel from 208 * it, punt. 209 * should not have more than one 210 * OpenBSD of DPME type. 211 */ 212 return ERDLAB; 213 } 214 } 215 } 216 return ERDLAB; 217 } 218 219 /* 220 * Find a valid disklabel. 221 */ 222 static int 223 search_label(devp, off, buf, lp, off0) 224 struct of_dev *devp; 225 u_long off; 226 char *buf; 227 struct disklabel *lp; 228 u_long off0; 229 { 230 size_t read; 231 struct dos_partition *p; 232 int i; 233 u_long poff; 234 static int recursion; 235 236 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) || 237 read != DEV_BSIZE) 238 return ERDLAB; 239 240 if (buf[510] != 0x55 || buf[511] != 0xaa) 241 return ERDLAB; 242 243 if (recursion++ <= 1) 244 off0 += off; 245 for (p = (struct dos_partition *)(buf + DOSPARTOFF), i = 4; 246 --i >= 0; p++) { 247 if (p->dp_typ == DOSPTYP_OPENBSD) { 248 poff = get_long(&p->dp_start) + off0; 249 if (strategy(devp, F_READ, poff + LABELSECTOR, 250 DEV_BSIZE, buf, &read) == 0 251 && read == DEV_BSIZE) { 252 if (!getdisklabel(buf, lp)) { 253 recursion--; 254 return 0; 255 } 256 } 257 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 258 || read != DEV_BSIZE) { 259 recursion--; 260 return ERDLAB; 261 } 262 } else if (p->dp_typ == DOSPTYP_EXTEND) { 263 poff = get_long(&p->dp_start); 264 if (!search_label(devp, poff, buf, lp, off0)) { 265 recursion--; 266 return 0; 267 } 268 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 269 || read != DEV_BSIZE) { 270 recursion--; 271 return ERDLAB; 272 } 273 } 274 } 275 recursion--; 276 return ERDLAB; 277 } 278 279 int 280 devopen(struct open_file *of, const char *name, char **file) 281 { 282 char *cp; 283 char fname[256]; 284 char buf[DEV_BSIZE]; 285 struct disklabel label; 286 int handle, part; 287 size_t read; 288 int error = 0; 289 290 if (ofdev.handle != -1) 291 panic("devopen"); 292 if (of->f_flags != F_READ) 293 return EPERM; 294 295 strlcpy(fname, name, sizeof fname); 296 cp = filename(fname); 297 if (cp == NULL) 298 return ENOENT; 299 strlcpy(buf, cp, sizeof buf); 300 strlcpy(opened_name, fname, sizeof opened_name); 301 302 strlcat(opened_name, ":", sizeof opened_name); 303 if (*buf != '/') 304 strlcat(opened_name, "/", sizeof opened_name); 305 306 strlcat(opened_name, buf, sizeof opened_name); 307 *file = opened_name + strlen(fname) + 1; 308 309 if ((handle = OF_finddevice(fname)) == -1) 310 return ENOENT; 311 if (OF_getprop(handle, "name", buf, sizeof buf) < 0) 312 return ENXIO; 313 if (OF_getprop(handle, "device_type", buf, sizeof buf) < 0) 314 return ENXIO; 315 if (!strcmp(buf, "block")) 316 /* 317 * For block devices, indicate raw partition 318 * (:0 in OpenFirmware) 319 */ 320 strlcat(fname, ":0", sizeof fname); 321 if ((handle = OF_open(fname)) == -1) 322 return ENXIO; 323 bzero(&ofdev, sizeof ofdev); 324 ofdev.handle = handle; 325 ofdev.dmabuf = NULL; 326 OF_call_method("dma-alloc", handle, 1, 1, MAXPHYS, &ofdev.dmabuf); 327 if (!strcmp(buf, "block")) { 328 ofdev.type = OFDEV_DISK; 329 ofdev.bsize = DEV_BSIZE; 330 /* First try to find a disklabel without MBR partitions */ 331 if (strategy(&ofdev, F_READ, 332 LABELSECTOR, DEV_BSIZE, buf, &read) != 0 || 333 read != DEV_BSIZE || 334 getdisklabel(buf, &label)) { 335 /* Else try MBR partitions */ 336 error = read_mac_label(&ofdev, buf, &label); 337 if (error == ERDLAB) 338 error = search_label(&ofdev, 0, buf, &label, 0); 339 340 if (error && error != ERDLAB) 341 goto bad; 342 } 343 344 if (error == ERDLAB) { 345 /* No label, just use complete disk */ 346 ofdev.partoff = 0; 347 } else { 348 part = 0; /* how to pass this parameter */ 349 ofdev.partoff = label.d_partitions[part].p_offset; 350 } 351 352 of->f_dev = devsw; 353 of->f_devdata = &ofdev; 354 bcopy(&file_system_ufs, file_system, sizeof file_system[0]); 355 bcopy(&file_system_cd9660, file_system + 1, 356 sizeof file_system[0]); 357 bcopy(&file_system_hfs, file_system + 2, 358 sizeof file_system[0]); 359 nfsys = 3; 360 return 0; 361 } 362 if (!strcmp(buf, "network")) { 363 ofdev.type = OFDEV_NET; 364 of->f_dev = devsw; 365 of->f_devdata = &ofdev; 366 bcopy(&file_system_nfs, file_system, sizeof file_system[0]); 367 nfsys = 1; 368 if (error = net_open(&ofdev)) 369 goto bad; 370 return 0; 371 } 372 error = EFTYPE; 373 bad: 374 OF_close(handle); 375 ofdev.handle = -1; 376 return error; 377 } 378