Chameleon

Chameleon Svn Source Tree

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

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 *
24 *
25 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * All rights reserved. The CMU software License Agreement specifies
29 * the terms and conditions for use and redistribution.
30 *
31 *
32 * INTEL CORPORATION PROPRIETARY INFORMATION
33 *
34 * This software is supplied under the terms of a license agreement or
35 * nondisclosure agreement with Intel Corporation and may not be copied
36 * nor disclosed except in accordance with the terms of that agreement.
37 *
38 * Copyright 1988, 1989 Intel Corporation
39 *
40 *
41 * Copyright 1993 NeXT Computer, Inc.
42 * All rights reserved.
43 *
44 *
45 * Copyright 2007 VMware Inc.
46 * "Preboot" ramdisk support added by David Elliott
47 * GPT support added by David Elliott. Based on IOGUIDPartitionScheme.cpp.
48 */
49
50//Azi: style the rest later...
51
52// Allow UFS_SUPPORT to be overridden with preprocessor option.
53#ifndef UFS_SUPPORT
54// zef: Disabled UFS support
55#define UFS_SUPPORT 0
56#endif
57
58#if UFS_SUPPORT
59#include "ufs.h"
60#endif
61#include <limits.h>
62#include <IOKit/storage/IOApplePartitionScheme.h>
63#include <IOKit/storage/IOGUIDPartitionScheme.h>
64#include "libsaio.h"
65#include "boot.h"
66#include "bootstruct.h"
67#include "memory.h"
68#include "fdisk.h"
69#include "hfs.h"
70#include "ntfs.h"
71#include "exfat.h"
72#include "msdos.h"
73#include "ext2fs.h"
74#include "befs.h"
75#include "freebsd.h"
76#include "openbsd.h"
77#include "xml.h"
78#include "disk.h"
79// For EFI_GUID
80#include "efi.h"
81#include "efi_tables.h"
82
83typedef struct gpt_hdr gpt_hdr;
84typedef struct gpt_ent gpt_ent;
85
86#define PROBEFS_SIZE BPS * 4 /* buffer size for filesystem probe */
87#define CD_BPS 2048 /* CD-ROM block size */
88#define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */
89#define UFS_FRONT_PORCH 0
90#define kAPMSector 2 /* Sector number of Apple partition map */
91#define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
92#define ECC_CORRECTED_ERR 0x11
93
94/*
95 * IORound and IOTrunc convenience functions, in the spirit
96 * of vm's round_page() and trunc_page().
97 */
98#define IORound(value,multiple) \
99 ((((value) + (multiple) - 1) / (multiple)) * (multiple))
100
101#define IOTrunc(value,multiple) \
102 (((value) / (multiple)) * (multiple));
103
104//==========================================================================
105// Maps (E)BIOS return codes to message strings.
106
107struct NamedValue {
108unsigned char value;
109const char *name;
110};
111
112/*
113 * Map a disk drive to bootable volumes contained within.
114 */
115struct DiskBVMap {
116 int biosdev;// BIOS device number (unique)
117 BVRef bvr;// chain of boot volumes on the disk
118 int bvrcnt;// number of boot volumes
119 struct DiskBVMap *next;// linkage to next mapping
120};
121
122/*
123 * trackbuf points to the start of the track cache. Biosread()
124 * will store the sectors read from disk to this memory area.
125 *
126 * biosbuf points to a sector within the track cache, and is
127 * updated by Biosread().
128 */
129static char * const trackbuf = (char *) ptov(BIOS_ADDR);
130static char * biosbuf;
131
132static struct DiskBVMap *gDiskBVMap = NULL;
133static struct disk_blk0 *gBootSector = NULL;
134
135// Function pointers to be filled in if ramdisks are available:
136int (*p_ramdiskReadBytes)( int biosdev, unsigned int blkno,
137 unsigned int byteoff,
138 unsigned int byteCount, void * buffer ) = NULL;
139int (*p_get_ramdisk_info)(int biosdev, struct driveInfo *dip) = NULL;
140
141static bool getOSVersion(BVRef bvr, char *str);
142static bool cache_valid = false;
143
144static const struct NamedValue bios_errors[] =
145{
146{ 0x10, "Media error" },
147{ 0x11, "Corrected ECC error" },
148{ 0x20, "Controller or device error" },
149{ 0x40, "Seek failed" },
150{ 0x80, "Device timeout" },
151{ 0xAA, "Drive not ready" },
152{ 0x00, NULL }
153};
154
155static const struct NamedValue fdiskTypes[] =
156{
157{ FDISK_DOS12,"DOS_FAT_12" }, // 0x01
158{ FDISK_DOS16S,"DOS_FAT_16_S" }, // 0x04
159{ FDISK_DOS16B,"DOS_FAT_16" }, // 0x06
160{ FDISK_NTFS,"Windows NTFS" }, // 0x07
161{ FDISK_SMALLFAT32,"DOS_FAT_32" }, // 0x0B
162{ FDISK_FAT32,"Windows FAT_32" }, // 0x0C
163{ FDISK_DOS16SLBA,"Windows FAT_16" }, // 0x0E
164{ FDISK_WIN_LDM, "Windows_LDM" }, // 0x42
165{ FDISK_LINUX_SWAP, "Linux_Swap" }, // 0x82
166{ FDISK_LINUX,"Linux" }, // 0x83
167{ FDISK_LINUX_LVM, "Linux_LVM" }, // 0x8E
168{ FDISK_FREEBSD,"FreeBSD" }, // 0xA5
169{ FDISK_OPENBSD,"OpenBSD" }, // 0xA6
170{ FDISK_NEXTNAME, "Apple_Rhapsody_UFS" }, // 0xA7
171{ FDISK_UFS,"Apple UFS" }, // 0xA8
172{ FDISK_NETBSD, "NetBSD" }, // 0xA9
173{ FDISK_BOOTER,"Apple_Boot" }, // 0xAB
174{ FDISK_ENCRYPTED, "Apple_Encrypted" }, // 0xAE
175{ FDISK_HFS,"Apple HFS" }, // 0xAF
176{ 0xCD,"CD-ROM" }, // 0xCD
177{ FDISK_BEFS, "Haiku" }, // 0xEB
178{ FDISK_LINUX_RAID, "Linux_RAID" }, // 0xFD
179{ 0x00,NULL } /* must be last */
180};
181
182//==============================================================================
183
184extern void spinActivityIndicator(int sectors);
185
186//==========================================================================
187
188static int getDriveInfo( int biosdev, struct driveInfo *dip )
189{
190static struct driveInfo cached_di;
191int cc;
192
193// Real BIOS devices are 8-bit, so anything above that is for internal use.
194// Don't cache ramdisk drive info since it doesn't require several BIOS
195// calls and is thus not worth it.
196if (biosdev >= 0x100)
197{
198if (p_get_ramdisk_info != NULL)
199{
200cc = (*p_get_ramdisk_info)(biosdev, dip);
201}
202else
203{
204cc = -1;
205}
206if (cc < 0)
207{
208dip->valid = 0;
209return -1;
210}
211else
212{
213return 0;
214}
215}
216
217if (!cached_di.valid || biosdev != cached_di.biosdev)
218{
219cc = get_drive_info(biosdev, &cached_di);
220
221if (cc < 0)
222{
223cached_di.valid = 0;
224DEBUG_DISK(("get_drive_info returned error\n"));
225return (-1); // BIOS call error
226}
227}
228
229bcopy(&cached_di, dip, sizeof(cached_di));
230
231return 0;
232}
233
234//==========================================================================
235
236static const char * getNameForValue( const struct NamedValue * nameTable,
237 unsigned char value )
238{
239const struct NamedValue *np;
240
241for ( np = nameTable; np->value; np++)
242{
243if (np->value == value)
244{
245return np->name;
246}
247}
248
249return NULL;
250}
251
252//==============================================================================
253
254static const char * bios_error(int errnum)
255{
256static char errorstr[] = "Error 0x00";
257const char * errname;
258
259errname = getNameForValue(bios_errors, errnum);
260
261if (errname)
262{
263return errname;
264}
265
266sprintf(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
847BVRef 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));
979if ( map )
980 {
981map->biosdev = biosdev;
982map->bvr = NULL;
983map->bvrcnt = 0;
984map->next = gDiskBVMap;
985gDiskBVMap = map;
986
987// Create a record for each partition found on the disk.
988
989while ( getNextFDiskPartition( biosdev, &partno, &part ) )
990{
991DEBUG_DISK(("%s: part %d [%X]\n", __FUNCTION__, partno, part->systid));
992bvr = 0;
993
994switch ( part->systid )
995{
996#if UFS_SUPPORT
997case FDISK_UFS:
998bvr = newFDiskBVRef(
999biosdev, partno,
1000part->relsect + UFS_FRONT_PORCH/BPS,
1001part,
1002UFSInitPartition,
1003UFSLoadFile,
1004UFSReadFile,
1005UFSGetDirEntry,
1006UFSGetFileBlock,
1007UFSGetUUID,
1008UFSGetDescription,
1009UFSFree,
10100,
1011kBIOSDevTypeHardDrive, 0);
1012break;
1013#endif
1014
1015case FDISK_HFS:
1016bvr = newFDiskBVRef(
1017biosdev, partno,
1018part->relsect,
1019part,
1020HFSInitPartition,
1021HFSLoadFile,
1022HFSReadFile,
1023HFSGetDirEntry,
1024HFSGetFileBlock,
1025HFSGetUUID,
1026HFSGetDescription,
1027HFSFree,
10280,
1029kBIOSDevTypeHardDrive, 0);
1030break;
1031
1032// turbo - we want the booter type scanned also
1033case FDISK_BOOTER:
1034if (part->bootid & FDISK_ACTIVE)
1035{
1036gBIOSBootVolume = newFDiskBVRef(
1037biosdev, partno,
1038part->relsect,
1039part,
1040HFSInitPartition,
1041HFSLoadFile,
1042HFSReadFile,
1043HFSGetDirEntry,
1044HFSGetFileBlock,
1045HFSGetUUID,
1046HFSGetDescription,
1047HFSFree,
10480,
1049kBIOSDevTypeHardDrive, 0);
1050}
1051break;
1052
1053#if UFS_SUPPORT
1054case FDISK_BOOTER:
1055booterUFS = newFDiskBVRef(
1056biosdev, partno,
1057((part->relsect + spc - 1) / spc) * spc,
1058part,
1059UFSInitPartition,
1060UFSLoadFile,
1061UFSReadFile,
1062UFSGetDirEntry,
1063UFSGetFileBlock,
1064UFSGetUUID,
1065UFSGetDescription,
1066UFSFree,
10670,
1068kBIOSDevTypeHardDrive, 0);
1069break;
1070#endif
1071
1072case FDISK_FAT32:
1073case FDISK_DOS12:
1074case FDISK_DOS16S:
1075case FDISK_DOS16B:
1076case FDISK_SMALLFAT32:
1077case FDISK_DOS16SLBA:
1078bvr = newFDiskBVRef(
1079biosdev, partno,
1080part->relsect,
1081part,
1082MSDOSInitPartition,
1083MSDOSLoadFile,
1084MSDOSReadFile,
1085MSDOSGetDirEntry,
1086MSDOSGetFileBlock,
1087MSDOSGetUUID,
1088MSDOSGetDescription,
1089MSDOSFree,
10900,
1091kBIOSDevTypeHardDrive, 0);
1092break;
1093
1094case FDISK_NTFS:
1095bvr = newFDiskBVRef(
1096biosdev, partno,
1097part->relsect,
1098part,
10990, 0, 0, 0, 0,
1100NTFSGetUUID,
1101NTFSGetDescription,
1102(BVFree)free,
11030,
1104kBIOSDevTypeHardDrive, 0);
1105break;
1106
1107case FDISK_LINUX:
1108bvr = newFDiskBVRef(
1109biosdev, partno,
1110part->relsect,
1111part,
11120, 0, 0, 0, 0,
1113EX2GetUUID,
1114EX2GetDescription,
1115(BVFree)free,
11160,
1117kBIOSDevTypeHardDrive, 0);
1118break;
1119
1120case FDISK_BEFS:
1121bvr = newFDiskBVRef(
1122biosdev, partno,
1123part->relsect,
1124part,
11250, 0, 0, 0, 0, 0,
1126BeFSGetDescription,
1127(BVFree)free,
11280,
1129kBIOSDevTypeHardDrive, 0);
1130break;
1131
1132case FDISK_FREEBSD:
1133bvr = newFDiskBVRef(
1134biosdev, partno,
1135part->relsect,
1136part,
11370, 0, 0, 0, 0, 0,
1138FreeBSDGetDescription,
1139(BVFree)free,
11400,
1141kBIOSDevTypeHardDrive, 0);
1142break;
1143
1144case FDISK_OPENBSD:
1145bvr = newFDiskBVRef(
1146biosdev, partno,
1147part->relsect,
1148part,
11490, 0, 0, 0, 0, 0,
1150OpenBSDGetDescription,
1151(BVFree)free,
11520,
1153kBIOSDevTypeHardDrive, 0);
1154break;
1155
1156default:
1157bvr = newFDiskBVRef(
1158biosdev, partno,
1159part->relsect,
1160part,
11610, 0, 0, 0, 0, 0, 0,
1162(BVFree)free,
11630,
1164kBIOSDevTypeHardDrive, 0);
1165break;
1166}
1167
1168if ( bvr )
1169{
1170bvr->next = map->bvr;
1171map->bvr = bvr;
1172map->bvrcnt++;
1173}
1174}
1175
1176#if UFS_SUPPORT
1177// Booting from a CD with an UFS filesystem embedded
1178// in a booter partition.
1179
1180if ( booterUFS )
1181{
1182if ( map->bvrcnt == 0 )
1183{
1184map->bvr = booterUFS;
1185map->bvrcnt++;
1186}
1187else
1188{
1189free( booterUFS );
1190}
1191}
1192#endif
1193}
1194} while (0);
1195
1196#if UNUSED
1197/*
1198 * If no FDisk partition, then we will check for
1199 * an Apple partition map elsewhere.
1200 */
1201if (map && map->bvrcnt == 0)
1202{
1203static struct fdisk_part cdpart;
1204cdpart.systid = 0xCD;
1205
1206/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
1207bvr = newFDiskBVRef(
1208biosdev, 0,
12090,
1210&cdpart,
1211HFSInitPartition,
1212HFSLoadFile,
1213HFSReadFile,
1214HFSGetDirEntry,
1215HFSGetFileBlock,
1216HFSGetUUID,
1217HFSGetDescription,
1218HFSFree,
12190,
1220kBIOSDevTypeHardDrive, 0);
1221bvr->next = map->bvr;
1222map->bvr = bvr;
1223map->bvrcnt++;
1224}
1225#endif
1226// Actually this should always be true given the above code
1227// (unless malloc failed above)
1228if(map && (map == gDiskBVMap))
1229{
1230// Don't leave a null map in the chain
1231if((map->bvrcnt == 0) && (map->bvr == NULL))
1232{
1233gDiskBVMap = map->next;
1234free(map);
1235map = NULL;
1236}
1237}
1238
1239if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1240
1241return map ? map->bvr : NULL;
1242}
1243
1244//==============================================================================
1245
1246static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
1247{
1248struct DiskBVMap*map;
1249struct Block0*block0_p;
1250unsigned intblksize;
1251unsigned intfactor;
1252void*buffer = malloc(BPS);
1253
1254if (!buffer)
1255{
1256return NULL;
1257}
1258
1259bzero(buffer,BPS);
1260
1261/* Check for alternate block size */
1262if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0)
1263{
1264return NULL;
1265}
1266
1267block0_p = buffer;
1268if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE)
1269{
1270blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1271if (blksize != BPS)
1272{
1273free(buffer);
1274buffer = malloc(blksize);
1275if (!buffer)
1276{
1277return NULL;
1278}
1279bzero(buffer,BPS);
1280}
1281factor = blksize / BPS;
1282}
1283else
1284{
1285blksize = BPS;
1286factor = 1;
1287}
1288
1289do
1290{
1291// Create a new mapping.
1292
1293map = (struct DiskBVMap *) malloc( sizeof(*map) );
1294if ( map )
1295{
1296int error;
1297DPME *dpme_p = (DPME *)buffer;
1298UInt32 i, npart = UINT_MAX;
1299BVRef bvr;
1300
1301map->biosdev = biosdev;
1302map->bvr = NULL;
1303map->bvrcnt = 0;
1304map->next = gDiskBVMap;
1305gDiskBVMap = map;
1306
1307for (i = 0; i < npart; i++)
1308{
1309error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1310
1311if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE)
1312{
1313break;
1314}
1315
1316if (i == 0)
1317{
1318npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1319}
1320/*
1321printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1322dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1323dpme.dpme_pblock_start, dpme.dpme_pblocks,
1324dpme.dpme_lblock_start, dpme.dpme_lblocks,
1325dpme.dpme_boot_block);
1326*/
1327
1328if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0)
1329{
1330bvr = newAPMBVRef(biosdev,
1331i,
1332OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1333dpme_p,
1334HFSInitPartition,
1335HFSLoadFile,
1336HFSReadFile,
1337HFSGetDirEntry,
1338HFSGetFileBlock,
1339HFSGetUUID,
1340HFSGetDescription,
1341HFSFree,
13420,
1343kBIOSDevTypeHardDrive, 0);
1344bvr->next = map->bvr;
1345map->bvr = bvr;
1346map->bvrcnt++;
1347}
1348}
1349}
1350} while (0);
1351
1352if (buffer)
1353{
1354free(buffer);
1355}
1356
1357if (countPtr)
1358{
1359*countPtr = map ? map->bvrcnt : 0;
1360}
1361
1362return map ? map->bvr : NULL;
1363}
1364
1365//==============================================================================
1366
1367static bool isPartitionUsed(gpt_ent * partition)
1368{
1369
1370// Ask whether the given partition is used.
1371
1372return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1373}
1374
1375//==============================================================================
1376
1377static BVRef diskScanGPTBootVolumes(int biosdev, int * countPtr)
1378{
1379struct DiskBVMap *map = NULL;
1380
1381void *buffer = malloc(BPS);
1382
1383int error;
1384
1385if ((error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer )) != 0)
1386{
1387verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1388goto scanErr;
1389}
1390struct REAL_disk_blk0 *fdiskMap = buffer;
1391if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1392{
1393verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1394goto scanErr;
1395}
1396
1397int fdiskID = 0;
1398unsigned index;
1399for ( index = 0; index < FDISK_NPART; index++ )
1400{
1401if ( fdiskMap->parts[index].systid )
1402{
1403if ( fdiskMap->parts[index].systid == 0xEE )
1404{
1405// Fail if two 0xEE partitions are present which
1406// means the FDISK code will wind up parsing it.
1407if ( fdiskID )
1408{
1409goto scanErr;
1410}
1411
1412fdiskID = index + 1;
1413}
1414}
1415}
1416
1417if ( fdiskID == 0 )
1418{
1419goto scanErr;
1420}
1421
1422verbose("Attempting to read GPT\n");
1423
1424if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1425{
1426goto scanErr;
1427}
1428
1429gpt_hdr *headerMap = buffer;
1430
1431// Determine whether the partition header signature is present.
1432
1433if (memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)))
1434{
1435goto scanErr;
1436}
1437
1438// Determine whether the partition header size is valid.
1439
1440UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1441UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1442
1443if (headerSize < offsetof(gpt_hdr, padding))
1444{
1445goto scanErr;
1446}
1447
1448if ( headerSize > BPS )
1449{
1450goto scanErr;
1451}
1452
1453// Determine whether the partition header checksum is valid.
1454
1455headerMap->hdr_crc_self = 0;
1456
1457if ( crc32(0, headerMap, headerSize) != headerCheck )
1458{
1459goto scanErr;
1460}
1461
1462// Determine whether the partition entry size is valid.
1463
1464UInt64gptBlock= 0;
1465UInt32gptCheck= 0;
1466UInt32gptCount= 0;
1467UInt32gptID= 0;
1468gpt_ent*gptMap= 0;
1469UInt32gptSize= 0;
1470
1471gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1472gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1473gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1474gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1475
1476if ( gptSize < sizeof(gpt_ent) )
1477{
1478goto scanErr;
1479}
1480
1481// Allocate a buffer large enough to hold one map, rounded to a media block.
1482free(buffer);
1483buffer = NULL;
1484
1485UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1486if (bufferSize == 0)
1487{
1488goto scanErr;
1489}
1490buffer = malloc(bufferSize);
1491if (!buffer)
1492{
1493 goto scanErr;
1494}
1495
1496if (readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1497{
1498goto scanErr;
1499}
1500verbose("Read GPT\n");
1501
1502// Allocate a new map for this BIOS device and insert it into the chain
1503map = malloc(sizeof(*map));
1504if (!map)
1505{
1506goto scanErr;
1507}
1508map->biosdev = biosdev;
1509map->bvr = NULL;
1510map->bvrcnt = 0;
1511map->next = gDiskBVMap;
1512gDiskBVMap = map;
1513
1514// fdisk like partition type id.
1515int fsType = 0;
1516
1517for(gptID = 1; gptID <= gptCount; ++gptID)
1518{
1519BVRef bvr = NULL;
1520unsigned int bvrFlags = 0;
1521
1522// size on disk can be larger than sizeof(gpt_ent)
1523gptMap = (gpt_ent *)(buffer + ((gptID - 1) * gptSize));
1524
1525// NOTE: EFI_GUID's are in LE and we know we're on an x86.
1526// The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1527
1528if (isPartitionUsed(gptMap))
1529{
1530char stringuuid[100];
1531efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1532verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1533
1534// Getting fdisk like partition type.
1535fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1536
1537if ( (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) )
1538{
1539bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1540bvr = newGPTBVRef(biosdev,
1541gptID,
1542gptMap->ent_lba_start,
1543gptMap,
1544HFSInitPartition,
1545HFSLoadFile,
1546HFSReadFile,
1547HFSGetDirEntry,
1548HFSGetFileBlock,
1549HFSGetUUID,
1550HFSGetDescription,
1551HFSFree,
15520,
1553kBIOSDevTypeHardDrive, bvrFlags);
1554}
1555
1556// zef - foreign OS support
1557if ((efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1558(efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1559{
1560switch (fsType)
1561{
1562case FDISK_NTFS:
1563bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
15640, 0, 0, 0, 0, NTFSGetUUID, NTFSGetDescription,
1565(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1566break;
1567
1568case FDISK_LINUX:
1569bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
15700, 0, 0, 0, 0, EX2GetUUID, EX2GetDescription,
1571(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1572break;
1573
1574case FDISK_FAT32:
1575case FDISK_DOS12:
1576case FDISK_DOS16B:
1577bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1578MSDOSInitPartition,
1579MSDOSLoadFile,
1580MSDOSReadFile,
1581MSDOSGetDirEntry,
1582MSDOSGetFileBlock,
1583MSDOSGetUUID,
1584MSDOSGetDescription,
1585MSDOSFree,
15860, kBIOSDevTypeHardDrive, 0);
1587break;
1588
1589case FDISK_PSEUDO_EXFAT:
1590bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1591 EXFATInitPartition,
1592 EXFATLoadFile,
1593 EXFATReadFile,
1594 EXFATGetDirEntry,
1595 EXFATGetFileBlock,
1596 EXFATGetUUID,
1597 EXFATGetDescription,
1598 EXFATFree,
1599 0, kBIOSDevTypeHardDrive, 0);
1600break;
1601
1602default:
1603bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
16040, 0, 0, 0, 0, 0, 0,
1605(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1606break;
1607}
1608
1609}
1610
1611// turbo - save our booter partition
1612// zef - only on original boot device
1613if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ) {
1614switch (fsType) {
1615case FDISK_HFS:
1616if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1617bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1618HFSInitPartition,
1619HFSLoadFile,
1620HFSReadFile,
1621HFSGetDirEntry,
1622HFSGetFileBlock,
1623HFSGetUUID,
1624HFSGetDescription,
1625HFSFree,
16260, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1627}
1628break;
1629
1630case FDISK_FAT32:
1631if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1632bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1633MSDOSInitPartition,
1634MSDOSLoadFile,
1635MSDOSReadFile,
1636MSDOSGetDirEntry,
1637MSDOSGetFileBlock,
1638MSDOSGetUUID,
1639MSDOSGetDescription,
1640MSDOSFree,
16410, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1642}
1643break;
1644
1645default:
1646if (biosdev == gBIOSDev)
1647{
1648gBIOSBootVolume = bvr;
1649}
1650break;
1651}
1652}
1653
1654if (bvr)
1655{
1656// Fixup bvr with the fake fdisk partition type.
1657if (fsType > 0) {
1658bvr->part_type = fsType;
1659}
1660
1661bvr->next = map->bvr;
1662map->bvr = bvr;
1663++map->bvrcnt;
1664}
1665
1666}
1667}
1668
1669scanErr:
1670if (buffer)
1671{
1672free(buffer);
1673}
1674
1675if(map)
1676{
1677if(countPtr) *countPtr = map->bvrcnt;
1678{
1679return map->bvr;
1680}
1681
1682}
1683else
1684{
1685if(countPtr) *countPtr = 0;
1686{
1687return NULL;
1688}
1689}
1690}
1691
1692//==============================================================================
1693
1694static bool getOSVersion(BVRef bvr, char *str)
1695{
1696bool valid = false;
1697config_file_t systemVersion;
1698char dirSpec[512];
1699
1700/*
1701 * Only look for OS Version on HFS+
1702 */
1703if (bvr->fs_readfile != HFSReadFile)
1704{
1705return valid;
1706}
1707
1708// OS X Recovery
1709sprintf(dirSpec, "hd(%d,%d)/com.apple.recovery.boot/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1710
1711if (!loadConfigFile(dirSpec, &systemVersion))
1712{
1713bvr->OSisInstaller = true;
1714valid = true;
1715}
1716
1717if (!valid)
1718{
1719// OS X Standard
1720sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1721
1722if (!loadConfigFile(dirSpec, &systemVersion))
1723{
1724bvr->OSisInstaller = true;
1725valid = true;
1726}
1727else
1728{
1729// OS X Server
1730sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1731
1732if (!loadConfigFile(dirSpec, &systemVersion))
1733{
1734bvr->OSisServer = true;
1735valid = true;
1736}
1737/*else
1738{
1739sprintf(dirSpec, "hd(%d,%d)/.IAProductInfo", BIOS_DEV_UNIT(bvr), bvr->part_no);
1740
1741if (!loadConfigFile(dirSpec, &systemVersion))
1742{
1743
1744}
1745}
1746*/
1747}
1748}
1749
1750if (valid)
1751{
1752const char *val;
1753int len;
1754
1755if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1756{
1757// getValueForKey uses const char for val
1758// so copy it and trim
1759*str = '\0';
1760// crazybirdy
1761if (len > 4 && (val[3] == '1'))
1762{
1763strncat(str, val, MIN(len, 5));
1764}
1765else
1766{
1767strncat(str, val, MIN(len, 4));
1768}
1769}
1770else
1771{
1772valid = false;
1773}
1774}
1775
1776if(!valid)
1777{
1778int fh = -1;
1779sprintf(dirSpec, "hd(%d,%d)/.PhysicalMediaInstall", BIOS_DEV_UNIT(bvr), bvr->part_no);
1780fh = open(dirSpec, 0);
1781
1782if (fh >= 0)
1783{
1784valid = true;
1785bvr->OSisInstaller = true;
1786strcpy(bvr->OSVersion, "10.7"); // 10.7 +
1787close(fh);
1788}
1789else
1790{
1791sprintf(dirSpec, "hd(%d,%d)/.IAPhysicalMedia", BIOS_DEV_UNIT(bvr), bvr->part_no);
1792fh = open(dirSpec, 0);
1793
1794if (fh >= 0)
1795{
1796valid = true;
1797bvr->OSisInstaller = true;
1798strcpy(bvr->OSVersion, "10.9"); // 10.9 +
1799}
1800else
1801{
1802close(fh);
1803}
1804}
1805}
1806return valid;
1807}
1808
1809//==============================================================================
1810
1811static void scanFSLevelBVRSettings(BVRef chain)
1812{
1813BVRef bvr;
1814char dirSpec[512], fileSpec[512];
1815char label[BVSTRLEN];
1816int ret;
1817long flags;
1818u_int32_t time;
1819int fh, fileSize, error;
1820
1821for (bvr = chain; bvr; bvr = bvr->next)
1822{
1823ret = -1;
1824error = 0;
1825
1826//
1827// Check for alternate volume label on boot helper partitions.
1828//
1829if (bvr->flags & kBVFlagBooter)
1830{
1831sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1832strcpy(fileSpec, ".disk_label.contentDetails");
1833ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1834if (!ret)
1835{
1836fh = open(strcat(dirSpec, fileSpec), 0);
1837fileSize = file_size(fh);
1838if (fileSize > 0 && fileSize < BVSTRLEN)
1839{
1840if (read(fh, label, fileSize) != fileSize)
1841{
1842error = -1;
1843}
1844}
1845else
1846{
1847error = -1;
1848}
1849
1850close(fh);
1851
1852if (!error)
1853{
1854label[fileSize] = '\0';
1855strcpy(bvr->altlabel, label);
1856}
1857}
1858}
1859
1860// Check for SystemVersion.plist or ServerVersion.plist to determine if a volume hosts an installed system.
1861
1862if (bvr->flags & kBVFlagNativeBoot)
1863{
1864if (getOSVersion(bvr, bvr->OSVersion) == true)
1865{
1866bvr->flags |= kBVFlagSystemVolume;
1867}
1868}
1869
1870}
1871}
1872
1873//==============================================================================
1874
1875void rescanBIOSDevice(int biosdev)
1876{
1877struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1878if (oldMap == NULL)
1879{
1880return;
1881}
1882
1883CacheReset();
1884diskFreeMap(oldMap);
1885oldMap = NULL;
1886scanBootVolumes(biosdev, 0);
1887}
1888
1889//==============================================================================
1890
1891struct DiskBVMap* diskResetBootVolumes(int biosdev)
1892{
1893struct DiskBVMap * map;
1894struct DiskBVMap *prevMap = NULL;
1895for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1896if ( biosdev == map->biosdev ) {
1897break;
1898}
1899}
1900
1901if(map != NULL) {
1902verbose("Resetting BIOS device %xh\n", biosdev);
1903// Reset the biosbuf cache
1904cache_valid = false;
1905if(map == gDiskBVMap)
1906{
1907gDiskBVMap = map->next;
1908}
1909else if(prevMap != NULL)
1910{
1911prevMap->next = map->next;
1912}
1913else
1914{
1915stop("diskResetBootVolumes error\n");
1916return NULL;
1917}
1918}
1919// Return the old map, either to be freed, or reinserted later
1920return map;
1921}
1922
1923//==============================================================================
1924
1925// Frees a DiskBVMap and all of its BootVolume's
1926void diskFreeMap(struct DiskBVMap *map)
1927{
1928if(map != NULL)
1929{
1930while(map->bvr != NULL)
1931{
1932BVRef bvr = map->bvr;
1933map->bvr = bvr->next;
1934(*bvr->bv_free)(bvr);
1935}
1936
1937free(map);
1938}
1939}
1940
1941//==============================================================================
1942
1943BVRef diskScanBootVolumes(int biosdev, int * countPtr)
1944{
1945struct DiskBVMap *map;
1946BVRef bvr;
1947int count = 0;
1948
1949// Find an existing mapping for this device.
1950
1951for (map = gDiskBVMap; map; map = map->next)
1952{
1953if (biosdev == map->biosdev)
1954{
1955count = map->bvrcnt;
1956break;
1957}
1958}
1959
1960if (map == NULL)
1961{
1962bvr = diskScanGPTBootVolumes(biosdev, &count);
1963if (bvr == NULL)
1964{
1965bvr = diskScanFDiskBootVolumes(biosdev, &count);
1966}
1967
1968if (bvr == NULL)
1969{
1970bvr = diskScanAPMBootVolumes(biosdev, &count);
1971}
1972
1973if (bvr)
1974{
1975scanFSLevelBVRSettings(bvr);
1976}
1977}
1978else
1979{
1980bvr = map->bvr;
1981}
1982
1983if (countPtr)
1984{
1985*countPtr += count;
1986}
1987
1988return bvr;
1989}
1990
1991//==============================================================================
1992
1993BVRef getBVChainForBIOSDev(int biosdev)
1994{
1995BVRef chain = NULL;
1996struct DiskBVMap * map = NULL;
1997
1998for (map = gDiskBVMap; map; map = map->next)
1999{
2000if (map->biosdev == biosdev)
2001{
2002chain = map->bvr;
2003break;
2004}
2005}
2006
2007return chain;
2008}
2009
2010//==============================================================================
2011
2012BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
2013{
2014BVRef chain = NULL;
2015BVRef bvr = NULL;
2016BVRef newBVR = NULL;
2017BVRef prevBVR = NULL;
2018
2019struct DiskBVMap * map = NULL;
2020int bvCount = 0;
2021
2022const char *raw = 0;
2023char* val = 0;
2024int len;
2025
2026getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
2027if(raw)
2028{
2029val = XMLDecode(raw);
2030}
2031
2032/*
2033 * Traverse gDISKBVmap to get references for
2034 * individual bvr chains of each drive.
2035 */
2036for (map = gDiskBVMap; map; map = map->next)
2037{
2038for (bvr = map->bvr; bvr; bvr = bvr->next)
2039{
2040/*
2041 * Save the last bvr.
2042 */
2043if (newBVR)
2044{
2045prevBVR = newBVR;
2046}
2047
2048/*
2049 * Allocate and copy the matched bvr entry into a new one.
2050 */
2051newBVR = (BVRef) malloc(sizeof(*newBVR));
2052if (!newBVR)
2053{
2054continue;
2055}
2056bzero(newBVR,sizeof(*newBVR));
2057
2058bcopy(bvr, newBVR, sizeof(*newBVR));
2059
2060/*
2061 * Adjust the new bvr's fields.
2062 */
2063newBVR->next = NULL;
2064newBVR->filtered = true;
2065
2066if ( (!allowFlags || newBVR->flags & allowFlags)
2067&& (!denyFlags || !(newBVR->flags & denyFlags) )
2068&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
2069)
2070{
2071newBVR->visible = true;
2072}
2073
2074/*
2075 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
2076 * to be able to hide foreign partitions from the boot menu.
2077 *
2078 */
2079if ( (newBVR->flags & kBVFlagForeignBoot) )
2080{
2081char *start, *next = val;
2082long len = 0;
2083do
2084{
2085start = strbreak(next, &next, &len);
2086if(len && matchVolumeToString(newBVR, start, len) )
2087{
2088newBVR->visible = false;
2089}
2090}
2091while ( next && *next );
2092}
2093
2094/*
2095 * Use the first bvr entry as the starting chain pointer.
2096 */
2097if (!chain)
2098{
2099chain = newBVR;
2100}
2101
2102/*
2103 * Update the previous bvr's link pointer to use the new memory area.
2104 */
2105if (prevBVR)
2106{
2107prevBVR->next = newBVR;
2108}
2109
2110if (newBVR->visible)
2111{
2112bvCount++;
2113}
2114}
2115}
2116
2117#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
2118for (bvr = chain; bvr; bvr = bvr->next)
2119{
2120if (!bvr)
2121{
2122break;
2123}
2124printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
2125}
2126printf("count: %d\n", bvCount);
2127getchar();
2128#endif
2129
2130*count = bvCount;
2131
2132free(val);
2133return chain;
2134}
2135
2136//==============================================================================
2137
2138int freeFilteredBVChain(const BVRef chain)
2139{
2140int ret = 1;
2141BVRef bvr = chain;
2142BVRef nextBVR = NULL;
2143
2144while (bvr)
2145{
2146if (!bvr)
2147{
2148break;
2149}
2150
2151nextBVR = bvr->next;
2152
2153if (bvr->filtered)
2154{
2155free(bvr);
2156}
2157else
2158{
2159ret = 0;
2160break;
2161}
2162
2163bvr = nextBVR;
2164}
2165
2166return ret;
2167}
2168
2169//==============================================================================
2170
2171bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
2172{
2173char testStr[128];
2174
2175if ( !bvr || !match || !*match)
2176{
2177return 0;
2178}
2179
2180if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
2181{
2182 return 0;
2183}
2184
2185// Try to match hd(x,y) first.
2186sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
2187if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2188{
2189return true;
2190}
2191
2192// Try to match volume UUID.
2193if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
2194{
2195if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2196{
2197return true;
2198}
2199}
2200
2201// Try to match volume label (always quoted).
2202if ( bvr->description )
2203{
2204bvr->description(bvr, testStr, sizeof(testStr)-1);
2205if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2206{
2207return true;
2208}
2209}
2210
2211return false;
2212}
2213
2214//==============================================================================
2215
2216/* If Rename Partition has defined an alias, then extract it for description purpose.
2217 * The format for the rename string is the following:
2218 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
2219 */
2220
2221bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
2222{
2223char *aliasList, *entryStart, *entryNext;
2224
2225if ( !str || strMaxLen <= 0)
2226{
2227return false;
2228}
2229
2230aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
2231if ( !aliasList )
2232{
2233return false;
2234}
2235
2236for ( entryStart = entryNext = aliasList; entryNext && *entryNext; entryStart = entryNext )
2237{
2238char *volStart, *volEnd, *aliasStart;
2239long volLen, aliasLen;
2240
2241// Delimit current entry
2242entryNext = strchr(entryStart, ';');
2243if ( entryNext )
2244{
2245*entryNext = '\0';
2246entryNext++;
2247}
2248
2249volStart = strbreak(entryStart, &volEnd, &volLen);
2250if(!volLen)
2251{
2252continue;
2253}
2254
2255aliasStart = strbreak(volEnd, 0, &aliasLen);
2256if(!aliasLen)
2257{
2258continue;
2259}
2260
2261if ( matchVolumeToString(bvr, volStart, volLen) )
2262{
2263strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
2264free(aliasList);
2265
2266return true;
2267}
2268}
2269
2270free(aliasList);
2271return false;
2272}
2273
2274//==============================================================================
2275
2276void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
2277{
2278unsigned char type;
2279char *p = str;
2280
2281if(!bvr || !p || strMaxLen <= 0)
2282{
2283return;
2284}
2285
2286type = (unsigned char) bvr->part_type;
2287
2288if (useDeviceDescription)
2289{
2290int len = getDeviceDescription(bvr, str);
2291if(len >= strMaxLen)
2292{
2293return;
2294}
2295
2296strcpy(str + len, bvr->OSisInstaller ? " (Installer) " : " ");
2297len += bvr->OSisInstaller ? 13 : 1;
2298strMaxLen -= len;
2299p += len;
2300}
2301
2302/* See if a partition rename is preferred */
2303if (getVolumeLabelAlias(bvr, p, strMaxLen))
2304{
2305strncpy(bvr->label, p, strMaxLen);
2306return; // we're done here no need to seek for real name
2307}
2308
2309// Get the volume label using filesystem specific functions or use the alternate volume label if available.
2310
2311if (*bvr->altlabel != '\0')
2312{
2313strncpy(p, bvr->altlabel, strMaxLen);
2314}
2315else if (bvr->description)
2316{
2317bvr->description(bvr, p, strMaxLen);
2318}
2319
2320if (*p == '\0')
2321{
2322const char * name = getNameForValue( fdiskTypes, type );
2323
2324if (name == NULL)
2325{
2326name = bvr->type_name;
2327}
2328
2329if (name == NULL)
2330{
2331sprintf(p, "TYPE %02X", type);
2332}
2333else
2334{
2335strncpy(p, name, strMaxLen);
2336}
2337}
2338
2339// Set the devices label
2340sprintf(bvr->label, p);
2341}
2342
2343
2344//==============================================================================
2345
2346int readBootSector(int biosdev, unsigned int secno, void *buffer)
2347{
2348int error;
2349struct disk_blk0 * bootSector = (struct disk_blk0 *)buffer;
2350
2351if (bootSector == NULL)
2352{
2353if (gBootSector == NULL)
2354{
2355gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2356
2357if (gBootSector == NULL)
2358{
2359return -1;
2360}
2361}
2362
2363bootSector = gBootSector;
2364}
2365
2366error = readBytes(biosdev, secno, 0, BPS, bootSector);
2367
2368if (error || bootSector->signature != DISK_SIGNATURE)
2369{
2370return -1;
2371}
2372return 0;
2373}
2374
2375//==============================================================================
2376
2377/*
2378 * Format of boot1f32 block.
2379 */
2380
2381#define BOOT1F32_MAGIC "BOOT "
2382#define BOOT1F32_MAGICLEN 11
2383
2384struct disk_boot1f32_blk
2385{
2386unsigned char init[3];
2387unsigned char fsheader[87];
2388unsigned char magic[BOOT1F32_MAGICLEN];
2389unsigned char bootcode[409];
2390unsigned short signature;
2391};
2392
2393//==============================================================================
2394
2395int testFAT32EFIBootSector(int biosdev, unsigned int secno, void *buffer)
2396{
2397struct disk_boot1f32_blk *bootSector = (struct disk_boot1f32_blk *)buffer;
2398int error;
2399
2400if (bootSector == NULL)
2401{
2402if (gBootSector == NULL)
2403{
2404gBootSector = (struct disk_blk0 *)malloc(sizeof(*gBootSector));
2405if ( gBootSector == NULL )
2406{
2407return -1;
2408}
2409}
2410bootSector = (struct disk_boot1f32_blk *)gBootSector;
2411}
2412
2413error = readBytes(biosdev, secno, 0, BPS, bootSector);
2414if (error || bootSector->signature != DISK_SIGNATURE || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2415{
2416return -1;
2417}
2418return 0;
2419}
2420
2421
2422//==============================================================================
2423// Handle seek request from filesystem modules.
2424
2425void diskSeek(BVRef bvr, long long position)
2426{
2427bvr->fs_boff = position / BPS;
2428bvr->fs_byteoff = position % BPS;
2429}
2430
2431
2432//==============================================================================
2433// Handle read request from filesystem modules.
2434
2435int diskRead(BVRef bvr, long addr, long length)
2436{
2437return readBytes(bvr->biosdev, bvr->fs_boff + bvr->part_boff, bvr->fs_byteoff, length, (void *) addr);
2438}
2439
2440//==============================================================================
2441
2442int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2443{
2444int secs;
2445unsigned char *cbuf = (unsigned char *)buffer;
2446unsigned int copy_len;
2447int rc;
2448
2449if ((len & (BPS-1)) != 0)
2450{
2451error("raw disk read not sector aligned");
2452return -1;
2453}
2454secno += bvr->part_boff;
2455
2456cache_valid = false;
2457
2458while (len > 0)
2459{
2460secs = len / BPS;
2461if (secs > N_CACHE_SECS)
2462{
2463secs = N_CACHE_SECS;
2464}
2465copy_len = secs * BPS;
2466
2467//printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2468if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0)
2469{
2470/* Ignore corrected ECC errors */
2471if (rc != ECC_CORRECTED_ERR)
2472{
2473error(" EBIOS read error: %s\n", bios_error(rc), rc);
2474error(" Block %d Sectors %d\n", secno, secs);
2475return rc;
2476}
2477}
2478bcopy( trackbuf, cbuf, copy_len );
2479len -= copy_len;
2480cbuf += copy_len;
2481secno += secs;
2482spinActivityIndicator(secs);
2483}
2484
2485return 0;
2486}
2487
2488//==============================================================================
2489
2490int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2491{
2492 int secs;
2493 unsigned char *cbuf = (unsigned char *)buffer;
2494 unsigned int copy_len;
2495 int rc;
2496
2497if ((len & (BPS-1)) != 0)
2498{
2499error("raw disk write not sector aligned");
2500return -1;
2501}
2502secno += bvr->part_boff;
2503
2504cache_valid = false;
2505
2506while (len > 0)
2507{
2508secs = len / BPS;
2509if (secs > N_CACHE_SECS)
2510{
2511secs = N_CACHE_SECS;
2512}
2513copy_len = secs * BPS;
2514
2515bcopy( cbuf, trackbuf, copy_len );
2516//printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2517if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0)
2518{
2519error(" EBIOS write error: %s\n", bios_error(rc), rc);
2520error(" Block %d Sectors %d\n", secno, secs);
2521return rc;
2522}
2523
2524len -= copy_len;
2525cbuf += copy_len;
2526secno += secs;
2527spinActivityIndicator(secs);
2528}
2529
2530return 0;
2531}
2532
2533//==============================================================================
2534
2535int diskIsCDROM(BVRef bvr)
2536{
2537struct driveInfo di;
2538
2539if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation)
2540{
2541return 1;
2542}
2543return 0;
2544}
2545
2546//==============================================================================
2547
2548int biosDevIsCDROM(int biosdev)
2549{
2550struct driveInfo di;
2551
2552if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2553{
2554return 1;
2555}
2556return 0;
2557}
2558

Archive Download this file

Revision: 2549