Chameleon

Chameleon Svn Source Tree

Root/branches/Bungo/i386/libsaio/disk.c

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

Archive Download this file

Revision: HEAD