Chameleon

Chameleon Svn Source Tree

Root/trunk/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{
1844fh = open(strcat(dirSpec, fileSpec), 0);
1845fileSize = file_size(fh);
1846if (fileSize > 0 && fileSize < BVSTRLEN)
1847{
1848if (read(fh, label, fileSize) != fileSize)
1849{
1850error = -1;
1851}
1852}
1853else
1854{
1855error = -1;
1856}
1857
1858close(fh);
1859
1860if (!error)
1861{
1862label[fileSize] = '\0';
1863strlcpy(bvr->altlabel, label, sizeof(bvr->altlabel));
1864}
1865}
1866}
1867
1868// Check for SystemVersion.plist or ServerVersion.plist to determine if a volume hosts an installed system.
1869
1870if (bvr->flags & kBVFlagNativeBoot)
1871{
1872if (getOSVersion(bvr, bvr->OSVersion) == true)
1873{
1874bvr->flags |= kBVFlagSystemVolume;
1875}
1876}
1877
1878}
1879}
1880
1881//==============================================================================
1882
1883void rescanBIOSDevice(int biosdev)
1884{
1885struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1886if (oldMap == NULL)
1887{
1888return;
1889}
1890
1891CacheReset();
1892diskFreeMap(oldMap);
1893oldMap = NULL;
1894scanBootVolumes(biosdev, 0);
1895}
1896
1897//==============================================================================
1898
1899struct DiskBVMap* diskResetBootVolumes(int biosdev)
1900{
1901struct DiskBVMap * map;
1902struct DiskBVMap *prevMap = NULL;
1903for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1904if ( biosdev == map->biosdev ) {
1905break;
1906}
1907}
1908
1909if(map != NULL) {
1910verbose("Resetting BIOS device %xh\n", biosdev);
1911// Reset the biosbuf cache
1912cache_valid = false;
1913if(map == gDiskBVMap)
1914{
1915gDiskBVMap = map->next;
1916}
1917else if(prevMap != NULL)
1918{
1919prevMap->next = map->next;
1920}
1921else
1922{
1923stop("diskResetBootVolumes error\n");
1924return NULL;
1925}
1926}
1927// Return the old map, either to be freed, or reinserted later
1928return map;
1929}
1930
1931//==============================================================================
1932
1933// Frees a DiskBVMap and all of its BootVolume's
1934void diskFreeMap(struct DiskBVMap *map)
1935{
1936if(map != NULL)
1937{
1938while(map->bvr != NULL)
1939{
1940BVRef bvr = map->bvr;
1941map->bvr = bvr->next;
1942(*bvr->bv_free)(bvr);
1943}
1944
1945free(map);
1946}
1947}
1948
1949//==============================================================================
1950
1951BVRef diskScanBootVolumes(int biosdev, int * countPtr)
1952{
1953struct DiskBVMap *map;
1954BVRef bvr;
1955int count = 0;
1956
1957// Find an existing mapping for this device.
1958
1959for (map = gDiskBVMap; map; map = map->next)
1960{
1961if (biosdev == map->biosdev)
1962{
1963count = map->bvrcnt;
1964break;
1965}
1966}
1967
1968if (map == NULL)
1969{
1970bvr = diskScanGPTBootVolumes(biosdev, &count);
1971if (bvr == NULL)
1972{
1973bvr = diskScanFDiskBootVolumes(biosdev, &count);
1974}
1975
1976if (bvr == NULL)
1977{
1978bvr = diskScanAPMBootVolumes(biosdev, &count);
1979}
1980
1981if (bvr)
1982{
1983scanFSLevelBVRSettings(bvr);
1984}
1985}
1986else
1987{
1988bvr = map->bvr;
1989}
1990
1991if (countPtr)
1992{
1993*countPtr += count;
1994}
1995
1996return bvr;
1997}
1998
1999//==============================================================================
2000
2001BVRef getBVChainForBIOSDev(int biosdev)
2002{
2003BVRef chain = NULL;
2004struct DiskBVMap * map = NULL;
2005
2006for (map = gDiskBVMap; map; map = map->next)
2007{
2008if (map->biosdev == biosdev)
2009{
2010chain = map->bvr;
2011break;
2012}
2013}
2014
2015return chain;
2016}
2017
2018//==============================================================================
2019
2020BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
2021{
2022BVRef chain = NULL;
2023BVRef bvr = NULL;
2024BVRef newBVR = NULL;
2025BVRef prevBVR = NULL;
2026
2027struct DiskBVMap * map = NULL;
2028int bvCount = 0;
2029
2030const char *raw = 0;
2031char* val = 0;
2032int len;
2033
2034getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
2035if(raw)
2036{
2037val = XMLDecode(raw);
2038}
2039
2040/*
2041 * Traverse gDISKBVmap to get references for
2042 * individual bvr chains of each drive.
2043 */
2044for (map = gDiskBVMap; map; map = map->next)
2045{
2046for (bvr = map->bvr; bvr; bvr = bvr->next)
2047{
2048/*
2049 * Save the last bvr.
2050 */
2051if (newBVR)
2052{
2053prevBVR = newBVR;
2054}
2055
2056/*
2057 * Allocate and copy the matched bvr entry into a new one.
2058 */
2059newBVR = (BVRef) malloc(sizeof(*newBVR));
2060if (!newBVR)
2061{
2062continue;
2063}
2064bzero(newBVR,sizeof(*newBVR));
2065
2066bcopy(bvr, newBVR, sizeof(*newBVR));
2067
2068/*
2069 * Adjust the new bvr's fields.
2070 */
2071newBVR->next = NULL;
2072newBVR->filtered = true;
2073
2074if ( (!allowFlags || newBVR->flags & allowFlags)
2075&& (!denyFlags || !(newBVR->flags & denyFlags) )
2076&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
2077)
2078{
2079newBVR->visible = true;
2080}
2081
2082/*
2083 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
2084 * to be able to hide foreign partitions from the boot menu.
2085 *
2086 */
2087if ( (newBVR->flags & kBVFlagForeignBoot) )
2088{
2089char *start, *next = val;
2090long len = 0;
2091do
2092{
2093start = strbreak(next, &next, &len);
2094if(len && matchVolumeToString(newBVR, start, len) )
2095{
2096newBVR->visible = false;
2097}
2098}
2099while ( next && *next );
2100}
2101
2102/*
2103 * Use the first bvr entry as the starting chain pointer.
2104 */
2105if (!chain)
2106{
2107chain = newBVR;
2108}
2109
2110/*
2111 * Update the previous bvr's link pointer to use the new memory area.
2112 */
2113if (prevBVR)
2114{
2115prevBVR->next = newBVR;
2116}
2117
2118if (newBVR->visible)
2119{
2120bvCount++;
2121}
2122}
2123}
2124
2125#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
2126for (bvr = chain; bvr; bvr = bvr->next)
2127{
2128if (!bvr)
2129{
2130break;
2131}
2132printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
2133}
2134printf("count: %d\n", bvCount);
2135getchar();
2136#endif
2137
2138*count = bvCount;
2139
2140free(val);
2141return chain;
2142}
2143
2144//==============================================================================
2145
2146int freeFilteredBVChain(const BVRef chain)
2147{
2148int ret = 1;
2149BVRef bvr = chain;
2150BVRef nextBVR = NULL;
2151
2152while (bvr)
2153{
2154if (!bvr)
2155{
2156break;
2157}
2158
2159nextBVR = bvr->next;
2160
2161if (bvr->filtered)
2162{
2163free(bvr);
2164}
2165else
2166{
2167ret = 0;
2168break;
2169}
2170
2171bvr = nextBVR;
2172}
2173
2174return ret;
2175}
2176
2177//==============================================================================
2178
2179bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
2180{
2181char testStr[128];
2182
2183if ( !bvr || !match || !*match)
2184{
2185return 0;
2186}
2187
2188if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
2189{
2190 return 0;
2191}
2192
2193// Try to match hd(x,y) first.
2194snprintf(testStr, sizeof(testStr), "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
2195if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2196{
2197return true;
2198}
2199
2200// Try to match volume UUID.
2201if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
2202{
2203if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2204{
2205return true;
2206}
2207}
2208
2209// Try to match volume label (always quoted).
2210if ( bvr->description )
2211{
2212bvr->description(bvr, testStr, sizeof(testStr)-1);
2213if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2214{
2215return true;
2216}
2217}
2218
2219return false;
2220}
2221
2222//==============================================================================
2223
2224/* If Rename Partition has defined an alias, then extract it for description purpose.
2225 * The format for the rename string is the following:
2226 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
2227 */
2228
2229static bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
2230{
2231char *aliasList, *entryStart, *entryNext;
2232
2233if ( !str || strMaxLen <= 0)
2234{
2235return false;
2236}
2237
2238aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
2239if ( !aliasList )
2240{
2241return false;
2242}
2243
2244for ( entryStart = entryNext = aliasList; entryNext && *entryNext; entryStart = entryNext )
2245{
2246char *volStart, *volEnd, *aliasStart;
2247long volLen, aliasLen;
2248
2249// Delimit current entry
2250entryNext = strchr(entryStart, ';');
2251if ( entryNext )
2252{
2253*entryNext = '\0';
2254entryNext++;
2255}
2256
2257volStart = strbreak(entryStart, &volEnd, &volLen);
2258if(!volLen)
2259{
2260continue;
2261}
2262
2263aliasStart = strbreak(volEnd, 0, &aliasLen);
2264if(!aliasLen)
2265{
2266continue;
2267}
2268
2269if ( matchVolumeToString(bvr, volStart, volLen) )
2270{
2271strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
2272free(aliasList);
2273
2274return true;
2275}
2276}
2277
2278free(aliasList);
2279return false;
2280}
2281
2282//==============================================================================
2283
2284void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
2285{
2286unsigned char type;
2287char *p = str;
2288
2289if(!bvr || !p || strMaxLen <= 0)
2290{
2291return;
2292}
2293
2294type = (unsigned char) bvr->part_type;
2295
2296if (useDeviceDescription)
2297{
2298int len = getDeviceDescription(bvr, str);
2299if(len >= strMaxLen)
2300{
2301return;
2302}
2303
2304strcpy(str + len, bvr->OSisInstaller ? " (Installer " : " (");
2305len += bvr->OSisInstaller ? 12 : 2;
2306strcpy(str + len, bvr->OSVersion);
2307len += strlen(bvr->OSVersion);
2308strcpy(str + len, ") ");
2309len += 2;
2310
2311strMaxLen -= len;
2312p += len;
2313}
2314
2315/* See if a partition rename is preferred */
2316if (getVolumeLabelAlias(bvr, p, strMaxLen))
2317{
2318strncpy(bvr->label, p, strMaxLen);
2319return; // we're done here no need to seek for real name
2320}
2321
2322// Get the volume label using filesystem specific functions or use the alternate volume label if available.
2323
2324if (*bvr->altlabel != '\0')
2325{
2326strncpy(p, bvr->altlabel, strMaxLen);
2327}
2328else if (bvr->description)
2329{
2330bvr->description(bvr, p, strMaxLen);
2331}
2332
2333if (*p == '\0')
2334{
2335const char * name = getNameForValue( fdiskTypes, type );
2336
2337if (name == NULL)
2338{
2339name = bvr->type_name;
2340}
2341
2342if (name == NULL)
2343{
2344snprintf(p, strMaxLen, "TYPE %02X", type);
2345}
2346else
2347{
2348strncpy(p, name, strMaxLen);
2349}
2350}
2351
2352// Set the devices label
2353snprintf(bvr->label, sizeof(bvr->label), p);
2354}
2355
2356
2357//==============================================================================
2358
2359int readBootSector(int biosdev, unsigned int secno, void *buffer)
2360{
2361int error;
2362struct disk_blk0 * bootSector = (struct disk_blk0 *)buffer;
2363
2364if (bootSector == NULL)
2365{
2366if (gBootSector == NULL)
2367{
2368gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2369
2370if (gBootSector == NULL)
2371{
2372return -1;
2373}
2374}
2375
2376bootSector = gBootSector;
2377}
2378
2379error = readBytes(biosdev, secno, 0, BPS, bootSector);
2380
2381if (error || bootSector->signature != DISK_SIGNATURE)
2382{
2383return -1;
2384}
2385return 0;
2386}
2387
2388//==============================================================================
2389
2390/*
2391 * Format of boot1f32 block.
2392 */
2393
2394#define BOOT1F32_MAGIC "BOOT "
2395#define BOOT1F32_MAGICLEN 11
2396
2397struct disk_boot1f32_blk
2398{
2399unsigned char init[3];
2400unsigned char fsheader[87];
2401unsigned char magic[BOOT1F32_MAGICLEN];
2402unsigned char bootcode[409];
2403unsigned short signature;
2404};
2405
2406//==============================================================================
2407
2408int testFAT32EFIBootSector(int biosdev, unsigned int secno, void *buffer)
2409{
2410struct disk_boot1f32_blk *bootSector = (struct disk_boot1f32_blk *)buffer;
2411int error;
2412
2413if (bootSector == NULL)
2414{
2415if (gBootSector == NULL)
2416{
2417gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2418if ( gBootSector == NULL )
2419{
2420return -1;
2421}
2422}
2423bootSector = (struct disk_boot1f32_blk *)gBootSector;
2424}
2425
2426error = readBytes(biosdev, secno, 0, BPS, bootSector);
2427if (error || bootSector->signature != DISK_SIGNATURE || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2428{
2429return -1;
2430}
2431return 0;
2432}
2433
2434
2435//==============================================================================
2436// Handle seek request from filesystem modules.
2437
2438void diskSeek(BVRef bvr, long long position)
2439{
2440bvr->fs_boff = position / BPS;
2441bvr->fs_byteoff = position % BPS;
2442}
2443
2444
2445//==============================================================================
2446// Handle read request from filesystem modules.
2447
2448int diskRead(BVRef bvr, long addr, long length)
2449{
2450return readBytes(bvr->biosdev, bvr->fs_boff + bvr->part_boff, bvr->fs_byteoff, length, (void *) addr);
2451}
2452
2453//==============================================================================
2454
2455int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2456{
2457int secs;
2458unsigned char *cbuf = (unsigned char *)buffer;
2459unsigned int copy_len;
2460int rc;
2461
2462if ((len & (BPS-1)) != 0)
2463{
2464error("raw disk read not sector aligned");
2465return -1;
2466}
2467secno += bvr->part_boff;
2468
2469cache_valid = false;
2470
2471while (len > 0)
2472{
2473secs = len / BPS;
2474if (secs > N_CACHE_SECS)
2475{
2476secs = N_CACHE_SECS;
2477}
2478copy_len = secs * BPS;
2479
2480//printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2481if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0)
2482{
2483/* Ignore corrected ECC errors */
2484if (rc != ECC_CORRECTED_ERR)
2485{
2486error(" EBIOS read error: %s\n", bios_error(rc), rc);
2487error(" Block %d Sectors %d\n", secno, secs);
2488return rc;
2489}
2490}
2491bcopy( trackbuf, cbuf, copy_len );
2492len -= copy_len;
2493cbuf += copy_len;
2494secno += secs;
2495spinActivityIndicator(secs);
2496}
2497
2498return 0;
2499}
2500
2501//==============================================================================
2502
2503int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2504{
2505 int secs;
2506 unsigned char *cbuf = (unsigned char *)buffer;
2507 unsigned int copy_len;
2508 int rc;
2509
2510if ((len & (BPS-1)) != 0)
2511{
2512error("raw disk write not sector aligned");
2513return -1;
2514}
2515secno += bvr->part_boff;
2516
2517cache_valid = false;
2518
2519while (len > 0)
2520{
2521secs = len / BPS;
2522if (secs > N_CACHE_SECS)
2523{
2524secs = N_CACHE_SECS;
2525}
2526copy_len = secs * BPS;
2527
2528bcopy( cbuf, trackbuf, copy_len );
2529//printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2530if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0)
2531{
2532error(" EBIOS write error: %s\n", bios_error(rc), rc);
2533error(" Block %d Sectors %d\n", secno, secs);
2534return rc;
2535}
2536
2537len -= copy_len;
2538cbuf += copy_len;
2539secno += secs;
2540spinActivityIndicator(secs);
2541}
2542
2543return 0;
2544}
2545
2546//==============================================================================
2547
2548int diskIsCDROM(BVRef bvr)
2549{
2550struct driveInfo di;
2551
2552if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation)
2553{
2554return 1;
2555}
2556return 0;
2557}
2558
2559//==============================================================================
2560
2561int biosDevIsCDROM(int biosdev)
2562{
2563struct driveInfo di;
2564
2565if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2566{
2567return 1;
2568}
2569return 0;
2570}
2571

Archive Download this file

Revision: 2613