Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/disk.c

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

Archive Download this file

Revision: 2713