Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2026