Chameleon

Chameleon Svn Source Tree

Root/branches/chucko/i386/libsaio/disk.c

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

Archive Download this file

Revision: 2454