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/*
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 )
751{
752bvr->flags |= kBVFlagNativeBoot;
753
754if ( probe && initFunc( bvr ) != 0 )
755{
756// filesystem probe failed.
757
758DEBUG_DISK(("%s: failed probe on dev %x part %d\n", __FUNCTION__, biosdev, partno));
759
760(*bvr->bv_free)(bvr);
761bvr = NULL;
762}
763else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
764{
765bvr->flags |= kBVFlagBootable;
766}
767}
768else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
769{
770bvr->flags |= kBVFlagForeignBoot;
771}
772else
773{
774(*bvr->bv_free)(bvr);
775bvr = NULL;
776}
777}
778if (bvr)
779{
780bvr->flags |= bvrFlags;
781}
782return bvr;
783}
784
785//==============================================================================
786
787/* A note on partition numbers:
788 * IOKit makes the primary partitions numbers 1-4, and then
789 * extended partitions are numbered consecutively 5 and up.
790 * So, for example, if you have two primary partitions and
791 * one extended partition they will be numbered 1, 2, 5.
792 */
793
794static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
795{
796 const struct fdisk_part * part;
797 struct DiskBVMap * map;
798 int partno = -1;
799 BVRef bvr;
800#if UFS_SUPPORT
801 BVRef booterUFS = NULL;
802#endif
803 int spc;
804 struct driveInfo di;
805 boot_drive_info_t *dp;
806
807/* Initialize disk info */
808
809if (getDriveInfo(biosdev, &di) != 0)
810{
811return NULL;
812}
813
814dp = &di.di;
815spc = (dp->params.phys_spt * dp->params.phys_heads);
816
817if (spc == 0)
818{
819/* This is probably a CD-ROM; punt on the geometry. */
820spc = 1;
821}
822
823 do {
824 // Create a new mapping.
825
826 map = (struct DiskBVMap *) malloc( sizeof(*map) );
827 if ( map )
828 {
829 map->biosdev = biosdev;
830 map->bvr = NULL;
831 map->bvrcnt = 0;
832 map->next = gDiskBVMap;
833 gDiskBVMap = map;
834
835 // Create a record for each partition found on the disk.
836
837 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
838 {
839 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
840 partno, part->systid));
841 bvr = 0;
842
843 switch ( part->systid )
844 {
845#if UFS_SUPPORT
846 case FDISK_UFS:
847 bvr = newFDiskBVRef(
848 biosdev, partno,
849 part->relsect + UFS_FRONT_PORCH/BPS,
850 part,
851 UFSInitPartition,
852 UFSLoadFile,
853 UFSReadFile,
854 UFSGetDirEntry,
855 UFSGetFileBlock,
856 UFSGetUUID,
857 UFSGetDescription,
858 UFSFree,
859 0,
860 kBIOSDevTypeHardDrive, 0);
861 break;
862#endif
863
864 case FDISK_HFS:
865 bvr = newFDiskBVRef(
866 biosdev, partno,
867 part->relsect,
868 part,
869 HFSInitPartition,
870 HFSLoadFile,
871 HFSReadFile,
872 HFSGetDirEntry,
873 HFSGetFileBlock,
874 HFSGetUUID,
875 HFSGetDescription,
876 HFSFree,
877 0,
878 kBIOSDevTypeHardDrive, 0);
879 break;
880
881 // turbo - we want the booter type scanned also
882 case FDISK_BOOTER:
883 if (part->bootid & FDISK_ACTIVE)
884 gBIOSBootVolume = newFDiskBVRef(
885 biosdev, partno,
886 part->relsect,
887 part,
888 HFSInitPartition,
889 HFSLoadFile,
890 HFSReadFile,
891 HFSGetDirEntry,
892 HFSGetFileBlock,
893 HFSGetUUID,
894 HFSGetDescription,
895 HFSFree,
896 0,
897 kBIOSDevTypeHardDrive, 0);
898 break;
899
900#if UFS_SUPPORT
901 case FDISK_BOOTER:
902 booterUFS = newFDiskBVRef(
903 biosdev, partno,
904 ((part->relsect + spc - 1) / spc) * spc,
905 part,
906 UFSInitPartition,
907 UFSLoadFile,
908 UFSReadFile,
909 UFSGetDirEntry,
910 UFSGetFileBlock,
911 UFSGetUUID,
912 UFSGetDescription,
913 UFSFree,
914 0,
915 kBIOSDevTypeHardDrive, 0);
916 break;
917#endif
918
919 case FDISK_FAT32:
920 case FDISK_DOS12:
921 case FDISK_DOS16S:
922 case FDISK_DOS16B:
923 case FDISK_SMALLFAT32:
924 case FDISK_DOS16SLBA:
925 bvr = newFDiskBVRef(
926 biosdev, partno,
927 part->relsect,
928 part,
929 MSDOSInitPartition,
930 MSDOSLoadFile,
931 MSDOSReadFile,
932 MSDOSGetDirEntry,
933 MSDOSGetFileBlock,
934 MSDOSGetUUID,
935 MSDOSGetDescription,
936 MSDOSFree,
937 0,
938 kBIOSDevTypeHardDrive, 0);
939 break;
940
941 case FDISK_NTFS:
942 bvr = newFDiskBVRef(
943 biosdev, partno,
944 part->relsect,
945 part,
946 0, 0, 0, 0, 0,
947 NTFSGetUUID,
948 NTFSGetDescription,
949 (BVFree)free,
950 0, kBIOSDevTypeHardDrive, 0);
951 break;
952
953 case FDISK_LINUX:
954 bvr = newFDiskBVRef(
955 biosdev, partno,
956 part->relsect,
957 part,
958 0, 0, 0, 0, 0,
959 EX2GetUUID,
960 EX2GetDescription,
961 (BVFree)free,
962 0, kBIOSDevTypeHardDrive, 0);
963 break;
964
965 case FDISK_BEFS:
966 bvr = newFDiskBVRef(
967 biosdev, partno,
968 part->relsect,
969 part,
970 0, 0, 0, 0, 0, 0,
971 BeFSGetDescription,
972 (BVFree)free,
973 0, kBIOSDevTypeHardDrive, 0);
974 break;
975
976 case FDISK_FREEBSD:
977 bvr = newFDiskBVRef(
978 biosdev, partno,
979 part->relsect,
980 part,
981 0, 0, 0, 0, 0, 0,
982 FreeBSDGetDescription,
983 (BVFree)free,
984 0, kBIOSDevTypeHardDrive, 0);
985 break;
986
987 case FDISK_OPENBSD:
988 bvr = newFDiskBVRef(
989 biosdev, partno,
990 part->relsect,
991 part,
992 0, 0, 0, 0, 0, 0,
993 OpenBSDGetDescription,
994 (BVFree)free,
995 0, kBIOSDevTypeHardDrive, 0);
996 break;
997
998 default:
999 bvr = newFDiskBVRef(
1000 biosdev, partno,
1001 part->relsect,
1002 part,
1003 0, 0, 0, 0, 0, 0, 0,
1004 (BVFree)free,
1005 0,
1006 kBIOSDevTypeHardDrive, 0);
1007 break;
1008 }
1009
1010 if ( bvr )
1011 {
1012 bvr->next = map->bvr;
1013 map->bvr = bvr;
1014 map->bvrcnt++;
1015 }
1016 }
1017
1018#if UFS_SUPPORT
1019 // Booting from a CD with an UFS filesystem embedded
1020 // in a booter partition.
1021
1022if ( booterUFS )
1023{
1024if ( map->bvrcnt == 0 )
1025{
1026map->bvr = booterUFS;
1027map->bvrcnt++;
1028}
1029else
1030{
1031free( booterUFS );
1032}
1033}
1034#endif
1035}
1036} while (0);
1037
1038/*
1039 * If no FDisk partition, then we will check for
1040 * an Apple partition map elsewhere.
1041 */
1042#if UNUSED
1043if (map && map->bvrcnt == 0)
1044{
1045static struct fdisk_part cdpart;
1046cdpart.systid = 0xCD;
1047
1048/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
1049bvr = newFDiskBVRef(
1050biosdev, 0,
10510,
1052&cdpart,
1053HFSInitPartition,
1054HFSLoadFile,
1055HFSReadFile,
1056HFSGetDirEntry,
1057HFSGetFileBlock,
1058HFSGetUUID,
1059HFSGetDescription,
1060HFSFree,
10610,
1062kBIOSDevTypeHardDrive, 0);
1063bvr->next = map->bvr;
1064map->bvr = bvr;
1065map->bvrcnt++;
1066}
1067#endif
1068// Actually this should always be true given the above code
1069// (unless malloc failed above)
1070if(map && map == gDiskBVMap)
1071{
1072// Don't leave a null map in the chain
1073if(map->bvrcnt == 0 && map->bvr == NULL)
1074{
1075gDiskBVMap = map->next;
1076free(map);
1077map = NULL;
1078}
1079}
1080
1081if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1082
1083return map ? map->bvr : NULL;
1084}
1085
1086//==============================================================================
1087
1088static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
1089{
1090struct DiskBVMap * map;
1091struct Block0 *block0_p;
1092unsigned int blksize;
1093unsigned int factor;
1094void *buffer = malloc(BPS);
1095
1096if (!buffer)
1097{
1098return NULL;
1099}
1100bzero(buffer,BPS);
1101
1102/* Check for alternate block size */
1103if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0)
1104{
1105return NULL;
1106}
1107block0_p = buffer;
1108if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE)
1109{
1110blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1111if (blksize != BPS)
1112{
1113free(buffer);
1114buffer = malloc(blksize);
1115if (!buffer)
1116{
1117return NULL;
1118}
1119bzero(buffer,BPS);
1120}
1121factor = blksize / BPS;
1122}
1123else
1124{
1125blksize = BPS;
1126factor = 1;
1127}
1128
1129do
1130{
1131// Create a new mapping.
1132
1133map = (struct DiskBVMap *) malloc( sizeof(*map) );
1134if ( map )
1135{
1136int error;
1137DPME *dpme_p = (DPME *)buffer;
1138UInt32 i, npart = UINT_MAX;
1139BVRef bvr;
1140
1141map->biosdev = biosdev;
1142map->bvr = NULL;
1143map->bvrcnt = 0;
1144map->next = gDiskBVMap;
1145gDiskBVMap = map;
1146
1147for (i=0; i<npart; i++)
1148{
1149error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1150
1151if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE)
1152{
1153break;
1154}
1155
1156if (i==0)
1157{
1158npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1159}
1160/*
1161printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1162dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1163dpme.dpme_pblock_start, dpme.dpme_pblocks,
1164dpme.dpme_lblock_start, dpme.dpme_lblocks,
1165dpme.dpme_boot_block);
1166*/
1167
1168if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0)
1169{
1170bvr = newAPMBVRef(biosdev,
1171i,
1172OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1173dpme_p,
1174HFSInitPartition,
1175HFSLoadFile,
1176HFSReadFile,
1177HFSGetDirEntry,
1178HFSGetFileBlock,
1179HFSGetUUID,
1180HFSGetDescription,
1181HFSFree,
11820,
1183kBIOSDevTypeHardDrive, 0);
1184bvr->next = map->bvr;
1185map->bvr = bvr;
1186map->bvrcnt++;
1187}
1188}
1189}
1190} while (0);
1191
1192free(buffer);
1193
1194if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1195
1196return map ? map->bvr : NULL;
1197}
1198
1199//==============================================================================
1200
1201/*
1202 * Trying to figure out the filsystem type of a given partition.
1203 */
1204static int probeFileSystem(int biosdev, unsigned int blkoff)
1205{
1206// detected filesystem type;
1207int result = -1;
1208int fatbits;
1209
1210// Allocating buffer for 4 sectors.
1211const void * probeBuffer = malloc(PROBEFS_SIZE);
1212if (probeBuffer == NULL)
1213{
1214goto exit;
1215}
1216
1217// Reading first 4 sectors of current partition
1218int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
1219
1220if (error)
1221{
1222goto exit;
1223}
1224
1225if (HFSProbe(probeBuffer))
1226{
1227result = FDISK_HFS;
1228}
1229else if (EX2Probe(probeBuffer))
1230{
1231result = FDISK_LINUX;
1232}
1233else if (FreeBSDProbe(probeBuffer))
1234{
1235result = FDISK_FREEBSD;
1236}
1237
1238else if (OpenBSDProbe(probeBuffer))
1239{
1240result = FDISK_OPENBSD;
1241}
1242
1243else if (BeFSProbe(probeBuffer))
1244{
1245result = FDISK_BEFS;
1246}
1247
1248else if (NTFSProbe(probeBuffer))
1249{
1250result = FDISK_NTFS;
1251}
1252
1253else if ( (fatbits = MSDOSProbe(probeBuffer)) )
1254{
1255switch (fatbits)
1256{
1257case 32:
1258default:
1259result = FDISK_FAT32;
1260break;
1261case 16:
1262result = FDISK_DOS16B;
1263break;
1264case 12:
1265result = FDISK_DOS12;
1266break;
1267}
1268}
1269else
1270{
1271// Couldn't detect filesystem type
1272result = 0;
1273}
1274
1275exit:
1276if (probeBuffer != NULL) free((void *)probeBuffer);
1277{
1278return result;
1279}
1280}
1281
1282//==============================================================================
1283
1284static bool isPartitionUsed(gpt_ent * partition)
1285{
1286
1287// Ask whether the given partition is used.
1288
1289return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1290}
1291
1292//==============================================================================
1293
1294static BVRef diskScanGPTBootVolumes(int biosdev, int * countPtr)
1295{
1296struct DiskBVMap *map = NULL;
1297
1298void *buffer = malloc(BPS);
1299
1300int error;
1301if ( (error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer )) != 0)
1302{
1303verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1304goto scanErr;
1305}
1306struct REAL_disk_blk0 *fdiskMap = buffer;
1307if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1308{
1309verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1310goto scanErr;
1311}
1312
1313int fdiskID = 0;
1314unsigned index;
1315for ( index = 0; index < FDISK_NPART; index++ )
1316{
1317if ( fdiskMap->parts[index].systid )
1318{
1319if ( fdiskMap->parts[index].systid == 0xEE )
1320{
1321// Fail if two 0xEE partitions are present which
1322// means the FDISK code will wind up parsing it.
1323if ( fdiskID )
1324{
1325goto scanErr;
1326}
1327
1328fdiskID = index + 1;
1329}
1330}
1331}
1332
1333if ( fdiskID == 0 )
1334{
1335goto scanErr;
1336}
1337
1338verbose("Attempting to read GPT\n");
1339
1340if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1341{
1342goto scanErr;
1343}
1344
1345gpt_hdr *headerMap = buffer;
1346
1347// Determine whether the partition header signature is present.
1348
1349if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1350{
1351goto scanErr;
1352}
1353
1354// Determine whether the partition header size is valid.
1355
1356UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1357UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1358
1359if ( headerSize < offsetof(gpt_hdr, padding) )
1360{
1361goto scanErr;
1362}
1363
1364if ( headerSize > BPS )
1365{
1366goto scanErr;
1367}
1368
1369// Determine whether the partition header checksum is valid.
1370
1371headerMap->hdr_crc_self = 0;
1372
1373if ( crc32(0, headerMap, headerSize) != headerCheck )
1374{
1375goto scanErr;
1376}
1377
1378// Determine whether the partition entry size is valid.
1379
1380UInt64 gptBlock = 0;
1381UInt32 gptCheck = 0;
1382UInt32 gptCount = 0;
1383UInt32 gptID = 0;
1384gpt_ent * gptMap = 0;
1385UInt32 gptSize = 0;
1386
1387gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1388gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1389gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1390gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1391
1392if ( gptSize < sizeof(gpt_ent) )
1393{
1394goto scanErr;
1395}
1396
1397// Allocate a buffer large enough to hold one map, rounded to a media block.
1398free(buffer);
1399buffer = NULL;
1400
1401UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1402if (bufferSize == 0)
1403{
1404goto scanErr;
1405}
1406buffer = malloc(bufferSize);
1407if (!buffer)
1408{
1409 goto scanErr;
1410}
1411
1412if (readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1413{
1414goto scanErr;
1415}
1416verbose("Read GPT\n");
1417
1418// Allocate a new map for this BIOS device and insert it into the chain
1419map = malloc(sizeof(*map));
1420if (!map)
1421{
1422goto scanErr;
1423}
1424map->biosdev = biosdev;
1425map->bvr = NULL;
1426map->bvrcnt = 0;
1427map->next = gDiskBVMap;
1428gDiskBVMap = map;
1429
1430// fdisk like partition type id.
1431int fsType = 0;
1432
1433for(gptID = 1; gptID <= gptCount; ++gptID) {
1434BVRef bvr = NULL;
1435unsigned int bvrFlags = 0;
1436
1437// size on disk can be larger than sizeof(gpt_ent)
1438gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1439
1440// NOTE: EFI_GUID's are in LE and we know we're on an x86.
1441// The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1442
1443if (isPartitionUsed(gptMap)) {
1444char stringuuid[100];
1445efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1446verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1447
1448// Getting fdisk like partition type.
1449fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1450
1451if ( (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) ) {
1452bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1453bvr = newGPTBVRef(biosdev,
1454gptID,
1455gptMap->ent_lba_start,
1456gptMap,
1457HFSInitPartition,
1458HFSLoadFile,
1459HFSReadFile,
1460HFSGetDirEntry,
1461HFSGetFileBlock,
1462HFSGetUUID,
1463HFSGetDescription,
1464HFSFree,
14650,
1466kBIOSDevTypeHardDrive, bvrFlags);
1467}
1468
1469// zef - foreign OS support
1470if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1471(efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ) {
1472switch (fsType)
1473{
1474case FDISK_NTFS:
1475bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
14760, 0, 0, 0, 0, 0, NTFSGetDescription,
1477(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1478break;
1479
1480case FDISK_LINUX:
1481bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
14820, 0, 0, 0, 0, 0, EX2GetDescription,
1483(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1484break;
1485
1486default:
1487bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
14880, 0, 0, 0, 0, 0, 0,
1489(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1490break;
1491}
1492
1493}
1494
1495// turbo - save our booter partition
1496// zef - only on original boot device
1497if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ) {
1498switch (fsType) {
1499case FDISK_HFS:
1500if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1501bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1502HFSInitPartition,
1503HFSLoadFile,
1504HFSReadFile,
1505HFSGetDirEntry,
1506HFSGetFileBlock,
1507HFSGetUUID,
1508HFSGetDescription,
1509HFSFree,
15100, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1511}
1512break;
1513
1514case FDISK_FAT32:
1515if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0) {
1516bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1517MSDOSInitPartition,
1518MSDOSLoadFile,
1519MSDOSReadFile,
1520MSDOSGetDirEntry,
1521MSDOSGetFileBlock,
1522MSDOSGetUUID,
1523MSDOSGetDescription,
1524MSDOSFree,
15250, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1526}
1527break;
1528
1529default:
1530if (biosdev == gBIOSDev) {
1531gBIOSBootVolume = bvr;
1532}
1533break;
1534}
1535}
1536
1537if (bvr)
1538{
1539// Fixup bvr with the fake fdisk partition type.
1540if (fsType > 0) {
1541bvr->part_type = fsType;
1542}
1543
1544bvr->next = map->bvr;
1545map->bvr = bvr;
1546++map->bvrcnt;
1547}
1548
1549}
1550}
1551
1552scanErr:
1553if (buffer) {
1554free(buffer);
1555}
1556
1557if(map) {
1558if(countPtr) *countPtr = map->bvrcnt;
1559{
1560return map->bvr;
1561}
1562
1563} else {
1564if(countPtr) *countPtr = 0;
1565{
1566return NULL;
1567}
1568}
1569}
1570
1571//==============================================================================
1572
1573static bool getOSVersion(BVRef bvr, char *str)
1574{
1575bool valid = false;
1576config_file_t systemVersion;
1577char dirSpec[512];
1578
1579sprintf(dirSpec, "hd(%d,%d)/com.apple.recovery.boot/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1580
1581if (!loadConfigFile(dirSpec, &systemVersion))
1582{
1583bvr->OSisInstaller = true;
1584valid = true;
1585}
1586
1587if (!valid)
1588{
1589sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1590
1591if (!loadConfigFile(dirSpec, &systemVersion))
1592{
1593bvr->OSisInstaller = true;
1594valid = true;
1595}
1596else
1597{
1598sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1599
1600if (!loadConfigFile(dirSpec, &systemVersion))
1601{
1602bvr->OSisServer = true;
1603valid = true;
1604}
1605/*else
1606{
1607sprintf(dirSpec, "hd(%d,%d)/.IAProductInfo", BIOS_DEV_UNIT(bvr), bvr->part_no);
1608
1609if (!loadConfigFile(dirSpec, &systemVersion))
1610{
1611
1612}
1613}
1614*/
1615}
1616}
1617
1618if (valid)
1619{
1620const char *val;
1621int len;
1622
1623if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1624{
1625// getValueForKey uses const char for val
1626// so copy it and trim
1627*str = '\0';
1628// crazybirdy
1629if (len > 4 && (val[3] == '1'))
1630{
1631strncat(str, val, MIN(len, 5));
1632}
1633else
1634{
1635strncat(str, val, MIN(len, 4));
1636}
1637}
1638else
1639{
1640valid = false;
1641}
1642}
1643
1644if(!valid)
1645{
1646int fh = -1;
1647sprintf(dirSpec, "hd(%d,%d)/.PhysicalMediaInstall", BIOS_DEV_UNIT(bvr), bvr->part_no);
1648fh = open(dirSpec, 0);
1649
1650if (fh >= 0)
1651{
1652valid = true;
1653bvr->OSisInstaller = true;
1654strcpy(bvr->OSVersion, "10.7"); // 10.7 +
1655close(fh);
1656}
1657else
1658{
1659sprintf(dirSpec, "hd(%d,%d)/.IAPhysicalMedia", BIOS_DEV_UNIT(bvr), bvr->part_no);
1660fh = open(dirSpec, 0);
1661
1662if (fh >= 0)
1663{
1664valid = true;
1665bvr->OSisInstaller = true;
1666strcpy(bvr->OSVersion, "10.9"); // 10.9 +
1667}
1668else
1669{
1670close(fh);
1671}
1672}
1673}
1674return valid;
1675}
1676
1677//==============================================================================
1678
1679static void scanFSLevelBVRSettings(BVRef chain)
1680{
1681BVRef bvr;
1682char dirSpec[512], fileSpec[512];
1683char label[BVSTRLEN];
1684int ret;
1685long flags;
1686u_int32_t time;
1687int fh, fileSize, error;
1688
1689for (bvr = chain; bvr; bvr = bvr->next) {
1690ret = -1;
1691error = 0;
1692
1693//
1694// Check for alternate volume label on boot helper partitions.
1695//
1696if (bvr->flags & kBVFlagBooter) {
1697sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1698strcpy(fileSpec, ".disk_label.contentDetails");
1699ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1700if (!ret) {
1701fh = open(strcat(dirSpec, fileSpec), 0);
1702fileSize = file_size(fh);
1703if (fileSize > 0 && fileSize < BVSTRLEN) {
1704if (read(fh, label, fileSize) != fileSize) {
1705error = -1;
1706}
1707} else {
1708error = -1;
1709}
1710
1711close(fh);
1712
1713if (!error)
1714{
1715label[fileSize] = '\0';
1716strcpy(bvr->altlabel, label);
1717}
1718}
1719}
1720
1721// Check for SystemVersion.plist or ServerVersion.plist to determine if a volume hosts an installed system.
1722
1723if (bvr->flags & kBVFlagNativeBoot)
1724{
1725if (getOSVersion(bvr,bvr->OSVersion) == true)
1726{
1727bvr->flags |= kBVFlagSystemVolume;
1728}
1729}
1730}
1731}
1732
1733//==============================================================================
1734
1735void rescanBIOSDevice(int biosdev)
1736{
1737struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1738CacheReset();
1739diskFreeMap(oldMap);
1740oldMap = NULL;
1741scanBootVolumes(biosdev, 0);
1742}
1743
1744//==============================================================================
1745
1746struct DiskBVMap* diskResetBootVolumes(int biosdev)
1747{
1748struct DiskBVMap * map;
1749struct DiskBVMap *prevMap = NULL;
1750for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1751if ( biosdev == map->biosdev ) {
1752break;
1753}
1754}
1755
1756if(map != NULL) {
1757verbose("Resetting BIOS device %xh\n", biosdev);
1758// Reset the biosbuf cache
1759cache_valid = false;
1760if(map == gDiskBVMap) {
1761gDiskBVMap = map->next;
1762} else if(prevMap != NULL) {
1763prevMap->next = map->next;
1764} else {
1765stop("");
1766}
1767}
1768// Return the old map, either to be freed, or reinserted later
1769return map;
1770}
1771
1772//==============================================================================
1773
1774// Frees a DiskBVMap and all of its BootVolume's
1775void diskFreeMap(struct DiskBVMap *map)
1776{
1777if(map != NULL)
1778{
1779while(map->bvr != NULL)
1780{
1781BVRef bvr = map->bvr;
1782map->bvr = bvr->next;
1783(*bvr->bv_free)(bvr);
1784}
1785
1786free(map);
1787}
1788}
1789
1790//==============================================================================
1791
1792BVRef diskScanBootVolumes(int biosdev, int * countPtr)
1793{
1794struct DiskBVMap *map;
1795BVRef bvr;
1796int count = 0;
1797
1798// Find an existing mapping for this device.
1799
1800for (map = gDiskBVMap; map; map = map->next)
1801{
1802if (biosdev == map->biosdev)
1803{
1804count = map->bvrcnt;
1805break;
1806}
1807}
1808
1809if (map == NULL)
1810{
1811bvr = diskScanGPTBootVolumes(biosdev, &count);
1812if (bvr == NULL)
1813{
1814bvr = diskScanFDiskBootVolumes(biosdev, &count);
1815}
1816if (bvr == NULL)
1817{
1818bvr = diskScanAPMBootVolumes(biosdev, &count);
1819}
1820if (bvr)
1821{
1822scanFSLevelBVRSettings(bvr);
1823}
1824}
1825else
1826{
1827bvr = map->bvr;
1828}
1829if (countPtr)
1830{
1831*countPtr += count;
1832}
1833return bvr;
1834}
1835
1836//==============================================================================
1837
1838BVRef getBVChainForBIOSDev(int biosdev)
1839{
1840BVRef chain = NULL;
1841struct DiskBVMap * map = NULL;
1842
1843for (map = gDiskBVMap; map; map = map->next)
1844{
1845if (map->biosdev == biosdev)
1846{
1847chain = map->bvr;
1848break;
1849}
1850}
1851
1852return chain;
1853}
1854
1855//==============================================================================
1856
1857BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1858{
1859BVRef chain = NULL;
1860BVRef bvr = NULL;
1861BVRef newBVR = NULL;
1862BVRef prevBVR = NULL;
1863
1864struct DiskBVMap * map = NULL;
1865int bvCount = 0;
1866
1867const char *raw = 0;
1868char* val = 0;
1869int len;
1870
1871getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1872if(raw)
1873{
1874val = XMLDecode(raw);
1875}
1876
1877/*
1878 * Traverse gDISKBVmap to get references for
1879 * individual bvr chains of each drive.
1880 */
1881for (map = gDiskBVMap; map; map = map->next)
1882{
1883for (bvr = map->bvr; bvr; bvr = bvr->next)
1884{
1885/*
1886 * Save the last bvr.
1887 */
1888if (newBVR)
1889{
1890prevBVR = newBVR;
1891}
1892
1893/*
1894 * Allocate and copy the matched bvr entry into a new one.
1895 */
1896newBVR = (BVRef) malloc(sizeof(*newBVR));
1897if (!newBVR)
1898{
1899continue;
1900}
1901bcopy(bvr, newBVR, sizeof(*newBVR));
1902
1903/*
1904 * Adjust the new bvr's fields.
1905 */
1906newBVR->next = NULL;
1907newBVR->filtered = true;
1908
1909if ( (!allowFlags || newBVR->flags & allowFlags)
1910&& (!denyFlags || !(newBVR->flags & denyFlags) )
1911&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1912) {
1913newBVR->visible = true;
1914}
1915
1916/*
1917 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1918 * to be able to hide foreign partitions from the boot menu.
1919 *
1920 */
1921if ( (newBVR->flags & kBVFlagForeignBoot) ) {
1922char *start, *next = val;
1923long len = 0;
1924do
1925{
1926start = strbreak(next, &next, &len);
1927if(len && matchVolumeToString(newBVR, start, len) )
1928{
1929newBVR->visible = false;
1930}
1931}
1932while ( next && *next );
1933}
1934
1935/*
1936 * Use the first bvr entry as the starting chain pointer.
1937 */
1938if (!chain) {
1939chain = newBVR;
1940}
1941
1942/*
1943 * Update the previous bvr's link pointer to use the new memory area.
1944 */
1945if (prevBVR) {
1946prevBVR->next = newBVR;
1947}
1948
1949if (newBVR->visible) {
1950bvCount++;
1951}
1952}
1953}
1954
1955#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1956for (bvr = chain; bvr; bvr = bvr->next)
1957{
1958printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1959}
1960printf("count: %d\n", bvCount);
1961getchar();
1962#endif
1963
1964*count = bvCount;
1965
1966free(val);
1967return chain;
1968}
1969
1970//==============================================================================
1971
1972int freeFilteredBVChain(const BVRef chain)
1973{
1974int ret = 1;
1975BVRef bvr = chain;
1976BVRef nextBVR = NULL;
1977
1978while (bvr)
1979{
1980nextBVR = bvr->next;
1981
1982if (bvr->filtered)
1983{
1984free(bvr);
1985}
1986else
1987{
1988ret = 0;
1989break;
1990}
1991
1992bvr = nextBVR;
1993}
1994
1995return ret;
1996}
1997
1998//==============================================================================
1999
2000static const struct NamedValue fdiskTypes[] =
2001{
2002{ FDISK_NTFS,"Windows NTFS" },
2003{ FDISK_DOS12,"Windows FAT12" },
2004{ FDISK_DOS16B,"Windows FAT16" },
2005{ FDISK_DOS16S,"Windows FAT16" },
2006{ FDISK_DOS16SLBA,"Windows FAT16" },
2007{ FDISK_SMALLFAT32,"Windows FAT32" },
2008{ FDISK_FAT32,"Windows FAT32" },
2009{ FDISK_FREEBSD,"FreeBSD" },
2010{ FDISK_OPENBSD,"OpenBSD" },
2011{ FDISK_LINUX,"Linux" },
2012{ FDISK_UFS,"Apple UFS" },
2013{ FDISK_HFS,"Apple HFS" },
2014{ FDISK_BOOTER,"Apple Boot/UFS" },
2015{ FDISK_BEFS,"Haiku" },
2016{ 0xCD,"CD-ROM" },
2017{ 0x00,0 } /* must be last */
2018};
2019
2020//==============================================================================
2021
2022bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
2023{
2024char testStr[128];
2025
2026if ( !bvr || !match || !*match)
2027{
2028return 0;
2029}
2030
2031if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
2032{
2033 return 0;
2034}
2035
2036// Try to match hd(x,y) first.
2037sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
2038if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2039{
2040return true;
2041}
2042
2043// Try to match volume UUID.
2044if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
2045{
2046if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2047{
2048return true;
2049}
2050}
2051
2052// Try to match volume label (always quoted).
2053if ( bvr->description )
2054{
2055bvr->description(bvr, testStr, sizeof(testStr)-1);
2056if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
2057{
2058return true;
2059}
2060}
2061
2062return false;
2063}
2064
2065//==============================================================================
2066
2067/* If Rename Partition has defined an alias, then extract it for description purpose.
2068 * The format for the rename string is the following:
2069 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
2070 */
2071
2072bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
2073{
2074char *aliasList, *entryStart, *entryNext;
2075
2076if ( !str || strMaxLen <= 0)
2077{
2078return false;
2079}
2080
2081aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
2082if ( !aliasList )
2083{
2084return false;
2085}
2086
2087for ( entryStart = entryNext = aliasList; entryNext && *entryNext; entryStart = entryNext )
2088{
2089char *volStart, *volEnd, *aliasStart;
2090long volLen, aliasLen;
2091
2092// Delimit current entry
2093entryNext = strchr(entryStart, ';');
2094if ( entryNext )
2095{
2096*entryNext = '\0';
2097entryNext++;
2098}
2099
2100volStart = strbreak(entryStart, &volEnd, &volLen);
2101if(!volLen)
2102{
2103continue;
2104}
2105
2106aliasStart = strbreak(volEnd, 0, &aliasLen);
2107if(!aliasLen)
2108{
2109continue;
2110}
2111
2112if ( matchVolumeToString(bvr, volStart, volLen) )
2113{
2114strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
2115free(aliasList);
2116
2117return true;
2118}
2119}
2120
2121free(aliasList);
2122return false;
2123}
2124
2125//==============================================================================
2126
2127void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
2128{
2129unsigned char type;
2130char *p = str;
2131
2132if(!bvr || !p || strMaxLen <= 0)
2133{
2134return;
2135}
2136
2137type = (unsigned char) bvr->part_type;
2138
2139if (useDeviceDescription)
2140{
2141int len = getDeviceDescription(bvr, str);
2142if(len >= strMaxLen)
2143{
2144return;
2145}
2146
2147strcpy(str + len, bvr->OSisInstaller ? " (Installer) " : " ");
2148len += bvr->OSisInstaller ? 13 : 1;
2149strMaxLen -= len;
2150p += len;
2151}
2152
2153/* See if a partition rename is preferred */
2154if (getVolumeLabelAlias(bvr, p, strMaxLen))
2155{
2156strncpy(bvr->label, p, strMaxLen);
2157return; // we're done here no need to seek for real name
2158}
2159
2160// Get the volume label using filesystem specific functions or use the alternate volume label if available.
2161
2162if (*bvr->altlabel != '\0')
2163{
2164strncpy(p, bvr->altlabel, strMaxLen);
2165}
2166else if (bvr->description)
2167{
2168bvr->description(bvr, p, strMaxLen);
2169}
2170
2171if (*p == '\0')
2172{
2173const char * name = getNameForValue( fdiskTypes, type );
2174
2175if (name == NULL)
2176{
2177name = bvr->type_name;
2178}
2179
2180if (name == NULL)
2181{
2182sprintf(p, "TYPE %02x", type);
2183}
2184else
2185{
2186strncpy(p, name, strMaxLen);
2187}
2188}
2189
2190// Set the devices label
2191sprintf(bvr->label, p);
2192}
2193
2194
2195//==============================================================================
2196
2197int readBootSector(int biosdev, unsigned int secno, void * buffer)
2198{
2199int error;
2200struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
2201
2202if (bootSector == NULL)
2203{
2204if (gBootSector == NULL)
2205{
2206gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
2207
2208if (gBootSector == NULL)
2209{
2210return -1;
2211}
2212}
2213
2214bootSector = gBootSector;
2215}
2216
2217error = readBytes(biosdev, secno, 0, BPS, bootSector);
2218
2219if (error || bootSector->signature != DISK_SIGNATURE)
2220{
2221return -1;
2222}
2223return 0;
2224}
2225
2226//==============================================================================
2227
2228/*
2229 * Format of boot1f32 block.
2230 */
2231
2232#define BOOT1F32_MAGIC "BOOT "
2233#define BOOT1F32_MAGICLEN 11
2234
2235struct disk_boot1f32_blk
2236{
2237unsigned char init[3];
2238unsigned char fsheader[87];
2239unsigned char magic[BOOT1F32_MAGICLEN];
2240unsigned char bootcode[409];
2241unsigned short signature;
2242};
2243
2244//==============================================================================
2245
2246int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
2247{
2248struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
2249int error;
2250
2251if ( bootSector == NULL )
2252{
2253if ( gBootSector == NULL )
2254{
2255gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
2256if ( gBootSector == NULL )
2257{
2258return -1;
2259}
2260}
2261bootSector = (struct disk_boot1f32_blk *) gBootSector;
2262}
2263
2264error = readBytes( biosdev, secno, 0, BPS, bootSector );
2265if ( error || bootSector->signature != DISK_SIGNATURE || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2266{
2267return -1;
2268}
2269return 0;
2270}
2271
2272
2273//==============================================================================
2274// Handle seek request from filesystem modules.
2275
2276void diskSeek(BVRef bvr, long long position)
2277{
2278bvr->fs_boff = position / BPS;
2279bvr->fs_byteoff = position % BPS;
2280}
2281
2282
2283//==============================================================================
2284// Handle read request from filesystem modules.
2285
2286int diskRead(BVRef bvr, long addr, long length)
2287{
2288return readBytes(bvr->biosdev, bvr->fs_boff + bvr->part_boff, bvr->fs_byteoff, length, (void *) addr);
2289}
2290
2291//==============================================================================
2292
2293int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2294{
2295int secs;
2296unsigned char *cbuf = (unsigned char *)buffer;
2297unsigned int copy_len;
2298int rc;
2299
2300if ((len & (BPS-1)) != 0)
2301{
2302error("raw disk read not sector aligned");
2303return -1;
2304}
2305secno += bvr->part_boff;
2306
2307cache_valid = false;
2308
2309while (len > 0)
2310{
2311secs = len / BPS;
2312if (secs > N_CACHE_SECS)
2313{
2314secs = N_CACHE_SECS;
2315}
2316copy_len = secs * BPS;
2317
2318//printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2319if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0)
2320{
2321/* Ignore corrected ECC errors */
2322if (rc != ECC_CORRECTED_ERR)
2323{
2324error(" EBIOS read error: %s\n", bios_error(rc), rc);
2325error(" Block %d Sectors %d\n", secno, secs);
2326return rc;
2327}
2328}
2329bcopy( trackbuf, cbuf, copy_len );
2330len -= copy_len;
2331cbuf += copy_len;
2332secno += secs;
2333spinActivityIndicator(secs);
2334}
2335
2336return 0;
2337}
2338
2339//==============================================================================
2340
2341int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2342{
2343 int secs;
2344 unsigned char *cbuf = (unsigned char *)buffer;
2345 unsigned int copy_len;
2346 int rc;
2347
2348if ((len & (BPS-1)) != 0)
2349{
2350error("raw disk write not sector aligned");
2351return -1;
2352}
2353secno += bvr->part_boff;
2354
2355cache_valid = false;
2356
2357while (len > 0)
2358{
2359secs = len / BPS;
2360if (secs > N_CACHE_SECS)
2361{
2362secs = N_CACHE_SECS;
2363}
2364copy_len = secs * BPS;
2365
2366bcopy( cbuf, trackbuf, copy_len );
2367//printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2368if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0)
2369{
2370error(" EBIOS write error: %s\n", bios_error(rc), rc);
2371error(" Block %d Sectors %d\n", secno, secs);
2372return rc;
2373}
2374
2375len -= copy_len;
2376cbuf += copy_len;
2377secno += secs;
2378spinActivityIndicator(secs);
2379}
2380
2381return 0;
2382}
2383
2384//==============================================================================
2385
2386int diskIsCDROM(BVRef bvr)
2387{
2388struct driveInfo di;
2389
2390if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation)
2391{
2392return 1;
2393}
2394return 0;
2395}
2396
2397//==============================================================================
2398
2399int biosDevIsCDROM(int biosdev)
2400{
2401struct driveInfo di;
2402
2403if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2404{
2405return 1;
2406}
2407return 0;
2408}
2409

Archive Download this file

Revision: 2460