Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2587