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 } }; //ExFat
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);
1388if (!buffer)
1389{
1390 goto scanErr;
1391}
1392
1393if (readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1394{
1395goto scanErr;
1396}
1397verbose("Read GPT\n");
1398
1399// Allocate a new map for this BIOS device and insert it into the chain
1400map = malloc(sizeof(*map));
1401if (!map)
1402{
1403goto scanErr;
1404}
1405map->biosdev = biosdev;
1406map->bvr = NULL;
1407map->bvrcnt = 0;
1408map->next = gDiskBVMap;
1409gDiskBVMap = map;
1410
1411// fdisk like partition type id.
1412int fsType = 0;
1413
1414for(gptID = 1; gptID <= gptCount; ++gptID)
1415{
1416BVRef bvr = NULL;
1417unsigned int bvrFlags = 0;
1418
1419// size on disk can be larger than sizeof(gpt_ent)
1420gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1421
1422// NOTE: EFI_GUID's are in LE and we know we're on an x86.
1423// The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1424
1425if (isPartitionUsed(gptMap))
1426{
1427char stringuuid[100];
1428efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1429verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1430
1431// Getting fdisk like partition type.
1432fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1433
1434if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1435(efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1436{
1437bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1438bvr = newGPTBVRef(biosdev,
1439gptID,
1440gptMap->ent_lba_start,
1441gptMap,
1442HFSInitPartition,
1443HFSLoadFile,
1444HFSReadFile,
1445HFSGetDirEntry,
1446HFSGetFileBlock,
1447HFSGetUUID,
1448HFSGetDescription,
1449HFSFree,
14500,
1451kBIOSDevTypeHardDrive, bvrFlags);
1452}
1453
1454// zef - foreign OS support
1455if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1456(efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1457{
1458switch (fsType)
1459{
1460case FDISK_NTFS:
1461bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
14620, 0, 0, 0, 0, 0, NTFSGetDescription,
1463(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1464break;
1465
1466case FDISK_LINUX:
1467bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
14680, 0, 0, 0, 0, 0, EX2GetDescription,
1469(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1470break;
1471
1472default:
1473bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
14740, 0, 0, 0, 0, 0, 0,
1475(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1476break;
1477}
1478
1479}
1480
1481// turbo - save our booter partition
1482// zef - only on original boot device
1483if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1484{
1485switch (fsType)
1486{
1487case FDISK_HFS:
1488if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1489{
1490bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1491HFSInitPartition,
1492HFSLoadFile,
1493HFSReadFile,
1494HFSGetDirEntry,
1495HFSGetFileBlock,
1496HFSGetUUID,
1497HFSGetDescription,
1498HFSFree,
14990, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1500}
1501break;
1502
1503case FDISK_FAT32:
1504if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1505{
1506bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1507MSDOSInitPartition,
1508MSDOSLoadFile,
1509MSDOSReadFile,
1510MSDOSGetDirEntry,
1511MSDOSGetFileBlock,
1512MSDOSGetUUID,
1513MSDOSGetDescription,
1514MSDOSFree,
15150, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1516}
1517break;
1518
1519default:
1520if (biosdev == gBIOSDev)
1521{
1522gBIOSBootVolume = bvr;
1523}
1524break;
1525}
1526}
1527
1528if (bvr)
1529{
1530// Fixup bvr with the fake fdisk partition type.
1531if (fsType > 0)
1532{
1533bvr->part_type = fsType;
1534}
1535
1536bvr->next = map->bvr;
1537map->bvr = bvr;
1538++map->bvrcnt;
1539}
1540
1541}
1542}
1543
1544scanErr:
1545if (buffer)
1546{
1547free(buffer);
1548}
1549
1550if(map)
1551{
1552if(countPtr) *countPtr = map->bvrcnt;
1553{
1554return map->bvr;
1555}
1556
1557}
1558else
1559{
1560if(countPtr) *countPtr = 0;
1561{
1562return NULL;
1563}
1564}
1565}
1566
1567static bool getOSVersion(BVRef bvr, char *str)
1568{
1569bool valid = false;
1570config_file_t systemVersion;
1571char dirSpec[512];
1572
1573sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1574
1575if (!loadConfigFile(dirSpec, &systemVersion))
1576{
1577valid = true;
1578}
1579else
1580{
1581/* Mac OS X Server */
1582sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1583
1584if (!loadConfigFile(dirSpec, &systemVersion))
1585{
1586bvr->OSisServer = true;
1587valid = true;
1588}
1589}
1590
1591if (valid)
1592{
1593const char *val;
1594int len;
1595
1596if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1597{
1598// getValueForKey uses const char for val
1599// so copy it and trim
1600*str = '\0';
1601strncat(str, val, MIN(len, 4));
1602}
1603else
1604valid = false;
1605}
1606
1607if(!valid)
1608{
1609int fh = -1;
1610sprintf(dirSpec, "hd(%d,%d)/.PhysicalMediaInstall", BIOS_DEV_UNIT(bvr), bvr->part_no);
1611fh = open(dirSpec, 0);
1612
1613if (fh >= 0)
1614{
1615valid = true;
1616bvr->OSisInstaller = true;
1617strcpy(bvr->OSVersion, "10.7"); // 10.7 +
1618}
1619else
1620{
1621close(fh);
1622}
1623}
1624
1625return valid;
1626}
1627
1628//==============================================================================
1629
1630static void scanFSLevelBVRSettings(BVRef chain)
1631{
1632BVRef bvr;
1633char dirSpec[512], fileSpec[512];
1634char label[BVSTRLEN];
1635int ret;
1636long flags, time;
1637int fh, fileSize, error;
1638
1639for (bvr = chain; bvr; bvr = bvr->next)
1640{
1641ret = -1;
1642error = 0;
1643
1644//
1645// Check for alternate volume label on boot helper partitions.
1646//
1647if (bvr->flags & kBVFlagBooter)
1648{
1649sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1650strcpy(fileSpec, ".disk_label.contentDetails");
1651ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1652if (!ret)
1653{
1654fh = open(strcat(dirSpec, fileSpec), 0);
1655fileSize = file_size(fh);
1656if (fileSize > 0 && fileSize < BVSTRLEN)
1657{
1658if (read(fh, label, fileSize) != fileSize)
1659{
1660error = -1;
1661}
1662}
1663else
1664{
1665error = -1;
1666}
1667
1668close(fh);
1669
1670if (!error)
1671{
1672label[fileSize] = '\0';
1673strcpy(bvr->altlabel, label);
1674}
1675}
1676}
1677
1678// Check for SystemVersion.plist or ServerVersion.plist to determine if a volume hosts an installed system.
1679
1680if (bvr->flags & kBVFlagNativeBoot)
1681{
1682if (getOSVersion(bvr,bvr->OSVersion) == true)
1683{
1684bvr->flags |= kBVFlagSystemVolume;
1685}
1686}
1687
1688}
1689}
1690
1691void rescanBIOSDevice(int biosdev)
1692{
1693struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1694CacheReset();
1695diskFreeMap(oldMap);
1696oldMap = NULL;
1697scanBootVolumes(biosdev, 0);
1698}
1699
1700struct DiskBVMap* diskResetBootVolumes(int biosdev)
1701{
1702struct DiskBVMap * map;
1703struct DiskBVMap *prevMap = NULL;
1704for ( map = gDiskBVMap; map; prevMap = map, map = map->next )
1705{
1706if ( biosdev == map->biosdev )
1707{
1708break;
1709}
1710}
1711
1712if(map != NULL)
1713{
1714verbose("Resetting BIOS device %xh\n", biosdev);
1715// Reset the biosbuf cache
1716cache_valid = false;
1717if(map == gDiskBVMap)
1718{
1719gDiskBVMap = map->next;
1720}
1721else if(prevMap != NULL)
1722{
1723prevMap->next = map->next;
1724}
1725else
1726{
1727stop("");
1728}
1729}
1730// Return the old map, either to be freed, or reinserted later
1731return map;
1732}
1733
1734//==============================================================================
1735
1736// Frees a DiskBVMap and all of its BootVolume's
1737void diskFreeMap(struct DiskBVMap *map)
1738{
1739if(map != NULL)
1740{
1741while(map->bvr != NULL)
1742{
1743BVRef bvr = map->bvr;
1744map->bvr = bvr->next;
1745(*bvr->bv_free)(bvr);
1746}
1747
1748free(map);
1749}
1750}
1751
1752//==============================================================================
1753
1754BVRef diskScanBootVolumes(int biosdev, int * countPtr)
1755{
1756struct DiskBVMap * map = NULL;
1757BVRef bvr;
1758int count = 0;
1759
1760// Find an existing mapping for this device.
1761
1762for (map = gDiskBVMap; map; map = map->next)
1763{
1764if (biosdev == map->biosdev)
1765{
1766count = map->bvrcnt;
1767break;
1768}
1769}
1770
1771if (map == NULL)
1772{
1773bvr = diskScanGPTBootVolumes(biosdev, &count);
1774if (bvr == NULL)
1775{
1776bvr = diskScanFDiskBootVolumes(biosdev, &count);
1777}
1778if (bvr == NULL)
1779{
1780bvr = diskScanAPMBootVolumes(biosdev, &count);
1781}
1782if (bvr)
1783{
1784scanFSLevelBVRSettings(bvr);
1785}
1786}
1787else
1788{
1789bvr = map->bvr;
1790}
1791if (countPtr)
1792{
1793*countPtr += count;
1794}
1795return bvr;
1796}
1797
1798//==============================================================================
1799
1800BVRef getBVChainForBIOSDev(int biosdev)
1801{
1802BVRef chain = NULL;
1803struct DiskBVMap * map = NULL;
1804
1805for (map = gDiskBVMap; map; map = map->next)
1806{
1807if (map->biosdev == biosdev)
1808{
1809chain = map->bvr;
1810break;
1811}
1812}
1813
1814return chain;
1815}
1816
1817//==============================================================================
1818
1819BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1820{
1821BVRef chain = NULL;
1822BVRef bvr = NULL;
1823BVRef newBVR = NULL;
1824BVRef prevBVR = NULL;
1825
1826struct DiskBVMap * map = NULL;
1827int bvCount = 0;
1828
1829const char *raw = 0;
1830char* val = 0;
1831int len;
1832
1833getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1834if(raw)
1835{
1836val = XMLDecode(raw);
1837}
1838
1839/*
1840 * Traverse gDISKBVmap to get references for
1841 * individual bvr chains of each drive.
1842 */
1843for (map = gDiskBVMap; map; map = map->next)
1844{
1845for (bvr = map->bvr; bvr; bvr = bvr->next)
1846{
1847/*
1848 * Save the last bvr.
1849 */
1850if (newBVR)
1851{
1852prevBVR = newBVR;
1853}
1854
1855/*
1856 * Allocate and copy the matched bvr entry into a new one.
1857 */
1858newBVR = (BVRef) malloc(sizeof(*newBVR));
1859if (!newBVR)
1860{
1861continue;
1862}
1863bcopy(bvr, newBVR, sizeof(*newBVR));
1864
1865/*
1866 * Adjust the new bvr's fields.
1867 */
1868newBVR->next = NULL;
1869newBVR->filtered = true;
1870
1871if ( (!allowFlags || newBVR->flags & allowFlags)
1872&& (!denyFlags || !(newBVR->flags & denyFlags) )
1873&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1874)
1875{
1876newBVR->visible = true;
1877}
1878
1879/*
1880 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1881 * to be able to hide foreign partitions from the boot menu.
1882 *
1883 */
1884if ( (newBVR->flags & kBVFlagForeignBoot) )
1885{
1886char *start, *next = val;
1887long len = 0;
1888do
1889{
1890start = strbreak(next, &next, &len);
1891if(len && matchVolumeToString(newBVR, start, len) )
1892{
1893newBVR->visible = false;
1894}
1895}
1896while ( next && *next );
1897}
1898
1899/*
1900 * Use the first bvr entry as the starting chain pointer.
1901 */
1902if (!chain)
1903{
1904chain = newBVR;
1905}
1906
1907/*
1908 * Update the previous bvr's link pointer to use the new memory area.
1909 */
1910if (prevBVR)
1911{
1912prevBVR->next = newBVR;
1913}
1914
1915if (newBVR->visible)
1916{
1917bvCount++;
1918}
1919}
1920}
1921
1922#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1923for (bvr = chain; bvr; bvr = bvr->next)
1924{
1925printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1926}
1927printf("count: %d\n", bvCount);
1928getchar();
1929#endif
1930
1931*count = bvCount;
1932
1933free(val);
1934return chain;
1935}
1936
1937//==============================================================================
1938
1939int freeFilteredBVChain(const BVRef chain)
1940{
1941int ret = 1;
1942BVRef bvr = chain;
1943BVRef nextBVR = NULL;
1944
1945while (bvr)
1946{
1947nextBVR = bvr->next;
1948
1949if (bvr->filtered)
1950{
1951free(bvr);
1952}
1953else
1954{
1955ret = 0;
1956break;
1957}
1958
1959bvr = nextBVR;
1960}
1961
1962return ret;
1963}
1964
1965//==============================================================================
1966
1967static const struct NamedValue fdiskTypes[] =
1968{
1969{ FDISK_NTFS,"Windows NTFS" },
1970{ FDISK_DOS12,"Windows FAT12" },
1971{ FDISK_DOS16B,"Windows FAT16" },
1972{ FDISK_DOS16S,"Windows FAT16" },
1973{ FDISK_DOS16SLBA,"Windows FAT16" },
1974{ FDISK_SMALLFAT32,"Windows FAT32" },
1975{ FDISK_FAT32,"Windows FAT32" },
1976{ FDISK_FREEBSD,"FreeBSD" },
1977{ FDISK_OPENBSD,"OpenBSD" },
1978{ FDISK_LINUX,"Linux" },
1979{ FDISK_UFS,"Apple UFS" },
1980{ FDISK_HFS,"Apple HFS" },
1981{ FDISK_BOOTER,"Apple Boot/UFS" },
1982{ FDISK_BEFS,"Haiku" },
1983{ 0xCD,"CD-ROM" },
1984{ 0x00,0 } /* must be last */
1985};
1986
1987//==============================================================================
1988
1989bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1990{
1991char testStr[128];
1992
1993if ( !bvr || !match || !*match)
1994{
1995return 0;
1996}
1997
1998if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1999{
2000 return 0;
2001}
2002
2003// Try to match hd(x,y) first.
2004sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
2005if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2006{
2007return true;
2008}
2009
2010// Try to match volume UUID.
2011if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
2012{
2013if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2014{
2015return true;
2016}
2017}
2018
2019// Try to match volume label (always quoted).
2020if ( bvr->description )
2021{
2022bvr->description(bvr, testStr, sizeof(testStr)-1);
2023if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2024{
2025return true;
2026}
2027}
2028
2029return false;
2030}
2031
2032//==============================================================================
2033
2034/* If Rename Partition has defined an alias, then extract it for description purpose.
2035 * The format for the rename string is the following:
2036 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
2037 */
2038
2039bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
2040{
2041char *aliasList, *entryStart, *entryNext;
2042
2043if ( !str || strMaxLen <= 0)
2044{
2045return false;
2046}
2047
2048aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
2049if ( !aliasList )
2050{
2051return false;
2052}
2053
2054for ( entryStart = entryNext = aliasList; entryNext && *entryNext; entryStart = entryNext )
2055{
2056char *volStart, *volEnd, *aliasStart;
2057long volLen, aliasLen;
2058
2059// Delimit current entry
2060entryNext = strchr(entryStart, ';');
2061if ( entryNext )
2062{
2063*entryNext = '\0';
2064entryNext++;
2065}
2066
2067volStart = strbreak(entryStart, &volEnd, &volLen);
2068if(!volLen)
2069{
2070continue;
2071}
2072
2073aliasStart = strbreak(volEnd, 0, &aliasLen);
2074if(!aliasLen)
2075{
2076continue;
2077}
2078
2079if ( matchVolumeToString(bvr, volStart, volLen) )
2080{
2081strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
2082free(aliasList);
2083
2084return true;
2085}
2086}
2087
2088free(aliasList);
2089return false;
2090}
2091
2092//==============================================================================
2093
2094void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
2095{
2096unsigned char type;
2097char *p = str;
2098
2099if(!bvr || !p || strMaxLen <= 0)
2100{
2101return;
2102}
2103
2104type = (unsigned char) bvr->part_type;
2105
2106if (useDeviceDescription)
2107{
2108int len = getDeviceDescription(bvr, str);
2109if(len >= strMaxLen)
2110{
2111return;
2112}
2113
2114strcpy(str + len, bvr->OSisInstaller ? " (Installer) " : " ");
2115len += bvr->OSisInstaller ? 13 : 1;
2116strMaxLen -= len;
2117p += len;
2118}
2119
2120/* See if a partition rename is preferred */
2121if (getVolumeLabelAlias(bvr, p, strMaxLen))
2122{
2123strncpy(bvr->label, p, strMaxLen);
2124return; // we're done here no need to seek for real name
2125}
2126
2127// Get the volume label using filesystem specific functions or use the alternate volume label if available.
2128
2129if (*bvr->altlabel != '\0')
2130{
2131strncpy(p, bvr->altlabel, strMaxLen);
2132}
2133else if (bvr->description)
2134{
2135bvr->description(bvr, p, strMaxLen);
2136}
2137
2138if (*p == '\0')
2139{
2140const char * name = getNameForValue( fdiskTypes, type );
2141
2142if (name == NULL)
2143{
2144name = bvr->type_name;
2145}
2146
2147if (name == NULL)
2148{
2149sprintf(p, "TYPE %02x", type);
2150}
2151else
2152{
2153strncpy(p, name, strMaxLen);
2154}
2155}
2156
2157// Set the devices label
2158sprintf(bvr->label, p);
2159}
2160
2161
2162//==============================================================================
2163
2164int readBootSector(int biosdev, unsigned int secno, void * buffer)
2165{
2166int error;
2167struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
2168
2169if (bootSector == NULL)
2170{
2171if (gBootSector == NULL)
2172{
2173gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
2174
2175if (gBootSector == NULL)
2176{
2177return -1;
2178}
2179}
2180bootSector = gBootSector;
2181}
2182
2183error = readBytes(biosdev, secno, 0, BPS, bootSector);
2184
2185if (error || bootSector->signature != DISK_SIGNATURE)
2186{
2187return -1;
2188}
2189return 0;
2190}
2191
2192//==============================================================================
2193
2194/*
2195 * Format of boot1f32 block.
2196 */
2197
2198#define BOOT1F32_MAGIC "BOOT "
2199#define BOOT1F32_MAGICLEN 11
2200
2201struct disk_boot1f32_blk
2202{
2203unsigned char init[3];
2204unsigned char fsheader[87];
2205unsigned char magic[BOOT1F32_MAGICLEN];
2206unsigned char bootcode[409];
2207unsigned short signature;
2208};
2209
2210//==============================================================================
2211
2212int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
2213{
2214struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
2215int error;
2216
2217if ( bootSector == NULL )
2218{
2219if ( gBootSector == NULL )
2220{
2221gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
2222if ( gBootSector == NULL )
2223{
2224return -1;
2225}
2226}
2227bootSector = (struct disk_boot1f32_blk *) gBootSector;
2228}
2229
2230error = readBytes( biosdev, secno, 0, BPS, bootSector );
2231if ( error || bootSector->signature != DISK_SIGNATURE || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2232{
2233return -1;
2234}
2235return 0;
2236}
2237
2238
2239//==============================================================================
2240// Handle seek request from filesystem modules.
2241
2242void diskSeek(BVRef bvr, long long position)
2243{
2244bvr->fs_boff = position / BPS;
2245bvr->fs_byteoff = position % BPS;
2246}
2247
2248
2249//==============================================================================
2250// Handle read request from filesystem modules.
2251
2252int diskRead(BVRef bvr, long addr, long length)
2253{
2254return readBytes(bvr->biosdev, bvr->fs_boff + bvr->part_boff, bvr->fs_byteoff, length, (void *) addr);
2255}
2256
2257//==============================================================================
2258
2259int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2260{
2261int secs;
2262unsigned char *cbuf = (unsigned char *)buffer;
2263unsigned int copy_len;
2264int rc;
2265
2266if ((len & (BPS-1)) != 0)
2267{
2268error("raw disk read not sector aligned");
2269return -1;
2270}
2271secno += bvr->part_boff;
2272
2273cache_valid = false;
2274
2275while (len > 0)
2276{
2277secs = len / BPS;
2278if (secs > N_CACHE_SECS)
2279{
2280secs = N_CACHE_SECS;
2281}
2282copy_len = secs * BPS;
2283
2284//printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2285if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0)
2286{
2287/* Ignore corrected ECC errors */
2288if (rc != ECC_CORRECTED_ERR)
2289{
2290error(" EBIOS read error: %s\n", bios_error(rc), rc);
2291error(" Block %d Sectors %d\n", secno, secs);
2292return rc;
2293}
2294}
2295bcopy( trackbuf, cbuf, copy_len );
2296len -= copy_len;
2297cbuf += copy_len;
2298secno += secs;
2299spinActivityIndicator(secs);
2300}
2301
2302return 0;
2303}
2304
2305//==============================================================================
2306
2307int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2308{
2309 int secs;
2310 unsigned char *cbuf = (unsigned char *)buffer;
2311 unsigned int copy_len;
2312 int rc;
2313
2314if ((len & (BPS-1)) != 0)
2315{
2316error("raw disk write not sector aligned");
2317return -1;
2318}
2319secno += bvr->part_boff;
2320
2321cache_valid = false;
2322
2323while (len > 0)
2324{
2325secs = len / BPS;
2326if (secs > N_CACHE_SECS)
2327{
2328secs = N_CACHE_SECS;
2329}
2330copy_len = secs * BPS;
2331
2332bcopy( cbuf, trackbuf, copy_len );
2333//printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2334if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0)
2335{
2336error(" EBIOS write error: %s\n", bios_error(rc), rc);
2337error(" Block %d Sectors %d\n", secno, secs);
2338return rc;
2339}
2340
2341len -= copy_len;
2342cbuf += copy_len;
2343secno += secs;
2344spinActivityIndicator(secs);
2345}
2346
2347return 0;
2348}
2349
2350//==============================================================================
2351
2352int diskIsCDROM(BVRef bvr)
2353{
2354struct driveInfo di;
2355
2356if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation)
2357{
2358return 1;
2359}
2360return 0;
2361}
2362
2363//==============================================================================
2364
2365int biosDevIsCDROM(int biosdev)
2366{
2367struct driveInfo di;
2368
2369if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2370{
2371return 1;
2372}
2373return 0;
2374}
2375

Archive Download this file

Revision: 2131