| 1 | /*␊ |
| 2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.␊ |
| 3 | *␊ |
| 4 | * @APPLE_LICENSE_HEADER_START@␊ |
| 5 | * ␊ |
| 6 | * Portions Copyright (c) 1999-2003 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 2.0 (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␊ |
| 12 | * this file.␊ |
| 13 | * ␊ |
| 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␊ |
| 20 | * under the License.␊ |
| 21 | * ␊ |
| 22 | * @APPLE_LICENSE_HEADER_END@␊ |
| 23 | */␊ |
| 24 | /* ␊ |
| 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.␊ |
| 30 | */␊ |
| 31 | ␊ |
| 32 | /*␊ |
| 33 | * INTEL CORPORATION PROPRIETARY INFORMATION␊ |
| 34 | *␊ |
| 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.␊ |
| 38 | *␊ |
| 39 | * Copyright 1988, 1989 Intel Corporation␊ |
| 40 | */␊ |
| 41 | ␊ |
| 42 | /*␊ |
| 43 | * Copyright 1993 NeXT Computer, Inc.␊ |
| 44 | * All rights reserved.␊ |
| 45 | */␊ |
| 46 | ␊ |
| 47 | /*␊ |
| 48 | * Copyright 2007 VMware Inc.␊ |
| 49 | * "Preboot" ramdisk support added by David Elliott␊ |
| 50 | * GPT support added by David Elliott. Based on IOGUIDPartitionScheme.cpp.␊ |
| 51 | */␊ |
| 52 | ␊ |
| 53 | //#define UFS_SUPPORT 1 //Azi: error: duplicate case value␊ |
| 54 | ␊ |
| 55 | #include <limits.h>␊ |
| 56 | #include <IOKit/storage/IOApplePartitionScheme.h>␊ |
| 57 | #include <IOKit/storage/IOGUIDPartitionScheme.h>␊ |
| 58 | ␊ |
| 59 | // Allow UFS_SUPPORT to be overridden with preprocessor option.␊ |
| 60 | #ifndef UFS_SUPPORT␊ |
| 61 | // zef: Disabled UFS support␊ |
| 62 | #define UFS_SUPPORT 0␊ |
| 63 | #endif␊ |
| 64 | ␊ |
| 65 | //#include "libsaio.h"␊ |
| 66 | //#include "bootstruct.h"␊ |
| 67 | #include "boot.h"␊ |
| 68 | #include "memory.h"␊ |
| 69 | #include "fdisk.h"␊ |
| 70 | ␊ |
| 71 | #if UFS_SUPPORT␊ |
| 72 | #include "ufs.h"␊ |
| 73 | #endif␊ |
| 74 | ␊ |
| 75 | #include "hfs.h"␊ |
| 76 | #include "ntfs.h"␊ |
| 77 | #include "msdos.h"␊ |
| 78 | #include "ext2fs.h"␊ |
| 79 | #include "xml.h"␊ |
| 80 | #include "disk.h"␊ |
| 81 | // For EFI_GUID␊ |
| 82 | #include "efi.h"␊ |
| 83 | #include "efi_tables.h"␊ |
| 84 | ␊ |
| 85 | typedef struct gpt_hdr gpt_hdr;␊ |
| 86 | typedef struct gpt_ent gpt_ent;␊ |
| 87 | ␊ |
| 88 | #define PROBEFS_SIZE BPS * 4 /* buffer size for filesystem probe */␊ |
| 89 | #define CD_BPS 2048 /* CD-ROM block size */␊ |
| 90 | #define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */␊ |
| 91 | #define UFS_FRONT_PORCH 0␊ |
| 92 | #define kAPMSector 2 /* Sector number of Apple partition map */␊ |
| 93 | #define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */␊ |
| 94 | ␊ |
| 95 | /*␊ |
| 96 | * IORound and IOTrunc convenience functions, in the spirit␊ |
| 97 | * of vm's round_page() and trunc_page().␊ |
| 98 | */␊ |
| 99 | #define IORound(value,multiple) \␊ |
| 100 | ((((value) + (multiple) - 1) / (multiple)) * (multiple))␊ |
| 101 | ␊ |
| 102 | #define IOTrunc(value,multiple) \␊ |
| 103 | (((value) / (multiple)) * (multiple));␊ |
| 104 | ␊ |
| 105 | /*␊ |
| 106 | * trackbuf points to the start of the track cache. Biosread()␊ |
| 107 | * will store the sectors read from disk to this memory area.␊ |
| 108 | *␊ |
| 109 | * biosbuf points to a sector within the track cache, and is␊ |
| 110 | * updated by Biosread().␊ |
| 111 | */␊ |
| 112 | static char * const trackbuf = (char *) ptov(BIOS_ADDR);␊ |
| 113 | static char * biosbuf;␊ |
| 114 | ␊ |
| 115 | /*␊ |
| 116 | * Map a disk drive to bootable volumes contained within.␊ |
| 117 | */␊ |
| 118 | struct DiskBVMap {␊ |
| 119 | int biosdev; // BIOS device number (unique)␊ |
| 120 | BVRef bvr; // chain of boot volumes on the disk␊ |
| 121 | int bvrcnt; // number of boot volumes␊ |
| 122 | struct DiskBVMap * next; // linkage to next mapping␊ |
| 123 | };␊ |
| 124 | ␊ |
| 125 | static struct DiskBVMap * gDiskBVMap = NULL;␊ |
| 126 | static struct disk_blk0 * gBootSector = NULL;␊ |
| 127 | ␊ |
| 128 | // Function pointers to be filled in if ramdisks are available:␊ |
| 129 | int (*p_ramdiskReadBytes)( int biosdev, unsigned int blkno,␊ |
| 130 | unsigned int byteoff,␊ |
| 131 | unsigned int byteCount, void * buffer ) = NULL;␊ |
| 132 | int (*p_get_ramdisk_info)(int biosdev, struct driveInfo *dip) = NULL;␊ |
| 133 | ␊ |
| 134 | ␊ |
| 135 | extern void spinActivityIndicator(int sectors);␊ |
| 136 | ␊ |
| 137 | //==========================================================================␊ |
| 138 | ␊ |
| 139 | static int getDriveInfo( int biosdev, struct driveInfo *dip )␊ |
| 140 | {␊ |
| 141 | static struct driveInfo cached_di;␊ |
| 142 | int cc;␊ |
| 143 | ␊ |
| 144 | // Real BIOS devices are 8-bit, so anything above that is for internal use.␊ |
| 145 | // Don't cache ramdisk drive info since it doesn't require several BIOS␊ |
| 146 | // calls and is thus not worth it.␊ |
| 147 | if(biosdev >= 0x100)␊ |
| 148 | {␊ |
| 149 | if(p_get_ramdisk_info != NULL)␊ |
| 150 | cc = (*p_get_ramdisk_info)(biosdev, dip);␊ |
| 151 | else␊ |
| 152 | cc = -1;␊ |
| 153 | if(cc < 0)␊ |
| 154 | {␊ |
| 155 | dip->valid = 0;␊ |
| 156 | return -1;␊ |
| 157 | }␊ |
| 158 | else␊ |
| 159 | return 0;␊ |
| 160 | }␊ |
| 161 | ␊ |
| 162 | if ( !cached_di.valid || biosdev != cached_di.biosdev )␊ |
| 163 | {␊ |
| 164 | ␉cc = get_drive_info(biosdev, &cached_di);␊ |
| 165 | if (cc < 0) {␊ |
| 166 | ␉ cached_di.valid = 0;␊ |
| 167 | DEBUG_DISK(("get_drive_info returned error\n"));␊ |
| 168 | ␉ return (-1); // BIOS call error␊ |
| 169 | ␉}␊ |
| 170 | }␊ |
| 171 | ␊ |
| 172 | bcopy(&cached_di, dip, sizeof(cached_di));␊ |
| 173 | ␊ |
| 174 | return 0;␊ |
| 175 | }␊ |
| 176 | ␊ |
| 177 | //==========================================================================␊ |
| 178 | // Maps (E)BIOS return codes to message strings.␊ |
| 179 | ␊ |
| 180 | struct NamedValue {␊ |
| 181 | unsigned char value;␊ |
| 182 | const char * name;␊ |
| 183 | };␊ |
| 184 | ␊ |
| 185 | static const char * getNameForValue( const struct NamedValue * nameTable,␊ |
| 186 | unsigned char value )␊ |
| 187 | {␊ |
| 188 | const struct NamedValue * np;␊ |
| 189 | ␊ |
| 190 | for ( np = nameTable; np->value; np++)␊ |
| 191 | if (np->value == value)␊ |
| 192 | return np->name;␊ |
| 193 | ␊ |
| 194 | return NULL;␊ |
| 195 | }␊ |
| 196 | ␊ |
| 197 | #define ECC_CORRECTED_ERR 0x11␊ |
| 198 | ␊ |
| 199 | static const struct NamedValue bios_errors[] = {␊ |
| 200 | { 0x10, "Media error" },␊ |
| 201 | { 0x11, "Corrected ECC error" },␊ |
| 202 | { 0x20, "Controller or device error" },␊ |
| 203 | { 0x40, "Seek failed" },␊ |
| 204 | { 0x80, "Device timeout" },␊ |
| 205 | { 0xAA, "Drive not ready" },␊ |
| 206 | { 0x00, 0 }␊ |
| 207 | };␊ |
| 208 | ␊ |
| 209 | static const char * bios_error(int errnum)␊ |
| 210 | {␊ |
| 211 | static char errorstr[] = "Error 0x00";␊ |
| 212 | const char * errname;␊ |
| 213 | ␊ |
| 214 | errname = getNameForValue( bios_errors, errnum );␊ |
| 215 | if ( errname ) return errname;␊ |
| 216 | ␊ |
| 217 | sprintf(errorstr, "Error 0x%02x", errnum);␊ |
| 218 | return errorstr; // No string, print error code only␊ |
| 219 | }␊ |
| 220 | ␊ |
| 221 | //==========================================================================␊ |
| 222 | // Use BIOS INT13 calls to read the sector specified. This function will␊ |
| 223 | // also perform read-ahead to cache a few subsequent sector to the sector␊ |
| 224 | // cache.␊ |
| 225 | // ␊ |
| 226 | // Return:␊ |
| 227 | // 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.␊ |
| 228 | ␊ |
| 229 | static bool cache_valid = false;␊ |
| 230 | ␊ |
| 231 | static int Biosread( int biosdev, unsigned long long secno )␊ |
| 232 | {␊ |
| 233 | static int xbiosdev, xcyl, xhead;␊ |
| 234 | static unsigned int xsec, xnsecs;␊ |
| 235 | struct driveInfo di;␊ |
| 236 | ␊ |
| 237 | int rc = -1;␊ |
| 238 | int cyl, head, sec;␊ |
| 239 | int tries = 0;␊ |
| 240 | int bps, divisor;␊ |
| 241 | ␊ |
| 242 | if (getDriveInfo(biosdev, &di) < 0) {␊ |
| 243 | ␉return -1;␊ |
| 244 | }␊ |
| 245 | if (di.no_emulation) {␊ |
| 246 | ␉/* Always assume 2k block size; BIOS may lie about geometry */␊ |
| 247 | ␉bps = 2048;␊ |
| 248 | } else {␊ |
| 249 | ␉bps = di.di.params.phys_nbps;␊ |
| 250 | if (bps == 0) {␊ |
| 251 | return -1;␊ |
| 252 | }␊ |
| 253 | }␊ |
| 254 | divisor = bps / BPS;␊ |
| 255 | ␊ |
| 256 | DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));␊ |
| 257 | ␊ |
| 258 | // To read the disk sectors, use EBIOS if we can. Otherwise,␊ |
| 259 | // revert to the standard BIOS calls.␊ |
| 260 | ␊ |
| 261 | if ((biosdev >= kBIOSDevTypeHardDrive) &&␊ |
| 262 | (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))␊ |
| 263 | {␊ |
| 264 | if (cache_valid &&␊ |
| 265 | (biosdev == xbiosdev) &&␊ |
| 266 | (secno >= xsec) &&␊ |
| 267 | ((unsigned int)secno < (xsec + xnsecs)))␊ |
| 268 | {␊ |
| 269 | biosbuf = trackbuf + (BPS * (secno - xsec));␊ |
| 270 | return 0;␊ |
| 271 | }␊ |
| 272 | ␊ |
| 273 | xnsecs = N_CACHE_SECS;␊ |
| 274 | xsec = (secno / divisor) * divisor;␊ |
| 275 | cache_valid = false;␊ |
| 276 | ␊ |
| 277 | while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))␊ |
| 278 | {␊ |
| 279 | if (rc == ECC_CORRECTED_ERR) {␊ |
| 280 | /* Ignore corrected ECC errors */␊ |
| 281 | rc = 0;␊ |
| 282 | break;␊ |
| 283 | }␊ |
| 284 | error(" EBIOS read error: %s\n", bios_error(rc), rc);␊ |
| 285 | error(" Block 0x%x Sectors %d\n", secno, xnsecs);␊ |
| 286 | sleep(1);␊ |
| 287 | }␊ |
| 288 | }␊ |
| 289 | else␊ |
| 290 | {␊ |
| 291 | ␉/* spc = spt * heads */␊ |
| 292 | ␉int spc = (di.di.params.phys_spt * di.di.params.phys_heads);␊ |
| 293 | cyl = secno / spc;␊ |
| 294 | head = (secno % spc) / di.di.params.phys_spt;␊ |
| 295 | sec = secno % di.di.params.phys_spt;␊ |
| 296 | ␊ |
| 297 | if (cache_valid &&␊ |
| 298 | (biosdev == xbiosdev) &&␊ |
| 299 | (cyl == xcyl) &&␊ |
| 300 | (head == xhead) &&␊ |
| 301 | ((unsigned int)sec >= xsec) &&␊ |
| 302 | ((unsigned int)sec < (xsec + xnsecs)))␊ |
| 303 | {␊ |
| 304 | // this sector is in trackbuf cache␊ |
| 305 | biosbuf = trackbuf + (BPS * (sec - xsec));␊ |
| 306 | return 0;␊ |
| 307 | }␊ |
| 308 | ␊ |
| 309 | // Cache up to a track worth of sectors, but do not cross a␊ |
| 310 | // track boundary.␊ |
| 311 | ␊ |
| 312 | xcyl = cyl;␊ |
| 313 | xhead = head;␊ |
| 314 | xsec = sec;␊ |
| 315 | xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;␊ |
| 316 | cache_valid = false;␊ |
| 317 | ␊ |
| 318 | while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) &&␊ |
| 319 | (++tries < 5))␊ |
| 320 | {␊ |
| 321 | if (rc == ECC_CORRECTED_ERR) {␊ |
| 322 | /* Ignore corrected ECC errors */␊ |
| 323 | rc = 0;␊ |
| 324 | break;␊ |
| 325 | }␊ |
| 326 | error(" BIOS read error: %s\n", bios_error(rc), rc);␊ |
| 327 | error(" Block %d, Cyl %d Head %d Sector %d\n",␊ |
| 328 | secno, cyl, head, sec);␊ |
| 329 | sleep(1);␊ |
| 330 | }␊ |
| 331 | }␊ |
| 332 | ␊ |
| 333 | // If the BIOS reported success, mark the sector cache as valid.␊ |
| 334 | ␊ |
| 335 | if (rc == 0) {␊ |
| 336 | cache_valid = true;␊ |
| 337 | }␊ |
| 338 | biosbuf = trackbuf + (secno % divisor) * BPS;␊ |
| 339 | xbiosdev = biosdev;␊ |
| 340 | ␊ |
| 341 | spinActivityIndicator(xnsecs);␊ |
| 342 | ␊ |
| 343 | return rc;␊ |
| 344 | }␊ |
| 345 | ␊ |
| 346 | //==========================================================================␊ |
| 347 | ␊ |
| 348 | int testBiosread( int biosdev, unsigned long long secno )␊ |
| 349 | {␊ |
| 350 | ␉return Biosread(biosdev, secno);␊ |
| 351 | }␊ |
| 352 | ␊ |
| 353 | //==========================================================================␊ |
| 354 | ␊ |
| 355 | static int readBytes( int biosdev, unsigned long long blkno,␊ |
| 356 | unsigned int byteoff,␊ |
| 357 | unsigned int byteCount, void * buffer )␊ |
| 358 | {␊ |
| 359 | // ramdisks require completely different code for reading.␊ |
| 360 | if(p_ramdiskReadBytes != NULL && biosdev >= 0x100)␊ |
| 361 | return (*p_ramdiskReadBytes)(biosdev, blkno, byteoff, byteCount, buffer);␊ |
| 362 | ␊ |
| 363 | char * cbuf = (char *) buffer;␊ |
| 364 | int error;␊ |
| 365 | int copy_len;␊ |
| 366 | ␊ |
| 367 | DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__,␊ |
| 368 | biosdev, blkno, byteCount, (unsigned)cbuf));␊ |
| 369 | ␊ |
| 370 | for ( ; byteCount; cbuf += copy_len, blkno++ )␊ |
| 371 | {␊ |
| 372 | error = Biosread( biosdev, blkno );␊ |
| 373 | if ( error )␊ |
| 374 | {␊ |
| 375 | DEBUG_DISK(("error\n"));␊ |
| 376 | return (-1);␊ |
| 377 | }␊ |
| 378 | ␊ |
| 379 | copy_len = ((byteCount + byteoff) > BPS) ? (BPS - byteoff) : byteCount;␊ |
| 380 | bcopy( biosbuf + byteoff, cbuf, copy_len );␊ |
| 381 | byteCount -= copy_len;␊ |
| 382 | byteoff = 0;␊ |
| 383 | }␊ |
| 384 | ␊ |
| 385 | DEBUG_DISK(("done\n"));␊ |
| 386 | ␊ |
| 387 | return 0; ␊ |
| 388 | }␊ |
| 389 | ␊ |
| 390 | //==========================================================================␊ |
| 391 | ␊ |
| 392 | static int isExtendedFDiskPartition( const struct fdisk_part * part )␊ |
| 393 | {␊ |
| 394 | static unsigned char extParts[] =␊ |
| 395 | {␊ |
| 396 | 0x05, /* Extended */␊ |
| 397 | 0x0f, /* Win95 extended */␊ |
| 398 | 0x85, /* Linux extended */␊ |
| 399 | };␊ |
| 400 | ␊ |
| 401 | unsigned int i;␊ |
| 402 | ␊ |
| 403 | for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)␊ |
| 404 | {␊ |
| 405 | if (extParts[i] == part->systid) return 1;␊ |
| 406 | }␊ |
| 407 | return 0;␊ |
| 408 | }␊ |
| 409 | ␊ |
| 410 | //==========================================================================␊ |
| 411 | ␊ |
| 412 | static int getNextFDiskPartition( int biosdev, int * partno,␊ |
| 413 | const struct fdisk_part ** outPart )␊ |
| 414 | {␊ |
| 415 | static int sBiosdev = -1;␊ |
| 416 | static int sNextPartNo;␊ |
| 417 | static unsigned int sFirstBase;␊ |
| 418 | static unsigned int sExtBase;␊ |
| 419 | static unsigned int sExtDepth;␊ |
| 420 | static struct fdisk_part * sExtPart;␊ |
| 421 | struct fdisk_part * part;␊ |
| 422 | ␊ |
| 423 | if ( sBiosdev != biosdev || *partno < 0 )␊ |
| 424 | {␊ |
| 425 | // Fetch MBR.␊ |
| 426 | if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0;␊ |
| 427 | ␊ |
| 428 | sBiosdev = biosdev;␊ |
| 429 | sNextPartNo = 0;␊ |
| 430 | sFirstBase = 0;␊ |
| 431 | sExtBase = 0;␊ |
| 432 | sExtDepth = 0;␊ |
| 433 | sExtPart = NULL;␊ |
| 434 | }␊ |
| 435 | ␊ |
| 436 | while (1)␊ |
| 437 | {␊ |
| 438 | part = NULL;␊ |
| 439 | ␊ |
| 440 | if ( sNextPartNo < FDISK_NPART )␊ |
| 441 | {␊ |
| 442 | part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];␊ |
| 443 | }␊ |
| 444 | else if ( sExtPart )␊ |
| 445 | {␊ |
| 446 | unsigned int blkno = sExtPart->relsect + sFirstBase;␊ |
| 447 | ␊ |
| 448 | // Save the block offset of the first extended partition.␊ |
| 449 | ␊ |
| 450 | if (sExtDepth == 0) {␊ |
| 451 | sFirstBase = blkno;␊ |
| 452 | }␊ |
| 453 | sExtBase = blkno;␊ |
| 454 | ␊ |
| 455 | // Load extended partition table.␊ |
| 456 | ␊ |
| 457 | if ( readBootSector( biosdev, blkno, 0 ) == 0 )␊ |
| 458 | {␊ |
| 459 | sNextPartNo = 0;␊ |
| 460 | sExtDepth++;␊ |
| 461 | sExtPart = NULL;␊ |
| 462 | continue;␊ |
| 463 | }␊ |
| 464 | // Fall through to part == NULL␊ |
| 465 | }␊ |
| 466 | ␊ |
| 467 | if ( part == NULL ) break; // Reached end of partition chain.␊ |
| 468 | ␊ |
| 469 | // Advance to next partition number.␊ |
| 470 | ␊ |
| 471 | sNextPartNo++;␊ |
| 472 | ␊ |
| 473 | if ( isExtendedFDiskPartition(part) )␊ |
| 474 | {␊ |
| 475 | sExtPart = part;␊ |
| 476 | continue;␊ |
| 477 | }␊ |
| 478 | ␊ |
| 479 | // Skip empty slots.␊ |
| 480 | ␊ |
| 481 | if ( part->systid == 0x00 )␊ |
| 482 | {␊ |
| 483 | continue;␊ |
| 484 | }␊ |
| 485 | ␊ |
| 486 | // Change relative offset to an absolute offset.␊ |
| 487 | part->relsect += sExtBase;␊ |
| 488 | ␊ |
| 489 | *outPart = part;␊ |
| 490 | *partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;␊ |
| 491 | ␊ |
| 492 | break;␊ |
| 493 | }␊ |
| 494 | ␊ |
| 495 | return (part != NULL);␊ |
| 496 | }␊ |
| 497 | ␊ |
| 498 | //==========================================================================␊ |
| 499 | ␊ |
| 500 | static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,␊ |
| 501 | const struct fdisk_part * part,␊ |
| 502 | FSInit initFunc, FSLoadFile loadFunc,␊ |
| 503 | FSReadFile readFunc,␊ |
| 504 | FSGetDirEntry getdirFunc,␊ |
| 505 | FSGetFileBlock getBlockFunc,␊ |
| 506 | FSGetUUID getUUIDFunc,␊ |
| 507 | BVGetDescription getDescriptionFunc,␊ |
| 508 | BVFree bvFreeFunc,␊ |
| 509 | int probe, int type, unsigned int bvrFlags )␊ |
| 510 | {␊ |
| 511 | BVRef bvr = (BVRef) malloc( sizeof(*bvr) );␊ |
| 512 | if ( bvr )␊ |
| 513 | {␊ |
| 514 | bzero(bvr, sizeof(*bvr));␊ |
| 515 | ␊ |
| 516 | bvr->biosdev = biosdev;␊ |
| 517 | bvr->part_no = partno;␊ |
| 518 | bvr->part_boff = blkoff;␊ |
| 519 | bvr->part_type = part->systid;␊ |
| 520 | bvr->fs_loadfile = loadFunc;␊ |
| 521 | bvr->fs_readfile = readFunc;␊ |
| 522 | bvr->fs_getdirentry = getdirFunc;␊ |
| 523 | bvr->fs_getfileblock= getBlockFunc;␊ |
| 524 | bvr->fs_getuuid = getUUIDFunc;␊ |
| 525 | bvr->description = getDescriptionFunc;␊ |
| 526 | bvr->type = type;␊ |
| 527 | bvr->bv_free = bvFreeFunc;␊ |
| 528 | ␊ |
| 529 | if ((part->bootid & FDISK_ACTIVE) && (part->systid == FDISK_HFS))␊ |
| 530 | bvr->flags |= kBVFlagPrimary;␊ |
| 531 | ␊ |
| 532 | // Probe the filesystem.␊ |
| 533 | ␊ |
| 534 | if ( initFunc )␊ |
| 535 | {␊ |
| 536 | bvr->flags |= kBVFlagNativeBoot;␊ |
| 537 | ␊ |
| 538 | if ( probe && initFunc( bvr ) != 0 )␊ |
| 539 | {␊ |
| 540 | // filesystem probe failed.␊ |
| 541 | ␊ |
| 542 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n",␊ |
| 543 | __FUNCTION__, biosdev, partno));␊ |
| 544 | ␊ |
| 545 | (*bvr->bv_free)(bvr);␊ |
| 546 | bvr = NULL;␊ |
| 547 | }␊ |
| 548 | if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
| 549 | {␊ |
| 550 | ␉bvr->flags |= kBVFlagBootable;␊ |
| 551 | }␊ |
| 552 | }␊ |
| 553 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
| 554 | {␊ |
| 555 | bvr->flags |= kBVFlagForeignBoot;␊ |
| 556 | }␊ |
| 557 | else␊ |
| 558 | {␊ |
| 559 | (*bvr->bv_free)(bvr);␊ |
| 560 | bvr = NULL;␊ |
| 561 | }␊ |
| 562 | }␊ |
| 563 | if (bvr) bvr->flags |= bvrFlags;␊ |
| 564 | return bvr;␊ |
| 565 | }␊ |
| 566 | ␊ |
| 567 | //==========================================================================␊ |
| 568 | ␊ |
| 569 | BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,␊ |
| 570 | const DPME * part,␊ |
| 571 | FSInit initFunc, FSLoadFile loadFunc,␊ |
| 572 | FSReadFile readFunc,␊ |
| 573 | FSGetDirEntry getdirFunc,␊ |
| 574 | FSGetFileBlock getBlockFunc,␊ |
| 575 | FSGetUUID getUUIDFunc,␊ |
| 576 | BVGetDescription getDescriptionFunc,␊ |
| 577 | BVFree bvFreeFunc,␊ |
| 578 | int probe, int type, unsigned int bvrFlags )␊ |
| 579 | {␊ |
| 580 | BVRef bvr = (BVRef) malloc( sizeof(*bvr) );␊ |
| 581 | if ( bvr )␊ |
| 582 | {␊ |
| 583 | bzero(bvr, sizeof(*bvr));␊ |
| 584 | ␊ |
| 585 | bvr->biosdev = biosdev;␊ |
| 586 | bvr->part_no = partno;␊ |
| 587 | bvr->part_boff = blkoff;␊ |
| 588 | bvr->fs_loadfile = loadFunc;␊ |
| 589 | bvr->fs_readfile = readFunc;␊ |
| 590 | bvr->fs_getdirentry = getdirFunc;␊ |
| 591 | bvr->fs_getfileblock= getBlockFunc;␊ |
| 592 | bvr->fs_getuuid = getUUIDFunc;␊ |
| 593 | bvr->description = getDescriptionFunc;␊ |
| 594 | bvr->type = type;␊ |
| 595 | bvr->bv_free = bvFreeFunc;␊ |
| 596 | strlcpy(bvr->name, part->dpme_name, DPISTRLEN);␊ |
| 597 | strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);␊ |
| 598 | ␊ |
| 599 | /*␊ |
| 600 | if ( part->bootid & FDISK_ACTIVE )␊ |
| 601 | bvr->flags |= kBVFlagPrimary;␊ |
| 602 | */␊ |
| 603 | ␊ |
| 604 | // Probe the filesystem.␊ |
| 605 | ␊ |
| 606 | if ( initFunc )␊ |
| 607 | {␊ |
| 608 | bvr->flags |= kBVFlagNativeBoot | kBVFlagBootable | kBVFlagSystemVolume;␊ |
| 609 | ␊ |
| 610 | if ( probe && initFunc( bvr ) != 0 )␊ |
| 611 | {␊ |
| 612 | // filesystem probe failed.␊ |
| 613 | ␊ |
| 614 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n",␊ |
| 615 | __FUNCTION__, biosdev, partno));␊ |
| 616 | ␊ |
| 617 | (*bvr->bv_free)(bvr);␊ |
| 618 | bvr = NULL;␊ |
| 619 | }␊ |
| 620 | }␊ |
| 621 | /*␊ |
| 622 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
| 623 | {␊ |
| 624 | bvr->flags |= kBVFlagForeignBoot;␊ |
| 625 | }␊ |
| 626 | */␊ |
| 627 | else␊ |
| 628 | {␊ |
| 629 | (*bvr->bv_free)(bvr);␊ |
| 630 | bvr = NULL;␊ |
| 631 | }␊ |
| 632 | }␊ |
| 633 | if (bvr) bvr->flags |= bvrFlags;␊ |
| 634 | return bvr;␊ |
| 635 | }␊ |
| 636 | ␊ |
| 637 | //==========================================================================␊ |
| 638 | ␊ |
| 639 | // HFS+ GUID in LE form - Hierarchical File System (HFS+) partition - 48465300-0000-11AA-AA11-00306543ECAC␊ |
| 640 | EFI_GUID const GPT_HFS_GUID␉␉ = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
| 641 | ␊ |
| 642 | // turbo - Apple Boot partition - 426F6F74-0000-11AA-AA11-00306543ECAC␊ |
| 643 | EFI_GUID const GPT_BOOT_GUID␉ = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
| 644 | ␊ |
| 645 | // turbo - or an EFI System partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B␊ |
| 646 | EFI_GUID const GPT_EFISYS_GUID␉ = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };␊ |
| 647 | ␊ |
| 648 | // zef - Basic Data partition - EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support␊ |
| 649 | EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };␊ |
| 650 | ␊ |
| 651 | // Microsoft Reserved Partition E3C9E316-0B5C-4DB8-817DF92DF00215AE␊ |
| 652 | EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };␊ |
| 653 | ␊ |
| 654 | BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,␊ |
| 655 | const gpt_ent * part,␊ |
| 656 | FSInit initFunc, FSLoadFile loadFunc,␊ |
| 657 | FSReadFile readFunc,␊ |
| 658 | FSGetDirEntry getdirFunc,␊ |
| 659 | FSGetFileBlock getBlockFunc,␊ |
| 660 | FSGetUUID getUUIDFunc,␊ |
| 661 | BVGetDescription getDescriptionFunc,␊ |
| 662 | BVFree bvFreeFunc,␊ |
| 663 | int probe, int type, unsigned int bvrFlags )␊ |
| 664 | {␊ |
| 665 | BVRef bvr = (BVRef) malloc( sizeof(*bvr) );␊ |
| 666 | if ( bvr )␊ |
| 667 | {␊ |
| 668 | bzero(bvr, sizeof(*bvr));␊ |
| 669 | ␊ |
| 670 | bvr->biosdev = biosdev;␊ |
| 671 | bvr->part_no = partno;␊ |
| 672 | bvr->part_boff = blkoff;␊ |
| 673 | bvr->fs_loadfile = loadFunc;␊ |
| 674 | bvr->fs_readfile = readFunc;␊ |
| 675 | bvr->fs_getdirentry = getdirFunc;␊ |
| 676 | bvr->fs_getfileblock= getBlockFunc;␊ |
| 677 | bvr->fs_getuuid = getUUIDFunc;␊ |
| 678 | bvr->description = getDescriptionFunc;␊ |
| 679 | ␉bvr->type = type;␊ |
| 680 | bvr->bv_free = bvFreeFunc;␊ |
| 681 | // FIXME: UCS-2 -> UTF-8 the name␊ |
| 682 | strlcpy(bvr->name, "----", DPISTRLEN);␊ |
| 683 | if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)part->ent_type) == 0) ||␊ |
| 684 | (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)part->ent_type) == 0) )␊ |
| 685 | strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);␊ |
| 686 | else␊ |
| 687 | strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);␊ |
| 688 | ␊ |
| 689 | /*␊ |
| 690 | if ( part->bootid & FDISK_ACTIVE )␊ |
| 691 | bvr->flags |= kBVFlagPrimary;␊ |
| 692 | */␊ |
| 693 | ␊ |
| 694 | // Probe the filesystem.␊ |
| 695 | ␊ |
| 696 | if ( initFunc )␊ |
| 697 | {␊ |
| 698 | bvr->flags |= kBVFlagNativeBoot;␊ |
| 699 | ␊ |
| 700 | if ( probe && initFunc( bvr ) != 0 )␊ |
| 701 | {␊ |
| 702 | // filesystem probe failed.␊ |
| 703 | ␊ |
| 704 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n",␊ |
| 705 | __FUNCTION__, biosdev, partno));␊ |
| 706 | ␊ |
| 707 | (*bvr->bv_free)(bvr);␊ |
| 708 | bvr = NULL;␊ |
| 709 | }␊ |
| 710 | if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
| 711 | {␊ |
| 712 | ␉bvr->flags |= kBVFlagBootable;␊ |
| 713 | }␊ |
| 714 | }␊ |
| 715 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
| 716 | {␊ |
| 717 | bvr->flags |= kBVFlagForeignBoot;␊ |
| 718 | }␊ |
| 719 | else␊ |
| 720 | {␊ |
| 721 | (*bvr->bv_free)(bvr);␊ |
| 722 | bvr = NULL;␊ |
| 723 | }␊ |
| 724 | }␊ |
| 725 | if (bvr) bvr->flags |= bvrFlags;␊ |
| 726 | return bvr;␊ |
| 727 | }␊ |
| 728 | ␊ |
| 729 | //==========================================================================␊ |
| 730 | ␊ |
| 731 | /* A note on partition numbers:␊ |
| 732 | * IOKit makes the primary partitions numbers 1-4, and then␊ |
| 733 | * extended partitions are numbered consecutively 5 and up.␊ |
| 734 | * So, for example, if you have two primary partitions and␊ |
| 735 | * one extended partition they will be numbered 1, 2, 5.␊ |
| 736 | */␊ |
| 737 | ␊ |
| 738 | static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )␊ |
| 739 | {␊ |
| 740 | const struct fdisk_part * part;␊ |
| 741 | struct DiskBVMap * map;␊ |
| 742 | int partno = -1;␊ |
| 743 | BVRef bvr;␊ |
| 744 | #if UFS_SUPPORT␊ |
| 745 | BVRef booterUFS = NULL;␊ |
| 746 | #endif␊ |
| 747 | int spc;␊ |
| 748 | struct driveInfo di;␊ |
| 749 | boot_drive_info_t *dp;␊ |
| 750 | ␊ |
| 751 | /* Initialize disk info */␊ |
| 752 | if (getDriveInfo(biosdev, &di) != 0) {␊ |
| 753 | ␉return NULL;␊ |
| 754 | }␊ |
| 755 | dp = &di.di;␊ |
| 756 | spc = (dp->params.phys_spt * dp->params.phys_heads);␊ |
| 757 | if (spc == 0) {␊ |
| 758 | ␉/* This is probably a CD-ROM; punt on the geometry. */␊ |
| 759 | ␉spc = 1;␊ |
| 760 | }␊ |
| 761 | ␊ |
| 762 | do {␊ |
| 763 | // Create a new mapping.␊ |
| 764 | ␊ |
| 765 | map = (struct DiskBVMap *) malloc( sizeof(*map) );␊ |
| 766 | if ( map )␊ |
| 767 | {␊ |
| 768 | map->biosdev = biosdev;␊ |
| 769 | map->bvr = NULL;␊ |
| 770 | map->bvrcnt = 0;␊ |
| 771 | map->next = gDiskBVMap;␊ |
| 772 | gDiskBVMap = map;␊ |
| 773 | ␊ |
| 774 | // Create a record for each partition found on the disk.␊ |
| 775 | ␊ |
| 776 | while ( getNextFDiskPartition( biosdev, &partno, &part ) )␊ |
| 777 | {␊ |
| 778 | DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,␊ |
| 779 | partno, part->systid));␊ |
| 780 | bvr = 0;␊ |
| 781 | ␊ |
| 782 | switch ( part->systid )␊ |
| 783 | {␊ |
| 784 | #if UFS_SUPPORT␊ |
| 785 | case FDISK_UFS:␊ |
| 786 | bvr = newFDiskBVRef(␊ |
| 787 | biosdev, partno,␊ |
| 788 | part->relsect + UFS_FRONT_PORCH/BPS,␊ |
| 789 | part,␊ |
| 790 | UFSInitPartition,␊ |
| 791 | UFSLoadFile,␊ |
| 792 | UFSReadFile,␊ |
| 793 | UFSGetDirEntry,␊ |
| 794 | UFSGetFileBlock,␊ |
| 795 | UFSGetUUID,␊ |
| 796 | UFSGetDescription,␊ |
| 797 | UFSFree,␊ |
| 798 | 0,␊ |
| 799 | kBIOSDevTypeHardDrive, 0);␊ |
| 800 | break;␊ |
| 801 | #endif␊ |
| 802 | ␊ |
| 803 | case FDISK_HFS:␊ |
| 804 | bvr = newFDiskBVRef(␊ |
| 805 | biosdev, partno,␊ |
| 806 | part->relsect,␊ |
| 807 | part,␊ |
| 808 | HFSInitPartition,␊ |
| 809 | HFSLoadFile,␊ |
| 810 | HFSReadFile,␊ |
| 811 | HFSGetDirEntry,␊ |
| 812 | HFSGetFileBlock,␊ |
| 813 | HFSGetUUID,␊ |
| 814 | HFSGetDescription,␊ |
| 815 | HFSFree,␊ |
| 816 | 0,␊ |
| 817 | kBIOSDevTypeHardDrive, 0);␊ |
| 818 | break;␊ |
| 819 | ␊ |
| 820 | // turbo - we want the booter type scanned also␊ |
| 821 | case FDISK_BOOTER:␊ |
| 822 | if (part->bootid & FDISK_ACTIVE)␊ |
| 823 | gBIOSBootVolume = newFDiskBVRef(␊ |
| 824 | biosdev, partno,␊ |
| 825 | part->relsect,␊ |
| 826 | part,␊ |
| 827 | HFSInitPartition,␊ |
| 828 | HFSLoadFile,␊ |
| 829 | HFSReadFile,␊ |
| 830 | HFSGetDirEntry,␊ |
| 831 | HFSGetFileBlock,␊ |
| 832 | HFSGetUUID,␊ |
| 833 | HFSGetDescription,␊ |
| 834 | HFSFree,␊ |
| 835 | 0,␊ |
| 836 | kBIOSDevTypeHardDrive, 0);␊ |
| 837 | break;␊ |
| 838 | ␊ |
| 839 | #if UFS_SUPPORT␊ |
| 840 | case FDISK_BOOTER:␊ |
| 841 | booterUFS = newFDiskBVRef(␊ |
| 842 | biosdev, partno,␊ |
| 843 | ((part->relsect + spc - 1) / spc) * spc,␊ |
| 844 | part,␊ |
| 845 | UFSInitPartition,␊ |
| 846 | UFSLoadFile,␊ |
| 847 | UFSReadFile,␊ |
| 848 | UFSGetDirEntry,␊ |
| 849 | UFSGetFileBlock,␊ |
| 850 | UFSGetUUID,␊ |
| 851 | UFSGetDescription,␊ |
| 852 | UFSFree,␊ |
| 853 | 0,␊ |
| 854 | kBIOSDevTypeHardDrive, 0);␊ |
| 855 | break;␊ |
| 856 | #endif␊ |
| 857 | ␊ |
| 858 | case FDISK_FAT32:␊ |
| 859 | case FDISK_DOS12:␊ |
| 860 | case FDISK_DOS16S:␊ |
| 861 | case FDISK_DOS16B:␊ |
| 862 | case FDISK_SMALLFAT32:␊ |
| 863 | case FDISK_DOS16SLBA:␊ |
| 864 | bvr = newFDiskBVRef(␊ |
| 865 | biosdev, partno,␊ |
| 866 | part->relsect,␊ |
| 867 | part,␊ |
| 868 | MSDOSInitPartition,␊ |
| 869 | MSDOSLoadFile,␊ |
| 870 | MSDOSReadFile,␊ |
| 871 | MSDOSGetDirEntry,␊ |
| 872 | MSDOSGetFileBlock,␊ |
| 873 | MSDOSGetUUID,␊ |
| 874 | MSDOSGetDescription,␊ |
| 875 | MSDOSFree,␊ |
| 876 | 0,␊ |
| 877 | kBIOSDevTypeHardDrive, 0);␊ |
| 878 | break;␊ |
| 879 | ␉␉␉␉␉␉␊ |
| 880 | case FDISK_NTFS:␊ |
| 881 | bvr = newFDiskBVRef(␊ |
| 882 | biosdev, partno,␊ |
| 883 | part->relsect,␊ |
| 884 | part,␊ |
| 885 | 0, 0, 0, 0, 0,␊ |
| 886 | NTFSGetUUID,␊ |
| 887 | NTFSGetDescription,␊ |
| 888 | (BVFree)free,␊ |
| 889 | 0, kBIOSDevTypeHardDrive, 0);␊ |
| 890 | break;␊ |
| 891 | ␊ |
| 892 | case FDISK_LINUX:␊ |
| 893 | bvr = newFDiskBVRef(␊ |
| 894 | biosdev, partno,␊ |
| 895 | part->relsect,␊ |
| 896 | part,␊ |
| 897 | 0, 0, 0, 0, 0, 0,␊ |
| 898 | EX2GetDescription,␊ |
| 899 | (BVFree)free,␊ |
| 900 | 0, kBIOSDevTypeHardDrive, 0);␊ |
| 901 | break;␊ |
| 902 | ␉␉␉␉␊ |
| 903 | default:␊ |
| 904 | bvr = newFDiskBVRef(␊ |
| 905 | biosdev, partno,␊ |
| 906 | part->relsect,␊ |
| 907 | part,␊ |
| 908 | 0, 0, 0, 0, 0, 0, 0,␊ |
| 909 | (BVFree)free,␊ |
| 910 | 0,␊ |
| 911 | kBIOSDevTypeHardDrive, 0);␊ |
| 912 | break;␊ |
| 913 | }␊ |
| 914 | ␊ |
| 915 | if ( bvr )␊ |
| 916 | {␊ |
| 917 | bvr->next = map->bvr;␊ |
| 918 | map->bvr = bvr;␊ |
| 919 | map->bvrcnt++;␊ |
| 920 | }␊ |
| 921 | }␊ |
| 922 | ␊ |
| 923 | #if UFS_SUPPORT␊ |
| 924 | // Booting from a CD with an UFS filesystem embedded␊ |
| 925 | // in a booter partition.␊ |
| 926 | ␊ |
| 927 | if ( booterUFS )␊ |
| 928 | {␊ |
| 929 | if ( map->bvrcnt == 0 )␊ |
| 930 | {␊ |
| 931 | map->bvr = booterUFS;␊ |
| 932 | map->bvrcnt++;␊ |
| 933 | }␊ |
| 934 | else free( booterUFS );␊ |
| 935 | }␊ |
| 936 | #endif␊ |
| 937 | }␊ |
| 938 | } while (0);␊ |
| 939 | ␊ |
| 940 | /*␊ |
| 941 | * If no FDisk partition, then we will check for␊ |
| 942 | * an Apple partition map elsewhere.␊ |
| 943 | */␊ |
| 944 | #if UNUSED␊ |
| 945 | if (map->bvrcnt == 0) {␊ |
| 946 | ␉static struct fdisk_part cdpart;␊ |
| 947 | ␉cdpart.systid = 0xCD;␊ |
| 948 | ␊ |
| 949 | ␉/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */␊ |
| 950 | ␉bvr = newFDiskBVRef(␊ |
| 951 | ␉␉␉ biosdev, 0,␊ |
| 952 | ␉␉␉ 0,␊ |
| 953 | ␉␉␉ &cdpart,␊ |
| 954 | ␉␉␉ HFSInitPartition,␊ |
| 955 | ␉␉␉ HFSLoadFile,␊ |
| 956 | HFSReadFile,␊ |
| 957 | ␉␉␉ HFSGetDirEntry,␊ |
| 958 | HFSGetFileBlock,␊ |
| 959 | HFSGetUUID,␊ |
| 960 | ␉␉␉ 0,␊ |
| 961 | ␉␉␉ kBIOSDevTypeHardDrive);␊ |
| 962 | ␉bvr->next = map->bvr;␊ |
| 963 | ␉map->bvr = bvr;␊ |
| 964 | ␉map->bvrcnt++;␊ |
| 965 | }␊ |
| 966 | #endif␊ |
| 967 | // Actually this should always be true given the above code␊ |
| 968 | if(map == gDiskBVMap)␊ |
| 969 | {␊ |
| 970 | // Don't leave a null map in the chain␊ |
| 971 | if(map->bvrcnt == 0 && map->bvr == NULL)␊ |
| 972 | {␊ |
| 973 | gDiskBVMap = map->next;␊ |
| 974 | free(map);␊ |
| 975 | map = NULL;␊ |
| 976 | }␊ |
| 977 | }␊ |
| 978 | ␊ |
| 979 | if (countPtr) *countPtr = map ? map->bvrcnt : 0;␊ |
| 980 | ␊ |
| 981 | return map ? map->bvr : NULL;␊ |
| 982 | }␊ |
| 983 | ␊ |
| 984 | //==========================================================================␊ |
| 985 | ␊ |
| 986 | static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )␊ |
| 987 | {␊ |
| 988 | struct DiskBVMap * map;␊ |
| 989 | struct Block0 *block0_p;␊ |
| 990 | unsigned int blksize;␊ |
| 991 | unsigned int factor;␊ |
| 992 | void *buffer = malloc(BPS);␊ |
| 993 | ␊ |
| 994 | /* Check for alternate block size */␊ |
| 995 | if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {␊ |
| 996 | return NULL;␊ |
| 997 | }␊ |
| 998 | block0_p = buffer;␊ |
| 999 | if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {␊ |
| 1000 | blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);␊ |
| 1001 | if (blksize != BPS) {␊ |
| 1002 | free(buffer);␊ |
| 1003 | buffer = malloc(blksize);␊ |
| 1004 | }␊ |
| 1005 | factor = blksize / BPS;␊ |
| 1006 | } else {␊ |
| 1007 | blksize = BPS;␊ |
| 1008 | factor = 1;␊ |
| 1009 | }␊ |
| 1010 | ␊ |
| 1011 | do {␊ |
| 1012 | // Create a new mapping.␊ |
| 1013 | ␊ |
| 1014 | map = (struct DiskBVMap *) malloc( sizeof(*map) );␊ |
| 1015 | if ( map )␊ |
| 1016 | {␊ |
| 1017 | int error;␊ |
| 1018 | DPME *dpme_p = (DPME *)buffer;␊ |
| 1019 | UInt32 i, npart = UINT_MAX;␊ |
| 1020 | BVRef bvr;␊ |
| 1021 | ␊ |
| 1022 | map->biosdev = biosdev;␊ |
| 1023 | map->bvr = NULL;␊ |
| 1024 | map->bvrcnt = 0;␊ |
| 1025 | map->next = gDiskBVMap;␊ |
| 1026 | gDiskBVMap = map;␊ |
| 1027 | ␊ |
| 1028 | for (i=0; i<npart; i++) {␊ |
| 1029 | error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );␊ |
| 1030 | ␊ |
| 1031 | if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {␊ |
| 1032 | break;␊ |
| 1033 | }␊ |
| 1034 | ␊ |
| 1035 | if (i==0) {␊ |
| 1036 | npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);␊ |
| 1037 | }␊ |
| 1038 | /*␊ |
| 1039 | printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",␊ |
| 1040 | dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",␊ |
| 1041 | dpme.dpme_pblock_start, dpme.dpme_pblocks,␊ |
| 1042 | dpme.dpme_lblock_start, dpme.dpme_lblocks,␊ |
| 1043 | dpme.dpme_boot_block);␊ |
| 1044 | */␊ |
| 1045 | ␊ |
| 1046 | if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {␊ |
| 1047 | bvr = newAPMBVRef(biosdev,␊ |
| 1048 | i,␊ |
| 1049 | OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,␊ |
| 1050 | dpme_p,␊ |
| 1051 | HFSInitPartition,␊ |
| 1052 | HFSLoadFile,␊ |
| 1053 | HFSReadFile,␊ |
| 1054 | HFSGetDirEntry,␊ |
| 1055 | HFSGetFileBlock,␊ |
| 1056 | HFSGetUUID,␊ |
| 1057 | HFSGetDescription,␊ |
| 1058 | HFSFree,␊ |
| 1059 | 0,␊ |
| 1060 | kBIOSDevTypeHardDrive, 0);␊ |
| 1061 | bvr->next = map->bvr;␊ |
| 1062 | map->bvr = bvr;␊ |
| 1063 | map->bvrcnt++;␊ |
| 1064 | }␊ |
| 1065 | }␊ |
| 1066 | }␊ |
| 1067 | } while (0);␊ |
| 1068 | ␊ |
| 1069 | free(buffer);␊ |
| 1070 | ␊ |
| 1071 | if (countPtr) *countPtr = map ? map->bvrcnt : 0;␊ |
| 1072 | ␊ |
| 1073 | return map ? map->bvr : NULL;␊ |
| 1074 | }␊ |
| 1075 | ␊ |
| 1076 | //==========================================================================␊ |
| 1077 | ␊ |
| 1078 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -␊ |
| 1079 | ␊ |
| 1080 | /*␊ |
| 1081 | * Trying to figure out the filsystem type of a given partition.␊ |
| 1082 | */␊ |
| 1083 | static int probeFileSystem(int biosdev, unsigned int blkoff)␊ |
| 1084 | {␊ |
| 1085 | // detected filesystem type;␊ |
| 1086 | int result = -1;␊ |
| 1087 | int fatbits;␊ |
| 1088 | ␊ |
| 1089 | // Allocating buffer for 4 sectors.␊ |
| 1090 | const void * probeBuffer = malloc(PROBEFS_SIZE);␊ |
| 1091 | if (probeBuffer == NULL)␊ |
| 1092 | goto exit;␊ |
| 1093 | ␊ |
| 1094 | // Reading first 4 sectors of current partition␊ |
| 1095 | int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);␊ |
| 1096 | if (error)␊ |
| 1097 | goto exit;␊ |
| 1098 | ␊ |
| 1099 | if (HFSProbe(probeBuffer))␊ |
| 1100 | result = FDISK_HFS;␊ |
| 1101 | else if (EX2Probe(probeBuffer))␊ |
| 1102 | ␉ result = FDISK_LINUX;␊ |
| 1103 | else if (NTFSProbe(probeBuffer))␊ |
| 1104 | result = FDISK_NTFS;␊ |
| 1105 | else if (fatbits=MSDOSProbe(probeBuffer))␊ |
| 1106 | {␊ |
| 1107 | ␉ switch (fatbits)␊ |
| 1108 | ␉ {␊ |
| 1109 | ␉␉ case 32:␊ |
| 1110 | ␉␉ default:␊ |
| 1111 | ␉␉␉ result = FDISK_FAT32;␊ |
| 1112 | ␉␉␉ break;␊ |
| 1113 | ␉␉ case 16:␊ |
| 1114 | ␉␉␉ result = FDISK_DOS16B;␊ |
| 1115 | ␉␉␉ break;␊ |
| 1116 | ␉␉ case 12:␊ |
| 1117 | ␉␉␉ result = FDISK_DOS12;␊ |
| 1118 | ␉␉␉ break;␉␉␉ ␊ |
| 1119 | ␉ }␊ |
| 1120 | }␊ |
| 1121 | else␊ |
| 1122 | // Couldn't detect filesystem type␊ |
| 1123 | result = 0;␊ |
| 1124 | ␊ |
| 1125 | exit:␊ |
| 1126 | if (probeBuffer != NULL) free((void *)probeBuffer);␊ |
| 1127 | return result;␊ |
| 1128 | }␊ |
| 1129 | ␊ |
| 1130 | static bool isPartitionUsed(gpt_ent * partition)␊ |
| 1131 | {␊ |
| 1132 | //␊ |
| 1133 | // Ask whether the given partition is used.␊ |
| 1134 | //␊ |
| 1135 | ␊ |
| 1136 | return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;␊ |
| 1137 | }␊ |
| 1138 | ␊ |
| 1139 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -␊ |
| 1140 | ␊ |
| 1141 | static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )␊ |
| 1142 | {␊ |
| 1143 | struct DiskBVMap * map = NULL;␊ |
| 1144 | void *buffer = malloc(BPS);␊ |
| 1145 | int error;␊ |
| 1146 | if ( error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer ) != 0) {␊ |
| 1147 | verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);␊ |
| 1148 | goto scanErr;␊ |
| 1149 | }␊ |
| 1150 | struct REAL_disk_blk0 *fdiskMap = buffer;␊ |
| 1151 | if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )␊ |
| 1152 | {␊ |
| 1153 | verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);␊ |
| 1154 | goto scanErr;␊ |
| 1155 | }␊ |
| 1156 | ␊ |
| 1157 | int fdiskID = 0;␊ |
| 1158 | unsigned index;␊ |
| 1159 | for ( index = 0; index < FDISK_NPART; index++ )␊ |
| 1160 | {␊ |
| 1161 | if ( fdiskMap->parts[index].systid )␊ |
| 1162 | {␊ |
| 1163 | if ( fdiskMap->parts[index].systid == 0xEE )␊ |
| 1164 | {␊ |
| 1165 | // Fail if two 0xEE partitions are present which␊ |
| 1166 | // means the FDISK code will wind up parsing it.␊ |
| 1167 | if ( fdiskID ) goto scanErr;␊ |
| 1168 | ␊ |
| 1169 | fdiskID = index + 1;␊ |
| 1170 | }␊ |
| 1171 | }␊ |
| 1172 | }␊ |
| 1173 | ␊ |
| 1174 | if ( fdiskID == 0 ) goto scanErr;␊ |
| 1175 | verbose("Attempting to read GPT\n");␊ |
| 1176 | ␊ |
| 1177 | if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)␊ |
| 1178 | goto scanErr;␊ |
| 1179 | ␊ |
| 1180 | gpt_hdr *headerMap = buffer;␊ |
| 1181 | ␊ |
| 1182 | // Determine whether the partition header signature is present.␊ |
| 1183 | ␊ |
| 1184 | if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )␊ |
| 1185 | {␊ |
| 1186 | goto scanErr;␊ |
| 1187 | }␊ |
| 1188 | ␊ |
| 1189 | // Determine whether the partition header size is valid.␊ |
| 1190 | ␊ |
| 1191 | UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);␊ |
| 1192 | UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);␊ |
| 1193 | ␊ |
| 1194 | if ( headerSize < offsetof(gpt_hdr, padding) )␊ |
| 1195 | {␊ |
| 1196 | goto scanErr;␊ |
| 1197 | }␊ |
| 1198 | ␊ |
| 1199 | if ( headerSize > BPS )␊ |
| 1200 | {␊ |
| 1201 | goto scanErr;␊ |
| 1202 | }␊ |
| 1203 | ␊ |
| 1204 | // Determine whether the partition header checksum is valid.␊ |
| 1205 | ␊ |
| 1206 | headerMap->hdr_crc_self = 0;␊ |
| 1207 | ␊ |
| 1208 | if ( crc32(0, headerMap, headerSize) != headerCheck )␊ |
| 1209 | {␊ |
| 1210 | goto scanErr;␊ |
| 1211 | }␊ |
| 1212 | ␊ |
| 1213 | // Determine whether the partition entry size is valid.␊ |
| 1214 | ␊ |
| 1215 | UInt64 gptBlock = 0;␊ |
| 1216 | UInt32 gptCheck = 0;␊ |
| 1217 | UInt32 gptCount = 0;␊ |
| 1218 | UInt32 gptID = 0;␊ |
| 1219 | gpt_ent * gptMap = 0;␊ |
| 1220 | UInt32 gptSize = 0;␊ |
| 1221 | ␊ |
| 1222 | gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);␊ |
| 1223 | gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);␊ |
| 1224 | gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);␊ |
| 1225 | gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);␊ |
| 1226 | ␊ |
| 1227 | if ( gptSize < sizeof(gpt_ent) )␊ |
| 1228 | {␊ |
| 1229 | goto scanErr;␊ |
| 1230 | }␊ |
| 1231 | ␊ |
| 1232 | // Allocate a buffer large enough to hold one map, rounded to a media block.␊ |
| 1233 | free(buffer);␊ |
| 1234 | buffer = NULL;␊ |
| 1235 | ␊ |
| 1236 | UInt32 bufferSize = IORound(gptCount * gptSize, BPS);␊ |
| 1237 | if(bufferSize == 0)␊ |
| 1238 | goto scanErr;␊ |
| 1239 | buffer = malloc(bufferSize);␊ |
| 1240 | ␊ |
| 1241 | if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)␊ |
| 1242 | goto scanErr;␊ |
| 1243 | ␊ |
| 1244 | verbose("Read GPT\n");␊ |
| 1245 | ␊ |
| 1246 | // Allocate a new map for this BIOS device and insert it into the chain␊ |
| 1247 | map = malloc(sizeof(*map));␊ |
| 1248 | map->biosdev = biosdev;␊ |
| 1249 | map->bvr = NULL;␊ |
| 1250 | map->bvrcnt = 0;␊ |
| 1251 | map->next = gDiskBVMap;␊ |
| 1252 | gDiskBVMap = map;␊ |
| 1253 | ␊ |
| 1254 | // fdisk like partition type id.␊ |
| 1255 | int fsType = 0;␊ |
| 1256 | ␊ |
| 1257 | for(gptID = 1; gptID <= gptCount; ++gptID)␊ |
| 1258 | {␊ |
| 1259 | ␉␉␉␉BVRef bvr = NULL;␊ |
| 1260 | ␉␉␉␉unsigned int bvrFlags = 0;␊ |
| 1261 | ␊ |
| 1262 | // size on disk can be larger than sizeof(gpt_ent)␊ |
| 1263 | gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );␊ |
| 1264 | ␊ |
| 1265 | // NOTE: EFI_GUID's are in LE and we know we're on an x86.␊ |
| 1266 | // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.␊ |
| 1267 | ␊ |
| 1268 | if (isPartitionUsed(gptMap))␊ |
| 1269 | {␊ |
| 1270 | char stringuuid[100];␊ |
| 1271 | efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);␊ |
| 1272 | verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);␊ |
| 1273 | ␊ |
| 1274 | // Getting fdisk like partition type.␊ |
| 1275 | fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);␊ |
| 1276 | ␊ |
| 1277 | if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||␊ |
| 1278 | (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )␊ |
| 1279 | {␊ |
| 1280 | bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;␊ |
| 1281 | bvr = newGPTBVRef(biosdev,␊ |
| 1282 | gptID,␊ |
| 1283 | gptMap->ent_lba_start,␊ |
| 1284 | gptMap,␊ |
| 1285 | HFSInitPartition,␊ |
| 1286 | HFSLoadFile,␊ |
| 1287 | HFSReadFile,␊ |
| 1288 | HFSGetDirEntry,␊ |
| 1289 | HFSGetFileBlock,␊ |
| 1290 | HFSGetUUID,␊ |
| 1291 | HFSGetDescription,␊ |
| 1292 | HFSFree,␊ |
| 1293 | 0,␊ |
| 1294 | kBIOSDevTypeHardDrive, bvrFlags);␊ |
| 1295 | }␊ |
| 1296 | ␊ |
| 1297 | ␉␉␉// zef - foreign OS support␊ |
| 1298 | if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||␊ |
| 1299 | (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )␊ |
| 1300 | {␊ |
| 1301 | ␉␉␉␉␉␉␉switch (fsType)␊ |
| 1302 | {␊ |
| 1303 | ␉␉␉␉␉␉␉ case FDISK_NTFS:␊ |
| 1304 | ␉␉␉␉␉␉␉ bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
| 1305 | ␉ ␉␉␉␉␉␉␉␉0, 0, 0, 0, 0, 0, NTFSGetDescription,␊ |
| 1306 | ␉␉ ␉␉␉␉␉␉␉(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);␊ |
| 1307 | ␉␉␉␉␉␉␉␉break;␊ |
| 1308 | ␊ |
| 1309 | default:␊ |
| 1310 | bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
| 1311 | 0, 0, 0, 0, 0, 0, 0,␊ |
| 1312 | (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);␊ |
| 1313 | break;␊ |
| 1314 | }␊ |
| 1315 | ␉␉␉␉␉␉␉ ␊ |
| 1316 | }␊ |
| 1317 | ␊ |
| 1318 | // turbo - save our booter partition␊ |
| 1319 | // zef - only on original boot device␊ |
| 1320 | if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )␊ |
| 1321 | {␊ |
| 1322 | ␉␉␉␉␉␉␉switch (fsType)␊ |
| 1323 | {␊ |
| 1324 | case FDISK_HFS:␊ |
| 1325 | if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)␊ |
| 1326 | {␊ |
| 1327 | bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
| 1328 | HFSInitPartition,␊ |
| 1329 | HFSLoadFile,␊ |
| 1330 | HFSReadFile,␊ |
| 1331 | HFSGetDirEntry,␊ |
| 1332 | HFSGetFileBlock,␊ |
| 1333 | HFSGetUUID,␊ |
| 1334 | HFSGetDescription,␊ |
| 1335 | HFSFree,␊ |
| 1336 | 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);␊ |
| 1337 | }␊ |
| 1338 | break;␊ |
| 1339 | ␊ |
| 1340 | case FDISK_FAT32:␊ |
| 1341 | if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)␊ |
| 1342 | {␊ |
| 1343 | bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
| 1344 | MSDOSInitPartition,␊ |
| 1345 | MSDOSLoadFile,␊ |
| 1346 | MSDOSReadFile,␊ |
| 1347 | MSDOSGetDirEntry,␊ |
| 1348 | MSDOSGetFileBlock,␊ |
| 1349 | MSDOSGetUUID,␊ |
| 1350 | MSDOSGetDescription,␊ |
| 1351 | MSDOSFree,␊ |
| 1352 | 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);␊ |
| 1353 | }␊ |
| 1354 | break;␊ |
| 1355 | ␊ |
| 1356 | if (biosdev == gBIOSDev)␊ |
| 1357 | gBIOSBootVolume = bvr;␊ |
| 1358 | }␊ |
| 1359 | } ␊ |
| 1360 | ␊ |
| 1361 | ␉␉␉␉␉␉if (bvr)␊ |
| 1362 | ␉␉␉␉␉␉{␊ |
| 1363 | // Fixup bvr with the fake fdisk partition type.␊ |
| 1364 | if (fsType > 0) bvr->part_type = fsType;␊ |
| 1365 | ␊ |
| 1366 | ␉␉␉␉␉␉␉bvr->next = map->bvr;␊ |
| 1367 | ␉␉␉␉␉␉␉map->bvr = bvr;␊ |
| 1368 | ␉␉␉␉␉␉␉++map->bvrcnt;␊ |
| 1369 | ␉␉␉␉␉␉}␊ |
| 1370 | ␊ |
| 1371 | }␊ |
| 1372 | }␊ |
| 1373 | ␊ |
| 1374 | scanErr:␊ |
| 1375 | free(buffer);␊ |
| 1376 | ␊ |
| 1377 | if(map)␊ |
| 1378 | {␊ |
| 1379 | if(countPtr) *countPtr = map->bvrcnt;␊ |
| 1380 | return map->bvr;␊ |
| 1381 | }␊ |
| 1382 | else␊ |
| 1383 | {␊ |
| 1384 | if(countPtr) *countPtr = 0;␊ |
| 1385 | return NULL;␊ |
| 1386 | }␊ |
| 1387 | }␊ |
| 1388 | ␊ |
| 1389 | //==========================================================================␊ |
| 1390 | ␊ |
| 1391 | static void scanFSLevelBVRSettings(BVRef chain)␊ |
| 1392 | {␊ |
| 1393 | BVRef bvr;␊ |
| 1394 | char dirSpec[512], fileSpec[512];␊ |
| 1395 | char label[BVSTRLEN];␊ |
| 1396 | int ret;␊ |
| 1397 | long flags, time;␊ |
| 1398 | int fh, fileSize, error;␊ |
| 1399 | ␊ |
| 1400 | for (bvr = chain; bvr; bvr = bvr->next)␊ |
| 1401 | {␊ |
| 1402 | ret = -1;␊ |
| 1403 | error = 0;␊ |
| 1404 | ␊ |
| 1405 | //␊ |
| 1406 | // Check for alternate volume label on boot helper partitions.␊ |
| 1407 | //␊ |
| 1408 | if (bvr->flags & kBVFlagBooter)␊ |
| 1409 | {␊ |
| 1410 | sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);␊ |
| 1411 | strcpy(fileSpec, ".disk_label.contentDetails");␊ |
| 1412 | ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);␊ |
| 1413 | if (!ret)␊ |
| 1414 | {␊ |
| 1415 | fh = open(strcat(dirSpec, fileSpec), 0);␊ |
| 1416 | fileSize = file_size(fh);␊ |
| 1417 | if (fileSize > 0 && fileSize < BVSTRLEN)␊ |
| 1418 | {␊ |
| 1419 | if (read(fh, label, fileSize) != fileSize)␊ |
| 1420 | error = -1;␊ |
| 1421 | }␊ |
| 1422 | else␊ |
| 1423 | error = -1;␊ |
| 1424 | ␊ |
| 1425 | close(fh);␊ |
| 1426 | ␊ |
| 1427 | if (!error)␊ |
| 1428 | {␊ |
| 1429 | label[fileSize] = '\0';␊ |
| 1430 | strcpy(bvr->altlabel, label);␊ |
| 1431 | }␊ |
| 1432 | }␊ |
| 1433 | }␊ |
| 1434 | ␊ |
| 1435 | //␊ |
| 1436 | // Check for SystemVersion.plist or ServerVersion.plist␊ |
| 1437 | // to determine if a volume hosts an installed system.␊ |
| 1438 | //␊ |
| 1439 | if (bvr->flags & kBVFlagNativeBoot)␊ |
| 1440 | {␊ |
| 1441 | sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);␊ |
| 1442 | strcpy(fileSpec, "SystemVersion.plist");␊ |
| 1443 | ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);␊ |
| 1444 | ␊ |
| 1445 | if (ret == -1)␊ |
| 1446 | {␊ |
| 1447 | strcpy(fileSpec, "ServerVersion.plist");␊ |
| 1448 | ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);␊ |
| 1449 | }␊ |
| 1450 | ␊ |
| 1451 | if (!ret)␊ |
| 1452 | bvr->flags |= kBVFlagSystemVolume;␊ |
| 1453 | }␊ |
| 1454 | ␊ |
| 1455 | }␊ |
| 1456 | }␊ |
| 1457 | ␊ |
| 1458 | void rescanBIOSDevice(int biosdev)␊ |
| 1459 | {␊ |
| 1460 | ␉struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);␊ |
| 1461 | ␉CacheReset();␊ |
| 1462 | ␉diskFreeMap(oldMap);␊ |
| 1463 | ␉oldMap = NULL;␊ |
| 1464 | ␉scanBootVolumes(biosdev, 0);␊ |
| 1465 | }␊ |
| 1466 | ␊ |
| 1467 | struct DiskBVMap* diskResetBootVolumes(int biosdev)␊ |
| 1468 | {␊ |
| 1469 | struct DiskBVMap * map;␊ |
| 1470 | struct DiskBVMap *prevMap = NULL;␊ |
| 1471 | for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {␊ |
| 1472 | if ( biosdev == map->biosdev ) {␊ |
| 1473 | break;␊ |
| 1474 | }␊ |
| 1475 | }␊ |
| 1476 | if(map != NULL)␊ |
| 1477 | {␊ |
| 1478 | verbose("Resetting BIOS device %xh\n", biosdev);␊ |
| 1479 | // Reset the biosbuf cache␊ |
| 1480 | cache_valid = false;␊ |
| 1481 | if(map == gDiskBVMap)␊ |
| 1482 | gDiskBVMap = map->next;␊ |
| 1483 | else if(prevMap != NULL)␊ |
| 1484 | prevMap->next = map->next;␊ |
| 1485 | else␊ |
| 1486 | stop("");␊ |
| 1487 | }␊ |
| 1488 | // Return the old map, either to be freed, or reinserted later␊ |
| 1489 | return map;␊ |
| 1490 | }␊ |
| 1491 | ␊ |
| 1492 | // Frees a DiskBVMap and all of its BootVolume's␊ |
| 1493 | void diskFreeMap(struct DiskBVMap *map)␊ |
| 1494 | {␊ |
| 1495 | if(map != NULL)␊ |
| 1496 | {␊ |
| 1497 | while(map->bvr != NULL)␊ |
| 1498 | {␊ |
| 1499 | BVRef bvr = map->bvr;␊ |
| 1500 | map->bvr = bvr->next;␊ |
| 1501 | (*bvr->bv_free)(bvr);␊ |
| 1502 | }␊ |
| 1503 | free(map);␊ |
| 1504 | }␊ |
| 1505 | }␊ |
| 1506 | ␊ |
| 1507 | BVRef diskScanBootVolumes( int biosdev, int * countPtr )␊ |
| 1508 | {␊ |
| 1509 | struct DiskBVMap * map;␊ |
| 1510 | BVRef bvr;␊ |
| 1511 | int count = 0;␊ |
| 1512 | ␊ |
| 1513 | // Find an existing mapping for this device.␊ |
| 1514 | ␊ |
| 1515 | for ( map = gDiskBVMap; map; map = map->next ) {␊ |
| 1516 | if ( biosdev == map->biosdev ) {␊ |
| 1517 | count = map->bvrcnt;␊ |
| 1518 | break;␊ |
| 1519 | }␊ |
| 1520 | }␊ |
| 1521 | ␊ |
| 1522 | if (map == NULL) {␊ |
| 1523 | bvr = diskScanGPTBootVolumes(biosdev, &count);␊ |
| 1524 | if (bvr == NULL) {␊ |
| 1525 | bvr = diskScanFDiskBootVolumes(biosdev, &count);␊ |
| 1526 | }␊ |
| 1527 | if (bvr == NULL) {␊ |
| 1528 | bvr = diskScanAPMBootVolumes(biosdev, &count);␊ |
| 1529 | }␊ |
| 1530 | if (bvr)␊ |
| 1531 | {␊ |
| 1532 | scanFSLevelBVRSettings(bvr);␊ |
| 1533 | }␊ |
| 1534 | } else {␊ |
| 1535 | bvr = map->bvr;␊ |
| 1536 | }␊ |
| 1537 | if (countPtr) *countPtr += count;␊ |
| 1538 | return bvr;␊ |
| 1539 | }␊ |
| 1540 | ␊ |
| 1541 | BVRef getBVChainForBIOSDev(int biosdev)␊ |
| 1542 | {␊ |
| 1543 | BVRef chain = NULL;␊ |
| 1544 | struct DiskBVMap * map = NULL;␊ |
| 1545 | ␊ |
| 1546 | for (map = gDiskBVMap; map; map = map->next)␊ |
| 1547 | {␊ |
| 1548 | if (map->biosdev == biosdev)␊ |
| 1549 | {␊ |
| 1550 | chain = map->bvr;␊ |
| 1551 | break;␊ |
| 1552 | }␊ |
| 1553 | }␊ |
| 1554 | ␊ |
| 1555 | return chain;␊ |
| 1556 | }␊ |
| 1557 | ␊ |
| 1558 | BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)␊ |
| 1559 | {␊ |
| 1560 | BVRef chain = NULL;␊ |
| 1561 | BVRef bvr = NULL;␊ |
| 1562 | BVRef newBVR = NULL;␊ |
| 1563 | BVRef prevBVR = NULL;␊ |
| 1564 | ␊ |
| 1565 | struct DiskBVMap * map = NULL;␊ |
| 1566 | int bvCount = 0;␊ |
| 1567 | ␊ |
| 1568 | const char *raw = 0;␊ |
| 1569 | char* val = 0;␊ |
| 1570 | int len;␊ |
| 1571 | ␊ |
| 1572 | getValueForKey(kHidePartitionKey, &raw, &len, &bootInfo->bootConfig);␊ |
| 1573 | if(raw)␊ |
| 1574 | {␊ |
| 1575 | val = XMLDecode(raw); ␊ |
| 1576 | }␊ |
| 1577 | ␊ |
| 1578 | /*␊ |
| 1579 | * Traverse gDISKBVmap to get references for␊ |
| 1580 | * individual bvr chains of each drive.␊ |
| 1581 | */␊ |
| 1582 | for (map = gDiskBVMap; map; map = map->next)␊ |
| 1583 | {␊ |
| 1584 | for (bvr = map->bvr; bvr; bvr = bvr->next)␊ |
| 1585 | {␊ |
| 1586 | /*␊ |
| 1587 | * Save the last bvr.␊ |
| 1588 | */␊ |
| 1589 | if (newBVR) prevBVR = newBVR;␊ |
| 1590 | ␊ |
| 1591 | /*␊ |
| 1592 | * Allocate and copy the matched bvr entry into a new one.␊ |
| 1593 | */␊ |
| 1594 | newBVR = (BVRef) malloc(sizeof(*newBVR));␊ |
| 1595 | bcopy(bvr, newBVR, sizeof(*newBVR));␊ |
| 1596 | ␊ |
| 1597 | /*␊ |
| 1598 | * Adjust the new bvr's fields.␊ |
| 1599 | */␊ |
| 1600 | newBVR->next = NULL;␊ |
| 1601 | newBVR->filtered = true;␊ |
| 1602 | ␊ |
| 1603 | if ( (!allowFlags || newBVR->flags & allowFlags)␊ |
| 1604 | && (!denyFlags || !(newBVR->flags & denyFlags) )␊ |
| 1605 | && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)␊ |
| 1606 | )␊ |
| 1607 | newBVR->visible = true;␊ |
| 1608 | ␊ |
| 1609 | /*␊ |
| 1610 | * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,␊ |
| 1611 | * to be able to hide foreign partitions from the boot menu.␊ |
| 1612 | *␊ |
| 1613 | * Azi: disable the limit to foreign partitions.␊ |
| 1614 | */␊ |
| 1615 | if ( (newBVR->flags/* & kBVFlagForeignBoot*/) )␊ |
| 1616 | {␊ |
| 1617 | char *start, *next = val;␊ |
| 1618 | long len = 0; ␊ |
| 1619 | do␊ |
| 1620 | {␊ |
| 1621 | start = strbreak(next, &next, &len);␊ |
| 1622 | if(len && matchVolumeToString(newBVR, start, len) )␊ |
| 1623 | ␉ newBVR->visible = false;␊ |
| 1624 | }␊ |
| 1625 | while ( next && *next );␊ |
| 1626 | }␊ |
| 1627 | ␊ |
| 1628 | /*␊ |
| 1629 | * Use the first bvr entry as the starting chain pointer.␊ |
| 1630 | */␊ |
| 1631 | if (!chain)␊ |
| 1632 | chain = newBVR;␊ |
| 1633 | ␊ |
| 1634 | /*␊ |
| 1635 | * Update the previous bvr's link pointer to use the new memory area.␊ |
| 1636 | */␊ |
| 1637 | if (prevBVR)␊ |
| 1638 | prevBVR->next = newBVR;␊ |
| 1639 | ␊ |
| 1640 | if (newBVR->visible)␊ |
| 1641 | bvCount++;␊ |
| 1642 | }␊ |
| 1643 | }␊ |
| 1644 | ␊ |
| 1645 | #if DEBUG␊ |
| 1646 | for (bvr = chain; bvr; bvr = bvr->next)␊ |
| 1647 | {␊ |
| 1648 | printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);␊ |
| 1649 | }␊ |
| 1650 | printf("count: %d\n", bvCount);␊ |
| 1651 | getc();␊ |
| 1652 | #endif␊ |
| 1653 | ␊ |
| 1654 | *count = bvCount;␊ |
| 1655 | ␊ |
| 1656 | free(val); ␊ |
| 1657 | return chain;␊ |
| 1658 | }␊ |
| 1659 | ␊ |
| 1660 | int freeFilteredBVChain(const BVRef chain)␊ |
| 1661 | {␊ |
| 1662 | int ret = 1;␊ |
| 1663 | BVRef bvr = chain;␊ |
| 1664 | BVRef nextBVR = NULL;␊ |
| 1665 | ␊ |
| 1666 | while (bvr)␊ |
| 1667 | {␊ |
| 1668 | nextBVR = bvr->next;␊ |
| 1669 | ␊ |
| 1670 | if (bvr->filtered)␊ |
| 1671 | {␊ |
| 1672 | free(bvr);␊ |
| 1673 | }␊ |
| 1674 | else␊ |
| 1675 | {␊ |
| 1676 | ret = 0;␊ |
| 1677 | break;␊ |
| 1678 | }␊ |
| 1679 | ␊ |
| 1680 | bvr = nextBVR;␊ |
| 1681 | }␊ |
| 1682 | ␊ |
| 1683 | return ret;␊ |
| 1684 | }␊ |
| 1685 | ␊ |
| 1686 | //==========================================================================␊ |
| 1687 | ␊ |
| 1688 | static const struct NamedValue fdiskTypes[] =␊ |
| 1689 | {␊ |
| 1690 | { FDISK_NTFS, "Windows NTFS" },␊ |
| 1691 | ␉{ FDISK_DOS12, "Windows FAT12" },␊ |
| 1692 | ␉{ FDISK_DOS16B, "Windows FAT16" },␊ |
| 1693 | ␉{ FDISK_DOS16S, "Windows FAT16" },␊ |
| 1694 | ␉{ FDISK_DOS16SLBA, "Windows FAT16" },␊ |
| 1695 | ␉{ FDISK_SMALLFAT32, "Windows FAT32" },␊ |
| 1696 | ␉{ FDISK_FAT32, "Windows FAT32" },␊ |
| 1697 | { FDISK_LINUX, "Linux" },␊ |
| 1698 | { FDISK_UFS, "Apple UFS" },␊ |
| 1699 | { FDISK_HFS, "Apple HFS" },␊ |
| 1700 | { FDISK_BOOTER, "Apple Boot/UFS" },␊ |
| 1701 | { 0xCD, "CD-ROM" },␊ |
| 1702 | { 0x00, 0 } /* must be last */␊ |
| 1703 | };␊ |
| 1704 | ␊ |
| 1705 | //==========================================================================␊ |
| 1706 | ␊ |
| 1707 | bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)␊ |
| 1708 | {␊ |
| 1709 | ␉char testStr[128];␊ |
| 1710 | ␊ |
| 1711 | ␉if ( !bvr || !match || !*match)␊ |
| 1712 | ␉␉return 0;␊ |
| 1713 | ␉␊ |
| 1714 | ␉if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )␊ |
| 1715 | return 0;␊ |
| 1716 | ␊ |
| 1717 | // Try to match hd(x,y) first.␊ |
| 1718 | sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);␊ |
| 1719 | if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )␊ |
| 1720 | return true;␊ |
| 1721 | ␊ |
| 1722 | // Try to match volume UUID.␊ |
| 1723 | if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)␊ |
| 1724 | {␊ |
| 1725 | if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )␊ |
| 1726 | return true;␊ |
| 1727 | }␊ |
| 1728 | ␊ |
| 1729 | // Try to match volume label (always quoted).␊ |
| 1730 | if ( bvr->description )␊ |
| 1731 | {␊ |
| 1732 | bvr->description(bvr, testStr, sizeof(testStr)-1);␊ |
| 1733 | if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )␊ |
| 1734 | return true;␊ |
| 1735 | }␊ |
| 1736 | ␊ |
| 1737 | return false;␊ |
| 1738 | }␊ |
| 1739 | ␊ |
| 1740 | /* If Rename Partition has defined an alias, then extract it for description purpose.␊ |
| 1741 | * The format for the rename string is the following:␊ |
| 1742 | * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias";etc...␊ |
| 1743 | */␊ |
| 1744 | ␊ |
| 1745 | bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)␊ |
| 1746 | {␊ |
| 1747 | char *aliasList, *entryStart, *entryNext;␊ |
| 1748 | ␊ |
| 1749 | if ( !str || strMaxLen <= 0)␊ |
| 1750 | return false;␊ |
| 1751 | ␊ |
| 1752 | aliasList = XMLDecode(getStringForKey(kRenamePartitionKey, &bootInfo->bootConfig));␊ |
| 1753 | if ( !aliasList )␊ |
| 1754 | return false;␊ |
| 1755 | ␊ |
| 1756 | for ( entryStart = entryNext = aliasList;␊ |
| 1757 | entryNext && *entryNext;␊ |
| 1758 | entryStart = entryNext )␊ |
| 1759 | {␊ |
| 1760 | char *volStart, *volEnd, *aliasStart;␊ |
| 1761 | long volLen, aliasLen;␊ |
| 1762 | ␊ |
| 1763 | // Delimit current entry␊ |
| 1764 | entryNext = strchr(entryStart, ';');␊ |
| 1765 | if ( entryNext )␊ |
| 1766 | {␊ |
| 1767 | *entryNext = '\0';␊ |
| 1768 | entryNext++;␊ |
| 1769 | }␊ |
| 1770 | ␊ |
| 1771 | volStart = strbreak(entryStart, &volEnd, &volLen);␊ |
| 1772 | if(!volLen)␊ |
| 1773 | continue;␊ |
| 1774 | ␊ |
| 1775 | aliasStart = strbreak(volEnd, 0, &aliasLen);␊ |
| 1776 | if(!aliasLen)␊ |
| 1777 | continue;␊ |
| 1778 | ␊ |
| 1779 | if ( matchVolumeToString(bvr, volStart, volLen) )␊ |
| 1780 | { ␊ |
| 1781 | strncat(str, aliasStart, min(strMaxLen, aliasLen));␊ |
| 1782 | free(aliasList);␊ |
| 1783 | ␊ |
| 1784 | return true;␊ |
| 1785 | }␊ |
| 1786 | }␊ |
| 1787 | ␊ |
| 1788 | free(aliasList);␊ |
| 1789 | return false;␊ |
| 1790 | }␊ |
| 1791 | ␊ |
| 1792 | void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )␊ |
| 1793 | {␊ |
| 1794 | unsigned char type;␊ |
| 1795 | char *p = str;␊ |
| 1796 | ␊ |
| 1797 | if(!bvr || !p || strMaxLen <= 0)␊ |
| 1798 | return;␊ |
| 1799 | ␊ |
| 1800 | type = (unsigned char) bvr->part_type;␊ |
| 1801 | ␉␊ |
| 1802 | if (useDeviceDescription)␊ |
| 1803 | {␊ |
| 1804 | int len = getDeviceDescription(bvr, str);␊ |
| 1805 | if(len >= strMaxLen)␊ |
| 1806 | return;␊ |
| 1807 | ␊ |
| 1808 | strcpy(str + len, " ");␊ |
| 1809 | len++;␊ |
| 1810 | strMaxLen -= len;␊ |
| 1811 | p += len;␊ |
| 1812 | }␊ |
| 1813 | ␉␊ |
| 1814 | /* See if a partition rename is preferred */␊ |
| 1815 | if(getVolumeLabelAlias(bvr, p, strMaxLen)) {␊ |
| 1816 | strncpy(bvr->label, p, strMaxLen); ␊ |
| 1817 | return; // we're done here no need to seek for real name␊ |
| 1818 | }␊ |
| 1819 | ␊ |
| 1820 | //␊ |
| 1821 | // Get the volume label using filesystem specific functions␊ |
| 1822 | // or use the alternate volume label if available.␊ |
| 1823 | //␊ |
| 1824 | ␉if (*bvr->altlabel != '\0')␊ |
| 1825 | strncpy(p, bvr->altlabel, strMaxLen);␊ |
| 1826 | ␉else if (bvr->description)␊ |
| 1827 | bvr->description(bvr, p, strMaxLen);␊ |
| 1828 | ␊ |
| 1829 | if (*p == '\0') {␊ |
| 1830 | const char * name = getNameForValue( fdiskTypes, type );␊ |
| 1831 | if (name == NULL) {␊ |
| 1832 | name = bvr->type_name;␊ |
| 1833 | }␊ |
| 1834 | if (name == NULL) {␊ |
| 1835 | sprintf(p, "TYPE %02x", type);␊ |
| 1836 | } else {␊ |
| 1837 | strncpy(p, name, strMaxLen);␊ |
| 1838 | }␊ |
| 1839 | }␊ |
| 1840 | ␊ |
| 1841 | // Set the devices label␊ |
| 1842 | sprintf(bvr->label, p);␊ |
| 1843 | }␊ |
| 1844 | ␊ |
| 1845 | //==========================================================================␊ |
| 1846 | int readBootSector( int biosdev, unsigned int secno, void * buffer )␊ |
| 1847 | {␊ |
| 1848 | struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;␊ |
| 1849 | int error;␊ |
| 1850 | ␊ |
| 1851 | if ( bootSector == NULL )␊ |
| 1852 | {␊ |
| 1853 | if ( gBootSector == NULL )␊ |
| 1854 | {␊ |
| 1855 | gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));␊ |
| 1856 | if ( gBootSector == NULL ) return -1;␊ |
| 1857 | }␊ |
| 1858 | bootSector = gBootSector;␊ |
| 1859 | }␊ |
| 1860 | ␊ |
| 1861 | error = readBytes( biosdev, secno, 0, BPS, bootSector );␊ |
| 1862 | if ( error || bootSector->signature != DISK_SIGNATURE )␊ |
| 1863 | return -1;␊ |
| 1864 | ␊ |
| 1865 | return 0;␊ |
| 1866 | }␊ |
| 1867 | ␊ |
| 1868 | /*␊ |
| 1869 | * Format of boot1f32 block.␊ |
| 1870 | */␊ |
| 1871 | ␊ |
| 1872 | #define BOOT1F32_MAGIC "BOOT "␊ |
| 1873 | #define BOOT1F32_MAGICLEN 11␊ |
| 1874 | ␊ |
| 1875 | struct disk_boot1f32_blk {␊ |
| 1876 | unsigned char init[3];␊ |
| 1877 | unsigned char fsheader[87];␊ |
| 1878 | unsigned char magic[BOOT1F32_MAGICLEN];␊ |
| 1879 | unsigned char bootcode[409];␊ |
| 1880 | unsigned short signature;␊ |
| 1881 | };␊ |
| 1882 | ␊ |
| 1883 | int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )␊ |
| 1884 | {␊ |
| 1885 | struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;␊ |
| 1886 | int error;␊ |
| 1887 | ␊ |
| 1888 | if ( bootSector == NULL )␊ |
| 1889 | {␊ |
| 1890 | if ( gBootSector == NULL )␊ |
| 1891 | {␊ |
| 1892 | gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));␊ |
| 1893 | if ( gBootSector == NULL ) return -1;␊ |
| 1894 | }␊ |
| 1895 | bootSector = (struct disk_boot1f32_blk *) gBootSector;␊ |
| 1896 | }␊ |
| 1897 | ␊ |
| 1898 | error = readBytes( biosdev, secno, 0, BPS, bootSector );␊ |
| 1899 | if ( error || bootSector->signature != DISK_SIGNATURE␊ |
| 1900 | || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )␊ |
| 1901 | return -1;␊ |
| 1902 | ␊ |
| 1903 | return 0;␊ |
| 1904 | }␊ |
| 1905 | ␊ |
| 1906 | //==========================================================================␊ |
| 1907 | // Handle seek request from filesystem modules.␊ |
| 1908 | ␊ |
| 1909 | void diskSeek( BVRef bvr, long long position )␊ |
| 1910 | {␊ |
| 1911 | bvr->fs_boff = position / BPS;␊ |
| 1912 | bvr->fs_byteoff = position % BPS;␊ |
| 1913 | }␊ |
| 1914 | ␊ |
| 1915 | //==========================================================================␊ |
| 1916 | // Handle read request from filesystem modules.␊ |
| 1917 | ␊ |
| 1918 | int diskRead( BVRef bvr, long addr, long length )␊ |
| 1919 | {␊ |
| 1920 | return readBytes( bvr->biosdev,␊ |
| 1921 | bvr->fs_boff + bvr->part_boff,␊ |
| 1922 | bvr->fs_byteoff,␊ |
| 1923 | length,␊ |
| 1924 | (void *) addr );␊ |
| 1925 | }␊ |
| 1926 | ␊ |
| 1927 | int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )␊ |
| 1928 | {␊ |
| 1929 | int secs;␊ |
| 1930 | unsigned char *cbuf = (unsigned char *)buffer;␊ |
| 1931 | unsigned int copy_len;␊ |
| 1932 | int rc;␊ |
| 1933 | ␊ |
| 1934 | if ((len & (BPS-1)) != 0) {␊ |
| 1935 | error("raw disk read not sector aligned");␊ |
| 1936 | return -1;␊ |
| 1937 | }␊ |
| 1938 | secno += bvr->part_boff;␊ |
| 1939 | ␊ |
| 1940 | cache_valid = false;␊ |
| 1941 | ␊ |
| 1942 | while (len > 0) {␊ |
| 1943 | secs = len / BPS;␊ |
| 1944 | if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;␊ |
| 1945 | copy_len = secs * BPS;␊ |
| 1946 | ␊ |
| 1947 | //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);␊ |
| 1948 | if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {␊ |
| 1949 | /* Ignore corrected ECC errors */␊ |
| 1950 | if (rc != ECC_CORRECTED_ERR) {␊ |
| 1951 | error(" EBIOS read error: %s\n", bios_error(rc), rc);␊ |
| 1952 | error(" Block %d Sectors %d\n", secno, secs);␊ |
| 1953 | return rc;␊ |
| 1954 | }␊ |
| 1955 | }␊ |
| 1956 | bcopy( trackbuf, cbuf, copy_len );␊ |
| 1957 | len -= copy_len;␊ |
| 1958 | cbuf += copy_len;␊ |
| 1959 | secno += secs;␊ |
| 1960 | spinActivityIndicator(secs);␊ |
| 1961 | }␊ |
| 1962 | ␊ |
| 1963 | return 0;␊ |
| 1964 | }␊ |
| 1965 | ␊ |
| 1966 | int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )␊ |
| 1967 | {␊ |
| 1968 | int secs;␊ |
| 1969 | unsigned char *cbuf = (unsigned char *)buffer;␊ |
| 1970 | unsigned int copy_len;␊ |
| 1971 | int rc;␊ |
| 1972 | ␊ |
| 1973 | if ((len & (BPS-1)) != 0) {␊ |
| 1974 | error("raw disk write not sector aligned");␊ |
| 1975 | return -1;␊ |
| 1976 | }␊ |
| 1977 | secno += bvr->part_boff;␊ |
| 1978 | ␊ |
| 1979 | cache_valid = false;␊ |
| 1980 | ␊ |
| 1981 | while (len > 0) {␊ |
| 1982 | secs = len / BPS;␊ |
| 1983 | if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;␊ |
| 1984 | copy_len = secs * BPS;␊ |
| 1985 | ␊ |
| 1986 | bcopy( cbuf, trackbuf, copy_len );␊ |
| 1987 | //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);␊ |
| 1988 | if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {␊ |
| 1989 | error(" EBIOS write error: %s\n", bios_error(rc), rc);␊ |
| 1990 | error(" Block %d Sectors %d\n", secno, secs);␊ |
| 1991 | return rc;␊ |
| 1992 | }␊ |
| 1993 | len -= copy_len;␊ |
| 1994 | cbuf += copy_len;␊ |
| 1995 | secno += secs;␊ |
| 1996 | spinActivityIndicator(secs);␊ |
| 1997 | }␊ |
| 1998 | ␊ |
| 1999 | return 0;␊ |
| 2000 | }␊ |
| 2001 | ␊ |
| 2002 | //Azi: for device drawing purposes (gui.c)␊ |
| 2003 | int diskIsCDROM(BVRef bvr)␊ |
| 2004 | {␊ |
| 2005 | struct driveInfo di;␊ |
| 2006 | ␊ |
| 2007 | if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {␊ |
| 2008 | ␉return 1;␊ |
| 2009 | }␊ |
| 2010 | return 0;␊ |
| 2011 | }␊ |
| 2012 | ␊ |
| 2013 | int biosDevIsCDROM(int biosdev)␊ |
| 2014 | {␊ |
| 2015 | struct driveInfo di;␊ |
| 2016 | ␊ |
| 2017 | if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)␊ |
| 2018 | {␊ |
| 2019 | ␉return 1;␊ |
| 2020 | }␊ |
| 2021 | return 0;␊ |
| 2022 | }␊ |
| 2023 | |