Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2531