Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Package/i386/libsaio/disk.c

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//Azi: style the rest later...
54
55// Allow UFS_SUPPORT to be overridden with preprocessor option.
56#ifndef UFS_SUPPORT
57// zef: Disabled UFS support
58#define UFS_SUPPORT 0
59#endif
60
61#if UFS_SUPPORT
62#include "ufs.h"
63#endif
64#include <limits.h>
65#include <IOKit/storage/IOApplePartitionScheme.h>
66#include <IOKit/storage/IOGUIDPartitionScheme.h>
67#include "libsaio.h"
68#include "boot.h"
69#include "bootstruct.h"
70#include "memory.h"
71#include "fdisk.h"
72#include "hfs.h"
73#include "ntfs.h"
74#include "msdos.h"
75#include "ext2fs.h"
76#include "befs.h"
77#include "freebsd.h"
78#include "openbsd.h"
79#include "xml.h"
80#include "disk.h"
81// For EFI_GUID
82#include "efi.h"
83#include "efi_tables.h"
84
85typedef struct gpt_hdr gpt_hdr;
86typedef 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 */
112static char * const trackbuf = (char *) ptov(BIOS_ADDR);
113static char * biosbuf;
114
115/*
116 * Map a disk drive to bootable volumes contained within.
117 */
118struct 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
125static struct DiskBVMap * gDiskBVMap = NULL;
126static struct disk_blk0 * gBootSector = NULL;
127
128// Function pointers to be filled in if ramdisks are available:
129int (*p_ramdiskReadBytes)( int biosdev, unsigned int blkno,
130 unsigned int byteoff,
131 unsigned int byteCount, void * buffer ) = NULL;
132int (*p_get_ramdisk_info)(int biosdev, struct driveInfo *dip) = NULL;
133
134
135extern void spinActivityIndicator(int sectors);
136
137//==========================================================================
138
139static 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 {
164cc = 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
180struct NamedValue {
181 unsigned char value;
182 const char * name;
183};
184
185static 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
199static 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
209static 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
229static bool cache_valid = false;
230
231static 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) {
243return -1;
244 }
245 if (di.no_emulation) {
246/* Always assume 2k block size; BIOS may lie about geometry */
247bps = 2048;
248 } else {
249bps = 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 */
292int 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
348int testBiosread( int biosdev, unsigned long long secno )
349{
350return Biosread(biosdev, secno);
351}
352
353//==========================================================================
354
355static 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
392static 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
412static 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
500static 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
569BVRef 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// GUID's in LE form:
640// HFS+ partition - 48465300-0000-11AA-AA11-00306543ECAC
641EFI_GUID const GPT_HFS_GUID = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
642
643// turbo - Apple Boot Partition - 426F6F74-0000-11AA-AA11-00306543ECAC
644EFI_GUID const GPT_BOOT_GUID = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
645
646// turbo - or an EFI System Partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B
647EFI_GUID const GPT_EFISYS_GUID = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };
648
649// zef - Basic Data Partition - EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support
650EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };
651
652// Microsoft Reserved Partition - E3C9E316-0B5C-4DB8-817DF92DF00215AE
653EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };
654
655
656BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,
657 const gpt_ent * part,
658 FSInit initFunc, FSLoadFile loadFunc,
659 FSReadFile readFunc,
660 FSGetDirEntry getdirFunc,
661 FSGetFileBlock getBlockFunc,
662 FSGetUUID getUUIDFunc,
663 BVGetDescription getDescriptionFunc,
664 BVFree bvFreeFunc,
665 int probe, int type, unsigned int bvrFlags )
666{
667 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
668 if ( bvr )
669 {
670 bzero(bvr, sizeof(*bvr));
671
672 bvr->biosdev = biosdev;
673 bvr->part_no = partno;
674 bvr->part_boff = blkoff;
675 bvr->fs_loadfile = loadFunc;
676 bvr->fs_readfile = readFunc;
677 bvr->fs_getdirentry = getdirFunc;
678 bvr->fs_getfileblock= getBlockFunc;
679 bvr->fs_getuuid = getUUIDFunc;
680 bvr->description = getDescriptionFunc;
681 bvr->type = type;
682 bvr->bv_free = bvFreeFunc;
683 // FIXME: UCS-2 -> UTF-8 the name
684 strlcpy(bvr->name, "----", DPISTRLEN);
685 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)part->ent_type) == 0) ||
686 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)part->ent_type) == 0) )
687 strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);
688 else
689 strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);
690
691 /*
692 if ( part->bootid & FDISK_ACTIVE )
693 bvr->flags |= kBVFlagPrimary;
694 */
695
696 // Probe the filesystem.
697
698 if ( initFunc )
699 {
700 bvr->flags |= kBVFlagNativeBoot;
701
702 if ( probe && initFunc( bvr ) != 0 )
703 {
704 // filesystem probe failed.
705
706 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
707 __FUNCTION__, biosdev, partno));
708
709 (*bvr->bv_free)(bvr);
710 bvr = NULL;
711 }
712 if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
713 {
714 bvr->flags |= kBVFlagBootable;
715 }
716 }
717 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
718 {
719 bvr->flags |= kBVFlagForeignBoot;
720 }
721 else
722 {
723 (*bvr->bv_free)(bvr);
724 bvr = NULL;
725 }
726 }
727 if (bvr) bvr->flags |= bvrFlags;
728 return bvr;
729}
730
731//==========================================================================
732
733/* A note on partition numbers:
734 * IOKit makes the primary partitions numbers 1-4, and then
735 * extended partitions are numbered consecutively 5 and up.
736 * So, for example, if you have two primary partitions and
737 * one extended partition they will be numbered 1, 2, 5.
738 */
739
740static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
741{
742 const struct fdisk_part * part;
743 struct DiskBVMap * map;
744 int partno = -1;
745 BVRef bvr;
746#if UFS_SUPPORT
747 BVRef booterUFS = NULL;
748#endif
749 int spc;
750 struct driveInfo di;
751 boot_drive_info_t *dp;
752
753 /* Initialize disk info */
754 if (getDriveInfo(biosdev, &di) != 0) {
755return NULL;
756 }
757 dp = &di.di;
758 spc = (dp->params.phys_spt * dp->params.phys_heads);
759 if (spc == 0) {
760/* This is probably a CD-ROM; punt on the geometry. */
761spc = 1;
762 }
763
764 do {
765 // Create a new mapping.
766
767 map = (struct DiskBVMap *) malloc( sizeof(*map) );
768 if ( map )
769 {
770 map->biosdev = biosdev;
771 map->bvr = NULL;
772 map->bvrcnt = 0;
773 map->next = gDiskBVMap;
774 gDiskBVMap = map;
775
776 // Create a record for each partition found on the disk.
777
778 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
779 {
780 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
781 partno, part->systid));
782 bvr = 0;
783
784 switch ( part->systid )
785 {
786#if UFS_SUPPORT
787 case FDISK_UFS:
788 bvr = newFDiskBVRef(
789 biosdev, partno,
790 part->relsect + UFS_FRONT_PORCH/BPS,
791 part,
792 UFSInitPartition,
793 UFSLoadFile,
794 UFSReadFile,
795 UFSGetDirEntry,
796 UFSGetFileBlock,
797 UFSGetUUID,
798 UFSGetDescription,
799 UFSFree,
800 0,
801 kBIOSDevTypeHardDrive, 0);
802 break;
803#endif
804
805 case FDISK_HFS:
806 bvr = newFDiskBVRef(
807 biosdev, partno,
808 part->relsect,
809 part,
810 HFSInitPartition,
811 HFSLoadFile,
812 HFSReadFile,
813 HFSGetDirEntry,
814 HFSGetFileBlock,
815 HFSGetUUID,
816 HFSGetDescription,
817 HFSFree,
818 0,
819 kBIOSDevTypeHardDrive, 0);
820 break;
821
822 // turbo - we want the booter type scanned also
823 case FDISK_BOOTER:
824 if (part->bootid & FDISK_ACTIVE)
825 gBIOSBootVolume = newFDiskBVRef(
826 biosdev, partno,
827 part->relsect,
828 part,
829 HFSInitPartition,
830 HFSLoadFile,
831 HFSReadFile,
832 HFSGetDirEntry,
833 HFSGetFileBlock,
834 HFSGetUUID,
835 HFSGetDescription,
836 HFSFree,
837 0,
838 kBIOSDevTypeHardDrive, 0);
839 break;
840
841#if UFS_SUPPORT
842 case FDISK_BOOTER:
843 booterUFS = newFDiskBVRef(
844 biosdev, partno,
845 ((part->relsect + spc - 1) / spc) * spc,
846 part,
847 UFSInitPartition,
848 UFSLoadFile,
849 UFSReadFile,
850 UFSGetDirEntry,
851 UFSGetFileBlock,
852 UFSGetUUID,
853 UFSGetDescription,
854 UFSFree,
855 0,
856 kBIOSDevTypeHardDrive, 0);
857 break;
858#endif
859
860 case FDISK_FAT32:
861 case FDISK_DOS12:
862 case FDISK_DOS16S:
863 case FDISK_DOS16B:
864 case FDISK_SMALLFAT32:
865 case FDISK_DOS16SLBA:
866 bvr = newFDiskBVRef(
867 biosdev, partno,
868 part->relsect,
869 part,
870 MSDOSInitPartition,
871 MSDOSLoadFile,
872 MSDOSReadFile,
873 MSDOSGetDirEntry,
874 MSDOSGetFileBlock,
875 MSDOSGetUUID,
876 MSDOSGetDescription,
877 MSDOSFree,
878 0,
879 kBIOSDevTypeHardDrive, 0);
880 break;
881
882 case FDISK_NTFS:
883 bvr = newFDiskBVRef(
884 biosdev, partno,
885 part->relsect,
886 part,
887 0, 0, 0, 0, 0,
888 NTFSGetUUID,
889 NTFSGetDescription,
890 (BVFree)free,
891 0, kBIOSDevTypeHardDrive, 0);
892 break;
893
894 case FDISK_LINUX:
895 bvr = newFDiskBVRef(
896 biosdev, partno,
897 part->relsect,
898 part,
899 0, 0, 0, 0, 0, 0,
900 EX2GetDescription,
901 (BVFree)free,
902 0, kBIOSDevTypeHardDrive, 0);
903 break;
904
905 case FDISK_BEFS:
906 bvr = newFDiskBVRef(
907 biosdev, partno,
908 part->relsect,
909 part,
910 0, 0, 0, 0, 0, 0,
911 BeFSGetDescription,
912 (BVFree)free,
913 0, kBIOSDevTypeHardDrive, 0);
914 break;
915
916 case FDISK_FREEBSD:
917 bvr = newFDiskBVRef(
918 biosdev, partno,
919 part->relsect,
920 part,
921 0, 0, 0, 0, 0, 0,
922 FreeBSDGetDescription,
923 (BVFree)free,
924 0, kBIOSDevTypeHardDrive, 0);
925 break;
926
927 case FDISK_OPENBSD:
928 bvr = newFDiskBVRef(
929 biosdev, partno,
930 part->relsect,
931 part,
932 0, 0, 0, 0, 0, 0,
933 OpenBSDGetDescription,
934 (BVFree)free,
935 0, kBIOSDevTypeHardDrive, 0);
936 break;
937
938 default:
939 bvr = newFDiskBVRef(
940 biosdev, partno,
941 part->relsect,
942 part,
943 0, 0, 0, 0, 0, 0, 0,
944 (BVFree)free,
945 0,
946 kBIOSDevTypeHardDrive, 0);
947 break;
948 }
949
950 if ( bvr )
951 {
952 bvr->next = map->bvr;
953 map->bvr = bvr;
954 map->bvrcnt++;
955 }
956 }
957
958#if UFS_SUPPORT
959 // Booting from a CD with an UFS filesystem embedded
960 // in a booter partition.
961
962 if ( booterUFS )
963 {
964 if ( map->bvrcnt == 0 )
965 {
966 map->bvr = booterUFS;
967 map->bvrcnt++;
968 }
969 else free( booterUFS );
970 }
971#endif
972 }
973 } while (0);
974
975 /*
976 * If no FDisk partition, then we will check for
977 * an Apple partition map elsewhere.
978 */
979#if UNUSED
980 if (map->bvrcnt == 0) {
981static struct fdisk_part cdpart;
982cdpart.systid = 0xCD;
983
984/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
985bvr = newFDiskBVRef(
986 biosdev, 0,
987 0,
988 &cdpart,
989 HFSInitPartition,
990 HFSLoadFile,
991 HFSReadFile,
992 HFSGetDirEntry,
993 HFSGetFileBlock,
994 HFSGetUUID,
995 0,
996 kBIOSDevTypeHardDrive);
997bvr->next = map->bvr;
998map->bvr = bvr;
999map->bvrcnt++;
1000 }
1001#endif
1002 // Actually this should always be true given the above code
1003 if(map == gDiskBVMap)
1004 {
1005 // Don't leave a null map in the chain
1006 if(map->bvrcnt == 0 && map->bvr == NULL)
1007 {
1008 gDiskBVMap = map->next;
1009 free(map);
1010 map = NULL;
1011 }
1012 }
1013
1014 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1015
1016 return map ? map->bvr : NULL;
1017}
1018
1019//==========================================================================
1020
1021static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
1022{
1023 struct DiskBVMap * map;
1024 struct Block0 *block0_p;
1025 unsigned int blksize;
1026 unsigned int factor;
1027 void *buffer = malloc(BPS);
1028
1029 /* Check for alternate block size */
1030 if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
1031 return NULL;
1032 }
1033 block0_p = buffer;
1034 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
1035 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1036 if (blksize != BPS) {
1037 free(buffer);
1038 buffer = malloc(blksize);
1039 }
1040 factor = blksize / BPS;
1041 } else {
1042 blksize = BPS;
1043 factor = 1;
1044 }
1045
1046 do {
1047 // Create a new mapping.
1048
1049 map = (struct DiskBVMap *) malloc( sizeof(*map) );
1050 if ( map )
1051 {
1052 int error;
1053 DPME *dpme_p = (DPME *)buffer;
1054 UInt32 i, npart = UINT_MAX;
1055 BVRef bvr;
1056
1057 map->biosdev = biosdev;
1058 map->bvr = NULL;
1059 map->bvrcnt = 0;
1060 map->next = gDiskBVMap;
1061 gDiskBVMap = map;
1062
1063 for (i=0; i<npart; i++) {
1064 error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1065
1066 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
1067 break;
1068 }
1069
1070 if (i==0) {
1071 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1072 }
1073 /*
1074 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1075 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1076 dpme.dpme_pblock_start, dpme.dpme_pblocks,
1077 dpme.dpme_lblock_start, dpme.dpme_lblocks,
1078 dpme.dpme_boot_block);
1079 */
1080
1081 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
1082 bvr = newAPMBVRef(biosdev,
1083 i,
1084 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1085 dpme_p,
1086 HFSInitPartition,
1087 HFSLoadFile,
1088 HFSReadFile,
1089 HFSGetDirEntry,
1090 HFSGetFileBlock,
1091 HFSGetUUID,
1092 HFSGetDescription,
1093 HFSFree,
1094 0,
1095 kBIOSDevTypeHardDrive, 0);
1096 bvr->next = map->bvr;
1097 map->bvr = bvr;
1098 map->bvrcnt++;
1099 }
1100 }
1101 }
1102 } while (0);
1103
1104 free(buffer);
1105
1106 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1107
1108 return map ? map->bvr : NULL;
1109}
1110
1111//==========================================================================
1112
1113// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1114
1115/*
1116 * Trying to figure out the filsystem type of a given partition.
1117 */
1118static int probeFileSystem(int biosdev, unsigned int blkoff)
1119{
1120 // detected filesystem type;
1121 int result = -1;
1122 int fatbits;
1123
1124 // Allocating buffer for 4 sectors.
1125 const void * probeBuffer = malloc(PROBEFS_SIZE);
1126 if (probeBuffer == NULL)
1127 goto exit;
1128
1129 // Reading first 4 sectors of current partition
1130 int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
1131 if (error)
1132 goto exit;
1133
1134 if (HFSProbe(probeBuffer))
1135 result = FDISK_HFS;
1136 else if (EX2Probe(probeBuffer))
1137 result = FDISK_LINUX;
1138 else if (FreeBSDProbe(probeBuffer))
1139 result = FDISK_FREEBSD;
1140 else if (OpenBSDProbe(probeBuffer))
1141 result = FDISK_OPENBSD;
1142 else if (NTFSProbe(probeBuffer))
1143 result = FDISK_NTFS;
1144 else if (BeFSProbe(probeBuffer))
1145 result = FDISK_BEFS;
1146 else if (fatbits=MSDOSProbe(probeBuffer))
1147 {
1148 switch (fatbits)
1149 {
1150 case 32:
1151 default:
1152 result = FDISK_FAT32;
1153 break;
1154 case 16:
1155 result = FDISK_DOS16B;
1156 break;
1157 case 12:
1158 result = FDISK_DOS12;
1159 break;
1160 }
1161 }
1162 else
1163 // Couldn't detect filesystem type
1164 result = 0;
1165
1166exit:
1167 if (probeBuffer != NULL) free((void *)probeBuffer);
1168 return result;
1169}
1170
1171static bool isPartitionUsed(gpt_ent * partition)
1172{
1173 //
1174 // Ask whether the given partition is used.
1175 //
1176
1177 return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1178}
1179
1180// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1181
1182static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )
1183{
1184 struct DiskBVMap * map = NULL;
1185 void *buffer = malloc(BPS);
1186 int error;
1187 if ( error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer ) != 0) {
1188 verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1189 goto scanErr;
1190 }
1191 struct REAL_disk_blk0 *fdiskMap = buffer;
1192 if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1193 {
1194 verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1195 goto scanErr;
1196 }
1197
1198 int fdiskID = 0;
1199 unsigned index;
1200 for ( index = 0; index < FDISK_NPART; index++ )
1201 {
1202 if ( fdiskMap->parts[index].systid )
1203 {
1204 if ( fdiskMap->parts[index].systid == 0xEE )
1205 {
1206 // Fail if two 0xEE partitions are present which
1207 // means the FDISK code will wind up parsing it.
1208 if ( fdiskID ) goto scanErr;
1209
1210 fdiskID = index + 1;
1211 }
1212 }
1213 }
1214
1215 if ( fdiskID == 0 ) goto scanErr;
1216 verbose("Attempting to read GPT\n");
1217
1218 if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1219 goto scanErr;
1220
1221 gpt_hdr *headerMap = buffer;
1222
1223 // Determine whether the partition header signature is present.
1224
1225 if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1226 {
1227 goto scanErr;
1228 }
1229
1230 // Determine whether the partition header size is valid.
1231
1232 UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1233 UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1234
1235 if ( headerSize < offsetof(gpt_hdr, padding) )
1236 {
1237 goto scanErr;
1238 }
1239
1240 if ( headerSize > BPS )
1241 {
1242 goto scanErr;
1243 }
1244
1245 // Determine whether the partition header checksum is valid.
1246
1247 headerMap->hdr_crc_self = 0;
1248
1249 if ( crc32(0, headerMap, headerSize) != headerCheck )
1250 {
1251 goto scanErr;
1252 }
1253
1254 // Determine whether the partition entry size is valid.
1255
1256 UInt64 gptBlock = 0;
1257 UInt32 gptCheck = 0;
1258 UInt32 gptCount = 0;
1259 UInt32 gptID = 0;
1260 gpt_ent * gptMap = 0;
1261 UInt32 gptSize = 0;
1262
1263 gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1264 gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1265 gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1266 gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1267
1268 if ( gptSize < sizeof(gpt_ent) )
1269 {
1270 goto scanErr;
1271 }
1272
1273 // Allocate a buffer large enough to hold one map, rounded to a media block.
1274 free(buffer);
1275 buffer = NULL;
1276
1277 UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1278 if(bufferSize == 0)
1279 goto scanErr;
1280 buffer = malloc(bufferSize);
1281
1282 if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1283 goto scanErr;
1284
1285 verbose("Read GPT\n");
1286
1287 // Allocate a new map for this BIOS device and insert it into the chain
1288 map = malloc(sizeof(*map));
1289 map->biosdev = biosdev;
1290 map->bvr = NULL;
1291 map->bvrcnt = 0;
1292 map->next = gDiskBVMap;
1293 gDiskBVMap = map;
1294
1295 // fdisk like partition type id.
1296 int fsType = 0;
1297
1298 for(gptID = 1; gptID <= gptCount; ++gptID)
1299 {
1300BVRef bvr = NULL;
1301unsigned int bvrFlags = 0;
1302
1303 // size on disk can be larger than sizeof(gpt_ent)
1304 gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1305
1306 // NOTE: EFI_GUID's are in LE and we know we're on an x86.
1307 // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1308
1309 if (isPartitionUsed(gptMap))
1310 {
1311 char stringuuid[100];
1312 efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1313 verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1314
1315 // Getting fdisk like partition type.
1316 fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1317
1318 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1319 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1320 {
1321 bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1322 bvr = newGPTBVRef(biosdev,
1323 gptID,
1324 gptMap->ent_lba_start,
1325 gptMap,
1326 HFSInitPartition,
1327 HFSLoadFile,
1328 HFSReadFile,
1329 HFSGetDirEntry,
1330 HFSGetFileBlock,
1331 HFSGetUUID,
1332 HFSGetDescription,
1333 HFSFree,
1334 0,
1335 kBIOSDevTypeHardDrive, bvrFlags);
1336 }
1337
1338// zef - foreign OS support
1339 if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1340 (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1341 {
1342switch (fsType)
1343 {
1344 case FDISK_NTFS:
1345 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1346 0, 0, 0, 0, 0, 0, NTFSGetDescription,
1347 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1348break;
1349
1350 default:
1351 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1352 0, 0, 0, 0, 0, 0, 0,
1353 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1354 break;
1355 }
1356
1357 }
1358
1359 // turbo - save our booter partition
1360 // zef - only on original boot device
1361 if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1362 {
1363switch (fsType)
1364 {
1365 case FDISK_HFS:
1366 if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1367 {
1368 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1369 HFSInitPartition,
1370 HFSLoadFile,
1371 HFSReadFile,
1372 HFSGetDirEntry,
1373 HFSGetFileBlock,
1374 HFSGetUUID,
1375 HFSGetDescription,
1376 HFSFree,
1377 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1378 }
1379 break;
1380
1381 case FDISK_FAT32:
1382 if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1383 {
1384 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1385 MSDOSInitPartition,
1386 MSDOSLoadFile,
1387 MSDOSReadFile,
1388 MSDOSGetDirEntry,
1389 MSDOSGetFileBlock,
1390 MSDOSGetUUID,
1391 MSDOSGetDescription,
1392 MSDOSFree,
1393 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1394 }
1395 break;
1396
1397 if (biosdev == gBIOSDev)
1398 gBIOSBootVolume = bvr;
1399 }
1400 }
1401
1402if (bvr)
1403{
1404 // Fixup bvr with the fake fdisk partition type.
1405 if (fsType > 0) bvr->part_type = fsType;
1406
1407bvr->next = map->bvr;
1408map->bvr = bvr;
1409++map->bvrcnt;
1410}
1411
1412 }
1413 }
1414
1415scanErr:
1416 free(buffer);
1417
1418 if(map)
1419 {
1420 if(countPtr) *countPtr = map->bvrcnt;
1421 return map->bvr;
1422 }
1423 else
1424 {
1425 if(countPtr) *countPtr = 0;
1426 return NULL;
1427 }
1428}
1429
1430//==========================================================================
1431
1432static void scanFSLevelBVRSettings(BVRef chain)
1433{
1434 BVRef bvr;
1435 char dirSpec[512], fileSpec[512];
1436 char label[BVSTRLEN];
1437 int ret;
1438 long flags, time;
1439 int fh, fileSize, error;
1440
1441 for (bvr = chain; bvr; bvr = bvr->next)
1442 {
1443 ret = -1;
1444 error = 0;
1445
1446 //
1447 // Check for alternate volume label on boot helper partitions.
1448 //
1449 if (bvr->flags & kBVFlagBooter)
1450 {
1451 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1452 strcpy(fileSpec, ".disk_label.contentDetails");
1453 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1454 if (!ret)
1455 {
1456 fh = open(strcat(dirSpec, fileSpec), 0);
1457 fileSize = file_size(fh);
1458 if (fileSize > 0 && fileSize < BVSTRLEN)
1459 {
1460 if (read(fh, label, fileSize) != fileSize)
1461 error = -1;
1462 }
1463 else
1464 error = -1;
1465
1466 close(fh);
1467
1468 if (!error)
1469 {
1470 label[fileSize] = '\0';
1471 strcpy(bvr->altlabel, label);
1472 }
1473 }
1474 }
1475
1476 //
1477 // Check for SystemVersion.plist or ServerVersion.plist
1478 // to determine if a volume hosts an installed system.
1479 //
1480 if (bvr->flags & kBVFlagNativeBoot)
1481 {
1482 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1483 strcpy(fileSpec, "SystemVersion.plist");
1484 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1485
1486 if (ret == -1)
1487 {
1488 strcpy(fileSpec, "ServerVersion.plist");
1489 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1490 }
1491
1492 if (!ret)
1493 bvr->flags |= kBVFlagSystemVolume;
1494 }
1495
1496 }
1497}
1498
1499void rescanBIOSDevice(int biosdev)
1500{
1501struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1502CacheReset();
1503diskFreeMap(oldMap);
1504oldMap = NULL;
1505scanBootVolumes(biosdev, 0);
1506}
1507
1508struct DiskBVMap* diskResetBootVolumes(int biosdev)
1509{
1510 struct DiskBVMap * map;
1511 struct DiskBVMap *prevMap = NULL;
1512 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1513 if ( biosdev == map->biosdev ) {
1514 break;
1515 }
1516 }
1517 if(map != NULL)
1518 {
1519 verbose("Resetting BIOS device %xh\n", biosdev);
1520 // Reset the biosbuf cache
1521 cache_valid = false;
1522 if(map == gDiskBVMap)
1523 gDiskBVMap = map->next;
1524 else if(prevMap != NULL)
1525 prevMap->next = map->next;
1526 else
1527 stop("");
1528 }
1529 // Return the old map, either to be freed, or reinserted later
1530 return map;
1531}
1532
1533// Frees a DiskBVMap and all of its BootVolume's
1534void diskFreeMap(struct DiskBVMap *map)
1535{
1536 if(map != NULL)
1537 {
1538 while(map->bvr != NULL)
1539 {
1540 BVRef bvr = map->bvr;
1541 map->bvr = bvr->next;
1542 (*bvr->bv_free)(bvr);
1543 }
1544 free(map);
1545 }
1546}
1547
1548BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1549{
1550 struct DiskBVMap * map;
1551 BVRef bvr;
1552 int count = 0;
1553
1554 // Find an existing mapping for this device.
1555
1556 for ( map = gDiskBVMap; map; map = map->next ) {
1557 if ( biosdev == map->biosdev ) {
1558 count = map->bvrcnt;
1559 break;
1560 }
1561 }
1562
1563 if (map == NULL) {
1564 bvr = diskScanGPTBootVolumes(biosdev, &count);
1565 if (bvr == NULL) {
1566 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1567 }
1568 if (bvr == NULL) {
1569 bvr = diskScanAPMBootVolumes(biosdev, &count);
1570 }
1571 if (bvr)
1572 {
1573 scanFSLevelBVRSettings(bvr);
1574 }
1575 } else {
1576 bvr = map->bvr;
1577 }
1578 if (countPtr) *countPtr += count;
1579 return bvr;
1580}
1581
1582BVRef getBVChainForBIOSDev(int biosdev)
1583{
1584 BVRef chain = NULL;
1585 struct DiskBVMap * map = NULL;
1586
1587 for (map = gDiskBVMap; map; map = map->next)
1588 {
1589 if (map->biosdev == biosdev)
1590 {
1591 chain = map->bvr;
1592 break;
1593 }
1594 }
1595
1596 return chain;
1597}
1598
1599BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1600{
1601 BVRef chain = NULL;
1602 BVRef bvr = NULL;
1603 BVRef newBVR = NULL;
1604 BVRef prevBVR = NULL;
1605
1606 struct DiskBVMap * map = NULL;
1607 int bvCount = 0;
1608
1609 const char *raw = 0;
1610 char* val = 0;
1611 int len;
1612
1613 getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1614 if(raw)
1615 {
1616 val = XMLDecode(raw);
1617 }
1618
1619 /*
1620 * Traverse gDISKBVmap to get references for
1621 * individual bvr chains of each drive.
1622 */
1623 for (map = gDiskBVMap; map; map = map->next)
1624 {
1625 for (bvr = map->bvr; bvr; bvr = bvr->next)
1626 {
1627 /*
1628 * Save the last bvr.
1629 */
1630 if (newBVR) prevBVR = newBVR;
1631
1632 /*
1633 * Allocate and copy the matched bvr entry into a new one.
1634 */
1635 newBVR = (BVRef) malloc(sizeof(*newBVR));
1636 bcopy(bvr, newBVR, sizeof(*newBVR));
1637
1638 /*
1639 * Adjust the new bvr's fields.
1640 */
1641 newBVR->next = NULL;
1642 newBVR->filtered = true;
1643
1644 if ( (!allowFlags || newBVR->flags & allowFlags)
1645 && (!denyFlags || !(newBVR->flags & denyFlags) )
1646 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1647 )
1648 newBVR->visible = true;
1649
1650 /*
1651 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1652 * to be able to hide foreign partitions from the boot menu.
1653 *
1654 */
1655 if ( (newBVR->flags & kBVFlagForeignBoot) )
1656 {
1657 char *start, *next = val;
1658 long len = 0;
1659 do
1660 {
1661 start = strbreak(next, &next, &len);
1662 if(len && matchVolumeToString(newBVR, start, len) )
1663 newBVR->visible = false;
1664 }
1665 while ( next && *next );
1666 }
1667
1668 /*
1669 * Use the first bvr entry as the starting chain pointer.
1670 */
1671 if (!chain)
1672 chain = newBVR;
1673
1674 /*
1675 * Update the previous bvr's link pointer to use the new memory area.
1676 */
1677 if (prevBVR)
1678 prevBVR->next = newBVR;
1679
1680 if (newBVR->visible)
1681 bvCount++;
1682 }
1683 }
1684
1685#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1686 for (bvr = chain; bvr; bvr = bvr->next)
1687 {
1688 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1689 }
1690 printf("count: %d\n", bvCount);
1691 getchar();
1692#endif
1693
1694 *count = bvCount;
1695
1696 free(val);
1697 return chain;
1698}
1699
1700int freeFilteredBVChain(const BVRef chain)
1701{
1702 int ret = 1;
1703 BVRef bvr = chain;
1704 BVRef nextBVR = NULL;
1705
1706 while (bvr)
1707 {
1708 nextBVR = bvr->next;
1709
1710 if (bvr->filtered)
1711 {
1712 free(bvr);
1713 }
1714 else
1715 {
1716 ret = 0;
1717 break;
1718 }
1719
1720 bvr = nextBVR;
1721 }
1722
1723 return ret;
1724}
1725
1726//==========================================================================
1727
1728static const struct NamedValue fdiskTypes[] =
1729{
1730{ FDISK_NTFS,"Windows NTFS" },
1731{ FDISK_DOS12,"Windows FAT12" },
1732{ FDISK_DOS16B,"Windows FAT16" },
1733{ FDISK_DOS16S,"Windows FAT16" },
1734{ FDISK_DOS16SLBA,"Windows FAT16" },
1735{ FDISK_SMALLFAT32,"Windows FAT32" },
1736{ FDISK_FAT32,"Windows FAT32" },
1737{ FDISK_FREEBSD,"FreeBSD" },
1738{ FDISK_OPENBSD,"OpenBSD" },
1739{ FDISK_LINUX,"Linux" },
1740{ FDISK_UFS,"Apple UFS" },
1741{ FDISK_HFS,"Apple HFS" },
1742{ FDISK_BOOTER,"Apple Boot/UFS" },
1743{ FDISK_BEFS,"Haiku" },
1744{ 0xCD,"CD-ROM" },
1745{ 0x00,0 } /* must be last */
1746};
1747
1748//==========================================================================
1749
1750bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1751{
1752char testStr[128];
1753
1754if ( !bvr || !match || !*match)
1755return 0;
1756
1757if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1758 return 0;
1759
1760 // Try to match hd(x,y) first.
1761 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1762 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1763 return true;
1764
1765 // Try to match volume UUID.
1766 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1767 {
1768 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1769 return true;
1770 }
1771
1772 // Try to match volume label (always quoted).
1773 if ( bvr->description )
1774 {
1775 bvr->description(bvr, testStr, sizeof(testStr)-1);
1776 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1777 return true;
1778 }
1779
1780 return false;
1781}
1782
1783/* If Rename Partition has defined an alias, then extract it for description purpose.
1784 * The format for the rename string is the following:
1785 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
1786 */
1787
1788bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
1789{
1790 char *aliasList, *entryStart, *entryNext;
1791
1792 if ( !str || strMaxLen <= 0)
1793 return false;
1794
1795 aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
1796 if ( !aliasList )
1797 return false;
1798
1799 for ( entryStart = entryNext = aliasList;
1800 entryNext && *entryNext;
1801 entryStart = entryNext )
1802 {
1803 char *volStart, *volEnd, *aliasStart;
1804 long volLen, aliasLen;
1805
1806 // Delimit current entry
1807 entryNext = strchr(entryStart, ';');
1808 if ( entryNext )
1809 {
1810 *entryNext = '\0';
1811 entryNext++;
1812 }
1813
1814 volStart = strbreak(entryStart, &volEnd, &volLen);
1815 if(!volLen)
1816 continue;
1817
1818 aliasStart = strbreak(volEnd, 0, &aliasLen);
1819 if(!aliasLen)
1820 continue;
1821
1822 if ( matchVolumeToString(bvr, volStart, volLen) )
1823 {
1824 strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
1825 free(aliasList);
1826
1827 return true;
1828 }
1829 }
1830
1831 free(aliasList);
1832 return false;
1833}
1834
1835void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1836{
1837 unsigned char type;
1838 char *p = str;
1839
1840 if(!bvr || !p || strMaxLen <= 0)
1841 return;
1842
1843 type = (unsigned char) bvr->part_type;
1844
1845 if (useDeviceDescription)
1846 {
1847 int len = getDeviceDescription(bvr, str);
1848 if(len >= strMaxLen)
1849 return;
1850
1851 strcpy(str + len, " ");
1852 len++;
1853 strMaxLen -= len;
1854 p += len;
1855 }
1856
1857 /* See if a partition rename is preferred */
1858 if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
1859 strncpy(bvr->label, p, strMaxLen);
1860 return; // we're done here no need to seek for real name
1861 }
1862
1863 //
1864 // Get the volume label using filesystem specific functions
1865 // or use the alternate volume label if available.
1866 //
1867if (*bvr->altlabel != '\0')
1868 strncpy(p, bvr->altlabel, strMaxLen);
1869else if (bvr->description)
1870 bvr->description(bvr, p, strMaxLen);
1871
1872 if (*p == '\0') {
1873 const char * name = getNameForValue( fdiskTypes, type );
1874 if (name == NULL) {
1875 name = bvr->type_name;
1876 }
1877 if (name == NULL) {
1878 sprintf(p, "TYPE %02x", type);
1879 } else {
1880 strncpy(p, name, strMaxLen);
1881 }
1882 }
1883
1884 // Set the devices label
1885 sprintf(bvr->label, p);
1886}
1887
1888//==========================================================================
1889int readBootSector( int biosdev, unsigned int secno, void * buffer )
1890{
1891 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
1892 int error;
1893
1894 if ( bootSector == NULL )
1895 {
1896 if ( gBootSector == NULL )
1897 {
1898 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1899 if ( gBootSector == NULL ) return -1;
1900 }
1901 bootSector = gBootSector;
1902 }
1903
1904 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1905 if ( error || bootSector->signature != DISK_SIGNATURE )
1906 return -1;
1907
1908 return 0;
1909}
1910
1911/*
1912 * Format of boot1f32 block.
1913 */
1914
1915#define BOOT1F32_MAGIC "BOOT "
1916#define BOOT1F32_MAGICLEN 11
1917
1918struct disk_boot1f32_blk {
1919 unsigned char init[3];
1920 unsigned char fsheader[87];
1921 unsigned char magic[BOOT1F32_MAGICLEN];
1922 unsigned char bootcode[409];
1923 unsigned short signature;
1924};
1925
1926int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
1927{
1928 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
1929 int error;
1930
1931 if ( bootSector == NULL )
1932 {
1933 if ( gBootSector == NULL )
1934 {
1935 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1936 if ( gBootSector == NULL ) return -1;
1937 }
1938 bootSector = (struct disk_boot1f32_blk *) gBootSector;
1939 }
1940
1941 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1942 if ( error || bootSector->signature != DISK_SIGNATURE
1943 || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
1944 return -1;
1945
1946 return 0;
1947}
1948
1949//==========================================================================
1950// Handle seek request from filesystem modules.
1951
1952void diskSeek( BVRef bvr, long long position )
1953{
1954 bvr->fs_boff = position / BPS;
1955 bvr->fs_byteoff = position % BPS;
1956}
1957
1958//==========================================================================
1959// Handle read request from filesystem modules.
1960
1961int diskRead( BVRef bvr, long addr, long length )
1962{
1963 return readBytes( bvr->biosdev,
1964 bvr->fs_boff + bvr->part_boff,
1965 bvr->fs_byteoff,
1966 length,
1967 (void *) addr );
1968}
1969
1970int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1971{
1972 int secs;
1973 unsigned char *cbuf = (unsigned char *)buffer;
1974 unsigned int copy_len;
1975 int rc;
1976
1977 if ((len & (BPS-1)) != 0) {
1978 error("raw disk read not sector aligned");
1979 return -1;
1980 }
1981 secno += bvr->part_boff;
1982
1983 cache_valid = false;
1984
1985 while (len > 0) {
1986 secs = len / BPS;
1987 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1988 copy_len = secs * BPS;
1989
1990 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1991 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
1992 /* Ignore corrected ECC errors */
1993 if (rc != ECC_CORRECTED_ERR) {
1994 error(" EBIOS read error: %s\n", bios_error(rc), rc);
1995 error(" Block %d Sectors %d\n", secno, secs);
1996 return rc;
1997 }
1998 }
1999 bcopy( trackbuf, cbuf, copy_len );
2000 len -= copy_len;
2001 cbuf += copy_len;
2002 secno += secs;
2003 spinActivityIndicator(secs);
2004 }
2005
2006 return 0;
2007}
2008
2009int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2010{
2011 int secs;
2012 unsigned char *cbuf = (unsigned char *)buffer;
2013 unsigned int copy_len;
2014 int rc;
2015
2016 if ((len & (BPS-1)) != 0) {
2017 error("raw disk write not sector aligned");
2018 return -1;
2019 }
2020 secno += bvr->part_boff;
2021
2022 cache_valid = false;
2023
2024 while (len > 0) {
2025 secs = len / BPS;
2026 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2027 copy_len = secs * BPS;
2028
2029 bcopy( cbuf, trackbuf, copy_len );
2030 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2031 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
2032 error(" EBIOS write error: %s\n", bios_error(rc), rc);
2033 error(" Block %d Sectors %d\n", secno, secs);
2034 return rc;
2035 }
2036 len -= copy_len;
2037 cbuf += copy_len;
2038 secno += secs;
2039 spinActivityIndicator(secs);
2040 }
2041
2042 return 0;
2043}
2044
2045int diskIsCDROM(BVRef bvr)
2046{
2047 struct driveInfo di;
2048
2049 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
2050return 1;
2051 }
2052 return 0;
2053}
2054
2055int biosDevIsCDROM(int biosdev)
2056{
2057 struct driveInfo di;
2058
2059 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2060 {
2061 return 1;
2062 }
2063 return 0;
2064}
2065

Archive Download this file

Revision: 1441