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

Archive Download this file

Revision: 2507