Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1996