Chameleon

Chameleon Svn Source Tree

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

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 *
24 *
25 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * All rights reserved. The CMU software License Agreement specifies
29 * the terms and conditions for use and redistribution.
30 *
31 *
32 * 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//==============================================================================
738static BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,
739 const DPME * part,
740 FSInit initFunc, FSLoadFile loadFunc,
741 FSReadFile readFunc,
742 FSGetDirEntry getdirFunc,
743 FSGetFileBlock getBlockFunc,
744 FSGetUUID getUUIDFunc,
745 BVGetDescription getDescriptionFunc,
746 BVFree bvFreeFunc,
747 int probe, int type, unsigned int bvrFlags )
748{
749BVRef bvr = (BVRef)malloc(sizeof(*bvr));
750if ( bvr )
751{
752bzero(bvr, sizeof(*bvr));
753
754bvr->biosdev = biosdev;
755bvr->part_no = partno;
756bvr->part_boff = blkoff;
757bvr->fs_loadfile = loadFunc;
758bvr->fs_readfile = readFunc;
759bvr->fs_getdirentry = getdirFunc;
760bvr->fs_getfileblock= getBlockFunc;
761bvr->fs_getuuid = getUUIDFunc;
762bvr->description = getDescriptionFunc;
763bvr->type = type;
764bvr->bv_free = bvFreeFunc;
765strlcpy(bvr->name, part->dpme_name, DPISTRLEN);
766strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);
767
768/*
769if ( part->bootid & FDISK_ACTIVE )
770{
771bvr->flags |= kBVFlagPrimary;
772}
773*/
774
775// Probe the filesystem.
776
777if ( initFunc )
778{
779bvr->flags |= kBVFlagNativeBoot | kBVFlagBootable | kBVFlagSystemVolume;
780
781if ( probe && initFunc( bvr ) != 0 )
782{
783// filesystem probe failed.
784
785DEBUG_DISK(("%s: failed probe on dev %X part %d\n", __FUNCTION__, biosdev, partno));
786
787(*bvr->bv_free)(bvr);
788bvr = NULL;
789}
790}
791/*
792else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
793{
794bvr->flags |= kBVFlagForeignBoot;
795}
796*/
797else
798{
799(*bvr->bv_free)(bvr);
800bvr = NULL;
801}
802}
803
804if ( bvr )
805{
806bvr->flags |= bvrFlags;
807}
808
809return bvr;
810}
811
812//==============================================================================
813
814// GUID's in LE form:
815// HFS+ partition - 48465300-0000-11AA-AA11-00306543ECAC
816EFI_GUID const GPT_HFS_GUID= { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF00 "Apple HFS/HFS+"
817
818// turbo - Apple Boot Partition - 426F6F74-0000-11AA-AA11-00306543ECAC
819EFI_GUID const GPT_BOOT_GUID= { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAB00 "Apple boot"
820
821// turbo - or an EFI System Partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B
822EFI_GUID const GPT_EFISYS_GUID= { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } }; // 0xEF00 "EFI System"
823
824// zef - Basic Data Partition - EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support
825EFI_GUID const GPT_BASICDATA_GUID= { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } }; // 0x0100 "Microsoft basic data"
826
827// Microsoft Reserved Partition - E3C9E316-0B5C-4DB8-817DF92DF00215AE
828EFI_GUID const GPT_BASICDATA2_GUID= { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } }; // 0x0C01 "Microsoft reserved"
829
830// Apple OSX
831//EFI_GUID const GPT_UFS_GUID= { 0x55465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xA800 "Apple UFS"
832//EFI_GUID const GPT_RAID_GUID= { 0x52414944, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF01 "Apple RAID"
833//EFI_GUID const GPT_RAID_OFFLINE_GUID= { 0x52414944, 0x5f4f, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF02 "Apple RAID offline"
834//EFI_GUID const GPT_LABEL_GUID= { 0x4C616265, 0x6C00, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF03 "Apple label"
835//EFI_GUID const GPT_APPLETV_GUID= { 0x5265636F, 0x7665, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF04 "Apple TV recovery"
836EFI_GUID const GPT_CORESTORAGE_GUID= { 0x53746F72, 0x6167, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF05 "Apple Core storage"
837// same as Apple ZFS
838//EFI_GUID const GPT_ZFS_GUID= { 0x6A898CC3, 0x1DD2, 0x11B2, { 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }; // 0xBF01 "Solaris /usr & Apple ZFS
839
840static BVRef newGPTBVRef( int biosdev,
841 int partno,
842 unsigned int blkoff,
843 const gpt_ent *part,
844 FSInit initFunc,
845 FSLoadFile loadFunc,
846 FSReadFile readFunc,
847 FSGetDirEntry getdirFunc,
848 FSGetFileBlock getBlockFunc,
849 FSGetUUID getUUIDFunc,
850 BVGetDescription getDescriptionFunc,
851 BVFree bvFreeFunc,
852 int probe,
853 int type,
854 unsigned int bvrFlags )
855{
856BVRef bvr = (BVRef)malloc(sizeof(*bvr));
857if ( bvr )
858{
859bzero(bvr, sizeof(*bvr));
860
861bvr->biosdev = biosdev;
862bvr->part_no = partno;
863bvr->part_boff = blkoff;
864bvr->fs_loadfile = loadFunc;
865bvr->fs_readfile = readFunc;
866bvr->fs_getdirentry = getdirFunc;
867bvr->fs_getfileblock = getBlockFunc;
868bvr->fs_getuuid = getUUIDFunc;
869bvr->description = getDescriptionFunc;
870bvr->type = type;
871bvr->bv_free = bvFreeFunc;
872// FIXME: UCS-2 -> UTF-8 the name
873strlcpy(bvr->name, "----", DPISTRLEN);
874if ( (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) )
875{
876strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);
877}
878else
879{
880strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);
881}
882
883/*
884if ( part->bootid & FDISK_ACTIVE )
885{
886bvr->flags |= kBVFlagPrimary;
887}
888*/
889
890// Probe the filesystem.
891
892if ( initFunc )
893{
894bvr->flags |= kBVFlagNativeBoot;
895
896if ( probe && initFunc( bvr ) != 0 )
897{
898// filesystem probe failed.
899
900DEBUG_DISK(("%s: failed probe on dev %x part %d\n", __FUNCTION__, biosdev, partno));
901
902(*bvr->bv_free)(bvr);
903bvr = NULL;
904}
905else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
906{
907bvr->flags |= kBVFlagBootable;
908}
909}
910else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
911{
912bvr->flags |= kBVFlagForeignBoot;
913}
914else
915{
916(*bvr->bv_free)(bvr);
917bvr = NULL;
918}
919}
920
921if ( bvr )
922{
923bvr->flags |= bvrFlags;
924}
925
926return bvr;
927}
928
929//==============================================================================
930
931/* A note on partition numbers:
932 * IOKit makes the primary partitions numbers 1-4, and then
933 * extended partitions are numbered consecutively 5 and up.
934 * So, for example, if you have two primary partitions and
935 * one extended partition they will be numbered 1, 2, 5.
936 */
937static BVRef diskScanFDiskBootVolumes( int biosdev, int *countPtr )
938{
939 const struct fdisk_part*part;
940 struct DiskBVMap*map;
941 intpartno = -1;
942 BVRefbvr;
943#if UFS_SUPPORT
944 BVRefbooterUFS = NULL;
945#endif
946 intspc;
947 struct driveInfodi;
948 boot_drive_info_t*dp;
949
950verbose("\tAttempting to scan FDISK boot volumes [biosdev=%02Xh]:\n", biosdev);
951
952/* Initialize disk info */
953
954if (getDriveInfo(biosdev, &di) != 0)
955{
956return NULL;
957}
958
959dp = &di.di;
960spc = (dp->params.phys_spt * dp->params.phys_heads);
961
962if (spc == 0)
963{
964/* This is probably a CD-ROM; punt on the geometry. */
965spc = 1;
966}
967
968do
969{
970// Create a new mapping.
971
972map = (struct DiskBVMap *) malloc(sizeof(*map));
973
974if ( !map )
975{
976return NULL;
977}
978
979if ( map )
980 {
981map->biosdev = biosdev;
982map->bvr = NULL;
983map->bvrcnt = 0;
984map->next = gDiskBVMap;
985gDiskBVMap = map;
986
987// Create a record for each partition found on the disk.
988
989while ( getNextFDiskPartition( biosdev, &partno, &part ) )
990{
991DEBUG_DISK(("%s: part %d [%X]\n", __FUNCTION__, partno, part->systid));
992bvr = 0;
993
994switch ( part->systid )
995{
996#if UFS_SUPPORT
997case FDISK_UFS:
998bvr = newFDiskBVRef(
999biosdev, partno,
1000part->relsect + UFS_FRONT_PORCH/BPS,
1001part,
1002UFSInitPartition,
1003UFSLoadFile,
1004UFSReadFile,
1005UFSGetDirEntry,
1006UFSGetFileBlock,
1007UFSGetUUID,
1008UFSGetDescription,
1009UFSFree,
10100,
1011kBIOSDevTypeHardDrive, 0);
1012break;
1013#endif
1014
1015case FDISK_HFS:
1016bvr = newFDiskBVRef(
1017biosdev, partno,
1018part->relsect,
1019part,
1020HFSInitPartition,
1021HFSLoadFile,
1022HFSReadFile,
1023HFSGetDirEntry,
1024HFSGetFileBlock,
1025HFSGetUUID,
1026HFSGetDescription,
1027HFSFree,
10280,
1029kBIOSDevTypeHardDrive, 0);
1030break;
1031
1032// turbo - we want the booter type scanned also
1033case FDISK_BOOTER:
1034if (part->bootid & FDISK_ACTIVE)
1035{
1036gBIOSBootVolume = newFDiskBVRef(
1037biosdev, partno,
1038part->relsect,
1039part,
1040HFSInitPartition,
1041HFSLoadFile,
1042HFSReadFile,
1043HFSGetDirEntry,
1044HFSGetFileBlock,
1045HFSGetUUID,
1046HFSGetDescription,
1047HFSFree,
10480,
1049kBIOSDevTypeHardDrive, 0);
1050}
1051break;
1052
1053#if UFS_SUPPORT
1054case FDISK_BOOTER:
1055booterUFS = newFDiskBVRef(
1056biosdev, partno,
1057((part->relsect + spc - 1) / spc) * spc,
1058part,
1059UFSInitPartition,
1060UFSLoadFile,
1061UFSReadFile,
1062UFSGetDirEntry,
1063UFSGetFileBlock,
1064UFSGetUUID,
1065UFSGetDescription,
1066UFSFree,
10670,
1068kBIOSDevTypeHardDrive, 0);
1069break;
1070#endif
1071
1072case FDISK_FAT32:
1073case FDISK_DOS12:
1074case FDISK_DOS16S:
1075case FDISK_DOS16B:
1076case FDISK_SMALLFAT32:
1077case FDISK_DOS16SLBA:
1078bvr = newFDiskBVRef(
1079biosdev, partno,
1080part->relsect,
1081part,
1082MSDOSInitPartition,
1083MSDOSLoadFile,
1084MSDOSReadFile,
1085MSDOSGetDirEntry,
1086MSDOSGetFileBlock,
1087MSDOSGetUUID,
1088MSDOSGetDescription,
1089MSDOSFree,
10900,
1091kBIOSDevTypeHardDrive, 0);
1092break;
1093
1094case FDISK_NTFS:
1095bvr = newFDiskBVRef(
1096biosdev, partno,
1097part->relsect,
1098part,
10990, 0, 0, 0, 0,
1100NTFSGetUUID,
1101NTFSGetDescription,
1102(BVFree)free,
11030,
1104kBIOSDevTypeHardDrive, 0);
1105break;
1106
1107case FDISK_LINUX:
1108bvr = newFDiskBVRef(
1109biosdev, partno,
1110part->relsect,
1111part,
11120, 0, 0, 0, 0,
1113EX2GetUUID,
1114EX2GetDescription,
1115(BVFree)free,
11160,
1117kBIOSDevTypeHardDrive, 0);
1118break;
1119
1120case FDISK_BEFS:
1121bvr = newFDiskBVRef(
1122biosdev, partno,
1123part->relsect,
1124part,
11250, 0, 0, 0, 0, 0,
1126BeFSGetDescription,
1127(BVFree)free,
11280,
1129kBIOSDevTypeHardDrive, 0);
1130break;
1131
1132case FDISK_FREEBSD:
1133bvr = newFDiskBVRef(
1134biosdev, partno,
1135part->relsect,
1136part,
11370, 0, 0, 0, 0, 0,
1138FreeBSDGetDescription,
1139(BVFree)free,
11400,
1141kBIOSDevTypeHardDrive, 0);
1142break;
1143
1144case FDISK_OPENBSD:
1145bvr = newFDiskBVRef(
1146biosdev, partno,
1147part->relsect,
1148part,
11490, 0, 0, 0, 0, 0,
1150OpenBSDGetDescription,
1151(BVFree)free,
11520,
1153kBIOSDevTypeHardDrive, 0);
1154break;
1155
1156default:
1157bvr = newFDiskBVRef(
1158biosdev, partno,
1159part->relsect,
1160part,
11610, 0, 0, 0, 0, 0, 0,
1162(BVFree)free,
11630,
1164kBIOSDevTypeHardDrive, 0);
1165break;
1166}
1167
1168if ( bvr )
1169{
1170bvr->next = map->bvr;
1171map->bvr = bvr;
1172map->bvrcnt++;
1173}
1174}
1175
1176#if UFS_SUPPORT
1177// Booting from a CD with an UFS filesystem embedded
1178// in a booter partition.
1179
1180if ( booterUFS )
1181{
1182if ( map->bvrcnt == 0 )
1183{
1184map->bvr = booterUFS;
1185map->bvrcnt++;
1186}
1187else
1188{
1189free( booterUFS );
1190}
1191}
1192#endif
1193}
1194} while (0);
1195
1196#if UNUSED
1197/*
1198 * If no FDisk partition, then we will check for
1199 * an Apple partition map elsewhere.
1200 */
1201if (map && map->bvrcnt == 0)
1202{
1203static struct fdisk_part cdpart;
1204cdpart.systid = 0xCD;
1205
1206/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
1207bvr = newFDiskBVRef(
1208biosdev, 0,
12090,
1210&cdpart,
1211HFSInitPartition,
1212HFSLoadFile,
1213HFSReadFile,
1214HFSGetDirEntry,
1215HFSGetFileBlock,
1216HFSGetUUID,
1217HFSGetDescription,
1218HFSFree,
12190,
1220kBIOSDevTypeHardDrive, 0);
1221bvr->next = map->bvr;
1222map->bvr = bvr;
1223map->bvrcnt++;
1224}
1225#endif
1226// Actually this should always be true given the above code
1227// (unless malloc failed above)
1228if(map && (map == gDiskBVMap))
1229{
1230// Don't leave a null map in the chain
1231if((map->bvrcnt == 0) && (map->bvr == NULL))
1232{
1233gDiskBVMap = map->next;
1234free(map);
1235map = NULL;
1236}
1237}
1238
1239if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1240
1241return map ? map->bvr : NULL;
1242}
1243
1244//==============================================================================
1245static BVRef diskScanAPMBootVolumes( int biosdev, int *countPtr )
1246{
1247struct DiskBVMap*map;
1248struct Block0*block0_p;
1249unsigned intblksize;
1250unsigned intfactor;
1251
1252verbose("\tAttempting to scan APM boot volumes [biosdev=%02Xh]:\n", biosdev);
1253
1254void*buffer = malloc(BPS);
1255
1256if (!buffer)
1257{
1258return NULL;
1259}
1260
1261bzero(buffer,BPS);
1262
1263/* Check for alternate block size */
1264if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0)
1265{
1266return NULL;
1267}
1268
1269block0_p = buffer;
1270if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE)
1271{
1272blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1273if (blksize != BPS)
1274{
1275free(buffer);
1276buffer = malloc(blksize);
1277if (!buffer)
1278{
1279return NULL;
1280}
1281bzero(buffer,BPS);
1282}
1283factor = blksize / BPS;
1284}
1285else
1286{
1287blksize = BPS;
1288factor = 1;
1289}
1290
1291do
1292{
1293// Create a new mapping.
1294
1295map = (struct DiskBVMap *) malloc( sizeof(*map) );
1296if ( map )
1297{
1298int error;
1299DPME *dpme_p = (DPME *)buffer;
1300UInt32 i, npart = UINT_MAX;
1301BVRef bvr;
1302
1303map->biosdev = biosdev;
1304map->bvr = NULL;
1305map->bvrcnt = 0;
1306map->next = gDiskBVMap;
1307gDiskBVMap = map;
1308
1309for (i = 0; i < npart; i++)
1310{
1311error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1312
1313if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE)
1314{
1315break;
1316}
1317
1318if (i == 0)
1319{
1320npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1321}
1322/*
1323printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1324dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1325dpme.dpme_pblock_start, dpme.dpme_pblocks,
1326dpme.dpme_lblock_start, dpme.dpme_lblocks,
1327dpme.dpme_boot_block);
1328*/
1329
1330if (strncmp(dpme_p->dpme_type, "Apple_HFS", sizeof("Apple_HFS")) == 0)
1331{
1332bvr = newAPMBVRef(biosdev,
1333i,
1334OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1335dpme_p,
1336HFSInitPartition,
1337HFSLoadFile,
1338HFSReadFile,
1339HFSGetDirEntry,
1340HFSGetFileBlock,
1341HFSGetUUID,
1342HFSGetDescription,
1343HFSFree,
13440,
1345kBIOSDevTypeHardDrive, 0);
1346bvr->next = map->bvr;
1347map->bvr = bvr;
1348map->bvrcnt++;
1349}
1350}
1351}
1352} while (0);
1353
1354if (buffer)
1355{
1356free(buffer);
1357}
1358
1359if (countPtr)
1360{
1361*countPtr = map ? map->bvrcnt : 0;
1362}
1363
1364return map ? map->bvr : NULL;
1365}
1366
1367//==============================================================================
1368static bool isPartitionUsed(gpt_ent * partition)
1369{
1370
1371// Ask whether the given partition is used.
1372
1373return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1374}
1375
1376//==============================================================================
1377static BVRef diskScanGPTBootVolumes(int biosdev, int *countPtr)
1378{
1379verbose("\tAttempting to scan GPT boot volumes [biosdev=%02Xh]:\n", biosdev);
1380
1381struct DiskBVMap *map = NULL;
1382
1383void *buffer = malloc(BPS);
1384
1385int error;
1386
1387if ((error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer )) != 0)
1388{
1389verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1390goto scanErr;
1391}
1392struct REAL_disk_blk0 *fdiskMap = buffer;
1393if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1394{
1395verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1396goto scanErr;
1397}
1398
1399int fdiskID = 0;
1400unsigned index;
1401for ( index = 0; index < FDISK_NPART; index++ )
1402{
1403if ( fdiskMap->parts[index].systid )
1404{
1405if ( fdiskMap->parts[index].systid == 0xEE )
1406{
1407// Fail if two 0xEE partitions are present which
1408// means the FDISK code will wind up parsing it.
1409if ( fdiskID )
1410{
1411verbose("\t[diskScanGPTBootVolumes] Error! Two GPT protective MBR (fdisk=0xEE) partitions found on same device, skipping.\n");
1412goto scanErr;
1413}
1414
1415fdiskID = index + 1;
1416}
1417}
1418}
1419
1420if ( fdiskID == 0 )
1421{
1422goto scanErr;
1423}
1424
1425verbose("Attempting to read GPT\n");
1426
1427if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1428{
1429goto scanErr;
1430}
1431
1432gpt_hdr *headerMap = buffer;
1433
1434// Determine whether the partition header signature is present.
1435
1436if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1437{
1438goto scanErr;
1439}
1440
1441// Determine whether the partition header size is valid.
1442
1443UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1444UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1445
1446if (headerSize < offsetof(gpt_hdr, padding))
1447{
1448goto scanErr;
1449}
1450
1451if ( headerSize > BPS )
1452{
1453goto scanErr;
1454}
1455
1456// Determine whether the partition header checksum is valid.
1457
1458headerMap->hdr_crc_self = 0;
1459
1460if ( crc32(0, headerMap, headerSize) != headerCheck )
1461{
1462goto scanErr;
1463}
1464
1465// Determine whether the partition entry size is valid.
1466
1467UInt64gptBlock= 0;
1468UInt32gptCheck= 0;
1469UInt32gptCount= 0;
1470UInt32gptID= 0;
1471gpt_ent*gptMap= NULL;
1472UInt32gptSize= 0;
1473
1474gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1475gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1476gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1477gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1478
1479if ( gptSize < sizeof(gpt_ent) )
1480{
1481goto scanErr;
1482}
1483
1484// Allocate a buffer large enough to hold one map, rounded to a media block.
1485free(buffer);
1486buffer = NULL;
1487
1488UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1489if (bufferSize == 0)
1490{
1491goto scanErr;
1492}
1493buffer = malloc(bufferSize);
1494if (!buffer)
1495{
1496 goto scanErr;
1497}
1498
1499bzero(buffer,bufferSize);
1500
1501if (readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1502{
1503goto scanErr;
1504}
1505verbose("Read GPT\n");
1506
1507// Allocate a new map for this BIOS device and insert it into the chain
1508map = malloc(sizeof(*map));
1509if (!map)
1510{
1511goto scanErr;
1512}
1513map->biosdev = biosdev;
1514map->bvr = NULL;
1515map->bvrcnt = 0;
1516map->next = gDiskBVMap;
1517gDiskBVMap = map;
1518
1519// fdisk like partition type id.
1520int fsType = 0;
1521
1522for(gptID = 1; gptID <= gptCount; ++gptID)
1523{
1524BVRef bvr = NULL;
1525unsigned int bvrFlags = 0;
1526
1527// size on disk can be larger than sizeof(gpt_ent)
1528gptMap = (gpt_ent *)(buffer + ((gptID - 1) * gptSize));
1529
1530// NOTE: EFI_GUID's are in LE and we know we're on an x86.
1531// The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1532
1533if (isPartitionUsed(gptMap))
1534{
1535char stringuuid[100];
1536efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1537verbose("Reading GPT partition %d, type %s\n", (unsigned) gptID, stringuuid);
1538
1539// Getting fdisk like partition type.
1540fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1541
1542if ( (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) )
1543{
1544bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1545bvr = newGPTBVRef(biosdev,
1546gptID,
1547gptMap->ent_lba_start,
1548gptMap,
1549HFSInitPartition,
1550HFSLoadFile,
1551HFSReadFile,
1552HFSGetDirEntry,
1553HFSGetFileBlock,
1554HFSGetUUID,
1555HFSGetDescription,
1556HFSFree,
15570,
1558kBIOSDevTypeHardDrive, bvrFlags);
1559}
1560
1561// zef - foreign OS support
1562if ((efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1563(efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1564{
1565switch (fsType)
1566{
1567case FDISK_NTFS:
1568bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
15690, 0, 0, 0, 0, NTFSGetUUID, NTFSGetDescription,
1570(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1571break;
1572
1573case FDISK_LINUX:
1574bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
15750, 0, 0, 0, 0, EX2GetUUID, EX2GetDescription,
1576(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1577break;
1578
1579case FDISK_FAT32:
1580case FDISK_DOS12:
1581case FDISK_DOS16B:
1582bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1583MSDOSInitPartition,
1584MSDOSLoadFile,
1585MSDOSReadFile,
1586MSDOSGetDirEntry,
1587MSDOSGetFileBlock,
1588MSDOSGetUUID,
1589MSDOSGetDescription,
1590MSDOSFree,
15910, kBIOSDevTypeHardDrive, 0);
1592break;
1593
1594case FDISK_PSEUDO_EXFAT:
1595bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1596 EXFATInitPartition,
1597 EXFATLoadFile,
1598 EXFATReadFile,
1599 EXFATGetDirEntry,
1600 EXFATGetFileBlock,
1601 EXFATGetUUID,
1602 EXFATGetDescription,
1603 EXFATFree,
1604 0, kBIOSDevTypeHardDrive, 0);
1605break;
1606
1607default:
1608bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
16090, 0, 0, 0, 0, 0, 0,
1610(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1611break;
1612}
1613
1614}
1615
1616// turbo - save our booter partition
1617// zef - only on original boot device
1618if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ) {
1619switch (fsType) {
1620case FDISK_HFS:
1621if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1622bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1623HFSInitPartition,
1624HFSLoadFile,
1625HFSReadFile,
1626HFSGetDirEntry,
1627HFSGetFileBlock,
1628HFSGetUUID,
1629HFSGetDescription,
1630HFSFree,
16310, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1632}
1633break;
1634
1635case FDISK_FAT32:
1636if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1637bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1638MSDOSInitPartition,
1639MSDOSLoadFile,
1640MSDOSReadFile,
1641MSDOSGetDirEntry,
1642MSDOSGetFileBlock,
1643MSDOSGetUUID,
1644MSDOSGetDescription,
1645MSDOSFree,
16460, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1647}
1648break;
1649
1650default:
1651if (biosdev == gBIOSDev)
1652{
1653gBIOSBootVolume = bvr;
1654}
1655break;
1656}
1657}
1658
1659if (bvr)
1660{
1661// Fixup bvr with the fake fdisk partition type.
1662if (fsType > 0) {
1663bvr->part_type = fsType;
1664}
1665
1666bvr->next = map->bvr;
1667map->bvr = bvr;
1668++map->bvrcnt;
1669}
1670
1671}
1672}
1673
1674scanErr:
1675if (buffer)
1676{
1677free(buffer);
1678}
1679
1680if(map)
1681{
1682if(countPtr) *countPtr = map->bvrcnt;
1683{
1684return map->bvr;
1685}
1686
1687}
1688else
1689{
1690if(countPtr) *countPtr = 0;
1691{
1692return NULL;
1693}
1694}
1695}
1696
1697//==============================================================================
1698static bool getOSVersion(BVRef bvr, char *str)
1699{
1700bool valid = false;
1701config_file_t configFile;
1702char dirSpec[512];
1703const char *val; int len;
1704
1705const char *fakeOSVersion;
1706int fakeOSVersionInt;
1707// our pattern: avoiding to use full path. this help if the app is named as Beta or DP..
1708char *LionPattern= "Install%20Mac%20OS%20X%20Lion";// Install Mac OS Lion
1709char *MLPattern= "Install%20OS%20X%20Mountain%20Lion";// Install OS X Mountain Lion
1710char *MavPattern= "Install%20OS%20X%20Mavericks";// Install OS X Mavericks
1711char *YosPattern= "Install%20OS%20X%20Yosemite";// Install OS X Yosemite
1712char *YosPatternB= "Install%20OS%20X%2010.10";// Install OS X 10.10
1713char *ECPattern= "Install%20OS%20X%20El%20Capitan";// Install OS X El Capitan
1714char *ECPatternB= "Install%20OS%20X%2010.11";// Install OS X 10.11
1715char *SierraPattern= "Install%20macOS%20Sierra";// Install macOS Sierra
1716char *SierraPatternB= "Install%20macOS%20X%2010.12";// Install macOS 10.12
1717char *HSierraPattern= "Install%20macOS%20High%20Sierra";// Install macOS High Sierra
1718char *HSierraPatternB= "Install%20macOS%2010.13";// Install macOS 10.13
1719char *MojavePattern= "Install%20macOS%20Mojave";// Install macOS Mojave
1720char *MojavePatternB= "Install%20macOS%2010.14";// Install macOS 10.14
1721char *CatalinaPattern= "Install%20macOS%20Catalina";// Install macOS Catalina
1722char *CatalinaPatternB= "Install%20macOS%2010.15";// Install macOS 10.15
1723
1724/*
1725 * Only look for OS Version on HFS+
1726 */
1727if (bvr->fs_readfile != HFSReadFile)
1728{
1729return valid;
1730}
1731
1732/*
1733 * Micky1979, let it search for the right Version *.plist
1734 *
1735 * NOTE:
1736 * order is important because vanilla installer (createinstallermedia method 10.9 +) has both /.IABootFilesSystemVersion.plist and
1737 * /System/Library/CoreServices/SystemVersion.plist otherwise fail to recognize it as Installer!
1738 *
1739 * OS X Installer made by the Vanilla app for Lion and newer.
1740 * This kind of Installer can be a guest in a already working System, and produces some temporary files:
1741 * 1) ".IABootFiles" folder is created in the root of the same partition where the app reside.
1742 * 2) "Mac OS X Install Data" or "OS X Install Data" in the target partition
1743 * 3) The presence of ".IABootFilesSystemVersion.plist" file if present or not, distinguishes this installer
1744 * by the one create with "createinstallmedia" method (is present), so we know what kind of installer is.
1745 */
1746
1747// is an installer or a system to Upgrade OSX?
1748snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/.IAProductInfo", BIOS_DEV_UNIT(bvr), bvr->part_no);
1749
1750if (loadConfigFile(dirSpec, &configFile) == 0)
1751{
1752valid = true;
1753}
1754
1755if (valid)
1756{
1757// is createinstallmedia?
1758snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/.IABootFilesSystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1759if (loadConfigFile(dirSpec, &configFile) == 0)
1760{
1761valid = false;
1762}
1763else
1764{
1765// if not exist probably is a vanilla installer made w/o createinstallermedia method
1766snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/.IABootFiles/com.apple.Boot.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1767if (loadConfigFile(dirSpec, &configFile) == 0)
1768{
1769strncpy(bvr->comAppleBoot, dirSpec, strlen(dirSpec));
1770valid = true;
1771}
1772else
1773{
1774valid = false;
1775}
1776}
1777}
1778
1779if (valid)
1780{
1781/*
1782 * we don't know the real OS version, but "Kernel Flags" key contain the URL path to the app..
1783 * and we try to see if contain a match for our patterns ("Install%20OS%20X%20El%20Capitan" = 10.11)
1784 */
1785if (getValueForKey(kKernelFlagsKey, &val, &len, &configFile))
1786{
1787if(strstr(val, LionPattern))
1788{
1789fakeOSVersion = "10.7";
1790fakeOSVersionInt = 7;
1791valid = true;
1792}
1793else if(strstr(val, MLPattern))
1794{
1795fakeOSVersion = "10.8";
1796fakeOSVersionInt = 8;
1797valid = true;
1798}
1799else if(strstr(val, MavPattern))
1800{
1801fakeOSVersion = "10.9";
1802fakeOSVersionInt = 9;
1803valid = true;
1804}
1805else if( strstr(val, YosPattern) || strstr(val, YosPatternB) )
1806{
1807fakeOSVersion = "10.10";
1808fakeOSVersionInt = 10;
1809valid = true;
1810}
1811else if( strstr(val, ECPattern) || strstr(val, ECPatternB) )
1812{
1813fakeOSVersion = "10.11";
1814fakeOSVersionInt = 11;
1815valid = true;
1816}
1817else if( strstr(val, SierraPattern) || strstr(val, SierraPatternB) )
1818{
1819fakeOSVersion = "10.12";
1820fakeOSVersionInt = 12;
1821valid = true;
1822}
1823else if( strstr(val, HSierraPattern) || strstr(val, HSierraPatternB) )
1824{
1825fakeOSVersion = "10.13";
1826fakeOSVersionInt = 13;
1827valid = true;
1828}
1829else if( strstr(val, MojavePattern) || strstr(val, MojavePatternB) )
1830{
1831fakeOSVersion = "10.14";
1832fakeOSVersionInt = 14;
1833valid = true;
1834}
1835else if( strstr(val, CatalinaPattern) || strstr(val, CatalinaPatternB) )
1836{
1837fakeOSVersion = "10.15";
1838fakeOSVersionInt = 15;
1839valid = true;
1840}
1841else
1842{
1843valid = false;
1844}
1845}
1846else
1847{
1848valid = false;
1849}
1850}
1851
1852if (valid)
1853{
1854/*
1855 * if we are here that is an createinstallmedia Installer!
1856 * fake the OS version so we can find the right path to the kernelcache/prelinked!
1857 * To patch the kernelcache we aquire the "Darwin versionn" later..
1858 */
1859strncpy( bvr->OSFullVer, fakeOSVersion, strlen(fakeOSVersion) );
1860bvr->OSisInstaller = true;
1861// no SystemVersion.plist ...so no build...
1862strncpy( bvr->OSBuildVer, "INSTALLER", strlen("INSTALLER") );
1863return true;
1864}
1865
1866/*
1867 * Not valid? But we have the "/.IAProductInfo" in the root so this is not a conventional installer
1868 * and probably this is an Upgrade made by the "Install OS X app"
1869 */
1870if (!valid)
1871{
1872len = 0; val = 0;
1873// 10.9 and later use "/OS X Install Data" folder
1874snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/OS X Install Data/com.apple.Boot.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1875if (loadConfigFile(dirSpec, &configFile) == 0)
1876{
1877/*
1878 * bad is that we can't find what is the exactly Major OS version..
1879 * but what we need is the right path to the kernel cache:
1880 * kernelcache = 10.9 and 10.10
1881 * prelinkedkernel = 10.11 and later
1882
1883 * so we fake the OS version just to find the correct path!
1884 * .. later the right "Darwin Version" will use to patch the kernel cache!
1885 */
1886
1887if (getValueForKey("Kernel Cache", &val, &len, &configFile))
1888{
1889if(strstr(val, "prelinkedkernel")) // /OS X Install Data/prelinkedkernel
1890{
1891fakeOSVersion = "10.11"; // fake OS to find prelinkedkernel on newer OSes
1892
1893switch (fakeOSVersionInt)
1894{
1895case 11:
1896fakeOSVersion = "10.11";
1897break;
1898case 12:
1899fakeOSVersion = "10.12";
1900break;
1901case 13:
1902fakeOSVersion = "10.13";
1903break;
1904case 14:
1905fakeOSVersion = "10.14";
1906break;
1907default:
1908fakeOSVersion = "10.14";
1909break;
1910}
1911
1912valid = true;
1913}
1914else if(strstr(val, "kernelcache")) // /OS X Install Data/kernelcache
1915{
1916fakeOSVersion = "10.10"; // fake OS to find prelinkedkernel on 10.9 and 10.10
1917valid = true;
1918}
1919else
1920{
1921valid = false;
1922}
1923
1924if (valid)
1925{
1926strncpy( bvr->OSFullVer, fakeOSVersion, strlen(fakeOSVersion) );
1927bvr->OSisOSXUpgrade = true;
1928strncpy( bvr->OSBuildVer, "UPGRADE", strlen("UPGRADE") );
1929strncpy(bvr->comAppleBoot, dirSpec, strlen(dirSpec));
1930
1931return true;
1932}
1933}
1934else
1935{
1936valid = false;
1937}
1938
1939}
1940else
1941{
1942valid = false;
1943}
1944}
1945
1946if (!valid)
1947{
1948/*
1949 * Not valid? 10.8 and older use "/Mac OS X Install Data" folder..
1950 */
1951snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/Mac OS X Install Data/com.apple.Boot.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1952if (loadConfigFile(dirSpec, &configFile) == 0)
1953{
1954fakeOSVersion = "10.8"; // fake the OS version using 10.8.. just to find the kernelcache path for 10.7 and 10.8..
1955strncpy( bvr->OSFullVer, fakeOSVersion, strlen(fakeOSVersion) );
1956bvr->OSisMacOSXUpgrade = true;
1957// again no SystemVersion.plist, so no build version.. but is usefull to know that is a System upgrade..
1958strncpy( bvr->OSBuildVer, "UPGRADE", strlen("UPGRADE") );
1959strncpy(bvr->comAppleBoot, dirSpec, strlen(dirSpec));
1960return true;
1961}
1962}
1963
1964if (!valid)
1965{
1966len = 0; val = 0;
1967/*
1968 * Not valid? 10.13 and newer use "/macOS Install Data" folder..
1969 * and we have /macOS Install Data/Locked Files/Boot Files/SystemVersion.plist... thanks Apple!
1970 * NOTE: the stage 2 of this installation is already bootable (aug 13 2017)
1971 */
1972snprintf(dirSpec, sizeof(dirSpec),
1973"hd(%d,%d)/macOS Install Data/Locked Files/Boot Files/SystemVersion.plist",
1974BIOS_DEV_UNIT(bvr),
1975bvr->part_no);
1976if (loadConfigFile(dirSpec, &configFile) == 0)
1977{
1978if (getValueForKey(kProductVersion, &val, &len, &configFile))
1979{
1980// Copy the complete value into OSFullVer
1981strncpy( bvr->OSFullVer, val, len );
1982bvr->OSFullVer[len] = '\0'; /* null character manually added */
1983
1984// getValueForKey uses const char for val
1985// so copy it and trim
1986*str = '\0';
1987strncat(str, val, MIN(len, 5));
1988if(str[4] == '.')
1989{
1990str[4] = '\0';
1991}
1992bvr->OSisOSXUpgrade = true;
1993strncpy( bvr->OSBuildVer, "UPGRADE", strlen("UPGRADE") );
1994
1995len = 0; val = 0;
1996snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/macOS Install Data/Locked Files/Boot Files/com.apple.Boot.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1997if (loadConfigFile(dirSpec, &configFile) == 0)
1998{
1999strncpy(bvr->comAppleBoot, dirSpec, strlen(dirSpec));
2000}
2001return true;
2002}
2003}
2004}
2005
2006len = 0; val = 0;
2007
2008// OS X Installer createinstallermedia method for 10.9 and newer.
2009snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/.IABootFilesSystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
2010
2011if (loadConfigFile(dirSpec, &configFile) == 0)
2012{
2013bvr->OSisInstaller = true;
2014valid = true;
2015}
2016
2017// OS X Standard
2018if (!valid)
2019{
2020snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
2021
2022if (loadConfigFile(dirSpec, &configFile) == 0)
2023{
2024valid = true;
2025}
2026else
2027{
2028// OS X Server
2029snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
2030
2031if (loadConfigFile(dirSpec, &configFile) == 0)
2032{
2033bvr->OSisServer = true;
2034valid = true;
2035}
2036}
2037}
2038
2039if (!valid)
2040{
2041len = 0; val = 0;
2042snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/com.apple.recovery.boot/com.apple.Boot.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
2043if (loadConfigFile(dirSpec, &configFile) == 0)
2044{
2045strncpy(bvr->comAppleBoot, dirSpec, strlen(dirSpec));
2046}
2047
2048// OS X Recovery
2049sprintf(dirSpec, "hd(%d,%d)/com.apple.recovery.boot/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
2050
2051if (loadConfigFile(dirSpec, &configFile) == 0)
2052{
2053bvr->OSisRecovery = true;
2054valid = true;
2055}
2056}
2057
2058if (valid)
2059{
2060len = 0; val = 0;
2061// ProductVersion
2062if (getValueForKey(kProductVersion, &val, &len, &configFile))
2063{
2064// Copy the complete value into OSFullVer
2065strncpy( bvr->OSFullVer, val, len );
2066bvr->OSFullVer[len] = '\0'; /* null character manually added */
2067
2068// getValueForKey uses const char for val
2069// so copy it and trim
2070*str = '\0';
2071strncat(str, val, MIN(len, 5));
2072if(str[4] == '.')
2073{
2074str[4] = '\0';
2075}
2076
2077// ProductBuildVersion
2078if (getValueForKey(kProductBuildVersion, &val, &len, &configFile))
2079{
2080strncpy( bvr->OSBuildVer, val, len );
2081bvr->OSBuildVer[len] = '\0'; /* null character manually added */
2082}
2083
2084}
2085else
2086{
2087valid = false;
2088}
2089}
2090
2091return valid;
2092}
2093
2094//==============================================================================
2095static void scanFSLevelBVRSettings(BVRef chain)
2096{
2097BVRef bvr;
2098char dirSpec[512], fileSpec[512];
2099char label[BVSTRLEN];
2100int ret;
2101long flags;
2102u_int32_t time;
2103int fh, fileSize, error;
2104
2105for (bvr = chain; bvr; bvr = bvr->next)
2106{
2107ret = -1;
2108error = 0;
2109
2110//
2111// Check for alternate volume label on boot helper partitions.
2112//
2113if (bvr->flags & kBVFlagBooter)
2114{
2115snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
2116strlcpy(fileSpec, ".disk_label.contentDetails", sizeof(fileSpec));
2117ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
2118if (!ret)
2119{
2120strlcat(dirSpec, fileSpec, sizeof(dirSpec));
2121fh = open(dirSpec,0);
2122
2123fileSize = file_size(fh);
2124if (fileSize > 0 && fileSize < BVSTRLEN)
2125{
2126if (read(fh, label, fileSize) != fileSize)
2127{
2128error = -1;
2129}
2130}
2131else
2132{
2133error = -1;
2134}
2135
2136close(fh);
2137
2138if (!error)
2139{
2140label[fileSize] = '\0';
2141strlcpy(bvr->altlabel, label, sizeof(bvr->altlabel));
2142}
2143}
2144}
2145
2146// Check for SystemVersion.plist or ServerVersion.plist or com.apple.boot.plist to determine if a volume hosts an installed system.
2147
2148if (bvr->flags & kBVFlagNativeBoot)
2149{
2150if (getOSVersion(bvr, bvr->OSVersion) == true)
2151{
2152bvr->flags |= kBVFlagSystemVolume;
2153}
2154}
2155
2156}
2157}
2158
2159//==============================================================================
2160void rescanBIOSDevice(int biosdev)
2161{
2162struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
2163if (oldMap == NULL)
2164{
2165return;
2166}
2167
2168CacheReset();
2169diskFreeMap(oldMap);
2170oldMap = NULL;
2171scanBootVolumes(biosdev, 0);
2172}
2173
2174//==============================================================================
2175struct DiskBVMap* diskResetBootVolumes(int biosdev)
2176{
2177struct DiskBVMap * map;
2178struct DiskBVMap *prevMap = NULL;
2179for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
2180if ( biosdev == map->biosdev ) {
2181break;
2182}
2183}
2184
2185if(map != NULL) {
2186verbose("Resetting BIOS device %xh\n", biosdev);
2187// Reset the biosbuf cache
2188cache_valid = false;
2189if(map == gDiskBVMap)
2190{
2191gDiskBVMap = map->next;
2192}
2193else if(prevMap != NULL)
2194{
2195prevMap->next = map->next;
2196}
2197else
2198{
2199stop("diskResetBootVolumes error\n");
2200return NULL;
2201}
2202}
2203// Return the old map, either to be freed, or reinserted later
2204return map;
2205}
2206
2207//==============================================================================
2208// Frees a DiskBVMap and all of its BootVolume's
2209void diskFreeMap(struct DiskBVMap *map)
2210{
2211if(map != NULL)
2212{
2213while(map->bvr != NULL)
2214{
2215BVRef bvr = map->bvr;
2216map->bvr = bvr->next;
2217(*bvr->bv_free)(bvr);
2218}
2219
2220free(map);
2221}
2222}
2223
2224//==============================================================================
2225BVRef diskScanBootVolumes(int biosdev, int *countPtr)
2226{
2227struct DiskBVMap *map;
2228BVRef bvr;
2229int count = 0;
2230
2231// Find an existing mapping for this device.
2232
2233for (map = gDiskBVMap; map; map = map->next)
2234{
2235if (biosdev == map->biosdev)
2236{
2237count = map->bvrcnt;
2238break;
2239}
2240}
2241
2242if (map == NULL)
2243{
2244bvr = diskScanGPTBootVolumes(biosdev, &count);
2245if (bvr == NULL)
2246{
2247bvr = diskScanFDiskBootVolumes(biosdev, &count);
2248}
2249
2250if (bvr == NULL)
2251{
2252bvr = diskScanAPMBootVolumes(biosdev, &count);
2253}
2254
2255if (bvr)
2256{
2257scanFSLevelBVRSettings(bvr);
2258}
2259}
2260else
2261{
2262bvr = map->bvr;
2263}
2264
2265if (countPtr)
2266{
2267*countPtr += count;
2268}
2269
2270return bvr;
2271}
2272
2273//==============================================================================
2274BVRef getBVChainForBIOSDev(int biosdev)
2275{
2276BVRef chain = NULL;
2277struct DiskBVMap * map = NULL;
2278
2279for (map = gDiskBVMap; map; map = map->next)
2280{
2281if (map->biosdev == biosdev)
2282{
2283chain = map->bvr;
2284break;
2285}
2286}
2287
2288return chain;
2289}
2290
2291//==============================================================================
2292BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
2293{
2294BVRef chain = NULL;
2295BVRef bvr = NULL;
2296BVRef newBVR = NULL;
2297BVRef prevBVR = NULL;
2298
2299struct DiskBVMap * map = NULL;
2300int bvCount = 0;
2301
2302const char *raw = 0;
2303char* val = 0;
2304int len;
2305
2306getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
2307if(raw)
2308{
2309val = XMLDecode(raw);
2310}
2311
2312// Traverse gDISKBVmap to get references for
2313// individual bvr chains of each drive.
2314for (map = gDiskBVMap; map; map = map->next)
2315{
2316for (bvr = map->bvr; bvr; bvr = bvr->next)
2317{
2318// Save the last bvr.
2319if (newBVR)
2320{
2321prevBVR = newBVR;
2322}
2323
2324// Allocate and copy the matched bvr entry into a new one.
2325newBVR = (BVRef) malloc(sizeof(*newBVR));
2326if (!newBVR)
2327{
2328continue;
2329}
2330bzero(newBVR,sizeof(*newBVR));
2331
2332bcopy(bvr, newBVR, sizeof(*newBVR));
2333
2334// Adjust the new bvr's fields.
2335newBVR->next = NULL;
2336newBVR->filtered = true;
2337
2338if ( (!allowFlags || newBVR->flags & allowFlags)
2339&& (!denyFlags || !(newBVR->flags & denyFlags) )
2340&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
2341)
2342{
2343newBVR->visible = true;
2344}
2345
2346// Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
2347// to be able to hide foreign partitions from the boot menu.
2348
2349if ( (newBVR->flags & kBVFlagForeignBoot) )
2350{
2351char *start, *next = val;
2352long len = 0;
2353do
2354{
2355start = strbreak(next, &next, &len);
2356if(len && matchVolumeToString(newBVR, start, len) )
2357{
2358newBVR->visible = false;
2359}
2360}
2361while ( next && *next );
2362}
2363
2364// Use the first bvr entry as the starting chain pointer.
2365if (!chain)
2366{
2367chain = newBVR;
2368}
2369
2370// Update the previous bvr's link pointer to use the new memory area.
2371if (prevBVR)
2372{
2373prevBVR->next = newBVR;
2374}
2375
2376if (newBVR->visible)
2377{
2378bvCount++;
2379}
2380}
2381}
2382
2383#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
2384for (bvr = chain; bvr; bvr = bvr->next)
2385{
2386if (!bvr)
2387{
2388break;
2389}
2390printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
2391}
2392printf("count: %d\n", bvCount);
2393getchar();
2394#endif
2395
2396*count = bvCount;
2397
2398free(val);
2399return chain;
2400}
2401
2402//==============================================================================
2403int freeFilteredBVChain(const BVRef chain)
2404{
2405int ret = 1;
2406BVRef bvr = chain;
2407BVRef nextBVR = NULL;
2408
2409while (bvr)
2410{
2411if (!bvr)
2412{
2413break;
2414}
2415
2416nextBVR = bvr->next;
2417
2418if (bvr->filtered)
2419{
2420free(bvr);
2421}
2422else
2423{
2424ret = 0;
2425break;
2426}
2427
2428bvr = nextBVR;
2429}
2430
2431return ret;
2432}
2433
2434//==============================================================================
2435bool matchVolumeToString( BVRef bvr, const char *match, long matchLen)
2436{
2437char testStr[128];
2438
2439if ( !bvr || !match || !*match)
2440{
2441return 0;
2442}
2443
2444if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
2445{
2446 return 0;
2447}
2448
2449// Try to match hd(x,y) first.
2450snprintf(testStr, sizeof(testStr), "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
2451if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2452{
2453return true;
2454}
2455
2456// Try to match volume UUID.
2457if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
2458{
2459if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2460{
2461return true;
2462}
2463}
2464
2465// Try to match volume label (always quoted).
2466if ( bvr->description )
2467{
2468bvr->description(bvr, testStr, sizeof(testStr)-1);
2469if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2470{
2471return true;
2472}
2473}
2474
2475return false;
2476}
2477
2478//==============================================================================
2479/* If Rename Partition has defined an alias, then extract it for description purpose.
2480 * The format for the rename string is the following:
2481 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
2482 */
2483static bool getVolumeLabelAlias(BVRef bvr, char *str, long strMaxLen)
2484{
2485char *aliasList, *entryStart, *entryNext;
2486
2487if ( !str || strMaxLen <= 0)
2488{
2489return false;
2490}
2491
2492aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
2493if ( !aliasList )
2494{
2495return false;
2496}
2497
2498for ( entryStart = entryNext = aliasList; entryNext && *entryNext; entryStart = entryNext )
2499{
2500char *volStart, *volEnd, *aliasStart;
2501long volLen, aliasLen;
2502
2503// Delimit current entry
2504entryNext = strchr(entryStart, ';');
2505if ( entryNext )
2506{
2507*entryNext = '\0';
2508entryNext++;
2509}
2510
2511volStart = strbreak(entryStart, &volEnd, &volLen);
2512if(!volLen)
2513{
2514continue;
2515}
2516
2517aliasStart = strbreak(volEnd, 0, &aliasLen);
2518if(!aliasLen)
2519{
2520continue;
2521}
2522
2523if ( matchVolumeToString(bvr, volStart, volLen) )
2524{
2525strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
2526free(aliasList);
2527
2528return true;
2529}
2530}
2531
2532free(aliasList);
2533return false;
2534}
2535
2536//==============================================================================
2537void getBootVolumeDescription( BVRef bvr, char *str, long strMaxLen, bool useDeviceDescription )
2538{
2539unsigned char type;
2540char *p = str;
2541
2542if(!bvr || !p || strMaxLen <= 0)
2543{
2544return;
2545}
2546
2547type = (unsigned char) bvr->part_type;
2548
2549if (useDeviceDescription)
2550{
2551int len = getDeviceDescription(bvr, str);
2552if(len >= strMaxLen)
2553{
2554return;
2555}
2556
2557strcpy(str + len, bvr->OSisInstaller ? " (Installer " : " (");
2558len += bvr->OSisInstaller ? 12 : 2;
2559strcpy(str + len, bvr->OSVersion);
2560len += strlen(bvr->OSVersion);
2561strcpy(str + len, ") ");
2562len += 2;
2563
2564strMaxLen -= len;
2565p += len;
2566}
2567
2568/* See if a partition rename is preferred */
2569if (getVolumeLabelAlias(bvr, p, strMaxLen))
2570{
2571strncpy(bvr->label, p, strMaxLen);
2572return; // we're done here no need to seek for real name
2573}
2574
2575// Get the volume label using filesystem specific functions or use the alternate volume label if available.
2576
2577if (*bvr->altlabel != '\0')
2578{
2579strncpy(p, bvr->altlabel, strMaxLen);
2580}
2581else if (bvr->description)
2582{
2583bvr->description(bvr, p, strMaxLen);
2584}
2585
2586if (*p == '\0')
2587{
2588const char * name = getNameForValue( fdiskTypes, type );
2589
2590if (name == NULL)
2591{
2592name = bvr->type_name;
2593}
2594
2595if (name == NULL)
2596{
2597snprintf(p, strMaxLen, "TYPE %02X", type);
2598}
2599else
2600{
2601strncpy(p, name, strMaxLen);
2602}
2603}
2604
2605// Set the devices label
2606strncpy(bvr->label, p, sizeof(bvr->label) );
2607}
2608
2609//==============================================================================
2610int readBootSector(int biosdev, unsigned int secno, void *buffer)
2611{
2612int error;
2613struct disk_blk0 * bootSector = (struct disk_blk0 *)buffer;
2614
2615if (bootSector == NULL)
2616{
2617if (gBootSector == NULL)
2618{
2619gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2620
2621if (gBootSector == NULL)
2622{
2623return -1;
2624}
2625}
2626
2627bootSector = gBootSector;
2628}
2629
2630error = readBytes(biosdev, secno, 0, BPS, bootSector);
2631
2632if (error || bootSector->signature != DISK_SIGNATURE)
2633{
2634return -1;
2635}
2636return 0;
2637}
2638
2639//==============================================================================
2640/*
2641 * Format of boot1f32 block.
2642 */
2643#define BOOT1F32_MAGIC "BOOT "
2644#define BOOT1F32_MAGICLEN 11
2645
2646struct disk_boot1f32_blk
2647{
2648unsigned char init[3];
2649unsigned char fsheader[87];
2650unsigned char magic[BOOT1F32_MAGICLEN];
2651unsigned char bootcode[409];
2652unsigned short signature;
2653};
2654
2655//==============================================================================
2656
2657int testFAT32EFIBootSector(int biosdev, unsigned int secno, void *buffer)
2658{
2659struct disk_boot1f32_blk *bootSector = (struct disk_boot1f32_blk *)buffer;
2660int error;
2661
2662if (bootSector == NULL)
2663{
2664if (gBootSector == NULL)
2665{
2666gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2667if ( gBootSector == NULL )
2668{
2669return -1;
2670}
2671}
2672bootSector = (struct disk_boot1f32_blk *)gBootSector;
2673}
2674
2675error = readBytes(biosdev, secno, 0, BPS, bootSector);
2676if (error || bootSector->signature != DISK_SIGNATURE || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2677{
2678return -1;
2679}
2680return 0;
2681}
2682
2683//==============================================================================
2684// Handle seek request from filesystem modules.
2685void diskSeek(BVRef bvr, long long position)
2686{
2687bvr->fs_boff = position / BPS;
2688bvr->fs_byteoff = position % BPS;
2689}
2690
2691//==============================================================================
2692// Handle read request from filesystem modules.
2693int diskRead(BVRef bvr, long addr, long length)
2694{
2695return readBytes(bvr->biosdev, bvr->fs_boff + bvr->part_boff, bvr->fs_byteoff, length, (void *) addr);
2696}
2697
2698//==============================================================================
2699int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2700{
2701int secs;
2702unsigned char *cbuf = (unsigned char *)buffer;
2703unsigned int copy_len;
2704int rc;
2705
2706if ((len & (BPS-1)) != 0)
2707{
2708error("raw disk read not sector aligned");
2709return -1;
2710}
2711secno += bvr->part_boff;
2712
2713cache_valid = false;
2714
2715while (len > 0)
2716{
2717secs = len / BPS;
2718if (secs > N_CACHE_SECS)
2719{
2720secs = N_CACHE_SECS;
2721}
2722copy_len = secs * BPS;
2723
2724//printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2725if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0)
2726{
2727/* Ignore corrected ECC errors */
2728if (rc != ECC_CORRECTED_ERR)
2729{
2730error(" EBIOS read error: %s\n", bios_error(rc), rc);
2731error(" Block %d Sectors %d\n", secno, secs);
2732return rc;
2733}
2734}
2735bcopy( trackbuf, cbuf, copy_len );
2736len -= copy_len;
2737cbuf += copy_len;
2738secno += secs;
2739spinActivityIndicator(secs);
2740}
2741
2742return 0;
2743}
2744
2745//==============================================================================
2746int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2747{
2748 int secs;
2749 unsigned char *cbuf = (unsigned char *)buffer;
2750 unsigned int copy_len;
2751 int rc;
2752
2753if ((len & (BPS-1)) != 0)
2754{
2755error("raw disk write not sector aligned");
2756return -1;
2757}
2758secno += bvr->part_boff;
2759
2760cache_valid = false;
2761
2762while (len > 0)
2763{
2764secs = len / BPS;
2765if (secs > N_CACHE_SECS)
2766{
2767secs = N_CACHE_SECS;
2768}
2769copy_len = secs * BPS;
2770
2771bcopy( cbuf, trackbuf, copy_len );
2772//printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2773if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0)
2774{
2775error(" EBIOS write error: %s\n", bios_error(rc), rc);
2776error(" Block %d Sectors %d\n", secno, secs);
2777return rc;
2778}
2779
2780len -= copy_len;
2781cbuf += copy_len;
2782secno += secs;
2783spinActivityIndicator(secs);
2784}
2785
2786return 0;
2787}
2788
2789//==============================================================================
2790int diskIsCDROM(BVRef bvr)
2791{
2792struct driveInfo di;
2793
2794if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation)
2795{
2796return 1;
2797}
2798return 0;
2799}
2800
2801//==============================================================================
2802int biosDevIsCDROM(int biosdev)
2803{
2804struct driveInfo di;
2805
2806if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2807{
2808return 1;
2809}
2810return 0;
2811}
2812

Archive Download this file

Revision: 2922