Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2877