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

Archive Download this file

Revision: 2537