]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/disk.c
boot-122.tar.gz
[apple/boot.git] / i386 / libsaio / disk.c
1 /*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * All rights reserved. The CMU software License Agreement specifies
29 * the terms and conditions for use and redistribution.
30 */
31
32 /*
33 * INTEL CORPORATION PROPRIETARY INFORMATION
34 *
35 * This software is supplied under the terms of a license agreement or
36 * nondisclosure agreement with Intel Corporation and may not be copied
37 * nor disclosed except in accordance with the terms of that agreement.
38 *
39 * Copyright 1988, 1989 Intel Corporation
40 */
41
42 /*
43 * Copyright 1993 NeXT Computer, Inc.
44 * All rights reserved.
45 */
46
47 #include "bootstruct.h"
48 #include "libsaio.h"
49 #include "fdisk.h"
50 #include "ufs.h"
51 #include "hfs.h"
52 #include "ntfs.h"
53 #include "msdos.h"
54
55 #include <limits.h>
56 #include <IOKit/storage/IOApplePartitionScheme.h>
57
58 #define BPS 512 /* sector size of the device */
59 #define CD_BPS 2048 /* CD-ROM block size */
60 #define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */
61 #define UFS_FRONT_PORCH 0
62 #define kAPMSector 2 /* Sector number of Apple partition map */
63 #define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
64
65 /*
66 * trackbuf points to the start of the track cache. Biosread()
67 * will store the sectors read from disk to this memory area.
68 *
69 * biosbuf points to a sector within the track cache, and is
70 * updated by Biosread().
71 */
72 static char * const trackbuf = (char *) ptov(BIOS_ADDR);
73 static char * biosbuf;
74
75 /*
76 * Map a disk drive to bootable volumes contained within.
77 */
78 struct DiskBVMap {
79 int biosdev; // BIOS device number (unique)
80 BVRef bvr; // chain of boot volumes on the disk
81 int bvrcnt; // number of boot volumes
82 struct DiskBVMap * next; // linkage to next mapping
83 };
84
85 static struct DiskBVMap * gDiskBVMap = NULL;
86 static struct disk_blk0 * gBootSector = NULL;
87
88 extern void spinActivityIndicator();
89
90 static void getVolumeDescription(BVRef bvr, char * str, long strMaxLen);
91
92 //==========================================================================
93
94 static int getDriveInfo( int biosdev, struct driveInfo *dip )
95 {
96 static struct driveInfo cached_di;
97 int cc;
98
99 if ( !cached_di.valid || biosdev != cached_di.biosdev )
100 {
101 cc = get_drive_info(biosdev, &cached_di);
102 if (cc < 0) {
103 cached_di.valid = 0;
104 return (-1); // BIOS call error
105 }
106 }
107
108 bcopy(&cached_di, dip, sizeof(cached_di));
109
110 return 0;
111 }
112
113 //==========================================================================
114 // Maps (E)BIOS return codes to message strings.
115
116 struct NamedValue {
117 unsigned char value;
118 const char * name;
119 };
120
121 static const char * getNameForValue( const struct NamedValue * nameTable,
122 unsigned char value )
123 {
124 const struct NamedValue * np;
125
126 for ( np = nameTable; np->value; np++)
127 if (np->value == value)
128 return np->name;
129
130 return NULL;
131 }
132
133 #define ECC_CORRECTED_ERR 0x11
134
135 static const struct NamedValue bios_errors[] = {
136 { 0x10, "Media error" },
137 { 0x11, "Corrected ECC error" },
138 { 0x20, "Controller or device error" },
139 { 0x40, "Seek failed" },
140 { 0x80, "Device timeout" },
141 { 0xAA, "Drive not ready" },
142 { 0x00, 0 }
143 };
144
145 static const char * bios_error(int errnum)
146 {
147 static char errorstr[] = "Error 0x00";
148 const char * errname;
149
150 errname = getNameForValue( bios_errors, errnum );
151 if ( errname ) return errname;
152
153 sprintf(errorstr, "Error 0x%02x", errnum);
154 return errorstr; // No string, print error code only
155 }
156
157 //==========================================================================
158 // Use BIOS INT13 calls to read the sector specified. This function will
159 // also perform read-ahead to cache a few subsequent sector to the sector
160 // cache.
161 //
162 // Return:
163 // 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
164
165 static BOOL cache_valid = FALSE;
166
167 static int Biosread( int biosdev, unsigned int secno )
168 {
169 static int xbiosdev, xcyl, xhead;
170 static unsigned int xsec, xnsecs;
171 struct driveInfo di;
172
173 int rc = -1;
174 int cyl, head, sec;
175 int tries = 0;
176 int bps, divisor;
177
178 if (getDriveInfo(biosdev, &di) < 0) {
179 return -1;
180 }
181 if (di.no_emulation) {
182 /* Always assume 2k block size; BIOS may lie about geometry */
183 bps = 2048;
184 } else {
185 bps = di.di.params.phys_nbps;
186 if (bps == 0) {
187 return -1;
188 }
189 }
190 divisor = bps / BPS;
191
192 DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));
193
194 // To read the disk sectors, use EBIOS if we can. Otherwise,
195 // revert to the standard BIOS calls.
196
197 if ((biosdev >= kBIOSDevTypeHardDrive) &&
198 (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))
199 {
200 if (cache_valid &&
201 (biosdev == xbiosdev) &&
202 (secno >= xsec) &&
203 ((unsigned int)secno < (xsec + xnsecs)))
204 {
205 biosbuf = trackbuf + (BPS * (secno - xsec));
206 return 0;
207 }
208
209 xnsecs = N_CACHE_SECS;
210 xsec = (secno / divisor) * divisor;
211 cache_valid = FALSE;
212
213 while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))
214 {
215 if (rc == ECC_CORRECTED_ERR) {
216 /* Ignore corrected ECC errors */
217 rc = 0;
218 break;
219 }
220 error(" EBIOS read error: %s\n", bios_error(rc), rc);
221 error(" Block %d Sectors %d\n", secno, xnsecs);
222 sleep(1);
223 }
224 }
225 else
226 {
227 /* spc = spt * heads */
228 int spc = (di.di.params.phys_spt * di.di.params.phys_heads);
229 cyl = secno / spc;
230 head = (secno % spc) / di.di.params.phys_spt;
231 sec = secno % di.di.params.phys_spt;
232
233 if (cache_valid &&
234 (biosdev == xbiosdev) &&
235 (cyl == xcyl) &&
236 (head == xhead) &&
237 ((unsigned int)sec >= xsec) &&
238 ((unsigned int)sec < (xsec + xnsecs)))
239 {
240 // this sector is in trackbuf cache
241 biosbuf = trackbuf + (BPS * (sec - xsec));
242 return 0;
243 }
244
245 // Cache up to a track worth of sectors, but do not cross a
246 // track boundary.
247
248 xcyl = cyl;
249 xhead = head;
250 xsec = sec;
251 xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;
252 cache_valid = FALSE;
253
254 while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) &&
255 (++tries < 5))
256 {
257 if (rc == ECC_CORRECTED_ERR) {
258 /* Ignore corrected ECC errors */
259 rc = 0;
260 break;
261 }
262 error(" BIOS read error: %s\n", bios_error(rc), rc);
263 error(" Block %d, Cyl %d Head %d Sector %d\n",
264 secno, cyl, head, sec);
265 sleep(1);
266 }
267 }
268
269 // If the BIOS reported success, mark the sector cache as valid.
270
271 if (rc == 0) {
272 cache_valid = TRUE;
273 }
274 biosbuf = trackbuf + (secno % divisor) * BPS;
275 xbiosdev = biosdev;
276
277 spinActivityIndicator();
278
279 return rc;
280 }
281
282 //==========================================================================
283
284 static int readBytes( int biosdev, unsigned int blkno,
285 unsigned int byteCount, void * buffer )
286 {
287
288 char * cbuf = (char *) buffer;
289 int error;
290 int copy_len;
291
292 DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__,
293 biosdev, blkno, byteCount, (unsigned)cbuf));
294
295 for ( ; byteCount; cbuf += BPS, blkno++ )
296 {
297 error = Biosread( biosdev, blkno );
298 if ( error )
299 {
300 DEBUG_DISK(("error\n"));
301 return (-1);
302 }
303
304 copy_len = (byteCount > BPS) ? BPS : byteCount;
305 bcopy( biosbuf, cbuf, copy_len );
306 byteCount -= copy_len;
307 }
308
309 DEBUG_DISK(("done\n"));
310
311 return 0;
312 }
313
314 //==========================================================================
315
316 static int isExtendedFDiskPartition( const struct fdisk_part * part )
317 {
318 static unsigned char extParts[] =
319 {
320 0x05, /* Extended */
321 0x0f, /* Win95 extended */
322 0x85, /* Linux extended */
323 };
324
325 unsigned int i;
326
327 for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)
328 {
329 if (extParts[i] == part->systid) return 1;
330 }
331 return 0;
332 }
333
334 //==========================================================================
335
336 static int getNextFDiskPartition( int biosdev, int * partno,
337 const struct fdisk_part ** outPart )
338 {
339 static int sBiosdev = -1;
340 static int sNextPartNo;
341 static unsigned int sFirstBase;
342 static unsigned int sExtBase;
343 static unsigned int sExtDepth;
344 static struct fdisk_part * sExtPart;
345 struct fdisk_part * part;
346
347 if ( sBiosdev != biosdev || *partno < 0 )
348 {
349 // Fetch MBR.
350 if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0;
351
352 sBiosdev = biosdev;
353 sNextPartNo = 0;
354 sFirstBase = 0;
355 sExtBase = 0;
356 sExtDepth = 0;
357 sExtPart = NULL;
358 }
359
360 while (1)
361 {
362 part = NULL;
363
364 if ( sNextPartNo < FDISK_NPART )
365 {
366 part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];
367 }
368 else if ( sExtPart )
369 {
370 unsigned int blkno = sExtPart->relsect + sFirstBase;
371
372 // Save the block offset of the first extended partition.
373
374 if (sExtDepth == 0) {
375 sFirstBase = blkno;
376 }
377 sExtBase = blkno;
378
379 // Load extended partition table.
380
381 if ( readBootSector( biosdev, blkno, 0 ) == 0 )
382 {
383 sNextPartNo = 0;
384 sExtDepth++;
385 sExtPart = NULL;
386 continue;
387 }
388 // Fall through to part == NULL
389 }
390
391 if ( part == NULL ) break; // Reached end of partition chain.
392
393 // Advance to next partition number.
394
395 sNextPartNo++;
396
397 if ( isExtendedFDiskPartition(part) )
398 {
399 sExtPart = part;
400 continue;
401 }
402
403 // Skip empty slots.
404
405 if ( part->systid == 0x00 )
406 {
407 continue;
408 }
409
410 // Change relative offset to an absolute offset.
411 part->relsect += sExtBase;
412
413 *outPart = part;
414 *partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;
415
416 break;
417 }
418
419 return (part != NULL);
420 }
421
422 //==========================================================================
423
424 static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,
425 const struct fdisk_part * part,
426 FSInit initFunc, FSLoadFile loadFunc,
427 FSReadFile readFunc,
428 FSGetDirEntry getdirFunc,
429 FSGetFileBlock getBlockFunc,
430 BVGetDescription getDescriptionFunc,
431 int probe, int type )
432 {
433 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
434 if ( bvr )
435 {
436 bzero(bvr, sizeof(*bvr));
437
438 bvr->biosdev = biosdev;
439 bvr->part_no = partno;
440 bvr->part_boff = blkoff;
441 bvr->part_type = part->systid;
442 bvr->fs_loadfile = loadFunc;
443 bvr->fs_readfile = readFunc;
444 bvr->fs_getdirentry = getdirFunc;
445 bvr->fs_getfileblock= getBlockFunc;
446 bvr->description = getDescriptionFunc ?
447 getDescriptionFunc : getVolumeDescription;
448 bvr->type = type;
449
450 if ( part->bootid & FDISK_ACTIVE )
451 bvr->flags |= kBVFlagPrimary;
452
453 // Probe the filesystem.
454
455 if ( initFunc )
456 {
457 bvr->flags |= kBVFlagNativeBoot;
458
459 if ( probe && initFunc( bvr ) != 0 )
460 {
461 // filesystem probe failed.
462
463 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
464 __FUNCTION__, biosdev, partno));
465
466 free(bvr);
467 bvr = NULL;
468 }
469 }
470 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
471 {
472 bvr->flags |= kBVFlagForeignBoot;
473 }
474 else
475 {
476 free(bvr);
477 bvr = NULL;
478 }
479 }
480 return bvr;
481 }
482
483 //==========================================================================
484
485 BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,
486 const DPME * part,
487 FSInit initFunc, FSLoadFile loadFunc,
488 FSReadFile readFunc,
489 FSGetDirEntry getdirFunc,
490 FSGetFileBlock getBlockFunc,
491 BVGetDescription getDescriptionFunc,
492 int probe, int type )
493 {
494 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
495 if ( bvr )
496 {
497 bzero(bvr, sizeof(*bvr));
498
499 bvr->biosdev = biosdev;
500 bvr->part_no = partno;
501 bvr->part_boff = blkoff;
502 bvr->fs_loadfile = loadFunc;
503 bvr->fs_readfile = readFunc;
504 bvr->fs_getdirentry = getdirFunc;
505 bvr->fs_getfileblock= getBlockFunc;
506 bvr->description = getDescriptionFunc ?
507 getDescriptionFunc : getVolumeDescription;
508 bvr->type = type;
509 strlcpy(bvr->name, part->dpme_name, DPISTRLEN);
510 strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);
511
512 /*
513 if ( part->bootid & FDISK_ACTIVE )
514 bvr->flags |= kBVFlagPrimary;
515 */
516
517 // Probe the filesystem.
518
519 if ( initFunc )
520 {
521 bvr->flags |= kBVFlagNativeBoot;
522
523 if ( probe && initFunc( bvr ) != 0 )
524 {
525 // filesystem probe failed.
526
527 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
528 __FUNCTION__, biosdev, partno));
529
530 free(bvr);
531 bvr = NULL;
532 }
533 }
534 /*
535 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
536 {
537 bvr->flags |= kBVFlagForeignBoot;
538 }
539 */
540 else
541 {
542 free(bvr);
543 bvr = NULL;
544 }
545 }
546 return bvr;
547 }
548
549 //==========================================================================
550
551 /* A note on partition numbers:
552 * IOKit makes the primary partitions numbers 1-4, and then
553 * extended partitions are numbered consecutively 5 and up.
554 * So, for example, if you have two primary partitions and
555 * one extended partition they will be numbered 1, 2, 5.
556 */
557
558 static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
559 {
560 const struct fdisk_part * part;
561 struct DiskBVMap * map;
562 int partno = -1;
563 BVRef bvr;
564 BVRef booterUFS = NULL;
565 int spc;
566 struct driveInfo di;
567 boot_drive_info_t *dp;
568
569 /* Initialize disk info */
570 if (getDriveInfo(biosdev, &di) != 0) {
571 return NULL;
572 }
573 dp = &di.di;
574 spc = (dp->params.phys_spt * dp->params.phys_heads);
575 if (spc == 0) {
576 /* This is probably a CD-ROM; punt on the geometry. */
577 spc = 1;
578 }
579
580 do {
581 // Create a new mapping.
582
583 map = (struct DiskBVMap *) malloc( sizeof(*map) );
584 if ( map )
585 {
586 map->biosdev = biosdev;
587 map->bvr = NULL;
588 map->bvrcnt = 0;
589 map->next = gDiskBVMap;
590 gDiskBVMap = map;
591
592 // Create a record for each partition found on the disk.
593
594 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
595 {
596 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
597 partno, part->systid));
598 bvr = 0;
599
600 switch ( part->systid )
601 {
602 case FDISK_UFS:
603 bvr = newFDiskBVRef(
604 biosdev, partno,
605 part->relsect + UFS_FRONT_PORCH/BPS,
606 part,
607 UFSInitPartition,
608 UFSLoadFile,
609 UFSReadFile,
610 UFSGetDirEntry,
611 UFSGetFileBlock,
612 UFSGetDescription,
613 0,
614 kBIOSDevTypeHardDrive);
615 break;
616
617 case FDISK_HFS:
618 bvr = newFDiskBVRef(
619 biosdev, partno,
620 part->relsect,
621 part,
622 HFSInitPartition,
623 HFSLoadFile,
624 HFSReadFile,
625 HFSGetDirEntry,
626 HFSGetFileBlock,
627 HFSGetDescription,
628 0,
629 kBIOSDevTypeHardDrive);
630 break;
631
632 case FDISK_BOOTER:
633 booterUFS = newFDiskBVRef(
634 biosdev, partno,
635 ((part->relsect + spc - 1) / spc) * spc,
636 part,
637 UFSInitPartition,
638 UFSLoadFile,
639 UFSReadFile,
640 UFSGetDirEntry,
641 UFSGetFileBlock,
642 UFSGetDescription,
643 0,
644 kBIOSDevTypeHardDrive);
645 break;
646
647 case FDISK_NTFS:
648 bvr = newFDiskBVRef(
649 biosdev, partno,
650 part->relsect,
651 part,
652 0, 0, 0, 0, 0,
653 NTFSGetDescription,
654 0,
655 kBIOSDevTypeHardDrive);
656 break;
657
658 default:
659 bvr = newFDiskBVRef(
660 biosdev, partno,
661 part->relsect,
662 part,
663 0, 0, 0, 0, 0, 0, 0,
664 kBIOSDevTypeHardDrive);
665 break;
666 }
667
668 if ( bvr )
669 {
670 bvr->next = map->bvr;
671 map->bvr = bvr;
672 map->bvrcnt++;
673 }
674 }
675
676 // Booting from a CD with an UFS filesystem embedded
677 // in a booter partition.
678
679 if ( booterUFS )
680 {
681 if ( map->bvrcnt == 0 )
682 {
683 map->bvr = booterUFS;
684 map->bvrcnt++;
685 }
686 else free( booterUFS );
687 }
688 }
689 } while (0);
690
691 /*
692 * If no FDisk partition, then we will check for
693 * an Apple partition map elsewhere.
694 */
695 #if UNUSED
696 if (map->bvrcnt == 0) {
697 static struct fdisk_part cdpart;
698 cdpart.systid = 0xCD;
699
700 /* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
701 bvr = newFDiskBVRef(
702 biosdev, 0,
703 0,
704 &cdpart,
705 HFSInitPartition,
706 HFSLoadFile,
707 HFSReadFile,
708 HFSGetDirEntry,
709 HFSGetFileBlock,
710 0,
711 kBIOSDevTypeHardDrive);
712 bvr->next = map->bvr;
713 map->bvr = bvr;
714 map->bvrcnt++;
715 }
716 #endif
717
718 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
719
720 return map ? map->bvr : NULL;
721 }
722
723 //==========================================================================
724
725 static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
726 {
727 struct DiskBVMap * map;
728 struct Block0 *block0_p;
729 unsigned int blksize;
730 unsigned int factor;
731 void *buffer = malloc(BPS);
732
733 /* Check for alternate block size */
734 if (readBytes( biosdev, 0, BPS, buffer ) != 0) {
735 return NULL;
736 }
737 block0_p = buffer;
738 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
739 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
740 if (blksize != BPS) {
741 free(buffer);
742 buffer = malloc(blksize);
743 }
744 factor = blksize / BPS;
745 } else {
746 blksize = BPS;
747 factor = 1;
748 }
749
750 do {
751 // Create a new mapping.
752
753 map = (struct DiskBVMap *) malloc( sizeof(*map) );
754 if ( map )
755 {
756 int error;
757 DPME *dpme_p = (DPME *)buffer;
758 UInt32 i, npart = UINT_MAX;
759 BVRef bvr;
760
761 map->biosdev = biosdev;
762 map->bvr = NULL;
763 map->bvrcnt = 0;
764 map->next = gDiskBVMap;
765 gDiskBVMap = map;
766
767 for (i=0; i<npart; i++) {
768 error = readBytes( biosdev, (kAPMSector + i) * factor, blksize, buffer );
769
770 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
771 break;
772 }
773
774 if (i==0) {
775 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
776 }
777 /*
778 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
779 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
780 dpme.dpme_pblock_start, dpme.dpme_pblocks,
781 dpme.dpme_lblock_start, dpme.dpme_lblocks,
782 dpme.dpme_boot_block);
783 */
784
785 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
786 bvr = newAPMBVRef(biosdev,
787 i,
788 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
789 dpme_p,
790 HFSInitPartition,
791 HFSLoadFile,
792 HFSReadFile,
793 HFSGetDirEntry,
794 HFSGetFileBlock,
795 HFSGetDescription,
796 0,
797 kBIOSDevTypeHardDrive);
798 bvr->next = map->bvr;
799 map->bvr = bvr;
800 map->bvrcnt++;
801 }
802 }
803 }
804 } while (0);
805
806 free(buffer);
807
808 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
809
810 return map ? map->bvr : NULL;
811 }
812
813 //==========================================================================
814
815 BVRef diskScanBootVolumes( int biosdev, int * countPtr )
816 {
817 struct DiskBVMap * map;
818 BVRef bvr;
819 int count = 0;
820
821 // Find an existing mapping for this device.
822
823 for ( map = gDiskBVMap; map; map = map->next ) {
824 if ( biosdev == map->biosdev ) {
825 count = map->bvrcnt;
826 break;
827 }
828 }
829
830 if (map == NULL) {
831 bvr = diskScanFDiskBootVolumes(biosdev, &count);
832 if (bvr == NULL) {
833 bvr = diskScanAPMBootVolumes(biosdev, &count);
834 }
835 } else {
836 bvr = map->bvr;
837 }
838 if (countPtr) *countPtr = count;
839 return bvr;
840 }
841
842
843 //==========================================================================
844
845 static const struct NamedValue fdiskTypes[] =
846 {
847 { FDISK_NTFS, "Windows NTFS" },
848 { FDISK_FAT32, "Windows FAT32" },
849 { 0x83, "Linux" },
850 { FDISK_UFS, "Apple UFS" },
851 { FDISK_HFS, "Apple HFS" },
852 { FDISK_BOOTER, "Apple Boot/UFS" },
853 { 0xCD, "CD-ROM" },
854 { 0x00, 0 } /* must be last */
855 };
856
857 //==========================================================================
858
859 void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, BOOL verbose )
860 {
861 unsigned char type = (unsigned char) bvr->part_type;
862 const char * name = getNameForValue( fdiskTypes, type );
863 char *p;
864
865 if (name == NULL)
866 name = bvr->type_name;
867
868 p = str;
869 if ( name && verbose ) {
870 sprintf( str, "hd(%d,%d) ",
871 BIOS_DEV_UNIT(bvr), bvr->part_no);
872 for (; strMaxLen > 0 && *p != '\0'; p++, strMaxLen--);
873 } else {
874 *p = '\0';
875 }
876 bvr->description(bvr, p, strMaxLen);
877 if (*p == '\0') {
878 const char * name = getNameForValue( fdiskTypes, type );
879 if (name == NULL) {
880 name = bvr->type_name;
881 }
882 if (name == NULL) {
883 sprintf(p, "TYPE %02x", type);
884 } else {
885 strncpy(p, name, strMaxLen);
886 }
887 }
888 }
889
890 #if UNUSED
891 //==========================================================================
892
893 static int
894 getFAT32VolumeDescription( BVRef bvr, char *str, long strMaxLen)
895 {
896 struct fat32_header {
897 unsigned char code[3];
898 unsigned char oem_id[8];
899 unsigned char data[56];
900 unsigned long serial;
901 unsigned char label[11];
902 unsigned char fsid[8];
903 unsigned char reserved[420];
904 unsigned short signature;
905 } __attribute__((packed));
906
907 char *buf, *name;
908 struct fat32_header *fat32_p;
909 int label_len = sizeof(fat32_p->label);
910 int error;
911
912 buf = (char *)malloc(BPS);
913 name = (char *)malloc(label_len + 1);
914 fat32_p = (struct fat32_header *)buf;
915
916 diskSeek(bvr, 0ULL);
917 error = diskRead(bvr, (long)buf, BPS);
918 if ( error ) return 0;
919
920 if (fat32_p->signature != 0xaa55) return 0;
921
922 if (strMaxLen < label_len) label_len = strMaxLen;
923 strncpy(str, fat32_p->label, label_len);
924 str[label_len] = '\0';
925 return 1;
926 }
927 #endif
928
929 //==========================================================================
930
931 static void getVolumeDescription( BVRef bvr, char * str, long strMaxLen )
932 {
933 unsigned char type = (unsigned char) bvr->part_type;
934 const char * name = NULL;
935
936 /* First try a few types that we can figure out the
937 * volume description.
938 */
939 switch(type) {
940 case FDISK_FAT32:
941 str[0] = '\0';
942 MSDOSGetDescription(bvr, str, strMaxLen);
943 if (str[0] != '\0')
944 return;
945 break;
946
947 default: // Not one of our known types
948 break;
949 }
950
951 if (name == NULL)
952 name = getNameForValue( fdiskTypes, type );
953
954 if (name == NULL)
955 name = bvr->type_name;
956
957 if ( name )
958 strncpy( str, name, strMaxLen);
959 else
960 sprintf( str, "TYPE %02x", type);
961 }
962
963
964 //==========================================================================
965
966 int readBootSector( int biosdev, unsigned int secno, void * buffer )
967 {
968 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
969 int error;
970
971 if ( bootSector == NULL )
972 {
973 if ( gBootSector == NULL )
974 {
975 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
976 if ( gBootSector == NULL ) return -1;
977 }
978 bootSector = gBootSector;
979 }
980
981 error = readBytes( biosdev, secno, BPS, bootSector );
982 if ( error || bootSector->signature != DISK_SIGNATURE )
983 return -1;
984
985 return 0;
986 }
987
988 //==========================================================================
989 // Handle seek request from filesystem modules.
990
991 void diskSeek( BVRef bvr, long long position )
992 {
993 bvr->fs_boff = position / BPS;
994 }
995
996 //==========================================================================
997 // Handle read request from filesystem modules.
998
999 int diskRead( BVRef bvr, long addr, long length )
1000 {
1001 return readBytes( bvr->biosdev,
1002 bvr->fs_boff + bvr->part_boff,
1003 length,
1004 (void *) addr );
1005 }
1006
1007 int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1008 {
1009 int secs;
1010 unsigned char *cbuf = (unsigned char *)buffer;
1011 unsigned int copy_len;
1012 int rc;
1013
1014 if ((len & (BPS-1)) != 0) {
1015 error("raw disk read not sector aligned");
1016 return -1;
1017 }
1018 secno += bvr->part_boff;
1019
1020 cache_valid = FALSE;
1021
1022 while (len > 0) {
1023 secs = len / BPS;
1024 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1025 copy_len = secs * BPS;
1026
1027 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1028 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
1029 /* Ignore corrected ECC errors */
1030 if (rc != ECC_CORRECTED_ERR) {
1031 error(" EBIOS read error: %s\n", bios_error(rc), rc);
1032 error(" Block %d Sectors %d\n", secno, secs);
1033 return rc;
1034 }
1035 }
1036 bcopy( trackbuf, cbuf, copy_len );
1037 len -= copy_len;
1038 cbuf += copy_len;
1039 secno += secs;
1040 spinActivityIndicator();
1041 }
1042
1043 return 0;
1044 }
1045
1046 int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1047 {
1048 int secs;
1049 unsigned char *cbuf = (unsigned char *)buffer;
1050 unsigned int copy_len;
1051 int rc;
1052
1053 if ((len & (BPS-1)) != 0) {
1054 error("raw disk write not sector aligned");
1055 return -1;
1056 }
1057 secno += bvr->part_boff;
1058
1059 cache_valid = FALSE;
1060
1061 while (len > 0) {
1062 secs = len / BPS;
1063 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1064 copy_len = secs * BPS;
1065
1066 bcopy( cbuf, trackbuf, copy_len );
1067 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1068 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
1069 error(" EBIOS write error: %s\n", bios_error(rc), rc);
1070 error(" Block %d Sectors %d\n", secno, secs);
1071 return rc;
1072 }
1073 len -= copy_len;
1074 cbuf += copy_len;
1075 secno += secs;
1076 spinActivityIndicator();
1077 }
1078
1079 return 0;
1080 }
1081
1082 void turnOffFloppy(void)
1083 {
1084 /*
1085 * Disable floppy:
1086 * Hold controller in reset,
1087 * disable DMA and IRQ,
1088 * turn off floppy motors.
1089 */
1090 outb(0x3F2, 0x00);
1091 }