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

Archive Download this file

Revision: 2037