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

Archive Download this file

Revision: 2049