Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2469