Chameleon

Chameleon Svn Source Tree

Root/branches/zenith432/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
745static
746BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,
747 const DPME * part,
748 FSInit initFunc, FSLoadFile loadFunc,
749 FSReadFile readFunc,
750 FSGetDirEntry getdirFunc,
751 FSGetFileBlock getBlockFunc,
752 FSGetUUID getUUIDFunc,
753 BVGetDescription getDescriptionFunc,
754 BVFree bvFreeFunc,
755 int probe, int type, unsigned int bvrFlags )
756{
757BVRef bvr = (BVRef)malloc(sizeof(*bvr));
758if ( bvr )
759{
760bzero(bvr, sizeof(*bvr));
761
762bvr->biosdev = biosdev;
763bvr->part_no = partno;
764bvr->part_boff = blkoff;
765bvr->fs_loadfile = loadFunc;
766bvr->fs_readfile = readFunc;
767bvr->fs_getdirentry = getdirFunc;
768bvr->fs_getfileblock= getBlockFunc;
769bvr->fs_getuuid = getUUIDFunc;
770bvr->description = getDescriptionFunc;
771bvr->type = type;
772bvr->bv_free = bvFreeFunc;
773strlcpy(bvr->name, part->dpme_name, DPISTRLEN);
774strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);
775
776/*
777if ( part->bootid & FDISK_ACTIVE )
778{
779bvr->flags |= kBVFlagPrimary;
780}
781*/
782
783// Probe the filesystem.
784
785if ( initFunc )
786{
787bvr->flags |= kBVFlagNativeBoot | kBVFlagBootable | kBVFlagSystemVolume;
788
789if ( probe && initFunc( bvr ) != 0 )
790{
791// filesystem probe failed.
792
793DEBUG_DISK(("%s: failed probe on dev %X part %d\n", __FUNCTION__, biosdev, partno));
794
795(*bvr->bv_free)(bvr);
796bvr = NULL;
797}
798}
799/*
800else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
801{
802bvr->flags |= kBVFlagForeignBoot;
803}
804*/
805else
806{
807(*bvr->bv_free)(bvr);
808bvr = NULL;
809}
810}
811
812if ( bvr )
813{
814bvr->flags |= bvrFlags;
815}
816
817return bvr;
818}
819
820//==============================================================================
821
822// GUID's in LE form:
823// HFS+ partition - 48465300-0000-11AA-AA11-00306543ECAC
824EFI_GUID const GPT_HFS_GUID= { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF00 "Apple HFS/HFS+"
825
826// turbo - Apple Boot Partition - 426F6F74-0000-11AA-AA11-00306543ECAC
827EFI_GUID const GPT_BOOT_GUID= { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAB00 "Apple boot"
828
829// turbo - or an EFI System Partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B
830EFI_GUID const GPT_EFISYS_GUID= { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } }; // 0xEF00 "EFI System"
831
832// zef - Basic Data Partition - EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support
833EFI_GUID const GPT_BASICDATA_GUID= { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } }; // 0x0100 "Microsoft basic data"
834
835// Microsoft Reserved Partition - E3C9E316-0B5C-4DB8-817DF92DF00215AE
836EFI_GUID const GPT_BASICDATA2_GUID= { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } }; // 0x0C01 "Microsoft reserved"
837
838// Apple OSX
839//EFI_GUID const GPT_UFS_GUID= { 0x55465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xA800 "Apple UFS"
840//EFI_GUID const GPT_RAID_GUID= { 0x52414944, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF01 "Apple RAID"
841//EFI_GUID const GPT_RAID_OFFLINE_GUID= { 0x52414944, 0x5f4f, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF02 "Apple RAID offline"
842//EFI_GUID const GPT_LABEL_GUID= { 0x4C616265, 0x6C00, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF03 "Apple label"
843//EFI_GUID const GPT_APPLETV_GUID= { 0x5265636F, 0x7665, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF04 "Apple TV recovery"
844//EFI_GUID const GPT_CORESTORAGE_GUID= { 0x53746F72, 0x6167, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; // 0xAF05 "Apple Core storage"
845// same as Apple ZFS
846//EFI_GUID const GPT_ZFS_GUID= { 0x6A898CC3, 0x1DD2, 0x11B2, { 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }; // 0xBF01 "Solaris /usr & Apple ZFS
847
848static BVRef newGPTBVRef( int biosdev,
849 int partno,
850 unsigned int blkoff,
851 const gpt_ent *part,
852 FSInit initFunc,
853 FSLoadFile loadFunc,
854 FSReadFile readFunc,
855 FSGetDirEntry getdirFunc,
856 FSGetFileBlock getBlockFunc,
857 FSGetUUID getUUIDFunc,
858 BVGetDescription getDescriptionFunc,
859 BVFree bvFreeFunc,
860 int probe,
861 int type,
862 unsigned int bvrFlags )
863{
864BVRef bvr = (BVRef)malloc(sizeof(*bvr));
865if ( bvr )
866{
867bzero(bvr, sizeof(*bvr));
868
869bvr->biosdev = biosdev;
870bvr->part_no = partno;
871bvr->part_boff = blkoff;
872bvr->fs_loadfile = loadFunc;
873bvr->fs_readfile = readFunc;
874bvr->fs_getdirentry = getdirFunc;
875bvr->fs_getfileblock = getBlockFunc;
876bvr->fs_getuuid = getUUIDFunc;
877bvr->description = getDescriptionFunc;
878bvr->type = type;
879bvr->bv_free = bvFreeFunc;
880// FIXME: UCS-2 -> UTF-8 the name
881strlcpy(bvr->name, "----", DPISTRLEN);
882if ( (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) )
883{
884strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);
885}
886else
887{
888strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);
889}
890
891/*
892if ( part->bootid & FDISK_ACTIVE )
893{
894bvr->flags |= kBVFlagPrimary;
895}
896*/
897
898// Probe the filesystem.
899
900if ( initFunc )
901{
902bvr->flags |= kBVFlagNativeBoot;
903
904if ( probe && initFunc( bvr ) != 0 )
905{
906// filesystem probe failed.
907
908DEBUG_DISK(("%s: failed probe on dev %x part %d\n", __FUNCTION__, biosdev, partno));
909
910(*bvr->bv_free)(bvr);
911bvr = NULL;
912}
913else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
914{
915bvr->flags |= kBVFlagBootable;
916}
917}
918else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
919{
920bvr->flags |= kBVFlagForeignBoot;
921}
922else
923{
924(*bvr->bv_free)(bvr);
925bvr = NULL;
926}
927}
928
929if ( bvr )
930{
931bvr->flags |= bvrFlags;
932}
933
934return bvr;
935}
936
937//==============================================================================
938
939/* A note on partition numbers:
940 * IOKit makes the primary partitions numbers 1-4, and then
941 * extended partitions are numbered consecutively 5 and up.
942 * So, for example, if you have two primary partitions and
943 * one extended partition they will be numbered 1, 2, 5.
944 */
945
946static BVRef diskScanFDiskBootVolumes( int biosdev, int *countPtr )
947{
948 const struct fdisk_part*part;
949 struct DiskBVMap*map;
950 intpartno = -1;
951 BVRefbvr;
952#if UFS_SUPPORT
953 BVRefbooterUFS = NULL;
954#endif
955 intspc;
956 struct driveInfodi;
957 boot_drive_info_t*dp;
958
959/* Initialize disk info */
960
961if (getDriveInfo(biosdev, &di) != 0)
962{
963return NULL;
964}
965
966dp = &di.di;
967spc = (dp->params.phys_spt * dp->params.phys_heads);
968
969if (spc == 0)
970{
971/* This is probably a CD-ROM; punt on the geometry. */
972spc = 1;
973}
974
975do
976{
977// Create a new mapping.
978
979map = (struct DiskBVMap *) malloc(sizeof(*map));
980
981if ( !map )
982{
983return NULL;
984}
985
986if ( map )
987 {
988map->biosdev = biosdev;
989map->bvr = NULL;
990map->bvrcnt = 0;
991map->next = gDiskBVMap;
992gDiskBVMap = map;
993
994// Create a record for each partition found on the disk.
995
996while ( getNextFDiskPartition( biosdev, &partno, &part ) )
997{
998DEBUG_DISK(("%s: part %d [%X]\n", __FUNCTION__, partno, part->systid));
999bvr = 0;
1000
1001switch ( part->systid )
1002{
1003#if UFS_SUPPORT
1004case FDISK_UFS:
1005bvr = newFDiskBVRef(
1006biosdev, partno,
1007part->relsect + UFS_FRONT_PORCH/BPS,
1008part,
1009UFSInitPartition,
1010UFSLoadFile,
1011UFSReadFile,
1012UFSGetDirEntry,
1013UFSGetFileBlock,
1014UFSGetUUID,
1015UFSGetDescription,
1016UFSFree,
10170,
1018kBIOSDevTypeHardDrive, 0);
1019break;
1020#endif
1021
1022case FDISK_HFS:
1023bvr = newFDiskBVRef(
1024biosdev, partno,
1025part->relsect,
1026part,
1027HFSInitPartition,
1028HFSLoadFile,
1029HFSReadFile,
1030HFSGetDirEntry,
1031HFSGetFileBlock,
1032HFSGetUUID,
1033HFSGetDescription,
1034HFSFree,
10350,
1036kBIOSDevTypeHardDrive, 0);
1037break;
1038
1039// turbo - we want the booter type scanned also
1040case FDISK_BOOTER:
1041if (part->bootid & FDISK_ACTIVE)
1042{
1043gBIOSBootVolume = newFDiskBVRef(
1044biosdev, partno,
1045part->relsect,
1046part,
1047HFSInitPartition,
1048HFSLoadFile,
1049HFSReadFile,
1050HFSGetDirEntry,
1051HFSGetFileBlock,
1052HFSGetUUID,
1053HFSGetDescription,
1054HFSFree,
10550,
1056kBIOSDevTypeHardDrive, 0);
1057}
1058break;
1059
1060#if UFS_SUPPORT
1061case FDISK_BOOTER:
1062booterUFS = newFDiskBVRef(
1063biosdev, partno,
1064((part->relsect + spc - 1) / spc) * spc,
1065part,
1066UFSInitPartition,
1067UFSLoadFile,
1068UFSReadFile,
1069UFSGetDirEntry,
1070UFSGetFileBlock,
1071UFSGetUUID,
1072UFSGetDescription,
1073UFSFree,
10740,
1075kBIOSDevTypeHardDrive, 0);
1076break;
1077#endif
1078
1079case FDISK_FAT32:
1080case FDISK_DOS12:
1081case FDISK_DOS16S:
1082case FDISK_DOS16B:
1083case FDISK_SMALLFAT32:
1084case FDISK_DOS16SLBA:
1085bvr = newFDiskBVRef(
1086biosdev, partno,
1087part->relsect,
1088part,
1089MSDOSInitPartition,
1090MSDOSLoadFile,
1091MSDOSReadFile,
1092MSDOSGetDirEntry,
1093MSDOSGetFileBlock,
1094MSDOSGetUUID,
1095MSDOSGetDescription,
1096MSDOSFree,
10970,
1098kBIOSDevTypeHardDrive, 0);
1099break;
1100
1101case FDISK_NTFS:
1102bvr = newFDiskBVRef(
1103biosdev, partno,
1104part->relsect,
1105part,
11060, 0, 0, 0, 0,
1107NTFSGetUUID,
1108NTFSGetDescription,
1109(BVFree)free,
11100,
1111kBIOSDevTypeHardDrive, 0);
1112break;
1113
1114case FDISK_LINUX:
1115bvr = newFDiskBVRef(
1116biosdev, partno,
1117part->relsect,
1118part,
11190, 0, 0, 0, 0,
1120EX2GetUUID,
1121EX2GetDescription,
1122(BVFree)free,
11230,
1124kBIOSDevTypeHardDrive, 0);
1125break;
1126
1127case FDISK_BEFS:
1128bvr = newFDiskBVRef(
1129biosdev, partno,
1130part->relsect,
1131part,
11320, 0, 0, 0, 0, 0,
1133BeFSGetDescription,
1134(BVFree)free,
11350,
1136kBIOSDevTypeHardDrive, 0);
1137break;
1138
1139case FDISK_FREEBSD:
1140bvr = newFDiskBVRef(
1141biosdev, partno,
1142part->relsect,
1143part,
11440, 0, 0, 0, 0, 0,
1145FreeBSDGetDescription,
1146(BVFree)free,
11470,
1148kBIOSDevTypeHardDrive, 0);
1149break;
1150
1151case FDISK_OPENBSD:
1152bvr = newFDiskBVRef(
1153biosdev, partno,
1154part->relsect,
1155part,
11560, 0, 0, 0, 0, 0,
1157OpenBSDGetDescription,
1158(BVFree)free,
11590,
1160kBIOSDevTypeHardDrive, 0);
1161break;
1162
1163default:
1164bvr = newFDiskBVRef(
1165biosdev, partno,
1166part->relsect,
1167part,
11680, 0, 0, 0, 0, 0, 0,
1169(BVFree)free,
11700,
1171kBIOSDevTypeHardDrive, 0);
1172break;
1173}
1174
1175if ( bvr )
1176{
1177bvr->next = map->bvr;
1178map->bvr = bvr;
1179map->bvrcnt++;
1180}
1181}
1182
1183#if UFS_SUPPORT
1184// Booting from a CD with an UFS filesystem embedded
1185// in a booter partition.
1186
1187if ( booterUFS )
1188{
1189if ( map->bvrcnt == 0 )
1190{
1191map->bvr = booterUFS;
1192map->bvrcnt++;
1193}
1194else
1195{
1196free( booterUFS );
1197}
1198}
1199#endif
1200}
1201} while (0);
1202
1203#if UNUSED
1204/*
1205 * If no FDisk partition, then we will check for
1206 * an Apple partition map elsewhere.
1207 */
1208if (map && map->bvrcnt == 0)
1209{
1210static struct fdisk_part cdpart;
1211cdpart.systid = 0xCD;
1212
1213/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
1214bvr = newFDiskBVRef(
1215biosdev, 0,
12160,
1217&cdpart,
1218HFSInitPartition,
1219HFSLoadFile,
1220HFSReadFile,
1221HFSGetDirEntry,
1222HFSGetFileBlock,
1223HFSGetUUID,
1224HFSGetDescription,
1225HFSFree,
12260,
1227kBIOSDevTypeHardDrive, 0);
1228bvr->next = map->bvr;
1229map->bvr = bvr;
1230map->bvrcnt++;
1231}
1232#endif
1233// Actually this should always be true given the above code
1234// (unless malloc failed above)
1235if(map && (map == gDiskBVMap))
1236{
1237// Don't leave a null map in the chain
1238if((map->bvrcnt == 0) && (map->bvr == NULL))
1239{
1240gDiskBVMap = map->next;
1241free(map);
1242map = NULL;
1243}
1244}
1245
1246if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1247
1248return map ? map->bvr : NULL;
1249}
1250
1251//==============================================================================
1252
1253static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
1254{
1255struct DiskBVMap*map;
1256struct Block0*block0_p;
1257unsigned intblksize;
1258unsigned intfactor;
1259void*buffer = malloc(BPS);
1260
1261if (!buffer)
1262{
1263return NULL;
1264}
1265
1266bzero(buffer,BPS);
1267
1268/* Check for alternate block size */
1269if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0)
1270{
1271return NULL;
1272}
1273
1274block0_p = buffer;
1275if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE)
1276{
1277blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1278if (blksize != BPS)
1279{
1280free(buffer);
1281buffer = malloc(blksize);
1282if (!buffer)
1283{
1284return NULL;
1285}
1286bzero(buffer,BPS);
1287}
1288factor = blksize / BPS;
1289}
1290else
1291{
1292blksize = BPS;
1293factor = 1;
1294}
1295
1296do
1297{
1298// Create a new mapping.
1299
1300map = (struct DiskBVMap *) malloc( sizeof(*map) );
1301if ( map )
1302{
1303int error;
1304DPME *dpme_p = (DPME *)buffer;
1305UInt32 i, npart = UINT_MAX;
1306BVRef bvr;
1307
1308map->biosdev = biosdev;
1309map->bvr = NULL;
1310map->bvrcnt = 0;
1311map->next = gDiskBVMap;
1312gDiskBVMap = map;
1313
1314for (i = 0; i < npart; i++)
1315{
1316error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1317
1318if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE)
1319{
1320break;
1321}
1322
1323if (i == 0)
1324{
1325npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1326}
1327/*
1328printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1329dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1330dpme.dpme_pblock_start, dpme.dpme_pblocks,
1331dpme.dpme_lblock_start, dpme.dpme_lblocks,
1332dpme.dpme_boot_block);
1333*/
1334
1335if (strncmp(dpme_p->dpme_type, "Apple_HFS", sizeof("Apple_HFS")) == 0)
1336{
1337bvr = newAPMBVRef(biosdev,
1338i,
1339OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1340dpme_p,
1341HFSInitPartition,
1342HFSLoadFile,
1343HFSReadFile,
1344HFSGetDirEntry,
1345HFSGetFileBlock,
1346HFSGetUUID,
1347HFSGetDescription,
1348HFSFree,
13490,
1350kBIOSDevTypeHardDrive, 0);
1351bvr->next = map->bvr;
1352map->bvr = bvr;
1353map->bvrcnt++;
1354}
1355}
1356}
1357} while (0);
1358
1359if (buffer)
1360{
1361free(buffer);
1362}
1363
1364if (countPtr)
1365{
1366*countPtr = map ? map->bvrcnt : 0;
1367}
1368
1369return map ? map->bvr : NULL;
1370}
1371
1372//==============================================================================
1373
1374static bool isPartitionUsed(gpt_ent * partition)
1375{
1376
1377// Ask whether the given partition is used.
1378
1379return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1380}
1381
1382//==============================================================================
1383
1384static BVRef diskScanGPTBootVolumes(int biosdev, int * countPtr)
1385{
1386struct DiskBVMap *map = NULL;
1387
1388void *buffer = malloc(BPS);
1389
1390int error;
1391
1392if ((error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer )) != 0)
1393{
1394verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1395goto scanErr;
1396}
1397struct REAL_disk_blk0 *fdiskMap = buffer;
1398if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1399{
1400verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1401goto scanErr;
1402}
1403
1404int fdiskID = 0;
1405unsigned index;
1406for ( index = 0; index < FDISK_NPART; index++ )
1407{
1408if ( fdiskMap->parts[index].systid )
1409{
1410if ( fdiskMap->parts[index].systid == 0xEE )
1411{
1412// Fail if two 0xEE partitions are present which
1413// means the FDISK code will wind up parsing it.
1414if ( fdiskID )
1415{
1416goto scanErr;
1417}
1418
1419fdiskID = index + 1;
1420}
1421}
1422}
1423
1424if ( fdiskID == 0 )
1425{
1426goto scanErr;
1427}
1428
1429verbose("Attempting to read GPT\n");
1430
1431if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1432{
1433goto scanErr;
1434}
1435
1436gpt_hdr *headerMap = buffer;
1437
1438// Determine whether the partition header signature is present.
1439
1440if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1441{
1442goto scanErr;
1443}
1444
1445// Determine whether the partition header size is valid.
1446
1447UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1448UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1449
1450if (headerSize < offsetof(gpt_hdr, padding))
1451{
1452goto scanErr;
1453}
1454
1455if ( headerSize > BPS )
1456{
1457goto scanErr;
1458}
1459
1460// Determine whether the partition header checksum is valid.
1461
1462headerMap->hdr_crc_self = 0;
1463
1464if ( crc32(0, headerMap, headerSize) != headerCheck )
1465{
1466goto scanErr;
1467}
1468
1469// Determine whether the partition entry size is valid.
1470
1471UInt64gptBlock= 0;
1472UInt32gptCheck= 0;
1473UInt32gptCount= 0;
1474UInt32gptID= 0;
1475gpt_ent*gptMap= 0;
1476UInt32gptSize= 0;
1477
1478gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1479gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1480gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1481gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1482
1483if ( gptSize < sizeof(gpt_ent) )
1484{
1485goto scanErr;
1486}
1487
1488// Allocate a buffer large enough to hold one map, rounded to a media block.
1489free(buffer);
1490buffer = NULL;
1491
1492UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1493if (bufferSize == 0)
1494{
1495goto scanErr;
1496}
1497buffer = malloc(bufferSize);
1498if (!buffer)
1499{
1500 goto scanErr;
1501}
1502
1503bzero(buffer,bufferSize);
1504
1505if (readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1506{
1507goto scanErr;
1508}
1509verbose("Read GPT\n");
1510
1511// Allocate a new map for this BIOS device and insert it into the chain
1512map = malloc(sizeof(*map));
1513if (!map)
1514{
1515goto scanErr;
1516}
1517map->biosdev = biosdev;
1518map->bvr = NULL;
1519map->bvrcnt = 0;
1520map->next = gDiskBVMap;
1521gDiskBVMap = map;
1522
1523// fdisk like partition type id.
1524int fsType = 0;
1525
1526for(gptID = 1; gptID <= gptCount; ++gptID)
1527{
1528BVRef bvr = NULL;
1529unsigned int bvrFlags = 0;
1530
1531// size on disk can be larger than sizeof(gpt_ent)
1532gptMap = (gpt_ent *)(buffer + ((gptID - 1) * gptSize));
1533
1534// NOTE: EFI_GUID's are in LE and we know we're on an x86.
1535// The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1536
1537if (isPartitionUsed(gptMap))
1538{
1539char stringuuid[100];
1540efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1541verbose("Reading GPT partition %d, type %s\n", (unsigned) gptID, stringuuid);
1542
1543// Getting fdisk like partition type.
1544fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1545
1546if ( (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) )
1547{
1548bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1549bvr = newGPTBVRef(biosdev,
1550gptID,
1551gptMap->ent_lba_start,
1552gptMap,
1553HFSInitPartition,
1554HFSLoadFile,
1555HFSReadFile,
1556HFSGetDirEntry,
1557HFSGetFileBlock,
1558HFSGetUUID,
1559HFSGetDescription,
1560HFSFree,
15610,
1562kBIOSDevTypeHardDrive, bvrFlags);
1563}
1564
1565// zef - foreign OS support
1566if ((efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1567(efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1568{
1569switch (fsType)
1570{
1571case FDISK_NTFS:
1572bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
15730, 0, 0, 0, 0, NTFSGetUUID, NTFSGetDescription,
1574(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1575break;
1576
1577case FDISK_LINUX:
1578bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
15790, 0, 0, 0, 0, EX2GetUUID, EX2GetDescription,
1580(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1581break;
1582
1583case FDISK_FAT32:
1584case FDISK_DOS12:
1585case FDISK_DOS16B:
1586bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1587MSDOSInitPartition,
1588MSDOSLoadFile,
1589MSDOSReadFile,
1590MSDOSGetDirEntry,
1591MSDOSGetFileBlock,
1592MSDOSGetUUID,
1593MSDOSGetDescription,
1594MSDOSFree,
15950, kBIOSDevTypeHardDrive, 0);
1596break;
1597
1598case FDISK_PSEUDO_EXFAT:
1599bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1600 EXFATInitPartition,
1601 EXFATLoadFile,
1602 EXFATReadFile,
1603 EXFATGetDirEntry,
1604 EXFATGetFileBlock,
1605 EXFATGetUUID,
1606 EXFATGetDescription,
1607 EXFATFree,
1608 0, kBIOSDevTypeHardDrive, 0);
1609break;
1610
1611default:
1612bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
16130, 0, 0, 0, 0, 0, 0,
1614(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1615break;
1616}
1617
1618}
1619
1620// turbo - save our booter partition
1621// zef - only on original boot device
1622if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ) {
1623switch (fsType) {
1624case FDISK_HFS:
1625if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1626bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1627HFSInitPartition,
1628HFSLoadFile,
1629HFSReadFile,
1630HFSGetDirEntry,
1631HFSGetFileBlock,
1632HFSGetUUID,
1633HFSGetDescription,
1634HFSFree,
16350, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1636}
1637break;
1638
1639case FDISK_FAT32:
1640if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1641bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1642MSDOSInitPartition,
1643MSDOSLoadFile,
1644MSDOSReadFile,
1645MSDOSGetDirEntry,
1646MSDOSGetFileBlock,
1647MSDOSGetUUID,
1648MSDOSGetDescription,
1649MSDOSFree,
16500, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1651}
1652break;
1653
1654default:
1655if (biosdev == gBIOSDev)
1656{
1657gBIOSBootVolume = bvr;
1658}
1659break;
1660}
1661}
1662
1663if (bvr)
1664{
1665// Fixup bvr with the fake fdisk partition type.
1666if (fsType > 0) {
1667bvr->part_type = fsType;
1668}
1669
1670bvr->next = map->bvr;
1671map->bvr = bvr;
1672++map->bvrcnt;
1673}
1674
1675}
1676}
1677
1678scanErr:
1679if (buffer)
1680{
1681free(buffer);
1682}
1683
1684if(map)
1685{
1686if(countPtr) *countPtr = map->bvrcnt;
1687{
1688return map->bvr;
1689}
1690
1691}
1692else
1693{
1694if(countPtr) *countPtr = 0;
1695{
1696return NULL;
1697}
1698}
1699}
1700
1701//==============================================================================
1702
1703static bool getOSVersion(BVRef bvr, char *str)
1704{
1705bool valid = false;
1706config_file_t systemVersion;
1707char dirSpec[512];
1708
1709/*
1710 * Only look for OS Version on HFS+
1711 */
1712if (bvr->fs_readfile != HFSReadFile)
1713{
1714return valid;
1715}
1716
1717// OS X Recovery
1718sprintf(dirSpec, "hd(%d,%d)/com.apple.recovery.boot/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1719
1720if (!loadConfigFile(dirSpec, &systemVersion))
1721{
1722bvr->OSisInstaller = true;
1723valid = true;
1724}
1725
1726if (!valid)
1727{
1728// OS X Standard
1729snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1730
1731if (!loadConfigFile(dirSpec, &systemVersion))
1732{
1733bvr->OSisInstaller = false;
1734valid = true;
1735}
1736else
1737{
1738// OS X Server
1739snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1740
1741if (!loadConfigFile(dirSpec, &systemVersion))
1742{
1743bvr->OSisServer = false;
1744valid = true;
1745}
1746/*else
1747{
1748snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/.IAProductInfo", BIOS_DEV_UNIT(bvr), bvr->part_no);
1749
1750if (!loadConfigFile(dirSpec, &systemVersion))
1751{
1752
1753}
1754}
1755*/
1756}
1757
1758if ( LION )
1759{
1760int fh = -1;
1761snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/.PhysicalMediaInstall", BIOS_DEV_UNIT(bvr), bvr->part_no);
1762fh = open(dirSpec, 0);
1763
1764if (fh >= 0)
1765{
1766valid = true;
1767bvr->OSisInstaller = true;
1768strcpy(bvr->OSVersion, "10.7"); // 10.7 +
1769close(fh);
1770}
1771else
1772{
1773close(fh);
1774}
1775}
1776
1777// Mountain Lion ?
1778
1779if ( MAVERICKS )
1780{
1781int fh = -1;
1782snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/.IAPhysicalMedia", BIOS_DEV_UNIT(bvr), bvr->part_no);
1783fh = open(dirSpec, 0);
1784
1785if (fh >= 0)
1786{
1787valid = true;
1788bvr->OSisInstaller = true;
1789strcpy(bvr->OSVersion, "10.9"); // 10.9 +
1790}
1791else
1792{
1793close(fh);
1794}
1795}
1796
1797// Yosemite ?
1798
1799}
1800
1801if (valid)
1802{
1803const char *val;
1804int len;
1805
1806if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1807{
1808// getValueForKey uses const char for val
1809// so copy it and trim
1810*str = '\0';
1811strncat(str, val, MIN(len, 5));
1812if(str[4] == '.')
1813{
1814str[4] = '\0';
1815}
1816}
1817else
1818{
1819valid = false;
1820}
1821}
1822
1823return valid;
1824}
1825
1826//==============================================================================
1827
1828static void scanFSLevelBVRSettings(BVRef chain)
1829{
1830BVRef bvr;
1831char dirSpec[512], fileSpec[512];
1832char label[BVSTRLEN];
1833int ret;
1834long flags;
1835u_int32_t time;
1836int fh, fileSize, error;
1837
1838for (bvr = chain; bvr; bvr = bvr->next)
1839{
1840ret = -1;
1841error = 0;
1842
1843//
1844// Check for alternate volume label on boot helper partitions.
1845//
1846if (bvr->flags & kBVFlagBooter)
1847{
1848snprintf(dirSpec, sizeof(dirSpec), "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1849strlcpy(fileSpec, ".disk_label.contentDetails", sizeof(fileSpec));
1850ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1851if (!ret)
1852{
1853strlcat(dirSpec, fileSpec, sizeof(dirSpec));
1854fh = open(dirSpec,0);
1855
1856fileSize = file_size(fh);
1857if (fileSize > 0 && fileSize < BVSTRLEN)
1858{
1859if (read(fh, label, fileSize) != fileSize)
1860{
1861error = -1;
1862}
1863}
1864else
1865{
1866error = -1;
1867}
1868
1869close(fh);
1870
1871if (!error)
1872{
1873label[fileSize] = '\0';
1874strlcpy(bvr->altlabel, label, sizeof(bvr->altlabel));
1875}
1876}
1877}
1878
1879// Check for SystemVersion.plist or ServerVersion.plist to determine if a volume hosts an installed system.
1880
1881if (bvr->flags & kBVFlagNativeBoot)
1882{
1883if (getOSVersion(bvr, bvr->OSVersion) == true)
1884{
1885bvr->flags |= kBVFlagSystemVolume;
1886}
1887}
1888
1889}
1890}
1891
1892//==============================================================================
1893
1894void rescanBIOSDevice(int biosdev)
1895{
1896struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1897if (oldMap == NULL)
1898{
1899return;
1900}
1901
1902CacheReset();
1903diskFreeMap(oldMap);
1904oldMap = NULL;
1905scanBootVolumes(biosdev, 0);
1906}
1907
1908//==============================================================================
1909
1910struct DiskBVMap* diskResetBootVolumes(int biosdev)
1911{
1912struct DiskBVMap * map;
1913struct DiskBVMap *prevMap = NULL;
1914for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1915if ( biosdev == map->biosdev ) {
1916break;
1917}
1918}
1919
1920if(map != NULL) {
1921verbose("Resetting BIOS device %xh\n", biosdev);
1922// Reset the biosbuf cache
1923cache_valid = false;
1924if(map == gDiskBVMap)
1925{
1926gDiskBVMap = map->next;
1927}
1928else if(prevMap != NULL)
1929{
1930prevMap->next = map->next;
1931}
1932else
1933{
1934stop("diskResetBootVolumes error\n");
1935return NULL;
1936}
1937}
1938// Return the old map, either to be freed, or reinserted later
1939return map;
1940}
1941
1942//==============================================================================
1943
1944// Frees a DiskBVMap and all of its BootVolume's
1945void diskFreeMap(struct DiskBVMap *map)
1946{
1947if(map != NULL)
1948{
1949while(map->bvr != NULL)
1950{
1951BVRef bvr = map->bvr;
1952map->bvr = bvr->next;
1953(*bvr->bv_free)(bvr);
1954}
1955
1956free(map);
1957}
1958}
1959
1960//==============================================================================
1961
1962BVRef diskScanBootVolumes(int biosdev, int * countPtr)
1963{
1964struct DiskBVMap *map;
1965BVRef bvr;
1966int count = 0;
1967
1968// Find an existing mapping for this device.
1969
1970for (map = gDiskBVMap; map; map = map->next)
1971{
1972if (biosdev == map->biosdev)
1973{
1974count = map->bvrcnt;
1975break;
1976}
1977}
1978
1979if (map == NULL)
1980{
1981bvr = diskScanGPTBootVolumes(biosdev, &count);
1982if (bvr == NULL)
1983{
1984bvr = diskScanFDiskBootVolumes(biosdev, &count);
1985}
1986
1987if (bvr == NULL)
1988{
1989bvr = diskScanAPMBootVolumes(biosdev, &count);
1990}
1991
1992if (bvr)
1993{
1994scanFSLevelBVRSettings(bvr);
1995}
1996}
1997else
1998{
1999bvr = map->bvr;
2000}
2001
2002if (countPtr)
2003{
2004*countPtr += count;
2005}
2006
2007return bvr;
2008}
2009
2010//==============================================================================
2011
2012BVRef getBVChainForBIOSDev(int biosdev)
2013{
2014BVRef chain = NULL;
2015struct DiskBVMap * map = NULL;
2016
2017for (map = gDiskBVMap; map; map = map->next)
2018{
2019if (map->biosdev == biosdev)
2020{
2021chain = map->bvr;
2022break;
2023}
2024}
2025
2026return chain;
2027}
2028
2029//==============================================================================
2030
2031BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
2032{
2033BVRef chain = NULL;
2034BVRef bvr = NULL;
2035BVRef newBVR = NULL;
2036BVRef prevBVR = NULL;
2037
2038struct DiskBVMap * map = NULL;
2039int bvCount = 0;
2040
2041const char *raw = 0;
2042char* val = 0;
2043int len;
2044
2045getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
2046if(raw)
2047{
2048val = XMLDecode(raw);
2049}
2050
2051/*
2052 * Traverse gDISKBVmap to get references for
2053 * individual bvr chains of each drive.
2054 */
2055for (map = gDiskBVMap; map; map = map->next)
2056{
2057for (bvr = map->bvr; bvr; bvr = bvr->next)
2058{
2059/*
2060 * Save the last bvr.
2061 */
2062if (newBVR)
2063{
2064prevBVR = newBVR;
2065}
2066
2067/*
2068 * Allocate and copy the matched bvr entry into a new one.
2069 */
2070newBVR = (BVRef) malloc(sizeof(*newBVR));
2071if (!newBVR)
2072{
2073continue;
2074}
2075bzero(newBVR,sizeof(*newBVR));
2076
2077bcopy(bvr, newBVR, sizeof(*newBVR));
2078
2079/*
2080 * Adjust the new bvr's fields.
2081 */
2082newBVR->next = NULL;
2083newBVR->filtered = true;
2084
2085if ( (!allowFlags || newBVR->flags & allowFlags)
2086&& (!denyFlags || !(newBVR->flags & denyFlags) )
2087&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
2088)
2089{
2090newBVR->visible = true;
2091}
2092
2093/*
2094 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
2095 * to be able to hide foreign partitions from the boot menu.
2096 *
2097 */
2098if ( (newBVR->flags & kBVFlagForeignBoot) )
2099{
2100char *start, *next = val;
2101long len = 0;
2102do
2103{
2104start = strbreak(next, &next, &len);
2105if(len && matchVolumeToString(newBVR, start, len) )
2106{
2107newBVR->visible = false;
2108}
2109}
2110while ( next && *next );
2111}
2112
2113/*
2114 * Use the first bvr entry as the starting chain pointer.
2115 */
2116if (!chain)
2117{
2118chain = newBVR;
2119}
2120
2121/*
2122 * Update the previous bvr's link pointer to use the new memory area.
2123 */
2124if (prevBVR)
2125{
2126prevBVR->next = newBVR;
2127}
2128
2129if (newBVR->visible)
2130{
2131bvCount++;
2132}
2133}
2134}
2135
2136#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
2137for (bvr = chain; bvr; bvr = bvr->next)
2138{
2139if (!bvr)
2140{
2141break;
2142}
2143printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
2144}
2145printf("count: %d\n", bvCount);
2146getchar();
2147#endif
2148
2149*count = bvCount;
2150
2151free(val);
2152return chain;
2153}
2154
2155//==============================================================================
2156
2157int freeFilteredBVChain(const BVRef chain)
2158{
2159int ret = 1;
2160BVRef bvr = chain;
2161BVRef nextBVR = NULL;
2162
2163while (bvr)
2164{
2165if (!bvr)
2166{
2167break;
2168}
2169
2170nextBVR = bvr->next;
2171
2172if (bvr->filtered)
2173{
2174free(bvr);
2175}
2176else
2177{
2178ret = 0;
2179break;
2180}
2181
2182bvr = nextBVR;
2183}
2184
2185return ret;
2186}
2187
2188//==============================================================================
2189
2190bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
2191{
2192char testStr[128];
2193
2194if ( !bvr || !match || !*match)
2195{
2196return 0;
2197}
2198
2199if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
2200{
2201 return 0;
2202}
2203
2204// Try to match hd(x,y) first.
2205snprintf(testStr, sizeof(testStr), "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
2206if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2207{
2208return true;
2209}
2210
2211// Try to match volume UUID.
2212if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
2213{
2214if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2215{
2216return true;
2217}
2218}
2219
2220// Try to match volume label (always quoted).
2221if ( bvr->description )
2222{
2223bvr->description(bvr, testStr, sizeof(testStr)-1);
2224if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2225{
2226return true;
2227}
2228}
2229
2230return false;
2231}
2232
2233//==============================================================================
2234
2235/* If Rename Partition has defined an alias, then extract it for description purpose.
2236 * The format for the rename string is the following:
2237 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
2238 */
2239
2240static bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
2241{
2242char *aliasList, *entryStart, *entryNext;
2243
2244if ( !str || strMaxLen <= 0)
2245{
2246return false;
2247}
2248
2249aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
2250if ( !aliasList )
2251{
2252return false;
2253}
2254
2255for ( entryStart = entryNext = aliasList; entryNext && *entryNext; entryStart = entryNext )
2256{
2257char *volStart, *volEnd, *aliasStart;
2258long volLen, aliasLen;
2259
2260// Delimit current entry
2261entryNext = strchr(entryStart, ';');
2262if ( entryNext )
2263{
2264*entryNext = '\0';
2265entryNext++;
2266}
2267
2268volStart = strbreak(entryStart, &volEnd, &volLen);
2269if(!volLen)
2270{
2271continue;
2272}
2273
2274aliasStart = strbreak(volEnd, 0, &aliasLen);
2275if(!aliasLen)
2276{
2277continue;
2278}
2279
2280if ( matchVolumeToString(bvr, volStart, volLen) )
2281{
2282strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
2283free(aliasList);
2284
2285return true;
2286}
2287}
2288
2289free(aliasList);
2290return false;
2291}
2292
2293//==============================================================================
2294
2295void getBootVolumeDescription( BVRef bvr, char *str, long strMaxLen, bool useDeviceDescription )
2296{
2297unsigned char type;
2298char *p = str;
2299
2300if(!bvr || !p || strMaxLen <= 0)
2301{
2302return;
2303}
2304
2305type = (unsigned char) bvr->part_type;
2306
2307if (useDeviceDescription)
2308{
2309int len = getDeviceDescription(bvr, str);
2310if(len >= strMaxLen)
2311{
2312return;
2313}
2314
2315strcpy(str + len, bvr->OSisInstaller ? " (Installer " : " (");
2316len += bvr->OSisInstaller ? 12 : 2;
2317strcpy(str + len, bvr->OSVersion);
2318len += strlen(bvr->OSVersion);
2319strcpy(str + len, ") ");
2320len += 2;
2321
2322strMaxLen -= len;
2323p += len;
2324}
2325
2326/* See if a partition rename is preferred */
2327if (getVolumeLabelAlias(bvr, p, strMaxLen))
2328{
2329strncpy(bvr->label, p, strMaxLen);
2330return; // we're done here no need to seek for real name
2331}
2332
2333// Get the volume label using filesystem specific functions or use the alternate volume label if available.
2334
2335if (*bvr->altlabel != '\0')
2336{
2337strncpy(p, bvr->altlabel, strMaxLen);
2338}
2339else if (bvr->description)
2340{
2341bvr->description(bvr, p, strMaxLen);
2342}
2343
2344if (*p == '\0')
2345{
2346const char * name = getNameForValue( fdiskTypes, type );
2347
2348if (name == NULL)
2349{
2350name = bvr->type_name;
2351}
2352
2353if (name == NULL)
2354{
2355snprintf(p, strMaxLen, "TYPE %02X", type);
2356}
2357else
2358{
2359strncpy(p, name, strMaxLen);
2360}
2361}
2362
2363// Set the devices label
2364strncpy(bvr->label, p, sizeof bvr->label);
2365}
2366
2367
2368//==============================================================================
2369
2370int readBootSector(int biosdev, unsigned int secno, void *buffer)
2371{
2372int error;
2373struct disk_blk0 * bootSector = (struct disk_blk0 *)buffer;
2374
2375if (bootSector == NULL)
2376{
2377if (gBootSector == NULL)
2378{
2379gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2380
2381if (gBootSector == NULL)
2382{
2383return -1;
2384}
2385}
2386
2387bootSector = gBootSector;
2388}
2389
2390error = readBytes(biosdev, secno, 0, BPS, bootSector);
2391
2392if (error || bootSector->signature != DISK_SIGNATURE)
2393{
2394return -1;
2395}
2396return 0;
2397}
2398
2399//==============================================================================
2400
2401/*
2402 * Format of boot1f32 block.
2403 */
2404
2405#define BOOT1F32_MAGIC "BOOT "
2406#define BOOT1F32_MAGICLEN 11
2407
2408struct disk_boot1f32_blk
2409{
2410unsigned char init[3];
2411unsigned char fsheader[87];
2412unsigned char magic[BOOT1F32_MAGICLEN];
2413unsigned char bootcode[409];
2414unsigned short signature;
2415};
2416
2417//==============================================================================
2418
2419int testFAT32EFIBootSector(int biosdev, unsigned int secno, void *buffer)
2420{
2421struct disk_boot1f32_blk *bootSector = (struct disk_boot1f32_blk *)buffer;
2422int error;
2423
2424if (bootSector == NULL)
2425{
2426if (gBootSector == NULL)
2427{
2428gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2429if ( gBootSector == NULL )
2430{
2431return -1;
2432}
2433}
2434bootSector = (struct disk_boot1f32_blk *)gBootSector;
2435}
2436
2437error = readBytes(biosdev, secno, 0, BPS, bootSector);
2438if (error || bootSector->signature != DISK_SIGNATURE || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2439{
2440return -1;
2441}
2442return 0;
2443}
2444
2445
2446//==============================================================================
2447// Handle seek request from filesystem modules.
2448
2449void diskSeek(BVRef bvr, long long position)
2450{
2451bvr->fs_boff = position / BPS;
2452bvr->fs_byteoff = position % BPS;
2453}
2454
2455
2456//==============================================================================
2457// Handle read request from filesystem modules.
2458
2459int diskRead(BVRef bvr, long addr, long length)
2460{
2461return readBytes(bvr->biosdev, bvr->fs_boff + bvr->part_boff, bvr->fs_byteoff, length, (void *) addr);
2462}
2463
2464//==============================================================================
2465
2466int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2467{
2468int secs;
2469unsigned char *cbuf = (unsigned char *)buffer;
2470unsigned int copy_len;
2471int rc;
2472
2473if ((len & (BPS-1)) != 0)
2474{
2475error("raw disk read not sector aligned");
2476return -1;
2477}
2478secno += bvr->part_boff;
2479
2480cache_valid = false;
2481
2482while (len > 0)
2483{
2484secs = len / BPS;
2485if (secs > N_CACHE_SECS)
2486{
2487secs = N_CACHE_SECS;
2488}
2489copy_len = secs * BPS;
2490
2491//printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2492if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0)
2493{
2494/* Ignore corrected ECC errors */
2495if (rc != ECC_CORRECTED_ERR)
2496{
2497error(" EBIOS read error: %s\n", bios_error(rc), rc);
2498error(" Block %d Sectors %d\n", secno, secs);
2499return rc;
2500}
2501}
2502bcopy( trackbuf, cbuf, copy_len );
2503len -= copy_len;
2504cbuf += copy_len;
2505secno += secs;
2506spinActivityIndicator(secs);
2507}
2508
2509return 0;
2510}
2511
2512//==============================================================================
2513
2514int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2515{
2516 int secs;
2517 unsigned char *cbuf = (unsigned char *)buffer;
2518 unsigned int copy_len;
2519 int rc;
2520
2521if ((len & (BPS-1)) != 0)
2522{
2523error("raw disk write not sector aligned");
2524return -1;
2525}
2526secno += bvr->part_boff;
2527
2528cache_valid = false;
2529
2530while (len > 0)
2531{
2532secs = len / BPS;
2533if (secs > N_CACHE_SECS)
2534{
2535secs = N_CACHE_SECS;
2536}
2537copy_len = secs * BPS;
2538
2539bcopy( cbuf, trackbuf, copy_len );
2540//printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2541if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0)
2542{
2543error(" EBIOS write error: %s\n", bios_error(rc), rc);
2544error(" Block %d Sectors %d\n", secno, secs);
2545return rc;
2546}
2547
2548len -= copy_len;
2549cbuf += copy_len;
2550secno += secs;
2551spinActivityIndicator(secs);
2552}
2553
2554return 0;
2555}
2556
2557//==============================================================================
2558
2559int diskIsCDROM(BVRef bvr)
2560{
2561struct driveInfo di;
2562
2563if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation)
2564{
2565return 1;
2566}
2567return 0;
2568}
2569
2570//==============================================================================
2571
2572int biosDevIsCDROM(int biosdev)
2573{
2574struct driveInfo di;
2575
2576if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2577{
2578return 1;
2579}
2580return 0;
2581}
2582

Archive Download this file

Revision: 2630