]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/disk.c
84a8a61fd7cc74652bc8028a4db5e360e45496f6
[apple/boot.git] / i386 / libsaio / disk.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 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 1.1 (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
53 #include <limits.h>
54 #include <IOKit/storage/IOApplePartitionScheme.h>
55
56 #define BPS 512 /* sector size of the device */
57 #define CD_BPS 2048 /* CD-ROM block size */
58 #define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */
59 #define UFS_FRONT_PORCH 0
60 #define kAPMSector 2 /* Sector number of Apple partition map */
61 #define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
62
63 /*
64 * trackbuf points to the start of the track cache. Biosread()
65 * will store the sectors read from disk to this memory area.
66 *
67 * biosbuf points to a sector within the track cache, and is
68 * updated by Biosread().
69 */
70 static const char * const trackbuf = (char *) ptov(BIOS_ADDR);
71 static const char * biosbuf;
72
73 /*
74 * Map a disk drive to bootable volumes contained within.
75 */
76 struct DiskBVMap {
77 int biosdev; // BIOS device number (unique)
78 BVRef bvr; // chain of boot volumes on the disk
79 int bvrcnt; // number of boot volumes
80 struct DiskBVMap * next; // linkage to next mapping
81 };
82
83 static struct DiskBVMap * gDiskBVMap = NULL;
84 static struct disk_blk0 * gBootSector = NULL;
85
86 extern void spinActivityIndicator();
87
88 static void getVolumeDescription(BVRef bvr, char * str, long strMaxLen);
89
90 //==========================================================================
91
92 static int getDriveInfo( int biosdev, struct driveInfo *dip )
93 {
94 static struct driveInfo cached_di;
95 int cc;
96
97 if ( !cached_di.valid || biosdev != cached_di.biosdev )
98 {
99 cc = get_drive_info(biosdev, &cached_di);
100 if (cc < 0) {
101 cached_di.valid = 0;
102 return (-1); // BIOS call error
103 }
104 }
105
106 bcopy(&cached_di, dip, sizeof(cached_di));
107
108 return 0;
109 }
110
111 //==========================================================================
112 // Maps (E)BIOS return codes to message strings.
113
114 struct NamedValue {
115 unsigned char value;
116 const char * name;
117 };
118
119 static const char * getNameForValue( const struct NamedValue * nameTable,
120 unsigned char value )
121 {
122 const struct NamedValue * np;
123
124 for ( np = nameTable; np->value; np++)
125 if (np->value == value)
126 return np->name;
127
128 return NULL;
129 }
130
131 #define ECC_CORRECTED_ERR 0x11
132
133 static const struct NamedValue bios_errors[] = {
134 { 0x10, "Media error" },
135 { 0x11, "Corrected ECC error" },
136 { 0x20, "Controller or device error" },
137 { 0x40, "Seek failed" },
138 { 0x80, "Device timeout" },
139 { 0xAA, "Drive not ready" },
140 { 0x00, 0 }
141 };
142
143 static const char * bios_error(int errnum)
144 {
145 static char errorstr[] = "Error 0x00";
146 const char * errname;
147
148 errname = getNameForValue( bios_errors, errnum );
149 if ( errname ) return errname;
150
151 sprintf(errorstr, "Error 0x%02x", errnum);
152 return errorstr; // No string, print error code only
153 }
154
155 //==========================================================================
156 // Use BIOS INT13 calls to read the sector specified. This function will
157 // also perform read-ahead to cache a few subsequent sector to the sector
158 // cache.
159 //
160 // Return:
161 // 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
162
163 static int Biosread( int biosdev, unsigned int secno )
164 {
165 static int xbiosdev, xcyl, xhead;
166 static unsigned int xsec, xnsecs;
167 static BOOL cache_valid = FALSE;
168 struct driveInfo di;
169
170 int rc = -1;
171 int cyl, head, sec;
172 int tries = 0;
173 int bps, divisor;
174
175 if (getDriveInfo(biosdev, &di) < 0) {
176 return -1;
177 }
178 if (di.no_emulation) {
179 /* Always assume 2k block size; BIOS may lie about geometry */
180 bps = 2048;
181 } else {
182 bps = di.di.params.phys_nbps;
183 }
184 divisor = bps / BPS;
185
186 DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));
187
188 // To read the disk sectors, use EBIOS if we can. Otherwise,
189 // revert to the standard BIOS calls.
190
191 if ((biosdev >= kBIOSDevTypeHardDrive) &&
192 (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))
193 {
194 if (cache_valid &&
195 (biosdev == xbiosdev) &&
196 (secno >= xsec) &&
197 ((unsigned int)secno < (xsec + xnsecs)))
198 {
199 biosbuf = trackbuf + (BPS * (secno - xsec));
200 return 0;
201 }
202
203 xnsecs = N_CACHE_SECS;
204 xsec = (secno / divisor) * divisor;
205 cache_valid = FALSE;
206
207 while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))
208 {
209 if (rc == ECC_CORRECTED_ERR) {
210 /* Ignore corrected ECC errors */
211 rc = 0;
212 break;
213 }
214 error(" EBIOS read error: %s\n", bios_error(rc), rc);
215 error(" Block %d Sectors %d\n", secno, xnsecs);
216 sleep(1);
217 }
218 }
219 else
220 {
221 /* spc = spt * heads */
222 int spc = (di.di.params.phys_spt * di.di.params.phys_heads);
223 cyl = secno / spc;
224 head = (secno % spc) / di.di.params.phys_spt;
225 sec = secno % di.di.params.phys_spt;
226
227 if (cache_valid &&
228 (biosdev == xbiosdev) &&
229 (cyl == xcyl) &&
230 (head == xhead) &&
231 ((unsigned int)sec >= xsec) &&
232 ((unsigned int)sec < (xsec + xnsecs)))
233 {
234 // this sector is in trackbuf cache
235 biosbuf = trackbuf + (BPS * (sec - xsec));
236 return 0;
237 }
238
239 // Cache up to a track worth of sectors, but do not cross a
240 // track boundary.
241
242 xcyl = cyl;
243 xhead = head;
244 xsec = sec;
245 xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;
246 cache_valid = FALSE;
247
248 while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) &&
249 (++tries < 5))
250 {
251 if (rc == ECC_CORRECTED_ERR) {
252 /* Ignore corrected ECC errors */
253 rc = 0;
254 break;
255 }
256 error(" BIOS read error: %s\n", bios_error(rc), rc);
257 error(" Block %d, Cyl %d Head %d Sector %d\n",
258 secno, cyl, head, sec);
259 sleep(1);
260 }
261 }
262
263 // If the BIOS reported success, mark the sector cache as valid.
264
265 if (rc == 0) {
266 cache_valid = TRUE;
267 }
268 biosbuf = trackbuf + (secno % divisor) * BPS;
269 xbiosdev = biosdev;
270
271 spinActivityIndicator();
272
273 return rc;
274 }
275
276 //==========================================================================
277
278 static int readBytes( int biosdev, unsigned int blkno,
279 unsigned int byteCount, void * buffer )
280 {
281
282 char * cbuf = (char *) buffer;
283 int error;
284 int copy_len;
285
286 DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__,
287 biosdev, blkno, byteCount, (unsigned)cbuf));
288
289 for ( ; byteCount; cbuf += BPS, blkno++ )
290 {
291 error = Biosread( biosdev, blkno );
292 if ( error )
293 {
294 DEBUG_DISK(("error\n"));
295 return (-1);
296 }
297
298 copy_len = (byteCount > BPS) ? BPS : byteCount;
299 bcopy( biosbuf, cbuf, copy_len );
300 byteCount -= copy_len;
301 }
302
303 DEBUG_DISK(("done\n"));
304
305 return 0;
306 }
307
308 //==========================================================================
309
310 static int isExtendedFDiskPartition( const struct fdisk_part * part )
311 {
312 static unsigned char extParts[] =
313 {
314 0x05, /* Extended */
315 0x0f, /* Win95 extended */
316 0x85, /* Linux extended */
317 };
318
319 unsigned int i;
320
321 for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)
322 {
323 if (extParts[i] == part->systid) return 1;
324 }
325 return 0;
326 }
327
328 //==========================================================================
329
330 static int getNextFDiskPartition( int biosdev, int * partno,
331 const struct fdisk_part ** outPart )
332 {
333 static int sBiosdev = -1;
334 static int sNextPartNo;
335 static unsigned int sExtBase;
336 static unsigned int sExtDepth;
337 static struct fdisk_part * sExtPart;
338 struct fdisk_part * part;
339
340 if ( sBiosdev != biosdev || *partno < 0 )
341 {
342 // Fetch MBR.
343 if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0;
344
345 sBiosdev = biosdev;
346 sNextPartNo = 0;
347 sExtBase = 0;
348 sExtDepth = 0;
349 sExtPart = NULL;
350 }
351
352 while (1)
353 {
354 part = NULL;
355
356 if ( sNextPartNo < FDISK_NPART )
357 {
358 part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];
359 }
360 else if ( sExtPart )
361 {
362 unsigned int blkno = sExtPart->relsect + sExtBase;
363
364 // Save the block offset of the first extended partition.
365
366 if ( sExtDepth == 0 ) sExtBase = sExtPart->relsect;
367
368 // Load extended partition table.
369
370 if ( readBootSector( biosdev, blkno, 0 ) == 0 )
371 {
372 sNextPartNo = 0;
373 sExtDepth++;
374 sExtPart = NULL;
375 continue;
376 }
377 }
378
379 if ( part == NULL ) break; // Reached end of partition chain.
380
381 // Advance to next partition number.
382
383 sNextPartNo++;
384
385 // Assume at most one extended partition per table.
386
387 if ( isExtendedFDiskPartition(part) )
388 {
389 sExtPart = part;
390 continue;
391 }
392
393 // Skip empty slots.
394
395 if ( part->systid == 0x00 )
396 {
397 continue;
398 }
399
400 // Change relative offset to an absolute offset.
401
402 part->relsect += sExtBase;
403
404 *outPart = part;
405 *partno = sExtDepth ? (int)(sExtDepth + 4) : sNextPartNo;
406
407 break;
408 }
409
410 return (part != NULL);
411 }
412
413 //==========================================================================
414
415 static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,
416 const struct fdisk_part * part,
417 FSInit initFunc, FSLoadFile loadFunc,
418 FSGetDirEntry getdirFunc, int probe, int type )
419 {
420 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
421 if ( bvr )
422 {
423 bzero(bvr, sizeof(*bvr));
424
425 bvr->biosdev = biosdev;
426 bvr->part_no = partno;
427 bvr->part_boff = blkoff;
428 bvr->part_type = part->systid;
429 bvr->fs_loadfile = loadFunc;
430 bvr->fs_getdirentry = getdirFunc;
431 bvr->description = getVolumeDescription;
432 bvr->type = type;
433
434 if ( part->bootid & FDISK_ACTIVE )
435 bvr->flags |= kBVFlagPrimary;
436
437 // Probe the filesystem.
438
439 if ( initFunc )
440 {
441 bvr->flags |= kBVFlagNativeBoot;
442
443 if ( probe && initFunc( bvr ) != 0 )
444 {
445 // filesystem probe failed.
446
447 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
448 __FUNCTION__, biosdev, partno));
449
450 free(bvr);
451 bvr = NULL;
452 }
453 }
454 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
455 {
456 bvr->flags |= kBVFlagForeignBoot;
457 }
458 else
459 {
460 free(bvr);
461 bvr = NULL;
462 }
463 }
464 return bvr;
465 }
466
467 //==========================================================================
468
469 BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,
470 const DPME * part,
471 FSInit initFunc, FSLoadFile loadFunc,
472 FSGetDirEntry getdirFunc, int probe, int type )
473 {
474 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
475 if ( bvr )
476 {
477 bzero(bvr, sizeof(*bvr));
478
479 bvr->biosdev = biosdev;
480 bvr->part_no = partno;
481 bvr->part_boff = blkoff;
482 bvr->fs_loadfile = loadFunc;
483 bvr->fs_getdirentry = getdirFunc;
484 bvr->description = getVolumeDescription;
485 bvr->type = type;
486 strlcpy(bvr->name, part->dpme_name, DPISTRLEN);
487 strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);
488
489 /*
490 if ( part->bootid & FDISK_ACTIVE )
491 bvr->flags |= kBVFlagPrimary;
492 */
493
494 // Probe the filesystem.
495
496 if ( initFunc )
497 {
498 bvr->flags |= kBVFlagNativeBoot;
499
500 if ( probe && initFunc( bvr ) != 0 )
501 {
502 // filesystem probe failed.
503
504 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
505 __FUNCTION__, biosdev, partno));
506
507 free(bvr);
508 bvr = NULL;
509 }
510 }
511 /*
512 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
513 {
514 bvr->flags |= kBVFlagForeignBoot;
515 }
516 */
517 else
518 {
519 free(bvr);
520 bvr = NULL;
521 }
522 }
523 return bvr;
524 }
525
526 //==========================================================================
527
528 static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
529 {
530 const struct fdisk_part * part;
531 struct DiskBVMap * map;
532 int partno = -1;
533 BVRef bvr;
534 BVRef booterUFS = NULL;
535 int spc;
536 struct driveInfo di;
537 boot_drive_info_t *dp;
538
539 /* Initialize disk info */
540 if (getDriveInfo(biosdev, &di) != 0) {
541 return NULL;
542 }
543 dp = &di.di;
544 spc = (dp->params.phys_spt * dp->params.phys_heads);
545 if (spc == 0) {
546 /* This is probably a CD-ROM; punt on the geometry. */
547 spc = 1;
548 }
549
550 do {
551 // Create a new mapping.
552
553 map = (struct DiskBVMap *) malloc( sizeof(*map) );
554 if ( map )
555 {
556 map->biosdev = biosdev;
557 map->bvr = NULL;
558 map->bvrcnt = 0;
559 map->next = gDiskBVMap;
560 gDiskBVMap = map;
561
562 // Create a record for each partition found on the disk.
563
564 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
565 {
566 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
567 partno, part->systid));
568 bvr = 0;
569
570 switch ( part->systid )
571 {
572 case FDISK_UFS:
573 bvr = newFDiskBVRef(
574 biosdev, partno,
575 part->relsect + UFS_FRONT_PORCH/BPS,
576 part,
577 UFSInitPartition,
578 UFSLoadFile,
579 UFSGetDirEntry,
580 0,
581 kBIOSDevTypeHardDrive);
582 break;
583
584 case FDISK_HFS:
585 bvr = newFDiskBVRef(
586 biosdev, partno,
587 part->relsect,
588 part,
589 HFSInitPartition,
590 HFSLoadFile,
591 HFSGetDirEntry,
592 0,
593 kBIOSDevTypeHardDrive);
594 break;
595
596 case FDISK_BOOTER:
597 booterUFS = newFDiskBVRef(
598 biosdev, partno,
599 ((part->relsect + spc - 1) / spc) * spc,
600 part,
601 UFSInitPartition,
602 UFSLoadFile,
603 UFSGetDirEntry,
604 0,
605 kBIOSDevTypeHardDrive);
606 break;
607
608 default:
609 bvr = newFDiskBVRef(
610 biosdev, partno,
611 part->relsect,
612 part,
613 0, 0, 0, 0,
614 kBIOSDevTypeHardDrive);
615 break;
616 }
617
618 if ( bvr )
619 {
620 bvr->next = map->bvr;
621 map->bvr = bvr;
622 map->bvrcnt++;
623 }
624 }
625
626 // Booting from a CD with an UFS filesystem embedded
627 // in a booter partition.
628
629 if ( booterUFS )
630 {
631 if ( map->bvrcnt == 0 )
632 {
633 map->bvr = booterUFS;
634 map->bvrcnt++;
635 }
636 else free( booterUFS );
637 }
638 }
639 } while (0);
640
641 /*
642 * If no FDisk partition, then we will check for
643 * an Apple partition map elsewhere.
644 */
645 #if 0
646 if (map->bvrcnt == 0) {
647 static struct fdisk_part cdpart;
648 cdpart.systid = 0xCD;
649
650 /* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
651 bvr = newFDiskBVRef(
652 biosdev, 0,
653 0,
654 &cdpart,
655 HFSInitPartition,
656 HFSLoadFile,
657 HFSGetDirEntry,
658 0,
659 kBIOSDevTypeHardDrive);
660 bvr->next = map->bvr;
661 map->bvr = bvr;
662 map->bvrcnt++;
663 }
664 #endif
665
666 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
667
668 return map ? map->bvr : NULL;
669 }
670
671 //==========================================================================
672
673 static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
674 {
675 struct DiskBVMap * map;
676 struct Block0 *block0_p;
677 unsigned int blksize;
678 unsigned int factor;
679 void *buffer = malloc(BPS);
680
681 /* Check for alternate block size */
682 if (readBytes( biosdev, 0, BPS, buffer ) != 0) {
683 return NULL;
684 }
685 block0_p = buffer;
686 if (NXSwapBigShortToHost(block0_p->sbSig) == BLOCK0_SIGNATURE) {
687 blksize = NXSwapBigShortToHost(block0_p->sbBlkSize);
688 if (blksize != BPS) {
689 free(buffer);
690 buffer = malloc(blksize);
691 }
692 factor = blksize / BPS;
693 } else {
694 blksize = BPS;
695 factor = 1;
696 }
697
698 do {
699 // Create a new mapping.
700
701 map = (struct DiskBVMap *) malloc( sizeof(*map) );
702 if ( map )
703 {
704 int error;
705 DPME *dpme_p = (DPME *)buffer;
706 UInt32 i, npart = UINT_MAX;
707 BVRef bvr;
708
709 map->biosdev = biosdev;
710 map->bvr = NULL;
711 map->bvrcnt = 0;
712 map->next = gDiskBVMap;
713 gDiskBVMap = map;
714
715 for (i=0; i<npart; i++) {
716 error = readBytes( biosdev, (kAPMSector + i) * factor, blksize, buffer );
717
718 if (error || NXSwapBigShortToHost(dpme_p->dpme_signature) != DPME_SIGNATURE) {
719 break;
720 }
721
722 if (i==0) {
723 npart = NXSwapBigLongToHost(dpme_p->dpme_map_entries);
724 }
725 /*
726 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
727 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
728 dpme.dpme_pblock_start, dpme.dpme_pblocks,
729 dpme.dpme_lblock_start, dpme.dpme_lblocks,
730 dpme.dpme_boot_block);
731 */
732
733 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
734 bvr = newAPMBVRef(biosdev,
735 i,
736 NXSwapBigLongToHost(dpme_p->dpme_pblock_start) * factor,
737 dpme_p,
738 HFSInitPartition,
739 HFSLoadFile,
740 HFSGetDirEntry,
741 0,
742 kBIOSDevTypeHardDrive);
743 bvr->next = map->bvr;
744 map->bvr = bvr;
745 map->bvrcnt++;
746 }
747 }
748 }
749 } while (0);
750
751 free(buffer);
752
753 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
754
755 return map ? map->bvr : NULL;
756 }
757
758 //==========================================================================
759
760 BVRef diskScanBootVolumes( int biosdev, int * countPtr )
761 {
762 struct DiskBVMap * map;
763 BVRef bvr;
764 int count = 0;
765
766 // Find an existing mapping for this device.
767
768 for ( map = gDiskBVMap; map; map = map->next ) {
769 if ( biosdev == map->biosdev ) {
770 count = map->bvrcnt;
771 break;
772 }
773 }
774
775 if (map == NULL) {
776 bvr = diskScanFDiskBootVolumes(biosdev, &count);
777 if (bvr == NULL) {
778 bvr = diskScanAPMBootVolumes(biosdev, &count);
779 }
780 } else {
781 bvr = map->bvr;
782 }
783 if (countPtr) *countPtr = count;
784 return bvr;
785 }
786
787
788 //==========================================================================
789
790 static const struct NamedValue fdiskTypes[] =
791 {
792 { 0x07, "Windows NTFS" },
793 { 0x0c, "Windows FAT32" },
794 { 0x83, "Linux" },
795 { FDISK_UFS, "Apple UFS" },
796 { FDISK_HFS, "Apple HFS" },
797 { FDISK_BOOTER, "Apple Boot/UFS" },
798 { 0xCD, "CD-ROM" },
799 { 0x00, 0 } /* must be last */
800 };
801
802 static void getVolumeDescription( BVRef bvr, char * str, long strMaxLen )
803 {
804 unsigned char type = (unsigned char) bvr->part_type;
805 const char * name = getNameForValue( fdiskTypes, type );
806
807 if (name == NULL)
808 name = bvr->type_name;
809
810 if ( name )
811 sprintf( str, "hd(%d,%d) %s",
812 BIOS_DEV_UNIT(bvr), bvr->part_no, name );
813 else
814 sprintf( str, "hd(%d,%d) TYPE %02x",
815 BIOS_DEV_UNIT(bvr), bvr->part_no, type );
816 }
817
818
819 //==========================================================================
820
821 int readBootSector( int biosdev, unsigned int secno, void * buffer )
822 {
823 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
824 int error;
825
826 if ( bootSector == NULL )
827 {
828 if ( gBootSector == NULL )
829 {
830 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
831 if ( gBootSector == NULL ) return -1;
832 }
833 bootSector = gBootSector;
834 }
835
836 error = readBytes( biosdev, secno, BPS, bootSector );
837 if ( error || bootSector->signature != DISK_SIGNATURE )
838 return -1;
839
840 return 0;
841 }
842
843 //==========================================================================
844 // Handle seek request from filesystem modules.
845
846 void diskSeek( BVRef bvr, long long position )
847 {
848 bvr->fs_boff = position / BPS;
849 }
850
851 //==========================================================================
852 // Handle read request from filesystem modules.
853
854 int diskRead( BVRef bvr, long addr, long length )
855 {
856 return readBytes( bvr->biosdev,
857 bvr->fs_boff + bvr->part_boff,
858 length,
859 (void *) addr );
860 }
861
862 void turnOffFloppy(void)
863 {
864 /*
865 * Disable floppy:
866 * Hold controller in reset,
867 * disable DMA and IRQ,
868 * turn off floppy motors.
869 */
870 outb(0x3F2, 0x00);
871 }