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

Archive Download this file

Revision: 2620