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