/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.1 (the "License"). You may not use this file
+ * Source License Version 2.0 (the "License"). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
* All rights reserved.
*/
-#define DRIVER_PRIVATE
+#define UFS_SUPPORT 1
-#include "sys/types.h"
-#include "legacy/disk.h"
-#include "legacy/fdisk.h"
+#include "bootstruct.h"
#include "libsaio.h"
-#include "memory.h"
-
-/*
- * Type and constant definitions.
- */
-typedef struct disk_blk0 boot_sector;
-#define BOOT_SIGNATURE DISK_SIGNATURE
-#define PART_TYPE_EXT 0x05
-#define PART_TYPE_APPLE 0xa8
-#define UFS_FRONT_PORCH 0
-
-#if DEBUG
-#define DPRINT(x) { printf x; }
-#define DSPRINT(x) { printf x; sleep(1); }
-#else
-#define DPRINT(x)
-#define DSPRINT(x)
+#include "fdisk.h"
+#if UFS_SUPPORT
+#include "ufs.h"
#endif
+#include "hfs.h"
+#include "ntfs.h"
+#include "msdos.h"
-/*
- * Function prototypes.
- */
-extern void spinActivityIndicator();
-static void diskActivityHook();
-static int Biosread(int biosdev, int secno);
-static struct fdisk_part * find_partition(u_int8_t type,
- u_int8_t biosdev,
- BOOL mba);
-
-/*
- * diskinfo unpacking.
- */
-#define SPT(di) ((di) & 0xff)
-#define HEADS(di) ((((di)>>8) & 0xff) + 1)
-#define SPC(di) (SPT(di) * HEADS(di))
-#define BPS 512 /* sector size of the device */
-#define N_CACHE_SECS (BIOS_LEN / BPS)
-
-/*
- * Stores the geometry of the disk in order to
- * perform LBA to CHS translation for non EBIOS calls.
- */
-static struct diskinfo {
- int spt; /* sectors per track */
- int spc; /* sectors per cylinder */
-} diskinfo;
+#include <limits.h>
+#include <IOKit/storage/IOApplePartitionScheme.h>
-/*
- * Globals variables.
- */
-int label_secsize = BPS;
-char * b[NBUFS];
-daddr_t blknos[NBUFS];
-struct iob iob[NFILES];
+#define BPS 512 /* sector size of the device */
+#define CD_BPS 2048 /* CD-ROM block size */
+#define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */
+#define UFS_FRONT_PORCH 0
+#define kAPMSector 2 /* Sector number of Apple partition map */
+#define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
/*
- * intbuf points to the start of the sector cache. BIOS calls will
- * store the sectors read into this memory area. If cache_valid
- * is TRUE, then intbuf contents are valid. Otherwise, ignore the
- * cache and read from disk.
+ * trackbuf points to the start of the track cache. Biosread()
+ * will store the sectors read from disk to this memory area.
*
- * biosbuf points to a sector within the sector cache.
+ * biosbuf points to a sector within the track cache, and is
+ * updated by Biosread().
*/
-static char * const intbuf = (char *)ptov(BIOS_ADDR);
-static BOOL cache_valid = FALSE;
+static char * const trackbuf = (char *) ptov(BIOS_ADDR);
static char * biosbuf;
-/*==========================================================================
- *
+/*
+ * Map a disk drive to bootable volumes contained within.
*/
-void
-devopen(char * name, struct iob * io)
-{
- static int last_biosdev = -1;
- static daddr_t last_offset = 0;
+struct DiskBVMap {
+ int biosdev; // BIOS device number (unique)
+ BVRef bvr; // chain of boot volumes on the disk
+ int bvrcnt; // number of boot volumes
+ struct DiskBVMap * next; // linkage to next mapping
+};
- struct fdisk_part * part;
- long di;
+static struct DiskBVMap * gDiskBVMap = NULL;
+static struct disk_blk0 * gBootSector = NULL;
- io->i_error = 0;
- io->dirbuf_blkno = -1;
+extern void spinActivityIndicator();
- // Use cached values if possible.
- //
- if (io->biosdev == last_biosdev) {
- io->i_boff = last_offset;
- return;
- }
+static void getVolumeDescription(BVRef bvr, char * str, long strMaxLen);
- // initialize disk parameters -- spt and spc
- // must do this before doing reads from the device.
+//==========================================================================
- di = get_diskinfo(io->biosdev);
- if (di == 0) {
- io->i_error = ENXIO;
- return;
+static int getDriveInfo( int biosdev, struct driveInfo *dip )
+{
+ static struct driveInfo cached_di;
+ int cc;
+
+ if ( !cached_di.valid || biosdev != cached_di.biosdev )
+ {
+ cc = get_drive_info(biosdev, &cached_di);
+ if (cc < 0) {
+ cached_di.valid = 0;
+ DEBUG_DISK(("get_drive_info returned error\n"));
+ return (-1); // BIOS call error
+ }
}
- diskinfo.spt = SPT(di);
- diskinfo.spc = diskinfo.spt * HEADS(di);
-
- // FIXME - io->partition is ignored. Doesn't make sense anymore.
- // we also don't overwrite the 'name' argument.
- // Whats special about "$LBL" ?
+ bcopy(&cached_di, dip, sizeof(cached_di));
- part = find_partition(PART_TYPE_APPLE, io->biosdev, FALSE);
- if (part == NULL) {
- io->i_error = EIO;
- DSPRINT(("Unable to find partition: IO error\n"));
- } else {
- last_offset = io->i_boff = part->relsect + UFS_FRONT_PORCH/BPS;
- last_biosdev = io->biosdev;
- DSPRINT(("partition offset: %x\n", io->i_boff));
- }
+ return 0;
}
-/*==========================================================================
- *
- */
-void devflush()
-{
- cache_valid = FALSE; // invalidate the sector cache (intbuf)
-}
-
-/*==========================================================================
- *
- */
-int devread(struct iob * io)
-{
- long sector;
- int offset;
-// int dev;
-
- io->i_flgs |= F_RDDATA;
-
- io->i_error = 0; // assume the best
+//==========================================================================
+// Maps (E)BIOS return codes to message strings.
-// dev = io->i_ino.i_dev;
-
- sector = io->i_bn * (label_secsize/BPS);
-
- for (offset = 0; offset < io->i_cc; offset += BPS) {
-
- io->i_error = Biosread(io->biosdev, sector);
- if (io->i_error)
- return (-1);
-
- /* copy 1 sector from the internal buffer biosbuf into buf */
- bcopy(biosbuf, &io->i_ma[offset], BPS);
+struct NamedValue {
+ unsigned char value;
+ const char * name;
+};
- sector++;
- }
+static const char * getNameForValue( const struct NamedValue * nameTable,
+ unsigned char value )
+{
+ const struct NamedValue * np;
- io->i_flgs &= ~F_TYPEMASK;
+ for ( np = nameTable; np->value; np++)
+ if (np->value == value)
+ return np->name;
- return (io->i_cc);
+ return NULL;
}
-/*==========================================================================
- * Maps (E)BIOS return codes to message strings.
- */
-struct bios_error_info {
- int errno;
- const char * string;
-};
-
#define ECC_CORRECTED_ERR 0x11
-static struct bios_error_info bios_errors[] = {
- {0x10, "Media error"},
- {0x11, "Corrected ECC error"},
- {0x20, "Controller or device error"},
- {0x40, "Seek failed"},
- {0x80, "Device timeout"},
- {0xAA, "Drive not ready"},
- {0x00, 0}
+static const struct NamedValue bios_errors[] = {
+ { 0x10, "Media error" },
+ { 0x11, "Corrected ECC error" },
+ { 0x20, "Controller or device error" },
+ { 0x40, "Seek failed" },
+ { 0x80, "Device timeout" },
+ { 0xAA, "Drive not ready" },
+ { 0x00, 0 }
};
-static const char *
-bios_error(int errno)
+static const char * bios_error(int errnum)
{
- struct bios_error_info * bp;
-
- for (bp = bios_errors; bp->errno; bp++) {
- if (bp->errno == errno)
- return bp->string;
- }
- return "Error 0x%02x"; // No string, print error code only
+ static char errorstr[] = "Error 0x00";
+ const char * errname;
+
+ errname = getNameForValue( bios_errors, errnum );
+ if ( errname ) return errname;
+
+ sprintf(errorstr, "Error 0x%02x", errnum);
+ return errorstr; // No string, print error code only
}
-/*==========================================================================
- * Use BIOS INT13 calls to read the sector specified. This function will
- * also perform read-ahead to cache a few subsequent sector to the sector
- * cache.
- *
- * The fields in diskinfo structure must be filled in before calling this
- * function.
- *
- * Return:
- * Return code from INT13/F2 or INT13/F42 call. If operation was
- * successful, 0 is returned.
- *
- */
-static int
-Biosread(int biosdev, int secno)
+//==========================================================================
+// Use BIOS INT13 calls to read the sector specified. This function will
+// also perform read-ahead to cache a few subsequent sector to the sector
+// cache.
+//
+// Return:
+// 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
+
+static BOOL cache_valid = FALSE;
+
+static int Biosread( int biosdev, unsigned int secno )
{
- static int xbiosdev, xcyl, xhead, xsec, xnsecs;
-
- extern unsigned char uses_ebios[];
+ static int xbiosdev, xcyl, xhead;
+ static unsigned int xsec, xnsecs;
+ struct driveInfo di;
- int rc;
+ int rc = -1;
int cyl, head, sec;
- int spt, spc;
int tries = 0;
+ int bps, divisor;
- DSPRINT(("Biosread %d \n", secno));
+ if (getDriveInfo(biosdev, &di) < 0) {
+ return -1;
+ }
+ if (di.no_emulation) {
+ /* Always assume 2k block size; BIOS may lie about geometry */
+ bps = 2048;
+ } else {
+ bps = di.di.params.phys_nbps;
+ if (bps == 0) {
+ return -1;
+ }
+ }
+ divisor = bps / BPS;
+
+ DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));
// To read the disk sectors, use EBIOS if we can. Otherwise,
// revert to the standard BIOS calls.
- //
- if ((biosdev >= BIOS_DEV_HD) && uses_ebios[biosdev - BIOS_DEV_HD]) {
+
+ if ((biosdev >= kBIOSDevTypeHardDrive) &&
+ (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))
+ {
if (cache_valid &&
(biosdev == xbiosdev) &&
(secno >= xsec) &&
- (secno < (xsec + xnsecs)))
+ ((unsigned int)secno < (xsec + xnsecs)))
{
- biosbuf = intbuf + (BPS * (secno - xsec));
+ biosbuf = trackbuf + (BPS * (secno - xsec));
return 0;
}
xnsecs = N_CACHE_SECS;
- xsec = secno;
+ xsec = (secno / divisor) * divisor;
+ cache_valid = FALSE;
- while ((rc = ebiosread(biosdev, secno, xnsecs)) && (++tries < 5))
+ while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))
{
if (rc == ECC_CORRECTED_ERR) {
/* Ignore corrected ECC errors */
+ rc = 0;
break;
}
error(" EBIOS read error: %s\n", bios_error(rc), rc);
sleep(1);
}
}
- else {
- spt = diskinfo.spt; // From previous INT13/F8 call.
- spc = diskinfo.spc;
-
+ else
+ {
+ /* spc = spt * heads */
+ int spc = (di.di.params.phys_spt * di.di.params.phys_heads);
cyl = secno / spc;
- head = (secno % spc) / spt;
- sec = secno % spt;
+ head = (secno % spc) / di.di.params.phys_spt;
+ sec = secno % di.di.params.phys_spt;
if (cache_valid &&
(biosdev == xbiosdev) &&
(cyl == xcyl) &&
(head == xhead) &&
- (sec >= xsec) &&
- (sec < (xsec + xnsecs)))
+ ((unsigned int)sec >= xsec) &&
+ ((unsigned int)sec < (xsec + xnsecs)))
{
- // this sector is in intbuf cache
- biosbuf = intbuf + (BPS * (sec - xsec));
+ // this sector is in trackbuf cache
+ biosbuf = trackbuf + (BPS * (sec - xsec));
return 0;
}
// Cache up to a track worth of sectors, but do not cross a
// track boundary.
- //
+
xcyl = cyl;
xhead = head;
xsec = sec;
- xnsecs = ((sec + N_CACHE_SECS) > spt) ? (spt - sec) : N_CACHE_SECS;
+ xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;
+ cache_valid = FALSE;
while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) &&
(++tries < 5))
{
if (rc == ECC_CORRECTED_ERR) {
/* Ignore corrected ECC errors */
+ rc = 0;
break;
}
error(" BIOS read error: %s\n", bios_error(rc), rc);
}
// If the BIOS reported success, mark the sector cache as valid.
- //
+
if (rc == 0) {
cache_valid = TRUE;
}
- biosbuf = intbuf;
+ biosbuf = trackbuf + (secno % divisor) * BPS;
xbiosdev = biosdev;
- diskActivityHook();
+ spinActivityIndicator();
return rc;
}
-/*==========================================================================
- * Replace this function if you want to change
- * the way disk activity is indicated to the user.
- */
-void
-diskActivityHook(void)
+//==========================================================================
+
+static int readBytes( int biosdev, unsigned int blkno,
+ unsigned int byteoff,
+ unsigned int byteCount, void * buffer )
{
- spinActivityIndicator();
+
+ char * cbuf = (char *) buffer;
+ int error;
+ int copy_len;
+
+ DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__,
+ biosdev, blkno, byteCount, (unsigned)cbuf));
+
+ for ( ; byteCount; cbuf += copy_len, blkno++ )
+ {
+ error = Biosread( biosdev, blkno );
+ if ( error )
+ {
+ DEBUG_DISK(("error\n"));
+ return (-1);
+ }
+
+ copy_len = ((byteCount + byteoff) > BPS) ? (BPS - byteoff) : byteCount;
+ bcopy( biosbuf + byteoff, cbuf, copy_len );
+ byteCount -= copy_len;
+ byteoff = 0;
+ }
+
+ DEBUG_DISK(("done\n"));
+
+ return 0;
}
-/*==========================================================================
- * Returns YES if the partition type specified is an extended fdisk
- * partition.
- */
-static BOOL
-isExtendedPartition(u_int8_t type)
+//==========================================================================
+
+static int isExtendedFDiskPartition( const struct fdisk_part * part )
{
- int i;
-
- u_int8_t extended_partitions[] = {
- 0x05, /* Extended */
- 0x0f, /* Win95 extended */
- 0x85, /* Linux extended */
- };
-
- for (i = 0;
- i < sizeof(extended_partitions)/sizeof(extended_partitions[0]);
- i++)
- {
- if (extended_partitions[i] == type)
- return YES;
- }
- return NO;
+ static unsigned char extParts[] =
+ {
+ 0x05, /* Extended */
+ 0x0f, /* Win95 extended */
+ 0x85, /* Linux extended */
+ };
+
+ unsigned int i;
+
+ for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)
+ {
+ if (extParts[i] == part->systid) return 1;
+ }
+ return 0;
}
-/*==========================================================================
- * Traverse the fdisk partition tables on disk until a partition is found
- * that matches the specified type.
- *
- * Arguments:
- * type - Partition type to search for (e.g. 0xa7 for NeXTSTEP).
- * biosdev - BIOS device unit. 0x80 and up for hard-drive.
- * mba - If true, the partition found must be marked active.
- *
- * Return:
- * A pointer to the matching partition entry in biosbuf memory.
- * Note that the starting LBA field in the partition entry is
- * modified to contain the absolute sector address, rather than
- * the relative address.
- * A NULL is returned if a match is not found.
- *
- * There are certain fdisk rules that allows us to simplify the search.
- *
- * - There can be 0-1 extended partition entry in any partition table.
- * - In the MBR, there can be 0-4 primary partitions entries.
- * - In the extended partition, there can be 0-1 logical partition entry.
- *
- */
-struct fdisk_part *
-find_partition(u_int8_t type, u_int8_t biosdev, BOOL mba)
+//==========================================================================
+
+static int getNextFDiskPartition( int biosdev, int * partno,
+ const struct fdisk_part ** outPart )
{
-#define MAX_ITERATIONS 128
+ static int sBiosdev = -1;
+ static int sNextPartNo;
+ static unsigned int sFirstBase;
+ static unsigned int sExtBase;
+ static unsigned int sExtDepth;
+ static struct fdisk_part * sExtPart;
+ struct fdisk_part * part;
+
+ if ( sBiosdev != biosdev || *partno < 0 )
+ {
+ // Fetch MBR.
+ if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0;
+
+ sBiosdev = biosdev;
+ sNextPartNo = 0;
+ sFirstBase = 0;
+ sExtBase = 0;
+ sExtDepth = 0;
+ sExtPart = NULL;
+ }
- static u_int32_t iter = 0;
- static u_int32_t offset_root;
- static u_int32_t offset;
+ while (1)
+ {
+ part = NULL;
- int n;
- int rc;
- boot_sector * bootsect;
- struct fdisk_part * match = 0;
- struct fdisk_part * parts;
+ if ( sNextPartNo < FDISK_NPART )
+ {
+ part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];
+ }
+ else if ( sExtPart )
+ {
+ unsigned int blkno = sExtPart->relsect + sFirstBase;
- if (iter == 0) {
- if (rc = Biosread(biosdev, 0)) // Read MBR at sector zero.
- return 0;
- offset = 0;
- }
+ // Save the block offset of the first extended partition.
- bootsect = (boot_sector *) biosbuf;
- if (bootsect->signature != BOOT_SIGNATURE)
- return 0;
+ if (sExtDepth == 0) {
+ sFirstBase = blkno;
+ }
+ sExtBase = blkno;
- // Find a primary or a logical partition that matches the partition
- // type specified.
- //
- for (n = 0, parts = (struct fdisk_part *) bootsect->parts;
- n < 4;
- n++, parts++)
- {
- DSPRINT(("fdisk: [%d] %02x\n", iter, parts->systid));
+ // Load extended partition table.
+
+ if ( readBootSector( biosdev, blkno, 0 ) == 0 )
+ {
+ sNextPartNo = 0;
+ sExtDepth++;
+ sExtPart = NULL;
+ continue;
+ }
+ // Fall through to part == NULL
+ }
+
+ if ( part == NULL ) break; // Reached end of partition chain.
+
+ // Advance to next partition number.
+
+ sNextPartNo++;
+
+ if ( isExtendedFDiskPartition(part) )
+ {
+ sExtPart = part;
+ continue;
+ }
+
+ // Skip empty slots.
- if (mba && ((parts->bootid & 0x80) == 0))
+ if ( part->systid == 0x00 )
+ {
continue;
+ }
- if (parts->systid == type) {
- //
- // Found it!!!
- // Make the relsect field (LBA starting sector) absolute by
- // adding in the offset.
- //
- parts->relsect += offset;
+ // Change relative offset to an absolute offset.
+ part->relsect += sExtBase;
- DSPRINT(("Found: %x (%d)\n", parts->relsect, parts->numsect));
+ *outPart = part;
+ *partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;
- return parts;
+ break;
+ }
+
+ return (part != NULL);
+}
+
+//==========================================================================
+
+static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,
+ const struct fdisk_part * part,
+ FSInit initFunc, FSLoadFile loadFunc,
+ FSReadFile readFunc,
+ FSGetDirEntry getdirFunc,
+ FSGetFileBlock getBlockFunc,
+ FSGetUUID getUUIDFunc,
+ BVGetDescription getDescriptionFunc,
+ int probe, int type )
+{
+ BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
+ if ( bvr )
+ {
+ bzero(bvr, sizeof(*bvr));
+
+ bvr->biosdev = biosdev;
+ bvr->part_no = partno;
+ bvr->part_boff = blkoff;
+ bvr->part_type = part->systid;
+ bvr->fs_loadfile = loadFunc;
+ bvr->fs_readfile = readFunc;
+ bvr->fs_getdirentry = getdirFunc;
+ bvr->fs_getfileblock= getBlockFunc;
+ bvr->fs_getuuid = getUUIDFunc;
+ bvr->description = getDescriptionFunc ?
+ getDescriptionFunc : getVolumeDescription;
+ bvr->type = type;
+
+ if ( part->bootid & FDISK_ACTIVE )
+ bvr->flags |= kBVFlagPrimary;
+
+ // Probe the filesystem.
+
+ if ( initFunc )
+ {
+ bvr->flags |= kBVFlagNativeBoot;
+
+ if ( probe && initFunc( bvr ) != 0 )
+ {
+ // filesystem probe failed.
+
+ DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
+ __FUNCTION__, biosdev, partno));
+
+ free(bvr);
+ bvr = NULL;
+ }
+ }
+ else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
+ {
+ bvr->flags |= kBVFlagForeignBoot;
+ }
+ else
+ {
+ free(bvr);
+ bvr = NULL;
}
}
+ return bvr;
+}
- // Find if there is an extended partition entry that points to
- // an extended partition table. Note that we only allow up to
- // one extended partition per partition table.
- //
- for (n = 0, parts = (struct fdisk_part *) bootsect->parts;
- n < 4;
- n++, parts++)
+//==========================================================================
+
+BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,
+ const DPME * part,
+ FSInit initFunc, FSLoadFile loadFunc,
+ FSReadFile readFunc,
+ FSGetDirEntry getdirFunc,
+ FSGetFileBlock getBlockFunc,
+ FSGetUUID getUUIDFunc,
+ BVGetDescription getDescriptionFunc,
+ int probe, int type )
+{
+ BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
+ if ( bvr )
{
- DSPRINT(("fdisk: [E%d] %02x\n", iter, parts->systid));
+ bzero(bvr, sizeof(*bvr));
+
+ bvr->biosdev = biosdev;
+ bvr->part_no = partno;
+ bvr->part_boff = blkoff;
+ bvr->fs_loadfile = loadFunc;
+ bvr->fs_readfile = readFunc;
+ bvr->fs_getdirentry = getdirFunc;
+ bvr->fs_getfileblock= getBlockFunc;
+ bvr->fs_getuuid = getUUIDFunc;
+ bvr->description = getDescriptionFunc ?
+ getDescriptionFunc : getVolumeDescription;
+ bvr->type = type;
+ strlcpy(bvr->name, part->dpme_name, DPISTRLEN);
+ strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);
+
+ /*
+ if ( part->bootid & FDISK_ACTIVE )
+ bvr->flags |= kBVFlagPrimary;
+ */
+
+ // Probe the filesystem.
+
+ if ( initFunc )
+ {
+ bvr->flags |= kBVFlagNativeBoot;
- if (isExtendedPartition(parts->systid))
+ if ( probe && initFunc( bvr ) != 0 )
+ {
+ // filesystem probe failed.
+
+ DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
+ __FUNCTION__, biosdev, partno));
+
+ free(bvr);
+ bvr = NULL;
+ }
+ }
+ /*
+ else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
{
- if (iter > MAX_ITERATIONS) // limit recursion depth
- return 0;
+ bvr->flags |= kBVFlagForeignBoot;
+ }
+ */
+ else
+ {
+ free(bvr);
+ bvr = NULL;
+ }
+ }
+ return bvr;
+}
- if (iter == 0)
- offset = offset_root = parts->relsect;
- else
- offset = parts->relsect + offset_root;
+//==========================================================================
- iter++;
+/* A note on partition numbers:
+ * IOKit makes the primary partitions numbers 1-4, and then
+ * extended partitions are numbered consecutively 5 and up.
+ * So, for example, if you have two primary partitions and
+ * one extended partition they will be numbered 1, 2, 5.
+ */
- // Load extended partition table.
- //
- if (((rc = Biosread(biosdev, offset)) == 0) &&
- (bootsect->signature == BOOT_SIGNATURE))
+static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
+{
+ const struct fdisk_part * part;
+ struct DiskBVMap * map;
+ int partno = -1;
+ BVRef bvr;
+#if UFS_SUPPORT
+ BVRef booterUFS = NULL;
+#endif
+ int spc;
+ struct driveInfo di;
+ boot_drive_info_t *dp;
+
+ /* Initialize disk info */
+ if (getDriveInfo(biosdev, &di) != 0) {
+ return NULL;
+ }
+ dp = &di.di;
+ spc = (dp->params.phys_spt * dp->params.phys_heads);
+ if (spc == 0) {
+ /* This is probably a CD-ROM; punt on the geometry. */
+ spc = 1;
+ }
+
+ do {
+ // Create a new mapping.
+
+ map = (struct DiskBVMap *) malloc( sizeof(*map) );
+ if ( map )
+ {
+ map->biosdev = biosdev;
+ map->bvr = NULL;
+ map->bvrcnt = 0;
+ map->next = gDiskBVMap;
+ gDiskBVMap = map;
+
+ // Create a record for each partition found on the disk.
+
+ while ( getNextFDiskPartition( biosdev, &partno, &part ) )
{
- match = find_partition(type, biosdev, mba);
+ DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
+ partno, part->systid));
+ bvr = 0;
+
+ switch ( part->systid )
+ {
+#if UFS_SUPPORT
+ case FDISK_UFS:
+ bvr = newFDiskBVRef(
+ biosdev, partno,
+ part->relsect + UFS_FRONT_PORCH/BPS,
+ part,
+ UFSInitPartition,
+ UFSLoadFile,
+ UFSReadFile,
+ UFSGetDirEntry,
+ UFSGetFileBlock,
+ UFSGetUUID,
+ UFSGetDescription,
+ 0,
+ kBIOSDevTypeHardDrive);
+ break;
+#endif
+
+ case FDISK_HFS:
+ bvr = newFDiskBVRef(
+ biosdev, partno,
+ part->relsect,
+ part,
+ HFSInitPartition,
+ HFSLoadFile,
+ HFSReadFile,
+ HFSGetDirEntry,
+ HFSGetFileBlock,
+ HFSGetUUID,
+ HFSGetDescription,
+ 0,
+ kBIOSDevTypeHardDrive);
+ break;
+
+#if UFS_SUPPORT
+ case FDISK_BOOTER:
+ booterUFS = newFDiskBVRef(
+ biosdev, partno,
+ ((part->relsect + spc - 1) / spc) * spc,
+ part,
+ UFSInitPartition,
+ UFSLoadFile,
+ UFSReadFile,
+ UFSGetDirEntry,
+ UFSGetFileBlock,
+ UFSGetUUID,
+ UFSGetDescription,
+ 0,
+ kBIOSDevTypeHardDrive);
+ break;
+#endif
+
+ case FDISK_NTFS:
+ bvr = newFDiskBVRef(
+ biosdev, partno,
+ part->relsect,
+ part,
+ 0, 0, 0, 0, 0, 0,
+ NTFSGetDescription,
+ 0,
+ kBIOSDevTypeHardDrive);
+ break;
+
+ default:
+ bvr = newFDiskBVRef(
+ biosdev, partno,
+ part->relsect,
+ part,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ kBIOSDevTypeHardDrive);
+ break;
+ }
+
+ if ( bvr )
+ {
+ bvr->next = map->bvr;
+ map->bvr = bvr;
+ map->bvrcnt++;
+ }
}
-
- iter--;
- break;
+#if UFS_SUPPORT
+ // Booting from a CD with an UFS filesystem embedded
+ // in a booter partition.
+
+ if ( booterUFS )
+ {
+ if ( map->bvrcnt == 0 )
+ {
+ map->bvr = booterUFS;
+ map->bvrcnt++;
+ }
+ else free( booterUFS );
+ }
+#endif
}
+ } while (0);
+
+ /*
+ * If no FDisk partition, then we will check for
+ * an Apple partition map elsewhere.
+ */
+#if UNUSED
+ if (map->bvrcnt == 0) {
+ static struct fdisk_part cdpart;
+ cdpart.systid = 0xCD;
+
+ /* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
+ bvr = newFDiskBVRef(
+ biosdev, 0,
+ 0,
+ &cdpart,
+ HFSInitPartition,
+ HFSLoadFile,
+ HFSReadFile,
+ HFSGetDirEntry,
+ HFSGetFileBlock,
+ HFSGetUUID,
+ 0,
+ kBIOSDevTypeHardDrive);
+ bvr->next = map->bvr;
+ map->bvr = bvr;
+ map->bvrcnt++;
+ }
+#endif
+
+ if (countPtr) *countPtr = map ? map->bvrcnt : 0;
+
+ return map ? map->bvr : NULL;
+}
+
+//==========================================================================
+
+static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
+{
+ struct DiskBVMap * map;
+ struct Block0 *block0_p;
+ unsigned int blksize;
+ unsigned int factor;
+ void *buffer = malloc(BPS);
+
+ /* Check for alternate block size */
+ if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
+ return NULL;
+ }
+ block0_p = buffer;
+ if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
+ blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
+ if (blksize != BPS) {
+ free(buffer);
+ buffer = malloc(blksize);
+ }
+ factor = blksize / BPS;
+ } else {
+ blksize = BPS;
+ factor = 1;
}
- return match;
+ do {
+ // Create a new mapping.
+
+ map = (struct DiskBVMap *) malloc( sizeof(*map) );
+ if ( map )
+ {
+ int error;
+ DPME *dpme_p = (DPME *)buffer;
+ UInt32 i, npart = UINT_MAX;
+ BVRef bvr;
+
+ map->biosdev = biosdev;
+ map->bvr = NULL;
+ map->bvrcnt = 0;
+ map->next = gDiskBVMap;
+ gDiskBVMap = map;
+
+ for (i=0; i<npart; i++) {
+ error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
+
+ if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
+ break;
+ }
+
+ if (i==0) {
+ npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
+ }
+ /*
+ printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
+ dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
+ dpme.dpme_pblock_start, dpme.dpme_pblocks,
+ dpme.dpme_lblock_start, dpme.dpme_lblocks,
+ dpme.dpme_boot_block);
+ */
+
+ if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
+ bvr = newAPMBVRef(biosdev,
+ i,
+ OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
+ dpme_p,
+ HFSInitPartition,
+ HFSLoadFile,
+ HFSReadFile,
+ HFSGetDirEntry,
+ HFSGetFileBlock,
+ HFSGetUUID,
+ HFSGetDescription,
+ 0,
+ kBIOSDevTypeHardDrive);
+ bvr->next = map->bvr;
+ map->bvr = bvr;
+ map->bvrcnt++;
+ }
+ }
+ }
+ } while (0);
+
+ free(buffer);
+
+ if (countPtr) *countPtr = map ? map->bvrcnt : 0;
+
+ return map ? map->bvr : NULL;
+}
+
+//==========================================================================
+
+BVRef diskScanBootVolumes( int biosdev, int * countPtr )
+{
+ struct DiskBVMap * map;
+ BVRef bvr;
+ int count = 0;
+
+ // Find an existing mapping for this device.
+
+ for ( map = gDiskBVMap; map; map = map->next ) {
+ if ( biosdev == map->biosdev ) {
+ count = map->bvrcnt;
+ break;
+ }
+ }
+
+ if (map == NULL) {
+ bvr = diskScanFDiskBootVolumes(biosdev, &count);
+ if (bvr == NULL) {
+ bvr = diskScanAPMBootVolumes(biosdev, &count);
+ }
+ } else {
+ bvr = map->bvr;
+ }
+ if (countPtr) *countPtr = count;
+ return bvr;
+}
+
+
+//==========================================================================
+
+static const struct NamedValue fdiskTypes[] =
+{
+ { FDISK_NTFS, "Windows NTFS" },
+ { FDISK_FAT32, "Windows FAT32" },
+ { 0x83, "Linux" },
+ { FDISK_UFS, "Apple UFS" },
+ { FDISK_HFS, "Apple HFS" },
+ { FDISK_BOOTER, "Apple Boot/UFS" },
+ { 0xCD, "CD-ROM" },
+ { 0x00, 0 } /* must be last */
+};
+
+//==========================================================================
+
+void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, BOOL verbose )
+{
+ unsigned char type = (unsigned char) bvr->part_type;
+ const char * name = getNameForValue( fdiskTypes, type );
+ char *p;
+
+ if (name == NULL)
+ name = bvr->type_name;
+
+ p = str;
+ if ( name && verbose ) {
+ sprintf( str, "hd(%d,%d) ",
+ BIOS_DEV_UNIT(bvr), bvr->part_no);
+ for (; strMaxLen > 0 && *p != '\0'; p++, strMaxLen--);
+ } else {
+ *p = '\0';
+ }
+ bvr->description(bvr, p, strMaxLen);
+ if (*p == '\0') {
+ const char * name = getNameForValue( fdiskTypes, type );
+ if (name == NULL) {
+ name = bvr->type_name;
+ }
+ if (name == NULL) {
+ sprintf(p, "TYPE %02x", type);
+ } else {
+ strncpy(p, name, strMaxLen);
+ }
+ }
+}
+
+#if UNUSED
+//==========================================================================
+
+static int
+getFAT32VolumeDescription( BVRef bvr, char *str, long strMaxLen)
+{
+ struct fat32_header {
+ unsigned char code[3];
+ unsigned char oem_id[8];
+ unsigned char data[56];
+ unsigned long serial;
+ unsigned char label[11];
+ unsigned char fsid[8];
+ unsigned char reserved[420];
+ unsigned short signature;
+ } __attribute__((packed));
+
+ char *buf, *name;
+ struct fat32_header *fat32_p;
+ int label_len = sizeof(fat32_p->label);
+ int error;
+
+ buf = (char *)malloc(BPS);
+ name = (char *)malloc(label_len + 1);
+ fat32_p = (struct fat32_header *)buf;
+
+ diskSeek(bvr, 0ULL);
+ error = diskRead(bvr, (long)buf, BPS);
+ if ( error ) return 0;
+
+ if (fat32_p->signature != 0xaa55) return 0;
+
+ if (strMaxLen < label_len) label_len = strMaxLen;
+ strncpy(str, fat32_p->label, label_len);
+ str[label_len] = '\0';
+ return 1;
+}
+#endif
+
+//==========================================================================
+
+static void getVolumeDescription( BVRef bvr, char * str, long strMaxLen )
+{
+ unsigned char type = (unsigned char) bvr->part_type;
+ const char * name = NULL;
+
+ /* First try a few types that we can figure out the
+ * volume description.
+ */
+ switch(type) {
+ case FDISK_FAT32:
+ str[0] = '\0';
+ MSDOSGetDescription(bvr, str, strMaxLen);
+ if (str[0] != '\0')
+ return;
+ break;
+
+ default: // Not one of our known types
+ break;
+ }
+
+ if (name == NULL)
+ name = getNameForValue( fdiskTypes, type );
+
+ if (name == NULL)
+ name = bvr->type_name;
+
+ if ( name )
+ strncpy( str, name, strMaxLen);
+ else
+ sprintf( str, "TYPE %02x", type);
+}
+
+
+//==========================================================================
+
+int readBootSector( int biosdev, unsigned int secno, void * buffer )
+{
+ struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
+ int error;
+
+ if ( bootSector == NULL )
+ {
+ if ( gBootSector == NULL )
+ {
+ gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
+ if ( gBootSector == NULL ) return -1;
+ }
+ bootSector = gBootSector;
+ }
+
+ error = readBytes( biosdev, secno, 0, BPS, bootSector );
+ if ( error || bootSector->signature != DISK_SIGNATURE )
+ return -1;
+
+ return 0;
+}
+
+//==========================================================================
+// Handle seek request from filesystem modules.
+
+void diskSeek( BVRef bvr, long long position )
+{
+ bvr->fs_boff = position / BPS;
+ bvr->fs_byteoff = position % BPS;
+}
+
+//==========================================================================
+// Handle read request from filesystem modules.
+
+int diskRead( BVRef bvr, long addr, long length )
+{
+ return readBytes( bvr->biosdev,
+ bvr->fs_boff + bvr->part_boff,
+ bvr->fs_byteoff,
+ length,
+ (void *) addr );
+}
+
+int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
+{
+ int secs;
+ unsigned char *cbuf = (unsigned char *)buffer;
+ unsigned int copy_len;
+ int rc;
+
+ if ((len & (BPS-1)) != 0) {
+ error("raw disk read not sector aligned");
+ return -1;
+ }
+ secno += bvr->part_boff;
+
+ cache_valid = FALSE;
+
+ while (len > 0) {
+ secs = len / BPS;
+ if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
+ copy_len = secs * BPS;
+
+ //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
+ if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
+ /* Ignore corrected ECC errors */
+ if (rc != ECC_CORRECTED_ERR) {
+ error(" EBIOS read error: %s\n", bios_error(rc), rc);
+ error(" Block %d Sectors %d\n", secno, secs);
+ return rc;
+ }
+ }
+ bcopy( trackbuf, cbuf, copy_len );
+ len -= copy_len;
+ cbuf += copy_len;
+ secno += secs;
+ spinActivityIndicator();
+ }
+
+ return 0;
+}
+
+int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
+{
+ int secs;
+ unsigned char *cbuf = (unsigned char *)buffer;
+ unsigned int copy_len;
+ int rc;
+
+ if ((len & (BPS-1)) != 0) {
+ error("raw disk write not sector aligned");
+ return -1;
+ }
+ secno += bvr->part_boff;
+
+ cache_valid = FALSE;
+
+ while (len > 0) {
+ secs = len / BPS;
+ if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
+ copy_len = secs * BPS;
+
+ bcopy( cbuf, trackbuf, copy_len );
+ //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
+ if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
+ error(" EBIOS write error: %s\n", bios_error(rc), rc);
+ error(" Block %d Sectors %d\n", secno, secs);
+ return rc;
+ }
+ len -= copy_len;
+ cbuf += copy_len;
+ secno += secs;
+ spinActivityIndicator();
+ }
+
+ return 0;
+}
+
+
+int diskIsCDROM(BVRef bvr)
+{
+ struct driveInfo di;
+
+ if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
+ return 1;
+ }
+ return 0;
}