Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2238