Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2525