1 /** $MirOS: src/sys/arch/i386/stand/libsa/biosdev.c,v 1.47 2012/12/23 19:19:48 tg Exp $ */
2 /* $OpenBSD: biosdev.c,v 1.74 2008/06/25 15:32:18 reyk Exp $ */
3
4 /*
5 * Copyright (c) 1996 Michael Shalayeff
6 * Copyright (c) 2003 Tobias Weingartner
7 * Copyright (c) 2002, 2003, 2004, 2005, 2008, 2009, 2012
8 * Thorsten "mirabilos" Glaser <tg@mirbsd.org>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34 #include <sys/param.h>
35 #include <sys/reboot.h>
36 #include <sys/disklabel.h>
37 #include <machine/tss.h>
38 #include <machine/biosvar.h>
39 #include <lib/libsa/saerrno.h>
40 #include <lib/libsa/ustar.h>
41 #include <isofs/cd9660/iso.h>
42 #include "disk.h"
43 #include "debug.h"
44 #include "libsa.h"
45 #include "biosdev.h"
46
47 const char *biosdisk_err(u_int);
48 int biosdisk_errno(u_int);
49
50 extern int biosdev_lbaprobe(int drive);
51 extern int biosdev_CHS(int ah, int dev, int cyl, int head, int sec, int nsec);
52 extern int biosdev_LBA(int ah, int dev, u_int blk_lo, u_int blk_hi, int nsec);
53
54 extern int debug;
55 int i386_flag_oldbios = 0;
56
57 /*
58 * reset disk system
59 */
60 int
biosdreset(int dev)61 biosdreset(int dev)
62 {
63 int rv;
64
65 __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
66 : "0" (0), "d" (dev) : "%ecx", "cc");
67
68 return ((rv & 0xff)? rv >> 8 : 0);
69 }
70
71 /*
72 * Fill out a bios_diskinfo_t for this device.
73 * Return 0 if all ok.
74 * Return 1 if not ok.
75 */
76 int
bios_getdiskinfo(int dev,bios_diskinfo_t * pdi)77 bios_getdiskinfo(int dev, bios_diskinfo_t *pdi)
78 {
79 u_int rv;
80 int lback;
81
82 /* kernel interface, binary compatibility */
83 pdi->old_bios_edd = -1;
84
85 pdi->flags &= ~(BDI_LBA | BDI_EL_TORITO);
86 lback = biosdev_lbaprobe(dev);
87
88 /* Just reset, don't check return code */
89 rv = biosdreset(dev);
90
91 if (lback & 0x10) {
92 pdi->bios_number = dev;
93 /* CD-ROM, we don’t care what the BIOS says for CHS or LBA */
94 pdi->bios_heads = 16;
95 pdi->bios_cylinders = 16;
96 pdi->bios_sectors = 32;
97 /* https://www.mirbsd.org/permalinks/news_e20090126-tg.htm */
98 pdi->flags |= BDI_LBA | BDI_EL_TORITO;
99 pdi->old_bios_edd = (lback | 9) & 7;
100 return (0);
101 }
102
103 #ifdef BIOS_DEBUG
104 if (debug)
105 printf("getinfo: try #8, 0x%x, %p\n", dev, pdi);
106 #endif
107 __asm __volatile (DOINT(0x13) "\n\t"
108 "setc %b0; movzbl %h1, %1\n\t"
109 "movzbl %%cl, %3; andb $0x3f, %b3\n\t"
110 "xchgb %%cl, %%ch; rolb $2, %%ch"
111 : "=a" (rv), "=d" (pdi->bios_heads),
112 "=c" (pdi->bios_cylinders),
113 "=b" (pdi->bios_sectors)
114 : "0" (0x0800), "1" (dev) : "cc");
115
116 #ifdef BIOS_DEBUG
117 if (debug) {
118 printf("getinfo: got #8\n");
119 printf("disk 0x%x: %d,%d,%d\n", dev, pdi->bios_cylinders,
120 pdi->bios_heads, pdi->bios_sectors);
121 }
122 #endif
123
124 if (rv & 0xFF) {
125 if ((lback & 0x09) != 0x09)
126 return (1);
127 printf("bios_getdiskinfo(%X): LBA but no CHS: %X\n", dev, lback);
128 pdi->bios_heads = 15;
129 pdi->bios_cylinders = 15;
130 pdi->bios_sectors = 63;
131 }
132
133 /* Fix up info */
134 pdi->bios_number = dev;
135 pdi->bios_heads++;
136 pdi->bios_cylinders &= 0x3ff;
137 pdi->bios_cylinders++;
138
139 if ((lback & 0x09) == 0x09) {
140 pdi->flags |= BDI_LBA;
141 pdi->old_bios_edd = lback & 7;
142 } else if (pdi->bios_cylinders < 2 || pdi->bios_heads < 2 ||
143 pdi->bios_sectors < 1) {
144 #ifdef BIOS_DEBUG
145 printf("sanity: c/h/s values insane: %d/%d/%d\n",
146 pdi->bios_cylinders, pdi->bios_heads, pdi->bios_sectors);
147 #endif
148 return (1);
149 }
150
151 return (0);
152 }
153
154 /*
155 * Read given sector, handling retry/errors/etc.
156 */
157 int
biosd_io(int rw,bios_diskinfo_t * bd,daddr_t off,int nsect,void * buf)158 biosd_io(int rw, bios_diskinfo_t *bd, daddr_t off, int nsect, void *buf)
159 {
160 int rv, n, ssh = 0, i, spre = 0;
161 volatile int c, h, s; /* fsck gcc, uninitialised it is not */
162
163 #ifndef SMALL_BOOT
164 /* we do all I/O in 512 byte sectors, the El Torito BIOS doesn't */
165 if (bd->flags & BDI_EL_TORITO) {
166 ssh = 2; /* sector shift */
167 /* read only part of a CD sector */
168 if (off & 3) {
169 spre = off & 3;
170 off -= spre;
171 nsect += spre;
172 }
173 /* odd nsect does not matter, we read CDs one by one */
174 }
175 #endif
176
177 loop:
178 n = (ssh || i386_flag_oldbios) ? 1 << ssh : MIN(nsect, 4096/512);
179 if (!(bd->flags & BDI_LBA)) {
180 /* note: BDI_EL_TORITO implies BDI_LBA, d/w about ssh here */
181 btochs(off, c, h, s, bd->bios_heads, bd->bios_sectors);
182 if (s + n >= bd->bios_sectors)
183 n = bd->bios_sectors - s;
184 }
185 if ((buf || spre) && rw != F_READ)
186 memmove(bounce_buf + spre * 512, buf ? buf : bounce_buf,
187 MIN(n - spre, nsect) * 512);
188 /* try operation up to 5 times */
189 rv = 1;
190 i = 5;
191 while (rv && i--) {
192 if (bd->flags & BDI_LBA) {
193 #if 0
194 printf(" trying biosdev_LBA(%X, %X, %d, %d, %d)",
195 rw == F_READ ? 0x42 : 0x43, bd->bios_number,
196 (int)((off >> ssh) & 0xFFFFFFFF),
197 (int)(sizeof (daddr_t) > 4 ?
198 (off >> ssh) >> 32 : 0), n >> ssh);
199 #endif
200 rv = biosdev_LBA(rw == F_READ ? 0x42 : 0x43,
201 bd->bios_number, (off >> ssh) & 0xFFFFFFFF,
202 sizeof (daddr_t) > 4 ? (off >> ssh) >> 32 : 0,
203 n >> ssh);
204 } else {
205 #if 0
206 printf(" trying biosdev_CHS(%X, %X, %d, %d, %d, %d)",
207 rw == F_READ ? 0x02 : 0x03, bd->bios_number,
208 c, h, s, n);
209 #endif
210 rv = biosdev_CHS(rw == F_READ ? 0x02 : 0x03,
211 bd->bios_number, c, h, s, n);
212 }
213 /* printf(" => %X\n", rv); */
214 switch (rv) {
215 case 0x11: /* ECC corrected */
216 rv = 0;
217 case 0x00: /* no errors */
218 break;
219 default: /* all other errors */
220 #ifdef BIOS_DEBUG
221 if (debug)
222 printf("\nBIOS error 0x%X (%s)\n",
223 rv, biosdisk_err(rv));
224 #endif
225 biosdreset(bd->bios_number);
226 break;
227 }
228 }
229 #ifdef BIOS_DEBUG
230 if (debug) {
231 if (rv != 0)
232 printf("=0x%x(%s)", rv, biosdisk_err(rv));
233 putchar('\n');
234 }
235 #endif
236 if (rv)
237 return (rv);
238 if ((buf || spre) && rw == F_READ)
239 memmove(buf ? buf : bounce_buf, bounce_buf + spre * 512,
240 MIN(n - spre, nsect) * 512);
241 if ((nsect -= n) <= 0)
242 return (0);
243 if (!buf) {
244 #ifndef SMALL_BOOT
245 printf("panic: cannot loop biosd_io on bounce_buf\n");
246 #endif
247 return (0);
248 }
249 buf += (n - spre) * 512;
250 off += n;
251 spre = 0;
252 goto loop;
253 }
254
255 /*
256 * Try to read the bsd label on the given BIOS device
257 */
258 const char *
bios_getdisklabel(bios_diskinfo_t * bd,struct disklabel * label)259 bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label)
260 {
261 daddr_t off = 0;
262 struct dos_mbr *mbr = (struct dos_mbr *)bounce_buf;
263 int error, i;
264 long mbrofs;
265
266 /* Sanity check */
267 if (bd->bios_heads == 0 || bd->bios_sectors == 0)
268 return ("failed to read disklabel");
269
270 /* MBR is a harddisk thing */
271 if (bd->bios_number & 0x80) {
272 /* Read MBR */
273 mbrofs = DOSBBSECTOR;
274 loop:
275 error = biosd_io(F_READ, bd, mbrofs, 1, NULL);
276 if (error)
277 return (biosdisk_err(error));
278
279 if (!memcmp((char *)mbr + offsetof(ustar_hdr_t, magic),
280 ustar_magic_version, sizeof(ustar_magic_version)))
281 return "found ustar magic\n";
282
283 /* check mbr signature */
284 if (mbr->dmbr_sign != DOSMBR_SIGNATURE)
285 return "bad MBR signature\n";
286
287 /* extend all start offsets by mbrofs */
288 for (i = 0; i < NDOSPART; i++)
289 mbr->dmbr_parts[i].dp_start += mbrofs;
290
291 /* Search for MirBSD partition */
292 if (i386_userpt) for (i = 0; off == 0 && i < NDOSPART; i++)
293 if (mbr->dmbr_parts[i].dp_typ == i386_userpt)
294 off = i + 1;
295 if (!off) for (i = 0; off == 0 && i < NDOSPART; i++)
296 if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_MIRBSD)
297 off = i + 1;
298
299 /* just in case */
300 if (!off) for (i = 0; off == 0 && i < NDOSPART; i++)
301 if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_OPENBSD)
302 off = i + 1;
303
304 /* just in case */
305 if (!off) for (i = 0; off == 0 && i < NDOSPART; i++)
306 if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_NETBSD)
307 off = i + 1;
308
309 /* just in case */
310 if (!off) {
311 for (i = 0; off == 0 && i < NDOSPART; i++)
312 if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_EXTEND) {
313 mbrofs = mbr->dmbr_parts[i].dp_start;
314 goto loop;
315 }
316 for (i = 0; off == 0 && i < NDOSPART; i++)
317 if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_EXTENDL) {
318 mbrofs = mbr->dmbr_parts[i].dp_start;
319 goto loop;
320 }
321 for (i = 0; off == 0 && i < NDOSPART; i++)
322 if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_EXTENDLX) {
323 mbrofs = mbr->dmbr_parts[i].dp_start;
324 goto loop;
325 }
326 }
327 }
328 if (off) {
329 off = mbr->dmbr_parts[off - 1].dp_start + LABELSECTOR;
330 } else
331 off = LABELSECTOR;
332
333 /* Load BSD disklabel */
334 #ifdef BIOS_DEBUG
335 if (debug)
336 printf("loading disklabel @ %u\n", off);
337 #endif
338 /* read disklabel */
339 error = biosd_io(F_READ, bd, off, 1, NULL);
340
341 if (error)
342 return ("failed to read disklabel");
343
344 /* Fill in disklabel */
345 return (getdisklabel(bounce_buf, label));
346 }
347
348 int
biosopen(struct open_file * f,...)349 biosopen(struct open_file *f, ...)
350 {
351 va_list ap;
352 register char *cp, **file;
353 dev_t unit, part;
354 struct diskinfo *dip;
355 int i;
356
357 va_start(ap, f);
358 file = va_arg(ap, char **);
359 va_end(ap);
360
361 if (file == NULL || (cp = *file) == NULL)
362 return (EINVAL);
363
364 #ifdef BIOS_DEBUG
365 if (debug)
366 printf("biosopen(%s)\n", cp);
367 #endif
368
369 f->f_devdata = NULL;
370
371 /* search for device specification */
372 while (*cp != ':' && *cp)
373 ++cp;
374 if (*cp == '\0' || cp - *file < 2) {
375 cp = *file;
376 goto nodevspec;
377 }
378
379 for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
380 if (!strncmp(*file, dip->name, cp - *file - 1))
381 break;
382 if (!dip) {
383 cp = *file;
384 goto nodevspec;
385 }
386
387 /* get partition */
388 unit = cp[-2] - '0';
389 part = cp[-1] - 'a';
390 ++cp;
391
392 bootdev_dip = dip;
393
394 /* Fix up bootdev */
395 { dev_t bsd_dev;
396 bsd_dev = dip->bios_info.bsd_dev;
397 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
398 B_CONTROLLER(bsd_dev), unit, part);
399 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
400 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
401 }
402
403 nodevspec:
404 if ((dip = bootdev_dip) == NULL)
405 if ((dip = bootdev_dip = start_dip) == NULL)
406 return (EADAPT);
407
408 #ifdef BIOS_DEBUG
409 if (debug) {
410 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%s\n",
411 dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
412 dip->bios_info.flags & BDI_LBA ? "on" : "off");
413 }
414 #endif
415
416 /* Try for disklabel again (might be removable media) */
417 if ((i = disk_trylabel(dip)))
418 return (i);
419
420 f->f_devdata = dip;
421
422 if (*cp != 0)
423 *file = cp;
424 else
425 f->f_flags |= F_RAW;
426
427 return 0;
428 }
429
430 const u_char bidos_errs[] =
431 #ifndef SMALL_BOOT
432 /* ignored "\x00" "successful completion\0" */
433 "\x01" "invalid function/parameter\0"
434 "\x02" "address mark not found\0"
435 "\x03" "write-protected\0"
436 "\x04" "sector not found\0"
437 "\x05" "reset failed\0"
438 "\x06" "disk changed\0"
439 "\x07" "drive parameter activity failed\0"
440 "\x08" "DMA overrun\0"
441 "\x09" "data boundary error\0"
442 "\x0A" "bad sector detected\0"
443 "\x0B" "bad track detected\0"
444 "\x0C" "invalid media\0"
445 "\x0E" "control data address mark detected\0"
446 "\x0F" "DMA arbitration level out of range\0"
447 "\x10" "uncorrectable CRC or ECC error on read\0"
448 /* ignored "\x11" "data ECC corrected\0" */
449 "\x20" "controller failure\0"
450 "\x31" "no media in drive\0"
451 "\x32" "incorrect drive type in CMOS\0"
452 "\x40" "seek failed\0"
453 "\x80" "operation timed out\0"
454 "\xAA" "drive not ready\0"
455 "\xB0" "volume not locked in drive\0"
456 "\xB1" "volume locked in drive\0"
457 "\xB2" "volume not removable\0"
458 "\xB3" "volume in use\0"
459 "\xB4" "lock count exceeded\0"
460 "\xB5" "valid eject request failed\0"
461 "\xBB" "undefined error\0"
462 "\xCC" "write fault\0"
463 "\xE0" "status register error\0"
464 "\xFF" "sense operation failed\0"
465 #endif
466 "\x00" "\0";
467
468 const char *
biosdisk_err(u_int error)469 biosdisk_err(u_int error)
470 {
471 register const u_char *p = bidos_errs;
472
473 while (*p && *p != error)
474 while (*p++);
475
476 return ++p;
477 }
478
479 const struct biosdisk_errors {
480 u_char error;
481 u_char errno;
482 } tab[] = {
483 { 0x01, EINVAL },
484 { 0x03, EROFS },
485 { 0x08, EINVAL },
486 { 0x09, EINVAL },
487 { 0x0A, EBSE },
488 { 0x0B, EBSE },
489 { 0x0C, ENXIO },
490 { 0x0D, EINVAL },
491 { 0x10, EECC },
492 { 0x20, EHER },
493 { 0x31, ENXIO },
494 { 0x32, ENXIO },
495 { 0x00, EIO }
496 };
497
498 int
biosdisk_errno(u_int error)499 biosdisk_errno(u_int error)
500 {
501 register const struct biosdisk_errors *p;
502
503 if (error == 0)
504 return 0;
505
506 for (p = tab; p->error && p->error != error; p++);
507
508 return p->errno;
509 }
510
511 int
biosstrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)512 biosstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
513 size_t *rsize)
514 {
515 struct diskinfo *dip = (struct diskinfo *)devdata;
516 bios_diskinfo_t *bd = &dip->bios_info;
517 u_int8_t error = 0;
518 size_t nsect;
519
520 nsect = (size + DEV_BSIZE-1) / DEV_BSIZE;
521 if (rsize != NULL)
522 blk += dip->disklabel.
523 d_partitions[B_PARTITION(dip->bsddev)].p_offset;
524
525 /* Read all, sub-functions handle track boundaries */
526 error = biosd_io(rw, bd, blk, nsect, buf);
527
528 #ifdef BIOS_DEBUG
529 if (debug) {
530 if (error != 0)
531 printf("=0x%x(%s)", error, biosdisk_err(error));
532 putchar('\n');
533 }
534 #endif
535
536 if (rsize != NULL)
537 *rsize = nsect * DEV_BSIZE;
538
539 return (biosdisk_errno(error));
540 }
541
542 int
biosclose(struct open_file * f)543 biosclose(struct open_file *f)
544 {
545 f->f_devdata = NULL;
546
547 return 0;
548 }
549
550 int
biosioctl(struct open_file * f,u_long cmd,void * data)551 biosioctl(struct open_file *f, u_long cmd, void *data)
552 {
553 return 0;
554 }
555
556 int
disk_trylabel(struct diskinfo * dip)557 disk_trylabel(struct diskinfo *dip)
558 {
559 const char *st = NULL;
560 bios_diskinfo_t *bd = &dip->bios_info;
561 struct dos_mbr *mbr = (struct dos_mbr *)bounce_buf;
562 int i, totsiz;
563
564 if (dip->bios_info.flags & BDI_GOODLABEL)
565 return (0);
566
567 if (dip->bios_info.flags & BDI_BADLABEL) {
568 st = bios_getdisklabel(&dip->bios_info, &dip->disklabel);
569 if (st == NULL)
570 dip->bios_info.flags &= ~BDI_BADLABEL;
571 }
572
573 if (dip->bios_info.flags & BDI_BADLABEL ||
574 !(dip->bios_info.flags & BDI_GOODLABEL)) {
575 #ifndef SMALL_BOOT
576 int maybe_sun = 0;
577
578 /* create an imaginary disk label */
579
580 st = "failed to read disklabel";
581 if (bd->bios_heads == 0 || bd->bios_sectors == 0)
582 goto out;
583
584 totsiz = 2880;
585
586 if (!(bd->bios_number & 0x80) || bd->flags & BDI_EL_TORITO ||
587 (bios_bootpte.active & 0x7F) /* || !bios_bootpte.partyp */)
588 bios_bootpte.partyp = 0;
589 if (bd->bios_number & 0x80) {
590 /* read MBR */
591 i = biosd_io(F_READ, bd, DOSBBSECTOR, 1, NULL);
592 if (i)
593 goto nombr;
594 if (!memcmp((char *)mbr + offsetof(ustar_hdr_t, magic),
595 ustar_magic_version, sizeof(ustar_magic_version)))
596 goto nombr;
597 if (mbr->dmbr_sign != DOSMBR_SIGNATURE)
598 goto nombr;
599 if (bounce_buf[0x1FC] == 0xDA &&
600 bounce_buf[0x1FD] == 0xBE) {
601 for (i = 0x080; i < 0x088; ++i)
602 if (bounce_buf[i])
603 break;
604 if (i == 0x088) {
605 maybe_sun = 1;
606 bios_bootpte.partyp = 0;
607 }
608 }
609 for (i = 0; i < NDOSPART; i++)
610 if (mbr->dmbr_parts[i].dp_typ &&
611 (mbr->dmbr_parts[i].dp_start +
612 mbr->dmbr_parts[i].dp_size > totsiz))
613 totsiz = mbr->dmbr_parts[i].dp_start +
614 mbr->dmbr_parts[i].dp_size;
615 goto mbrok;
616 }
617 nombr:
618 for (i = 0; i < NDOSPART; i++)
619 mbr->dmbr_parts[i].dp_typ = 0;
620 mbrok:
621
622 dip->disklabel.d_secsize = 512;
623 dip->disklabel.d_ntracks = bd->bios_heads;
624 dip->disklabel.d_nsectors = bd->bios_sectors;
625 dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks *
626 dip->disklabel.d_nsectors;
627 totsiz += dip->disklabel.d_secpercyl - 1;
628 dip->disklabel.d_ncylinders = totsiz /
629 dip->disklabel.d_secpercyl;
630 memcpy(dip->disklabel.d_typename, "FAKE", 5);
631 dip->disklabel.d_type = DTYPE_VND;
632 strncpy(dip->disklabel.d_packname, "fictitious",
633 sizeof (dip->disklabel.d_packname));
634 dip->disklabel.d_secperunit = dip->disklabel.d_ncylinders *
635 dip->disklabel.d_secpercyl;
636 totsiz = dip->disklabel.d_secperunit;
637 dip->disklabel.d_rpm = 3600;
638 dip->disklabel.d_interleave = 1;
639
640 dip->disklabel.d_bbsize = 8192;
641 dip->disklabel.d_sbsize = 65536;
642
643 bzero(dip->disklabel.d_partitions,
644 sizeof (dip->disklabel.d_partitions));
645
646 if (bios_bootpte.partyp &&
647 (bios_bootpte.p_ofs || bios_bootpte.p_siz)) {
648 /* 'a' partition passed from MBR/SYSLINUX */
649 dip->disklabel.d_partitions[0].p_offset = bios_bootpte.p_ofs;
650 dip->disklabel.d_partitions[0].p_size = bios_bootpte.p_siz;
651 dip->disklabel.d_partitions[0].p_fstype = FS_MANUAL;
652 } else {
653 /* 'a' partition covering the "whole" disk */
654 dip->disklabel.d_partitions[0].p_offset = 0;
655 dip->disklabel.d_partitions[0].p_size = totsiz;
656 dip->disklabel.d_partitions[0].p_fstype =
657 maybe_sun ? FS_MANUAL : FS_OTHER;
658 }
659
660 /* The raw partition is special */
661 dip->disklabel.d_partitions[RAW_PART].p_offset = 0;
662 dip->disklabel.d_partitions[RAW_PART].p_size = totsiz;
663 dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
664
665 for (i = 0; i < NDOSPART; i++) {
666 if (!mbr->dmbr_parts[i].dp_typ)
667 continue;
668 dip->disklabel.d_partitions[RAW_PART+i+1].p_offset =
669 mbr->dmbr_parts[i].dp_start;
670 dip->disklabel.d_partitions[RAW_PART+i+1].p_size =
671 mbr->dmbr_parts[i].dp_size;
672 dip->disklabel.d_partitions[RAW_PART+i+1].p_fstype =
673 FS_MANUAL;
674 if (dip->disklabel.d_partitions[0].p_fstype ==
675 FS_MANUAL)
676 continue;
677 /* a GUID Partition Table cannot become 'a' slice */
678 if (mbr->dmbr_parts[i].dp_typ == 0xEE)
679 continue;
680 /* 'a' partition covering the first partition */
681 dip->disklabel.d_partitions[0].p_offset =
682 mbr->dmbr_parts[i].dp_start;
683 dip->disklabel.d_partitions[0].p_size =
684 mbr->dmbr_parts[i].dp_size;
685 dip->disklabel.d_partitions[0].p_fstype = FS_MANUAL;
686 }
687 #else /* SMALL_BOOT */
688 /* check if ustar, if so fake a disklabel */
689
690 st = "failed to read disklabel";
691 if (bd->bios_heads == 0 || bd->bios_sectors == 0)
692 goto out;
693
694 totsiz = 2880;
695
696 i = biosd_io(F_READ, bd, DOSBBSECTOR, 1, NULL);
697 if (i)
698 goto out;
699 if (memcmp((char *)mbr + offsetof(ustar_hdr_t, magic),
700 ustar_magic_version, sizeof(ustar_magic_version)))
701 goto out;
702
703 dip->disklabel.d_secsize = 512;
704 dip->disklabel.d_ntracks = bd->bios_heads;
705 dip->disklabel.d_nsectors = bd->bios_sectors;
706 dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks *
707 dip->disklabel.d_nsectors;
708 totsiz += dip->disklabel.d_secpercyl - 1;
709 dip->disklabel.d_ncylinders = totsiz /
710 dip->disklabel.d_secpercyl;
711 memcpy(dip->disklabel.d_typename, "FAKE", 5);
712 dip->disklabel.d_type = DTYPE_VND;
713 strncpy(dip->disklabel.d_packname, "fictitious",
714 sizeof (dip->disklabel.d_packname));
715 dip->disklabel.d_secperunit = dip->disklabel.d_ncylinders *
716 dip->disklabel.d_secpercyl;
717 totsiz = dip->disklabel.d_secperunit;
718 dip->disklabel.d_rpm = 300;
719 dip->disklabel.d_interleave = 1;
720
721 dip->disklabel.d_bbsize = 8192;
722 dip->disklabel.d_sbsize = 65536;
723
724 bzero(dip->disklabel.d_partitions,
725 sizeof (dip->disklabel.d_partitions));
726
727 /* 'a' partition covering the "whole" disk */
728 dip->disklabel.d_partitions[0].p_offset = 0;
729 dip->disklabel.d_partitions[0].p_size = totsiz;
730 dip->disklabel.d_partitions[0].p_fstype = FS_MANUAL;
731
732 /* The raw partition is special */
733 dip->disklabel.d_partitions[RAW_PART].p_offset = 0;
734 dip->disklabel.d_partitions[RAW_PART].p_size = totsiz;
735 dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
736 #endif
737 dip->disklabel.d_npartitions = MAXPARTITIONS;
738
739 dip->disklabel.d_magic = DISKMAGIC;
740 dip->disklabel.d_magic2 = DISKMAGIC;
741 dip->disklabel.d_checksum = dkcksum(&dip->disklabel);
742
743 dip->bios_info.flags &= ~BDI_BADLABEL;
744 dip->bios_info.flags |= BDI_GOODLABEL;
745 st = NULL;
746 }
747 out:
748 if ((dip->bios_info.flags & BDI_BADLABEL) && st == NULL)
749 st = "*none*";
750 if (st != NULL) {
751 printf("%s\n", st);
752 return ERDLAB;
753 }
754
755 return (0);
756 }
757