]> git.saurik.com Git - apple/boot.git/blame - i386/libsaio/disk.c
boot-111.tar.gz
[apple/boot.git] / i386 / libsaio / disk.c
CommitLineData
14c7c974
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
f083c6c3
A
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.
14c7c974
A
14 *
15 * The Original Code and all software distributed under the License are
f083c6c3 16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
f083c6c3
A
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.
14c7c974
A
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
f083c6c3 48#include "bootstruct.h"
14c7c974 49#include "libsaio.h"
75b89a82 50#include "fdisk.h"
f083c6c3
A
51#include "ufs.h"
52#include "hfs.h"
14c7c974 53
f083c6c3
A
54#include <limits.h>
55#include <IOKit/storage/IOApplePartitionScheme.h>
14c7c974 56
75b89a82 57#define BPS 512 /* sector size of the device */
f083c6c3
A
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 */
75b89a82 60#define UFS_FRONT_PORCH 0
f083c6c3
A
61#define kAPMSector 2 /* Sector number of Apple partition map */
62#define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
14c7c974
A
63
64/*
75b89a82
A
65 * trackbuf points to the start of the track cache. Biosread()
66 * will store the sectors read from disk to this memory area.
14c7c974 67 *
75b89a82
A
68 * biosbuf points to a sector within the track cache, and is
69 * updated by Biosread().
14c7c974 70 */
75b89a82
A
71static const char * const trackbuf = (char *) ptov(BIOS_ADDR);
72static const char * biosbuf;
14c7c974 73
75b89a82
A
74/*
75 * Map a disk drive to bootable volumes contained within.
14c7c974 76 */
75b89a82
A
77struct 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};
14c7c974 83
75b89a82
A
84static struct DiskBVMap * gDiskBVMap = NULL;
85static struct disk_blk0 * gBootSector = NULL;
14c7c974 86
75b89a82 87extern void spinActivityIndicator();
14c7c974 88
75b89a82 89static void getVolumeDescription(BVRef bvr, char * str, long strMaxLen);
14c7c974 90
75b89a82 91//==========================================================================
14c7c974 92
f083c6c3 93static int getDriveInfo( int biosdev, struct driveInfo *dip )
14c7c974 94{
f083c6c3
A
95 static struct driveInfo cached_di;
96 int cc;
75b89a82 97
f083c6c3 98 if ( !cached_di.valid || biosdev != cached_di.biosdev )
75b89a82 99 {
f083c6c3
A
100 cc = get_drive_info(biosdev, &cached_di);
101 if (cc < 0) {
102 cached_di.valid = 0;
103 return (-1); // BIOS call error
104 }
75b89a82 105 }
14c7c974 106
f083c6c3 107 bcopy(&cached_di, dip, sizeof(cached_di));
14c7c974 108
75b89a82
A
109 return 0;
110}
14c7c974 111
75b89a82
A
112//==========================================================================
113// Maps (E)BIOS return codes to message strings.
14c7c974 114
75b89a82
A
115struct NamedValue {
116 unsigned char value;
117 const char * name;
118};
14c7c974 119
75b89a82
A
120static const char * getNameForValue( const struct NamedValue * nameTable,
121 unsigned char value )
122{
123 const struct NamedValue * np;
14c7c974 124
75b89a82
A
125 for ( np = nameTable; np->value; np++)
126 if (np->value == value)
127 return np->name;
14c7c974 128
75b89a82 129 return NULL;
14c7c974
A
130}
131
14c7c974
A
132#define ECC_CORRECTED_ERR 0x11
133
75b89a82
A
134static 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 }
14c7c974
A
142};
143
75b89a82 144static const char * bios_error(int errnum)
14c7c974 145{
75b89a82
A
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
14c7c974
A
154}
155
75b89a82
A
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
164static int Biosread( int biosdev, unsigned int secno )
14c7c974 165{
75b89a82
A
166 static int xbiosdev, xcyl, xhead;
167 static unsigned int xsec, xnsecs;
168 static BOOL cache_valid = FALSE;
f083c6c3 169 struct driveInfo di;
14c7c974 170
75b89a82 171 int rc = -1;
14c7c974 172 int cyl, head, sec;
14c7c974 173 int tries = 0;
f083c6c3 174 int bps, divisor;
14c7c974 175
f083c6c3
A
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));
14c7c974
A
188
189 // To read the disk sectors, use EBIOS if we can. Otherwise,
190 // revert to the standard BIOS calls.
75b89a82
A
191
192 if ((biosdev >= kBIOSDevTypeHardDrive) &&
f083c6c3 193 (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))
75b89a82 194 {
14c7c974
A
195 if (cache_valid &&
196 (biosdev == xbiosdev) &&
197 (secno >= xsec) &&
f083c6c3 198 ((unsigned int)secno < (xsec + xnsecs)))
14c7c974 199 {
75b89a82 200 biosbuf = trackbuf + (BPS * (secno - xsec));
14c7c974
A
201 return 0;
202 }
203
204 xnsecs = N_CACHE_SECS;
f083c6c3 205 xsec = (secno / divisor) * divisor;
75b89a82 206 cache_valid = FALSE;
14c7c974 207
f083c6c3 208 while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))
14c7c974
A
209 {
210 if (rc == ECC_CORRECTED_ERR) {
211 /* Ignore corrected ECC errors */
75b89a82 212 rc = 0;
14c7c974
A
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 }
f083c6c3 220 else
75b89a82 221 {
f083c6c3
A
222 /* spc = spt * heads */
223 int spc = (di.di.params.phys_spt * di.di.params.phys_heads);
14c7c974 224 cyl = secno / spc;
f083c6c3
A
225 head = (secno % spc) / di.di.params.phys_spt;
226 sec = secno % di.di.params.phys_spt;
14c7c974
A
227
228 if (cache_valid &&
229 (biosdev == xbiosdev) &&
230 (cyl == xcyl) &&
231 (head == xhead) &&
f083c6c3
A
232 ((unsigned int)sec >= xsec) &&
233 ((unsigned int)sec < (xsec + xnsecs)))
14c7c974 234 {
75b89a82
A
235 // this sector is in trackbuf cache
236 biosbuf = trackbuf + (BPS * (sec - xsec));
14c7c974
A
237 return 0;
238 }
239
240 // Cache up to a track worth of sectors, but do not cross a
241 // track boundary.
75b89a82 242
14c7c974
A
243 xcyl = cyl;
244 xhead = head;
245 xsec = sec;
f083c6c3 246 xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;
75b89a82 247 cache_valid = FALSE;
14c7c974
A
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 */
75b89a82 254 rc = 0;
14c7c974
A
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.
75b89a82 265
14c7c974
A
266 if (rc == 0) {
267 cache_valid = TRUE;
268 }
f083c6c3 269 biosbuf = trackbuf + (secno % divisor) * BPS;
14c7c974
A
270 xbiosdev = biosdev;
271
75b89a82 272 spinActivityIndicator();
14c7c974
A
273
274 return rc;
275}
276
75b89a82
A
277//==========================================================================
278
279static int readBytes( int biosdev, unsigned int blkno,
280 unsigned int byteCount, void * buffer )
14c7c974 281{
75b89a82
A
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;
14c7c974
A
307}
308
75b89a82
A
309//==========================================================================
310
311static int isExtendedFDiskPartition( const struct fdisk_part * part )
14c7c974 312{
75b89a82
A
313 static unsigned char extParts[] =
314 {
315 0x05, /* Extended */
316 0x0f, /* Win95 extended */
317 0x85, /* Linux extended */
318 };
319
f083c6c3 320 unsigned int i;
75b89a82
A
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;
14c7c974
A
327}
328
75b89a82
A
329//==========================================================================
330
331static int getNextFDiskPartition( int biosdev, int * partno,
332 const struct fdisk_part ** outPart )
14c7c974 333{
75b89a82
A
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 }
14c7c974 352
75b89a82
A
353 while (1)
354 {
355 part = NULL;
14c7c974 356
75b89a82
A
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;
14c7c974 364
75b89a82
A
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;
f083c6c3 406 *partno = sExtDepth ? (int)(sExtDepth + 4) : sNextPartNo;
75b89a82
A
407
408 break;
14c7c974
A
409 }
410
75b89a82
A
411 return (part != NULL);
412}
413
414//==========================================================================
14c7c974 415
75b89a82
A
416static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,
417 const struct fdisk_part * part,
418 FSInit initFunc, FSLoadFile loadFunc,
f083c6c3 419 FSGetDirEntry getdirFunc, int probe, int type )
75b89a82
A
420{
421 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
422 if ( bvr )
14c7c974 423 {
75b89a82 424 bzero(bvr, sizeof(*bvr));
14c7c974 425
75b89a82
A
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;
f083c6c3 433 bvr->type = type;
75b89a82
A
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;
14c7c974 443
75b89a82
A
444 if ( probe && initFunc( bvr ) != 0 )
445 {
446 // filesystem probe failed.
14c7c974 447
75b89a82
A
448 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
449 __FUNCTION__, biosdev, partno));
14c7c974 450
75b89a82
A
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;
14c7c974
A
463 }
464 }
75b89a82
A
465 return bvr;
466}
14c7c974 467
75b89a82
A
468//==========================================================================
469
f083c6c3
A
470BVRef 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
529static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
75b89a82
A
530{
531 const struct fdisk_part * part;
532 struct DiskBVMap * map;
533 int partno = -1;
534 BVRef bvr;
535 BVRef booterUFS = NULL;
f083c6c3
A
536 int spc;
537 struct driveInfo di;
538 boot_drive_info_t *dp;
75b89a82 539
f083c6c3
A
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 }
14c7c974 550
f083c6c3 551 do {
75b89a82 552 // Create a new mapping.
14c7c974 553
75b89a82
A
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;
14c7c974 562
75b89a82
A
563 // Create a record for each partition found on the disk.
564
565 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
14c7c974 566 {
75b89a82
A
567 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
568 partno, part->systid));
75b89a82
A
569 bvr = 0;
570
571 switch ( part->systid )
572 {
573 case FDISK_UFS:
f083c6c3 574 bvr = newFDiskBVRef(
75b89a82
A
575 biosdev, partno,
576 part->relsect + UFS_FRONT_PORCH/BPS,
577 part,
578 UFSInitPartition,
579 UFSLoadFile,
580 UFSGetDirEntry,
f083c6c3
A
581 0,
582 kBIOSDevTypeHardDrive);
75b89a82
A
583 break;
584
585 case FDISK_HFS:
586 bvr = newFDiskBVRef(
587 biosdev, partno,
588 part->relsect,
589 part,
590 HFSInitPartition,
591 HFSLoadFile,
592 HFSGetDirEntry,
f083c6c3
A
593 0,
594 kBIOSDevTypeHardDrive);
75b89a82
A
595 break;
596
597 case FDISK_BOOTER:
75b89a82
A
598 booterUFS = newFDiskBVRef(
599 biosdev, partno,
600 ((part->relsect + spc - 1) / spc) * spc,
601 part,
602 UFSInitPartition,
603 UFSLoadFile,
604 UFSGetDirEntry,
f083c6c3
A
605 0,
606 kBIOSDevTypeHardDrive);
75b89a82
A
607 break;
608
609 default:
610 bvr = newFDiskBVRef(
611 biosdev, partno,
612 part->relsect,
613 part,
f083c6c3
A
614 0, 0, 0, 0,
615 kBIOSDevTypeHardDrive);
75b89a82
A
616 break;
617 }
618
619 if ( bvr )
620 {
621 bvr->next = map->bvr;
622 map->bvr = bvr;
623 map->bvrcnt++;
624 }
14c7c974 625 }
14c7c974 626
75b89a82
A
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
f083c6c3
A
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
75b89a82
A
667 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
668
669 return map ? map->bvr : NULL;
670}
671
f083c6c3
A
672//==========================================================================
673
674static 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
761BVRef 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
75b89a82
A
789//==========================================================================
790
791static 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" },
f083c6c3 799 { 0xCD, "CD-ROM" },
75b89a82
A
800 { 0x00, 0 } /* must be last */
801};
802
803static 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
f083c6c3
A
808 if (name == NULL)
809 name = bvr->type_name;
810
75b89a82
A
811 if ( name )
812 sprintf( str, "hd(%d,%d) %s",
f083c6c3 813 BIOS_DEV_UNIT(bvr), bvr->part_no, name );
75b89a82
A
814 else
815 sprintf( str, "hd(%d,%d) TYPE %02x",
f083c6c3 816 BIOS_DEV_UNIT(bvr), bvr->part_no, type );
75b89a82
A
817}
818
f083c6c3 819
75b89a82
A
820//==========================================================================
821
822int 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;
14c7c974 833 }
75b89a82 834 bootSector = gBootSector;
14c7c974 835 }
75b89a82
A
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
847void diskSeek( BVRef bvr, long long position )
848{
849 bvr->fs_boff = position / BPS;
850}
851
852//==========================================================================
853// Handle read request from filesystem modules.
854
855int 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 );
14c7c974 861}
f083c6c3
A
862
863void 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}