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