]>
git.saurik.com Git - apple/boot.git/blob - i386/libsaio/disk.c
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.
53 #define SPT(di) ((di) & 0xff)
54 #define HEADS(di) ((((di)>>8) & 0xff) + 1)
55 #define SPC(di) (SPT(di) * HEADS(di))
57 #define BPS 512 /* sector size of the device */
58 #define N_CACHE_SECS (BIOS_LEN / BPS)
59 #define UFS_FRONT_PORCH 0
62 * trackbuf points to the start of the track cache. Biosread()
63 * will store the sectors read from disk to this memory area.
65 * biosbuf points to a sector within the track cache, and is
66 * updated by Biosread().
68 static const char * const trackbuf
= (char *) ptov(BIOS_ADDR
);
69 static const char * biosbuf
;
72 * Map a disk drive to bootable volumes contained within.
75 int biosdev
; // BIOS device number (unique)
76 BVRef bvr
; // chain of boot volumes on the disk
77 int bvrcnt
; // number of boot volumes
78 struct DiskBVMap
* next
; // linkage to next mapping
81 static struct DiskBVMap
* gDiskBVMap
= NULL
;
82 static struct disk_blk0
* gBootSector
= NULL
;
84 extern long HFSInitPartition(CICell ih
);
85 extern long HFSLoadFile(CICell ih
, char * filePath
);
86 extern long HFSGetDirEntry(CICell ih
, char * dirPath
, long * dirIndex
,
87 char ** name
, long * flags
, long * time
);
89 extern long UFSInitPartition(CICell ih
);
90 extern long UFSLoadFile(CICell ih
, char * filePath
);
91 extern long UFSGetDirEntry(CICell ih
, char * dirPath
, long * dirIndex
,
92 char ** name
, long * flags
, long * time
);
94 extern void spinActivityIndicator();
96 static void getVolumeDescription(BVRef bvr
, char * str
, long strMaxLen
);
98 //==========================================================================
100 static int getDiskGeometry( int biosdev
, int * spt
, int * spc
)
102 static int cached_biosdev
= -1;
103 static int cached_spt
= 0;
104 static int cached_spc
= 0;
106 if ( biosdev
!= cached_biosdev
)
108 long di
= get_diskinfo(biosdev
);
109 if (di
== 0) return (-1); // BIOS call error
111 cached_spt
= SPT(di
);
112 cached_spc
= cached_spt
* HEADS(di
);
114 DEBUG_DISK(("%s: %d sectors, %d heads\n",
115 __FUNCTION__
, cached_spt
, (int)HEADS(di
)));
124 //==========================================================================
125 // Maps (E)BIOS return codes to message strings.
132 static const char * getNameForValue( const struct NamedValue
* nameTable
,
133 unsigned char value
)
135 const struct NamedValue
* np
;
137 for ( np
= nameTable
; np
->value
; np
++)
138 if (np
->value
== value
)
144 #define ECC_CORRECTED_ERR 0x11
146 static const struct NamedValue bios_errors
[] = {
147 { 0x10, "Media error" },
148 { 0x11, "Corrected ECC error" },
149 { 0x20, "Controller or device error" },
150 { 0x40, "Seek failed" },
151 { 0x80, "Device timeout" },
152 { 0xAA, "Drive not ready" },
156 static const char * bios_error(int errnum
)
158 static char errorstr
[] = "Error 0x00";
159 const char * errname
;
161 errname
= getNameForValue( bios_errors
, errnum
);
162 if ( errname
) return errname
;
164 sprintf(errorstr
, "Error 0x%02x", errnum
);
165 return errorstr
; // No string, print error code only
168 //==========================================================================
169 // Use BIOS INT13 calls to read the sector specified. This function will
170 // also perform read-ahead to cache a few subsequent sector to the sector
174 // 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
176 static int Biosread( int biosdev
, unsigned int secno
)
178 static int xbiosdev
, xcyl
, xhead
;
179 static unsigned int xsec
, xnsecs
;
180 static BOOL cache_valid
= FALSE
;
187 // DEBUG_DISK(("Biosread dev %x sec %d \n", biosdev, secno));
189 // To read the disk sectors, use EBIOS if we can. Otherwise,
190 // revert to the standard BIOS calls.
192 if ((biosdev
>= kBIOSDevTypeHardDrive
) &&
193 (uses_ebios
[biosdev
- kBIOSDevTypeHardDrive
] & EBIOS_FIXED_DISK_ACCESS
))
196 (biosdev
== xbiosdev
) &&
198 (secno
< (xsec
+ xnsecs
)))
200 biosbuf
= trackbuf
+ (BPS
* (secno
- xsec
));
204 xnsecs
= N_CACHE_SECS
;
208 while ((rc
= ebiosread(biosdev
, secno
, xnsecs
)) && (++tries
< 5))
210 if (rc
== ECC_CORRECTED_ERR
) {
211 /* Ignore corrected ECC errors */
215 error(" EBIOS read error: %s\n", bios_error(rc
), rc
);
216 error(" Block %d Sectors %d\n", secno
, xnsecs
);
220 else if ( getDiskGeometry(biosdev
, &spt
, &spc
) == 0 )
223 head
= (secno
% spc
) / spt
;
227 (biosdev
== xbiosdev
) &&
231 (sec
< (xsec
+ xnsecs
)))
233 // this sector is in trackbuf cache
234 biosbuf
= trackbuf
+ (BPS
* (sec
- xsec
));
238 // Cache up to a track worth of sectors, but do not cross a
244 xnsecs
= ((sec
+ N_CACHE_SECS
) > spt
) ? (spt
- sec
) : N_CACHE_SECS
;
247 while ((rc
= biosread(biosdev
, cyl
, head
, sec
, xnsecs
)) &&
250 if (rc
== ECC_CORRECTED_ERR
) {
251 /* Ignore corrected ECC errors */
255 error(" BIOS read error: %s\n", bios_error(rc
), rc
);
256 error(" Block %d, Cyl %d Head %d Sector %d\n",
257 secno
, cyl
, head
, sec
);
262 // If the BIOS reported success, mark the sector cache as valid.
270 spinActivityIndicator();
275 //==========================================================================
277 static int readBytes( int biosdev
, unsigned int blkno
,
278 unsigned int byteCount
, void * buffer
)
281 char * cbuf
= (char *) buffer
;
285 DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__
,
286 biosdev
, blkno
, byteCount
, (unsigned)cbuf
));
288 for ( ; byteCount
; cbuf
+= BPS
, blkno
++ )
290 error
= Biosread( biosdev
, blkno
);
293 DEBUG_DISK(("error\n"));
297 copy_len
= (byteCount
> BPS
) ? BPS
: byteCount
;
298 bcopy( biosbuf
, cbuf
, copy_len
);
299 byteCount
-= copy_len
;
302 DEBUG_DISK(("done\n"));
307 //==========================================================================
309 static int isExtendedFDiskPartition( const struct fdisk_part
* part
)
311 static unsigned char extParts
[] =
314 0x0f, /* Win95 extended */
315 0x85, /* Linux extended */
320 for (i
= 0; i
< sizeof(extParts
)/sizeof(extParts
[0]); i
++)
322 if (extParts
[i
] == part
->systid
) return 1;
327 //==========================================================================
329 static int getNextFDiskPartition( int biosdev
, int * partno
,
330 const struct fdisk_part
** outPart
)
332 static int sBiosdev
= -1;
333 static int sNextPartNo
;
334 static unsigned int sExtBase
;
335 static unsigned int sExtDepth
;
336 static struct fdisk_part
* sExtPart
;
337 struct fdisk_part
* part
;
339 if ( sBiosdev
!= biosdev
|| *partno
< 0 )
342 if ( readBootSector( biosdev
, DISK_BLK0
, 0 ) ) return 0;
355 if ( sNextPartNo
< FDISK_NPART
)
357 part
= (struct fdisk_part
*) gBootSector
->parts
[sNextPartNo
];
361 unsigned int blkno
= sExtPart
->relsect
+ sExtBase
;
363 // Save the block offset of the first extended partition.
365 if ( sExtDepth
== 0 ) sExtBase
= sExtPart
->relsect
;
367 // Load extended partition table.
369 if ( readBootSector( biosdev
, blkno
, 0 ) == 0 )
378 if ( part
== NULL
) break; // Reached end of partition chain.
380 // Advance to next partition number.
384 // Assume at most one extended partition per table.
386 if ( isExtendedFDiskPartition(part
) )
394 if ( part
->systid
== 0x00 )
399 // Change relative offset to an absolute offset.
401 part
->relsect
+= sExtBase
;
404 *partno
= sExtDepth
? (sExtDepth
+ 4) : sNextPartNo
;
409 return (part
!= NULL
);
412 //==========================================================================
414 static BVRef
newFDiskBVRef( int biosdev
, int partno
, unsigned int blkoff
,
415 const struct fdisk_part
* part
,
416 FSInit initFunc
, FSLoadFile loadFunc
,
417 FSGetDirEntry getdirFunc
, int probe
)
419 BVRef bvr
= (BVRef
) malloc( sizeof(*bvr
) );
422 bzero(bvr
, sizeof(*bvr
));
424 bvr
->biosdev
= biosdev
;
425 bvr
->part_no
= partno
;
426 bvr
->part_boff
= blkoff
;
427 bvr
->part_type
= part
->systid
;
428 bvr
->fs_loadfile
= loadFunc
;
429 bvr
->fs_getdirentry
= getdirFunc
;
430 bvr
->description
= getVolumeDescription
;
432 if ( part
->bootid
& FDISK_ACTIVE
)
433 bvr
->flags
|= kBVFlagPrimary
;
435 // Probe the filesystem.
439 bvr
->flags
|= kBVFlagNativeBoot
;
441 if ( probe
&& initFunc( bvr
) != 0 )
443 // filesystem probe failed.
445 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
446 __FUNCTION__
, biosdev
, partno
));
452 else if ( readBootSector( biosdev
, blkoff
, (void *)0x7e00 ) == 0 )
454 bvr
->flags
|= kBVFlagForeignBoot
;
465 //==========================================================================
467 BVRef
diskScanBootVolumes( int biosdev
, int * countPtr
)
469 const struct fdisk_part
* part
;
470 struct DiskBVMap
* map
;
473 BVRef booterUFS
= NULL
;
477 // Find an existing mapping for this device.
479 for ( map
= gDiskBVMap
; map
; map
= map
->next
)
481 if ( biosdev
== map
->biosdev
) break;
485 // Create a new mapping.
487 map
= (struct DiskBVMap
*) malloc( sizeof(*map
) );
490 map
->biosdev
= biosdev
;
493 map
->next
= gDiskBVMap
;
496 // Create a record for each partition found on the disk.
498 while ( getNextFDiskPartition( biosdev
, &partno
, &part
) )
500 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__
,
501 partno
, part
->systid
));
505 switch ( part
->systid
)
510 part
->relsect
+ UFS_FRONT_PORCH
/BPS
,
530 if (getDiskGeometry(biosdev
, &spt
, &spc
) != 0)
533 booterUFS
= newFDiskBVRef(
535 ((part
->relsect
+ spc
- 1) / spc
) * spc
,
554 bvr
->next
= map
->bvr
;
560 // Booting from a CD with an UFS filesystem embedded
561 // in a booter partition.
565 if ( map
->bvrcnt
== 0 )
567 map
->bvr
= booterUFS
;
570 else free( booterUFS
);
575 if (countPtr
) *countPtr
= map
? map
->bvrcnt
: 0;
577 return map
? map
->bvr
: NULL
;
580 //==========================================================================
582 static const struct NamedValue fdiskTypes
[] =
584 { 0x07, "Windows NTFS" },
585 { 0x0c, "Windows FAT32" },
587 { FDISK_UFS
, "Apple UFS" },
588 { FDISK_HFS
, "Apple HFS" },
589 { FDISK_BOOTER
, "Apple Boot/UFS" },
590 { 0x00, 0 } /* must be last */
593 static void getVolumeDescription( BVRef bvr
, char * str
, long strMaxLen
)
595 unsigned char type
= (unsigned char) bvr
->part_type
;
596 const char * name
= getNameForValue( fdiskTypes
, type
);
599 sprintf( str
, "hd(%d,%d) %s",
600 BIOS_DEV_UNIT(bvr
->biosdev
), bvr
->part_no
, name
);
602 sprintf( str
, "hd(%d,%d) TYPE %02x",
603 BIOS_DEV_UNIT(bvr
->biosdev
), bvr
->part_no
, type
);
606 //==========================================================================
608 int readBootSector( int biosdev
, unsigned int secno
, void * buffer
)
610 struct disk_blk0
* bootSector
= (struct disk_blk0
*) buffer
;
613 if ( bootSector
== NULL
)
615 if ( gBootSector
== NULL
)
617 gBootSector
= (struct disk_blk0
*) malloc(sizeof(*gBootSector
));
618 if ( gBootSector
== NULL
) return -1;
620 bootSector
= gBootSector
;
623 error
= readBytes( biosdev
, secno
, BPS
, bootSector
);
624 if ( error
|| bootSector
->signature
!= DISK_SIGNATURE
)
630 //==========================================================================
631 // Handle seek request from filesystem modules.
633 void diskSeek( BVRef bvr
, long long position
)
635 bvr
->fs_boff
= position
/ BPS
;
638 //==========================================================================
639 // Handle read request from filesystem modules.
641 int diskRead( BVRef bvr
, long addr
, long length
)
643 return readBytes( bvr
->biosdev
,
644 bvr
->fs_boff
+ bvr
->part_boff
,