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