Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1804