Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/libsaio/disk.c

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

Archive Download this file

Revision: 2323