| #include "disk.h"␊ |
| // For EFI_GUID␊ |
| #include "efi.h"␊ |
| #include "efi_tables.h"␊ |
| ␊ |
| ␊ |
| typedef struct gpt_hdr gpt_hdr;␊ |
| typedef struct gpt_ent gpt_ent;␊ |
| ␊ |
| #include "efi_tables.h"␊ |
| ␊ |
| #define PROBEFS_SIZE BPS * 4 /* buffer size for filesystem probe */␊ |
| #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 kAPMSector 2 /* Sector number of Apple partition map */␊ |
| #define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */␊ |
| ␊ |
| /*␊ |
| * IORound and IOTrunc convenience functions, in the spirit␊ |
| * of vm's round_page() and trunc_page().␊ |
| */␊ |
| #define IORound(value,multiple) \␊ |
| ((((value) + (multiple) - 1) / (multiple)) * (multiple))␊ |
| // IORound and IOTrunc convenience functions, in the spirit of vm's round_page() and trunc_page().␊ |
| #define IORound(value, multiple) ((((value) + (multiple) - 1) / (multiple)) * (multiple))␊ |
| #define IOTrunc(value, multiple) (((value) / (multiple)) * (multiple));␊ |
| ␊ |
| #define IOTrunc(value,multiple) \␊ |
| (((value) / (multiple)) * (multiple));␊ |
| // trackbuf points to the start of the track cache. Biosread() ␊ |
| // will store the sectors read from disk to this memory area.␊ |
| static char * const trackbuf = (char *) ptov(BIOS_ADDR);␊ |
| ␊ |
| /*␊ |
| * 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 track cache, and is␊ |
| * updated by Biosread().␊ |
| */␊ |
| static char * const trackbuf = (char *) ptov(BIOS_ADDR);␊ |
| // biosbuf points to a sector within the track cache, and is updated by Biosread().␊ |
| static char * biosbuf;␊ |
| ␊ |
| /*␊ |
| * Map a disk drive to bootable volumes contained within.␊ |
| */␊ |
| 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␊ |
| // Map a disk drive to bootable volumes contained within.␊ |
| 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.␊ |
| };␊ |
| ␊ |
| static struct DiskBVMap * gDiskBVMap = NULL;␊ |
| static struct disk_blk0 * gBootSector = NULL;␊ |
| ␊ |
| // Function pointers to be filled in if ramdisks are available:␊ |
| int (*p_ramdiskReadBytes)( int biosdev, unsigned int blkno,␊ |
| unsigned int byteoff,␊ |
| unsigned int byteCount, void * buffer ) = NULL;␊ |
| // Function pointers to be filled in when a ramdisk is available:␊ |
| int (*p_ramdiskReadBytes)(int biosdev, unsigned int blkno, unsigned int byteoff, unsigned int byteCount, void * buffer) = NULL;␊ |
| int (*p_get_ramdisk_info)(int biosdev, struct driveInfo *dip) = NULL;␊ |
| ␊ |
| static bool getOSVersion(BVRef bvr, char *str);␊ |
|
| ␊ |
| //==========================================================================␊ |
| ␊ |
| static int getDriveInfo( int biosdev, struct driveInfo *dip )␊ |
| static int getDriveInfo(int biosdev, struct driveInfo *dip)␊ |
| {␊ |
| static struct driveInfo cached_di;␊ |
| int cc;␊ |
| ␊ |
| // Real BIOS devices are 8-bit, so anything above that is for internal use.␊ |
| // Don't cache ramdisk drive info since it doesn't require several BIOS␊ |
| // calls and is thus not worth it.␊ |
| if(biosdev >= 0x100)␊ |
| {␊ |
| if(p_get_ramdisk_info != NULL)␊ |
| cc = (*p_get_ramdisk_info)(biosdev, dip);␊ |
| else␊ |
| cc = -1;␊ |
| if(cc < 0)␊ |
| {␊ |
| dip->valid = 0;␊ |
| return -1;␊ |
| }␊ |
| else␊ |
| return 0;␊ |
| }␊ |
| ␉static struct driveInfo cached_di;␊ |
| ␉int cc;␊ |
| ␊ |
| if ( !cached_di.valid || biosdev != cached_di.biosdev )␊ |
| {␊ |
| ␉// Real BIOS devices are 8-bit, so anything above that is for internal use.␊ |
| ␉// Don't cache ramdisk drive info since it doesn't require several BIOS␊ |
| ␉// calls and is thus not worth it.␊ |
| ␉if (biosdev >= 0x100)␊ |
| ␉{␊ |
| ␉␉if (p_get_ramdisk_info != NULL)␊ |
| ␉␉{␊ |
| ␉␉␉cc = (*p_get_ramdisk_info)(biosdev, dip);␊ |
| ␉␉}␊ |
| ␉␉else␊ |
| ␉␉{␊ |
| ␉␉␉cc = -1;␊ |
| ␉␉}␊ |
| ␉␉if (cc < 0)␊ |
| ␉␉{␊ |
| ␉␉␉dip->valid = 0;␊ |
| ␉␉␉return -1;␊ |
| ␉␉}␊ |
| ␉␉else␊ |
| ␉␉{␊ |
| ␉␉␉return 0;␊ |
| ␉␉}␊ |
| ␉}␊ |
| ␊ |
| ␉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␊ |
| ␊ |
| ␉␉if (cc < 0)␊ |
| ␉␉{␊ |
| ␉␉␉cached_di.valid = 0;␊ |
| ␉␉␉DEBUG_DISK(("get_drive_info returned error\n"));␊ |
| ␉␉␉return (-1); // BIOS call error␊ |
| ␉␉}␊ |
| ␉}␊ |
| }␊ |
| ␊ |
| bcopy(&cached_di, dip, sizeof(cached_di));␊ |
| ␉bcopy(&cached_di, dip, sizeof(cached_di));␊ |
| ␊ |
| return 0;␊ |
| ␉return 0;␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
| // Maps (E)BIOS return codes to message strings.␊ |
| ␊ |
| struct NamedValue {␊ |
| unsigned char value;␊ |
| const char * name;␊ |
| struct NamedValue␊ |
| {␊ |
| ␉unsigned char value;␊ |
| ␉const char * name;␊ |
| };␊ |
| ␊ |
| static const char * getNameForValue( const struct NamedValue * nameTable,␊ |
| unsigned char value )␊ |
| static const char * getNameForValue(const struct NamedValue * nameTable, unsigned char value)␊ |
| {␊ |
| const struct NamedValue * np;␊ |
| ␉const struct NamedValue * np;␊ |
| ␊ |
| for ( np = nameTable; np->value; np++)␊ |
| if (np->value == value)␊ |
| return np->name;␊ |
| ␊ |
| return NULL;␊ |
| ␉for ( np = nameTable; np->value; np++)␊ |
| ␉{␊ |
| ␉␉if (np->value == value)␊ |
| ␉␉{␊ |
| ␉␉␉return np->name;␊ |
| ␉␉}␊ |
| ␉}␊ |
| ␉return NULL;␊ |
| }␊ |
| ␊ |
| #define ECC_CORRECTED_ERR 0x11␊ |
| ␊ |
| 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 }␊ |
| ␉{ 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 errnum)␊ |
| {␊ |
| static char errorstr[] = "Error 0x00";␊ |
| const char * errname;␊ |
| ␉static char errorstr[] = "Error 0x00";␊ |
| ␉const char * errname;␊ |
| ␊ |
| errname = getNameForValue( bios_errors, errnum );␊ |
| if ( errname ) return errname;␊ |
| ␉errname = getNameForValue(bios_errors, errnum);␊ |
| ␊ |
| sprintf(errorstr, "Error 0x%02x", errnum);␊ |
| return errorstr; // No string, print error code only␊ |
| ␉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.␊ |
| // 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.␊ |
| // Returns 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 long long secno )␊ |
| static int Biosread(int biosdev, unsigned long long secno)␊ |
| {␊ |
| static int xbiosdev, xcyl, xhead;␊ |
| static unsigned int xsec, xnsecs;␊ |
| struct driveInfo di;␊ |
| ␉static int xbiosdev, xcyl, xhead;␊ |
| ␉static unsigned int xsec, xnsecs;␊ |
| ␉struct driveInfo di;␊ |
| ␊ |
| int rc = -1;␊ |
| int cyl, head, sec;␊ |
| int tries = 0;␊ |
| int bps, divisor;␊ |
| ␉int rc = -1;␊ |
| ␉int cyl, head, sec;␊ |
| ␉int tries = 0;␊ |
| ␉int bps, divisor;␊ |
| ␊ |
| 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;␊ |
| ␉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;␊ |
| ␊ |
| DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));␊ |
| ␉␉if (bps == 0)␊ |
| ␉␉{␊ |
| ␉␉␉return -1;␊ |
| ␉␉}␊ |
| ␉}␊ |
| ␉divisor = bps / BPS;␊ |
| ␊ |
| // To read the disk sectors, use EBIOS if we can. Otherwise,␊ |
| // revert to the standard BIOS calls.␊ |
| ␉DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));␊ |
| ␊ |
| if ((biosdev >= kBIOSDevTypeHardDrive) &&␊ |
| (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))␊ |
| {␊ |
| if (cache_valid &&␊ |
| (biosdev == xbiosdev) &&␊ |
| (secno >= xsec) &&␊ |
| ((unsigned int)secno < (xsec + xnsecs)))␊ |
| {␊ |
| biosbuf = trackbuf + (BPS * (secno - xsec));␊ |
| return 0;␊ |
| }␊ |
| ␉// To read the disk sectors, use EBIOS if we can. Otherwise,␊ |
| ␉// revert to the standard BIOS calls.␊ |
| ␊ |
| xnsecs = N_CACHE_SECS;␊ |
| xsec = (secno / divisor) * divisor;␊ |
| cache_valid = false;␊ |
| ␉if ((biosdev >= kBIOSDevTypeHardDrive) && (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))␊ |
| ␉{␊ |
| ␉␉if (cache_valid && (biosdev == xbiosdev) && (secno >= xsec) && ((unsigned int)secno < (xsec + xnsecs)))␊ |
| ␉␉{␊ |
| ␉␉␉biosbuf = trackbuf + (BPS * (secno - xsec));␊ |
| ␉␉␉return 0;␊ |
| ␉␉}␊ |
| ␊ |
| 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);␊ |
| error(" Block 0x%x Sectors %d\n", secno, xnsecs);␊ |
| sleep(1);␊ |
| }␊ |
| }␊ |
| else␊ |
| {␊ |
| ␉/* spc = spt * heads */␊ |
| ␉int spc = (di.di.params.phys_spt * di.di.params.phys_heads);␊ |
| cyl = secno / spc;␊ |
| head = (secno % spc) / di.di.params.phys_spt;␊ |
| sec = secno % di.di.params.phys_spt;␊ |
| ␉␉xnsecs = N_CACHE_SECS;␊ |
| ␉␉xsec = (secno / divisor) * divisor;␊ |
| ␉␉cache_valid = false;␊ |
| ␊ |
| if (cache_valid &&␊ |
| (biosdev == xbiosdev) &&␊ |
| (cyl == xcyl) &&␊ |
| (head == xhead) &&␊ |
| ((unsigned int)sec >= xsec) &&␊ |
| ((unsigned int)sec < (xsec + xnsecs)))␊ |
| {␊ |
| // this sector is in trackbuf cache␊ |
| biosbuf = trackbuf + (BPS * (sec - xsec));␊ |
| return 0;␊ |
| }␊ |
| ␉␉while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))␊ |
| ␉␉{␊ |
| ␉␉␉if (rc == ECC_CORRECTED_ERR)␊ |
| ␉␉␉{␊ |
| ␉␉␉␉/* Ignore corrected ECC errors */␊ |
| ␉␉␉␉rc = 0;␊ |
| ␉␉␉␉break;␊ |
| ␉␉␉}␊ |
| ␊ |
| // Cache up to a track worth of sectors, but do not cross a␊ |
| // track boundary.␊ |
| ␉␉␉error(" EBIOS read error: %s\n", bios_error(rc), rc);␊ |
| ␉␉␉error(" Block 0x%x Sectors %d\n", secno, xnsecs);␊ |
| ␉␉␉sleep(1);␊ |
| ␉␉}␊ |
| ␉}␊ |
| ␊ |
| xcyl = cyl;␊ |
| xhead = head;␊ |
| xsec = sec;␊ |
| xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;␊ |
| cache_valid = false;␊ |
| ␉else␊ |
| ␉{␊ |
| ␉␉/* spc = spt * heads */␊ |
| ␉␉int spc = (di.di.params.phys_spt * di.di.params.phys_heads);␊ |
| ␉␉cyl = secno / spc;␊ |
| ␉␉head = (secno % spc) / di.di.params.phys_spt;␊ |
| ␉␉sec = secno % di.di.params.phys_spt;␊ |
| ␊ |
| 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);␊ |
| error(" Block %d, Cyl %d Head %d Sector %d\n",␊ |
| secno, cyl, head, sec);␊ |
| sleep(1);␊ |
| }␊ |
| }␊ |
| ␉␉if (cache_valid && (biosdev == xbiosdev) && (cyl == xcyl) &&␊ |
| ␉␉␉(head == xhead) && ((unsigned int)sec < (xsec + xnsecs)))␊ |
| ␉␉{␊ |
| ␉␉␉// this sector is in trackbuf cache␊ |
| ␉␉␉biosbuf = trackbuf + (BPS * (sec - xsec));␊ |
| ␉␉␉return 0;␊ |
| ␉␉}␊ |
| ␊ |
| // If the BIOS reported success, mark the sector cache as valid.␊ |
| ␉␉// Cache up to a track worth of sectors, but do not cross a track boundary.␊ |
| ␊ |
| if (rc == 0) {␊ |
| cache_valid = true;␊ |
| }␊ |
| biosbuf = trackbuf + (secno % divisor) * BPS;␊ |
| xbiosdev = biosdev;␊ |
| ␉␉xcyl = cyl;␊ |
| ␉␉xhead = head;␊ |
| ␉␉xsec = sec;␊ |
| ␉␉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);␊ |
| ␉␉␉error(" Block %d, Cyl %d Head %d Sector %d\n",␊ |
| ␉␉␉secno, cyl, head, sec);␊ |
| ␉␉␉sleep(1);␊ |
| ␉␉}␊ |
| ␉}␊ |
| ␊ |
| ␉// If the BIOS reported success, mark the sector cache as valid.␊ |
| ␊ |
| ␉if (rc == 0)␊ |
| ␉{␊ |
| ␉␉cache_valid = true;␊ |
| ␉}␊ |
| ␊ |
| ␉biosbuf = trackbuf + (secno % divisor) * BPS;␊ |
| ␉xbiosdev = biosdev;␊ |
| ␊ |
| spinActivityIndicator(xnsecs);␊ |
| ␉spinActivityIndicator(xnsecs);␊ |
| ␊ |
| return rc;␊ |
| ␉return rc;␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
| ␊ |
| int testBiosread( int biosdev, unsigned long long secno )␊ |
| int testBiosread(int biosdev, unsigned long long secno)␊ |
| {␊ |
| ␉return Biosread(biosdev, secno);␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
| ␊ |
| static int readBytes( int biosdev, unsigned long long blkno,␊ |
| unsigned int byteoff,␊ |
| unsigned int byteCount, void * buffer )␊ |
| static int readBytes(int biosdev, unsigned long long blkno, unsigned int byteoff, unsigned int byteCount, void * buffer)␊ |
| {␊ |
| // ramdisks require completely different code for reading.␊ |
| if(p_ramdiskReadBytes != NULL && biosdev >= 0x100)␊ |
| return (*p_ramdiskReadBytes)(biosdev, blkno, byteoff, byteCount, buffer);␊ |
| ␉// ramdisks require completely different code for reading.␊ |
| ␉if(p_ramdiskReadBytes != NULL && biosdev >= 0x100)␊ |
| ␉{␊ |
| ␉␉return (*p_ramdiskReadBytes)(biosdev, blkno, byteoff, byteCount, buffer);␊ |
| ␉}␊ |
| ␊ |
| char * cbuf = (char *) buffer;␊ |
| int error;␊ |
| int copy_len;␊ |
| ␉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));␊ |
| ␉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);␊ |
| }␊ |
| ␉for (; byteCount; cbuf += copy_len, blkno++)␊ |
| ␉{␊ |
| ␉␉error = Biosread(biosdev, blkno);␊ |
| ␊ |
| copy_len = ((byteCount + byteoff) > BPS) ? (BPS - byteoff) : byteCount;␊ |
| bcopy( biosbuf + byteoff, cbuf, copy_len );␊ |
| byteCount -= copy_len;␊ |
| byteoff = 0;␊ |
| }␊ |
| ␉␉if (error)␊ |
| ␉␉{␊ |
| ␉␉␉DEBUG_DISK(("error\n"));␊ |
| ␉␉␉return (-1);␊ |
| ␉␉}␊ |
| ␊ |
| DEBUG_DISK(("done\n"));␊ |
| ␉␉copy_len = ((byteCount + byteoff) > BPS) ? (BPS - byteoff) : byteCount;␊ |
| ␉␉bcopy( biosbuf + byteoff, cbuf, copy_len );␊ |
| ␉␉byteCount -= copy_len;␊ |
| ␉␉byteoff = 0;␊ |
| ␉}␊ |
| ␊ |
| return 0; ␊ |
| ␉DEBUG_DISK(("done\n"));␊ |
| ␊ |
| ␉return 0; ␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
| ␊ |
| static int isExtendedFDiskPartition( const struct fdisk_part * part )␊ |
| {␊ |
| static unsigned char extParts[] =␊ |
| {␊ |
| 0x05, /* Extended */␊ |
| 0x0f, /* Win95 extended */␊ |
| 0x85, /* Linux extended */␊ |
| };␊ |
| ␉static unsigned char extParts[] =␊ |
| ␉{␊ |
| ␉␉0x05, /* Extended */␊ |
| ␉␉0x0f, /* Win95 extended */␊ |
| ␉␉0x85, /* Linux extended */␊ |
| ␉};␊ |
| ␊ |
| unsigned int i;␊ |
| ␉unsigned int i;␊ |
| ␊ |
| for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)␊ |
| {␊ |
| if (extParts[i] == part->systid) return 1;␊ |
| }␊ |
| return 0;␊ |
| ␉for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)␊ |
| ␉{␊ |
| ␉␉if (extParts[i] == part->systid)␊ |
| ␉␉{␊ |
| ␉␉␉return 1;␊ |
| ␉␉}␊ |
| ␉}␊ |
| ␉return 0;␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
|
| static int getNextFDiskPartition( int biosdev, int * partno,␊ |
| const struct fdisk_part ** outPart )␊ |
| {␊ |
| 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;␊ |
| ␉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;␊ |
| ␉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;␊ |
| }␊ |
| ␉␉sBiosdev = biosdev;␊ |
| ␉␉sNextPartNo = 0;␊ |
| ␉␉sFirstBase = 0;␊ |
| ␉␉sExtBase = 0;␊ |
| ␉␉sExtDepth = 0;␊ |
| ␉␉sExtPart = NULL;␊ |
| ␉}␊ |
| ␊ |
| while (1)␊ |
| {␊ |
| part = NULL;␊ |
| ␉while (1)␊ |
| ␉{␊ |
| ␉␉part = NULL;␊ |
| ␊ |
| if ( sNextPartNo < FDISK_NPART )␊ |
| {␊ |
| part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];␊ |
| }␊ |
| else if ( sExtPart )␊ |
| {␊ |
| unsigned int blkno = sExtPart->relsect + sFirstBase;␊ |
| ␉␉if ( sNextPartNo < FDISK_NPART )␊ |
| ␉␉{␊ |
| ␉␉␉part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];␊ |
| ␉␉}␊ |
| ␉␉else if ( sExtPart )␊ |
| ␉␉{␊ |
| ␉␉␉unsigned int blkno = sExtPart->relsect + sFirstBase;␊ |
| ␊ |
| // Save the block offset of the first extended partition.␊ |
| ␉␉␉// Save the block offset of the first extended partition.␊ |
| ␊ |
| if (sExtDepth == 0) {␊ |
| sFirstBase = blkno;␊ |
| }␊ |
| sExtBase = blkno;␊ |
| ␉␉␉if (sExtDepth == 0)␊ |
| ␉␉␉{␊ |
| ␉␉␉␉sFirstBase = blkno;␊ |
| ␉␉␉}␊ |
| ␉␉␉sExtBase = blkno;␊ |
| ␊ |
| // Load extended partition table.␊ |
| ␉␉␉// Load extended partition table.␊ |
| ␊ |
| if ( readBootSector( biosdev, blkno, 0 ) == 0 )␊ |
| {␊ |
| sNextPartNo = 0;␊ |
| sExtDepth++;␊ |
| sExtPart = NULL;␊ |
| continue;␊ |
| }␊ |
| // Fall through to part == NULL␊ |
| }␊ |
| ␉␉␉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.␊ |
| ␉␉if ( part == NULL ) break; // Reached end of partition chain.␊ |
| ␊ |
| // Advance to next partition number.␊ |
| ␉␉// Advance to next partition number.␊ |
| ␊ |
| sNextPartNo++;␊ |
| ␉␉sNextPartNo++;␊ |
| ␊ |
| if ( isExtendedFDiskPartition(part) )␊ |
| {␊ |
| sExtPart = part;␊ |
| continue;␊ |
| }␊ |
| ␉␉if ( isExtendedFDiskPartition(part) )␊ |
| ␉␉{␊ |
| ␉␉␉sExtPart = part;␊ |
| ␉␉␉continue;␊ |
| ␉␉}␊ |
| ␊ |
| // Skip empty slots.␊ |
| ␉␉// Skip empty slots.␊ |
| ␊ |
| if ( part->systid == 0x00 )␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␉␉if ( part->systid == 0x00 )␊ |
| ␉␉{␊ |
| ␉␉␉continue;␊ |
| ␉␉}␊ |
| ␊ |
| // Change relative offset to an absolute offset.␊ |
| part->relsect += sExtBase;␊ |
| ␉␉// Change relative offset to an absolute offset.␊ |
| ␉␉part->relsect += sExtBase;␊ |
| ␊ |
| *outPart = part;␊ |
| *partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;␊ |
| ␉␉*outPart = part;␊ |
| ␉␉*partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;␊ |
| ␊ |
| break;␊ |
| }␊ |
| ␉␉break;␊ |
| ␉}␊ |
| ␊ |
| return (part != NULL);␊ |
| ␉return (part != NULL);␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
|
| BVFree bvFreeFunc,␊ |
| int probe, int type, unsigned int bvrFlags )␊ |
| {␊ |
| BVRef bvr = (BVRef) malloc( sizeof(*bvr) );␊ |
| if ( bvr )␊ |
| {␊ |
| bzero(bvr, sizeof(*bvr));␊ |
| ␉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;␊ |
| bvr->type = type;␊ |
| bvr->bv_free = bvFreeFunc;␊ |
| ␉␉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;␊ |
| ␉␉bvr->type = type;␊ |
| ␉␉bvr->bv_free = bvFreeFunc;␊ |
| ␊ |
| if ((part->bootid & FDISK_ACTIVE) && (part->systid == FDISK_HFS))␊ |
| bvr->flags |= kBVFlagPrimary;␊ |
| ␊ |
| ␉␉if ((part->bootid & FDISK_ACTIVE) && (part->systid == FDISK_HFS))␊ |
| ␉␉{␊ |
| ␉␉␉bvr->flags |= kBVFlagPrimary;␊ |
| ␉␉}␊ |
| ␉␉␊ |
| // Probe the filesystem.␊ |
| ␊ |
| if ( initFunc )␊ |
|
| {␊ |
| // filesystem probe failed.␊ |
| ␊ |
| DEBUG_DISK(("%s: failed probe on dev %x part %d\n",␊ |
| __FUNCTION__, biosdev, partno));␊ |
| DEBUG_DISK(("%s: failed probe on dev %x part %d\n", __FUNCTION__, biosdev, partno));␊ |
| ␊ |
| (*bvr->bv_free)(bvr);␊ |
| bvr = NULL;␊ |
|
| bvr = NULL;␊ |
| }␊ |
| }␊ |
| if (bvr) bvr->flags |= bvrFlags;␊ |
| return bvr;␊ |
| ␊ |
| ␉if (bvr) bvr->flags |= bvrFlags;␊ |
| ␉{␊ |
| ␉␉return bvr;␊ |
| ␉}␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
|
| {␊ |
| // filesystem probe failed.␊ |
| ␊ |
| DEBUG_DISK(("%s: failed probe on dev %x part %d\n",␊ |
| __FUNCTION__, biosdev, partno));␊ |
| DEBUG_DISK(("%s: failed probe on dev %x part %d\n", __FUNCTION__, biosdev, partno));␊ |
| ␊ |
| (*bvr->bv_free)(bvr);␊ |
| bvr = NULL;␊ |
|
| //==========================================================================␊ |
| ␊ |
| // GUID's in LE form:␊ |
| // HFS+ partition - 48465300-0000-11AA-AA11-00306543ECAC␊ |
| // http://en.wikipedia.org/wiki/GUID_Partition_Table␊ |
| // 00000000-0000-0000-0000-000000000000 - Unused Entry partition ␊ |
| // 024DEE41-33E7-11D3-9D69-0008C781F39F - MBR partition scheme ␊ |
| // C12A7328-F81F-11D2-BA4B-00A0C93EC93B - turbo - or an EFI System Partition␊ |
| EFI_GUID const GPT_EFISYS_GUID␉ = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };␊ |
| // 21686148-6449-6E6F-744E-656564454649 - BIOS Boot partition ␊ |
| // E3C9E316-0B5C-4DB8-817D-F92DF00215AE - Microsoft Reserved Partition ␊ |
| EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };␊ |
| // EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 - zef - Basic Data Partition - for foreign OS support␊ |
| EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };␊ |
| // 5808C8AA-7E8F-42E0-85D2-E1E90434CFB3 - Logical Disk Manager metadata partition␊ |
| // AF9B60A0-1431-4F62-BC68-3311714A69AD - Logical Disk Manager data partition␊ |
| // DE94BBA4-06D1-4D40-A16A-BFD50179D6AC - Windows Recovery Environment␊ |
| // 48465300-0000-11AA-AA11-00306543ECAC - Hierarchical File System Plus (HFS+) partition␊ |
| EFI_GUID const GPT_HFS_GUID␉␉ = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
| ␊ |
| // turbo - Apple Boot Partition - 426F6F74-0000-11AA-AA11-00306543ECAC␊ |
| // 55465300-0000-11AA-AA11-00306543ECAC - Apple UFS ␊ |
| // 52414944-0000-11AA-AA11-00306543ECAC - Apple RAID partition␊ |
| // 426F6F74-0000-11AA-AA11-00306543ECAC - turbo - Apple Boot Partition␊ |
| EFI_GUID const GPT_BOOT_GUID␉ = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
| // 4C616265-6C00-11AA-AA11-00306543ECAC - Apple Label␊ |
| // 5265636F-7665-11AA-AA11-00306543ECAC - Apple TV Recovery partition␊ |
| // 53746F72-6167-11AA-AA11-00306543ECAC - Apple Core Storage (i.e. Lion FileVault) partition (Apple_Boot Recovery HD)␊ |
| // EFI_GUID const GPT_RECOVERY_GUID␉ = { 0x53746F72, 0x6167, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
| ␊ |
| // turbo - or an EFI System Partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B␊ |
| EFI_GUID const GPT_EFISYS_GUID␉ = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };␊ |
| ␊ |
| // zef - Basic Data Partition - EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support␊ |
| EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };␊ |
| ␊ |
| // Microsoft Reserved Partition - E3C9E316-0B5C-4DB8-817DF92DF00215AE␊ |
| EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };␊ |
| ␊ |
| ␊ |
| BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,␊ |
| const gpt_ent * part,␊ |
| FSInit initFunc, FSLoadFile loadFunc,␊ |
|
| ␉ ␉␉␉␉␉␉␉␉0, 0, 0, 0, 0, 0, NTFSGetDescription,␊ |
| ␉␉ ␉␉␉␉␉␉␉(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);␊ |
| ␉␉␉␉␉␉␉␉break;␊ |
| ␉␉␉␉␉␉␉ case FDISK_LINUX:␊ |
| ␉␉␉␉␉␉␉ bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
| ␉ ␉␉␉␉␉␉␉␉0, 0, 0, 0, 0, 0, EX2GetDescription,␊ |
| ␉␉ ␉␉␉␉␉␉␉(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);␊ |
| ␉␉␉␉␉␉␉␉break;␊ |
| ␊ |
| default:␊ |
| bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
|
| ␊ |
| BVRef diskScanBootVolumes( int biosdev, int * countPtr )␊ |
| {␊ |
| struct DiskBVMap * map;␊ |
| struct DiskBVMap * map = NULL;␊ |
| BVRef bvr;␊ |
| int count = 0;␊ |
| ␊ |
|
| volStart = strbreak(entryStart, &volEnd, &volLen);␊ |
| if(!volLen)␊ |
| continue;␊ |
| ␊ |
| ␊ |
| aliasStart = strbreak(volEnd, 0, &aliasLen);␊ |
| if(!aliasLen)␊ |
| continue;␊ |
| ␊ |
| ␊ |
| if ( matchVolumeToString(bvr, volStart, volLen) )␊ |
| { ␊ |
| {␊ |
| strncat(str, aliasStart, MIN(strMaxLen, aliasLen));␊ |
| free(aliasList);␊ |
| ␊ |
|
| return;␊ |
| ␊ |
| type = (unsigned char) bvr->part_type;␊ |
| ␉␊ |
| ␊ |
| if (useDeviceDescription)␊ |
| {␊ |
| int len = getDeviceDescription(bvr, str);␊ |
| if(len >= strMaxLen)␊ |
| return;␊ |
| ␊ |
| ␊ |
| strcpy(str + len, " ");␊ |
| len++;␊ |
| strMaxLen -= len;␊ |
| p += len;␊ |
| }␊ |
| ␉␊ |
| ␊ |
| /* See if a partition rename is preferred */␊ |
| if(getVolumeLabelAlias(bvr, p, strMaxLen)) {␊ |
| strncpy(bvr->label, p, strMaxLen); ␊ |
| return; // we're done here no need to seek for real name␊ |
| }␊ |
| ␊ |
| ␊ |
| //␊ |
| // Get the volume label using filesystem specific functions␊ |
| // or use the alternate volume label if available.␊ |
|
| strncpy(p, name, strMaxLen);␊ |
| }␊ |
| }␊ |
| ␊ |
| ␊ |
| // Set the devices label␊ |
| sprintf(bvr->label, p);␊ |
| }␊ |
| ␊ |
| //==========================================================================␊ |
| int readBootSector( int biosdev, unsigned int secno, void * buffer )␊ |
| int readBootSector(int biosdev, unsigned int secno, void * buffer)␊ |
| {␊ |
| struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;␊ |
| int error;␊ |
| ␉int error;␊ |
| ␉struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;␊ |
| ␊ |
| if ( bootSector == NULL )␊ |
| {␊ |
| if ( gBootSector == NULL )␊ |
| {␊ |
| gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));␊ |
| if ( gBootSector == NULL ) return -1;␊ |
| }␊ |
| ␉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;␊ |
| ␉error = readBytes(biosdev, secno, 0, BPS, bootSector);␊ |
| ␊ |
| return 0;␊ |
| ␉if (error || bootSector->signature != DISK_SIGNATURE)␊ |
| ␉{␊ |
| ␉␉return -1;␊ |
| ␉}␊ |
| ␉return 0;␊ |
| }␊ |
| ␊ |
| /*␊ |
|
| //==========================================================================␊ |
| // Handle seek request from filesystem modules.␊ |
| ␊ |
| void diskSeek( BVRef bvr, long long position )␊ |
| void diskSeek(BVRef bvr, long long position)␊ |
| {␊ |
| bvr->fs_boff = position / BPS;␊ |
| bvr->fs_byteoff = position % BPS;␊ |