Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/Chameleon/i386/libsaio/disk.c

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

Archive Download this file

Revision: 296