]>
git.saurik.com Git - apple/boot.git/blob - i386/libsaio/disk.c
84a8a61fd7cc74652bc8028a4db5e360e45496f6
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
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.
33 * INTEL CORPORATION PROPRIETARY INFORMATION
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.
39 * Copyright 1988, 1989 Intel Corporation
43 * Copyright 1993 NeXT Computer, Inc.
44 * All rights reserved.
47 #include "bootstruct.h"
54 #include <IOKit/storage/IOApplePartitionScheme.h>
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 */
64 * trackbuf points to the start of the track cache. Biosread()
65 * will store the sectors read from disk to this memory area.
67 * biosbuf points to a sector within the track cache, and is
68 * updated by Biosread().
70 static const char * const trackbuf
= (char *) ptov(BIOS_ADDR
);
71 static const char * biosbuf
;
74 * Map a disk drive to bootable volumes contained within.
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
83 static struct DiskBVMap
* gDiskBVMap
= NULL
;
84 static struct disk_blk0
* gBootSector
= NULL
;
86 extern void spinActivityIndicator();
88 static void getVolumeDescription(BVRef bvr
, char * str
, long strMaxLen
);
90 //==========================================================================
92 static int getDriveInfo( int biosdev
, struct driveInfo
*dip
)
94 static struct driveInfo cached_di
;
97 if ( !cached_di
.valid
|| biosdev
!= cached_di
.biosdev
)
99 cc
= get_drive_info(biosdev
, &cached_di
);
102 return (-1); // BIOS call error
106 bcopy(&cached_di
, dip
, sizeof(cached_di
));
111 //==========================================================================
112 // Maps (E)BIOS return codes to message strings.
119 static const char * getNameForValue( const struct NamedValue
* nameTable
,
120 unsigned char value
)
122 const struct NamedValue
* np
;
124 for ( np
= nameTable
; np
->value
; np
++)
125 if (np
->value
== value
)
131 #define ECC_CORRECTED_ERR 0x11
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" },
143 static const char * bios_error(int errnum
)
145 static char errorstr
[] = "Error 0x00";
146 const char * errname
;
148 errname
= getNameForValue( bios_errors
, errnum
);
149 if ( errname
) return errname
;
151 sprintf(errorstr
, "Error 0x%02x", errnum
);
152 return errorstr
; // No string, print error code only
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
161 // 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
163 static int Biosread( int biosdev
, unsigned int secno
)
165 static int xbiosdev
, xcyl
, xhead
;
166 static unsigned int xsec
, xnsecs
;
167 static BOOL cache_valid
= FALSE
;
175 if (getDriveInfo(biosdev
, &di
) < 0) {
178 if (di
.no_emulation
) {
179 /* Always assume 2k block size; BIOS may lie about geometry */
182 bps
= di
.di
.params
.phys_nbps
;
186 DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev
, secno
, bps
));
188 // To read the disk sectors, use EBIOS if we can. Otherwise,
189 // revert to the standard BIOS calls.
191 if ((biosdev
>= kBIOSDevTypeHardDrive
) &&
192 (di
.uses_ebios
& EBIOS_FIXED_DISK_ACCESS
))
195 (biosdev
== xbiosdev
) &&
197 ((unsigned int)secno
< (xsec
+ xnsecs
)))
199 biosbuf
= trackbuf
+ (BPS
* (secno
- xsec
));
203 xnsecs
= N_CACHE_SECS
;
204 xsec
= (secno
/ divisor
) * divisor
;
207 while ((rc
= ebiosread(biosdev
, secno
/ divisor
, xnsecs
/ divisor
)) && (++tries
< 5))
209 if (rc
== ECC_CORRECTED_ERR
) {
210 /* Ignore corrected ECC errors */
214 error(" EBIOS read error: %s\n", bios_error(rc
), rc
);
215 error(" Block %d Sectors %d\n", secno
, xnsecs
);
221 /* spc = spt * heads */
222 int spc
= (di
.di
.params
.phys_spt
* di
.di
.params
.phys_heads
);
224 head
= (secno
% spc
) / di
.di
.params
.phys_spt
;
225 sec
= secno
% di
.di
.params
.phys_spt
;
228 (biosdev
== xbiosdev
) &&
231 ((unsigned int)sec
>= xsec
) &&
232 ((unsigned int)sec
< (xsec
+ xnsecs
)))
234 // this sector is in trackbuf cache
235 biosbuf
= trackbuf
+ (BPS
* (sec
- xsec
));
239 // Cache up to a track worth of sectors, but do not cross a
245 xnsecs
= ((unsigned int)(sec
+ N_CACHE_SECS
) > di
.di
.params
.phys_spt
) ? (di
.di
.params
.phys_spt
- sec
) : N_CACHE_SECS
;
248 while ((rc
= biosread(biosdev
, cyl
, head
, sec
, xnsecs
)) &&
251 if (rc
== ECC_CORRECTED_ERR
) {
252 /* Ignore corrected ECC errors */
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
);
263 // If the BIOS reported success, mark the sector cache as valid.
268 biosbuf
= trackbuf
+ (secno
% divisor
) * BPS
;
271 spinActivityIndicator();
276 //==========================================================================
278 static int readBytes( int biosdev
, unsigned int blkno
,
279 unsigned int byteCount
, void * buffer
)
282 char * cbuf
= (char *) buffer
;
286 DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__
,
287 biosdev
, blkno
, byteCount
, (unsigned)cbuf
));
289 for ( ; byteCount
; cbuf
+= BPS
, blkno
++ )
291 error
= Biosread( biosdev
, blkno
);
294 DEBUG_DISK(("error\n"));
298 copy_len
= (byteCount
> BPS
) ? BPS
: byteCount
;
299 bcopy( biosbuf
, cbuf
, copy_len
);
300 byteCount
-= copy_len
;
303 DEBUG_DISK(("done\n"));
308 //==========================================================================
310 static int isExtendedFDiskPartition( const struct fdisk_part
* part
)
312 static unsigned char extParts
[] =
315 0x0f, /* Win95 extended */
316 0x85, /* Linux extended */
321 for (i
= 0; i
< sizeof(extParts
)/sizeof(extParts
[0]); i
++)
323 if (extParts
[i
] == part
->systid
) return 1;
328 //==========================================================================
330 static int getNextFDiskPartition( int biosdev
, int * partno
,
331 const struct fdisk_part
** outPart
)
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
;
340 if ( sBiosdev
!= biosdev
|| *partno
< 0 )
343 if ( readBootSector( biosdev
, DISK_BLK0
, 0 ) ) return 0;
356 if ( sNextPartNo
< FDISK_NPART
)
358 part
= (struct fdisk_part
*) gBootSector
->parts
[sNextPartNo
];
362 unsigned int blkno
= sExtPart
->relsect
+ sExtBase
;
364 // Save the block offset of the first extended partition.
366 if ( sExtDepth
== 0 ) sExtBase
= sExtPart
->relsect
;
368 // Load extended partition table.
370 if ( readBootSector( biosdev
, blkno
, 0 ) == 0 )
379 if ( part
== NULL
) break; // Reached end of partition chain.
381 // Advance to next partition number.
385 // Assume at most one extended partition per table.
387 if ( isExtendedFDiskPartition(part
) )
395 if ( part
->systid
== 0x00 )
400 // Change relative offset to an absolute offset.
402 part
->relsect
+= sExtBase
;
405 *partno
= sExtDepth
? (int)(sExtDepth
+ 4) : sNextPartNo
;
410 return (part
!= NULL
);
413 //==========================================================================
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
)
420 BVRef bvr
= (BVRef
) malloc( sizeof(*bvr
) );
423 bzero(bvr
, sizeof(*bvr
));
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
;
434 if ( part
->bootid
& FDISK_ACTIVE
)
435 bvr
->flags
|= kBVFlagPrimary
;
437 // Probe the filesystem.
441 bvr
->flags
|= kBVFlagNativeBoot
;
443 if ( probe
&& initFunc( bvr
) != 0 )
445 // filesystem probe failed.
447 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
448 __FUNCTION__
, biosdev
, partno
));
454 else if ( readBootSector( biosdev
, blkoff
, (void *)0x7e00 ) == 0 )
456 bvr
->flags
|= kBVFlagForeignBoot
;
467 //==========================================================================
469 BVRef
newAPMBVRef( int biosdev
, int partno
, unsigned int blkoff
,
471 FSInit initFunc
, FSLoadFile loadFunc
,
472 FSGetDirEntry getdirFunc
, int probe
, int type
)
474 BVRef bvr
= (BVRef
) malloc( sizeof(*bvr
) );
477 bzero(bvr
, sizeof(*bvr
));
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
;
486 strlcpy(bvr
->name
, part
->dpme_name
, DPISTRLEN
);
487 strlcpy(bvr
->type_name
, part
->dpme_type
, DPISTRLEN
);
490 if ( part->bootid & FDISK_ACTIVE )
491 bvr->flags |= kBVFlagPrimary;
494 // Probe the filesystem.
498 bvr
->flags
|= kBVFlagNativeBoot
;
500 if ( probe
&& initFunc( bvr
) != 0 )
502 // filesystem probe failed.
504 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
505 __FUNCTION__
, biosdev
, partno
));
512 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
514 bvr->flags |= kBVFlagForeignBoot;
526 //==========================================================================
528 static BVRef
diskScanFDiskBootVolumes( int biosdev
, int * countPtr
)
530 const struct fdisk_part
* part
;
531 struct DiskBVMap
* map
;
534 BVRef booterUFS
= NULL
;
537 boot_drive_info_t
*dp
;
539 /* Initialize disk info */
540 if (getDriveInfo(biosdev
, &di
) != 0) {
544 spc
= (dp
->params
.phys_spt
* dp
->params
.phys_heads
);
546 /* This is probably a CD-ROM; punt on the geometry. */
551 // Create a new mapping.
553 map
= (struct DiskBVMap
*) malloc( sizeof(*map
) );
556 map
->biosdev
= biosdev
;
559 map
->next
= gDiskBVMap
;
562 // Create a record for each partition found on the disk.
564 while ( getNextFDiskPartition( biosdev
, &partno
, &part
) )
566 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__
,
567 partno
, part
->systid
));
570 switch ( part
->systid
)
575 part
->relsect
+ UFS_FRONT_PORCH
/BPS
,
581 kBIOSDevTypeHardDrive
);
593 kBIOSDevTypeHardDrive
);
597 booterUFS
= newFDiskBVRef(
599 ((part
->relsect
+ spc
- 1) / spc
) * spc
,
605 kBIOSDevTypeHardDrive
);
614 kBIOSDevTypeHardDrive
);
620 bvr
->next
= map
->bvr
;
626 // Booting from a CD with an UFS filesystem embedded
627 // in a booter partition.
631 if ( map
->bvrcnt
== 0 )
633 map
->bvr
= booterUFS
;
636 else free( booterUFS
);
642 * If no FDisk partition, then we will check for
643 * an Apple partition map elsewhere.
646 if (map
->bvrcnt
== 0) {
647 static struct fdisk_part cdpart
;
648 cdpart
.systid
= 0xCD;
650 /* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
659 kBIOSDevTypeHardDrive
);
660 bvr
->next
= map
->bvr
;
666 if (countPtr
) *countPtr
= map
? map
->bvrcnt
: 0;
668 return map
? map
->bvr
: NULL
;
671 //==========================================================================
673 static BVRef
diskScanAPMBootVolumes( int biosdev
, int * countPtr
)
675 struct DiskBVMap
* map
;
676 struct Block0
*block0_p
;
677 unsigned int blksize
;
679 void *buffer
= malloc(BPS
);
681 /* Check for alternate block size */
682 if (readBytes( biosdev
, 0, BPS
, buffer
) != 0) {
686 if (NXSwapBigShortToHost(block0_p
->sbSig
) == BLOCK0_SIGNATURE
) {
687 blksize
= NXSwapBigShortToHost(block0_p
->sbBlkSize
);
688 if (blksize
!= BPS
) {
690 buffer
= malloc(blksize
);
692 factor
= blksize
/ BPS
;
699 // Create a new mapping.
701 map
= (struct DiskBVMap
*) malloc( sizeof(*map
) );
705 DPME
*dpme_p
= (DPME
*)buffer
;
706 UInt32 i
, npart
= UINT_MAX
;
709 map
->biosdev
= biosdev
;
712 map
->next
= gDiskBVMap
;
715 for (i
=0; i
<npart
; i
++) {
716 error
= readBytes( biosdev
, (kAPMSector
+ i
) * factor
, blksize
, buffer
);
718 if (error
|| NXSwapBigShortToHost(dpme_p
->dpme_signature
) != DPME_SIGNATURE
) {
723 npart
= NXSwapBigLongToHost(dpme_p
->dpme_map_entries
);
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);
733 if (strcmp(dpme_p
->dpme_type
, "Apple_HFS") == 0) {
734 bvr
= newAPMBVRef(biosdev
,
736 NXSwapBigLongToHost(dpme_p
->dpme_pblock_start
) * factor
,
742 kBIOSDevTypeHardDrive
);
743 bvr
->next
= map
->bvr
;
753 if (countPtr
) *countPtr
= map
? map
->bvrcnt
: 0;
755 return map
? map
->bvr
: NULL
;
758 //==========================================================================
760 BVRef
diskScanBootVolumes( int biosdev
, int * countPtr
)
762 struct DiskBVMap
* map
;
766 // Find an existing mapping for this device.
768 for ( map
= gDiskBVMap
; map
; map
= map
->next
) {
769 if ( biosdev
== map
->biosdev
) {
776 bvr
= diskScanFDiskBootVolumes(biosdev
, &count
);
778 bvr
= diskScanAPMBootVolumes(biosdev
, &count
);
783 if (countPtr
) *countPtr
= count
;
788 //==========================================================================
790 static const struct NamedValue fdiskTypes
[] =
792 { 0x07, "Windows NTFS" },
793 { 0x0c, "Windows FAT32" },
795 { FDISK_UFS
, "Apple UFS" },
796 { FDISK_HFS
, "Apple HFS" },
797 { FDISK_BOOTER
, "Apple Boot/UFS" },
799 { 0x00, 0 } /* must be last */
802 static void getVolumeDescription( BVRef bvr
, char * str
, long strMaxLen
)
804 unsigned char type
= (unsigned char) bvr
->part_type
;
805 const char * name
= getNameForValue( fdiskTypes
, type
);
808 name
= bvr
->type_name
;
811 sprintf( str
, "hd(%d,%d) %s",
812 BIOS_DEV_UNIT(bvr
), bvr
->part_no
, name
);
814 sprintf( str
, "hd(%d,%d) TYPE %02x",
815 BIOS_DEV_UNIT(bvr
), bvr
->part_no
, type
);
819 //==========================================================================
821 int readBootSector( int biosdev
, unsigned int secno
, void * buffer
)
823 struct disk_blk0
* bootSector
= (struct disk_blk0
*) buffer
;
826 if ( bootSector
== NULL
)
828 if ( gBootSector
== NULL
)
830 gBootSector
= (struct disk_blk0
*) malloc(sizeof(*gBootSector
));
831 if ( gBootSector
== NULL
) return -1;
833 bootSector
= gBootSector
;
836 error
= readBytes( biosdev
, secno
, BPS
, bootSector
);
837 if ( error
|| bootSector
->signature
!= DISK_SIGNATURE
)
843 //==========================================================================
844 // Handle seek request from filesystem modules.
846 void diskSeek( BVRef bvr
, long long position
)
848 bvr
->fs_boff
= position
/ BPS
;
851 //==========================================================================
852 // Handle read request from filesystem modules.
854 int diskRead( BVRef bvr
, long addr
, long length
)
856 return readBytes( bvr
->biosdev
,
857 bvr
->fs_boff
+ bvr
->part_boff
,
862 void turnOffFloppy(void)
866 * Hold controller in reset,
867 * disable DMA and IRQ,
868 * turn off floppy motors.