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
1026 if(map == gDiskBVMap)
1027 {
1028 // Don't leave a null map in the chain
1029 if(map->bvrcnt == 0 && map->bvr == NULL)
1030 {
1031 gDiskBVMap = map->next;
1032 free(map);
1033 map = NULL;
1034 }
1035 }
1036
1037 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1038
1039 return map ? map->bvr : NULL;
1040}
1041
1042//==========================================================================
1043
1044static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
1045{
1046 struct DiskBVMap * map;
1047 struct Block0 *block0_p;
1048 unsigned int blksize;
1049 unsigned int factor;
1050 void *buffer = malloc(BPS);
1051
1052 /* Check for alternate block size */
1053 if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
1054 return NULL;
1055 }
1056 block0_p = buffer;
1057 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
1058 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1059 if (blksize != BPS) {
1060 free(buffer);
1061 buffer = malloc(blksize);
1062 }
1063 factor = blksize / BPS;
1064 } else {
1065 blksize = BPS;
1066 factor = 1;
1067 }
1068
1069 do {
1070 // Create a new mapping.
1071
1072 map = (struct DiskBVMap *) malloc( sizeof(*map) );
1073 if ( map )
1074 {
1075 int error;
1076 DPME *dpme_p = (DPME *)buffer;
1077 UInt32 i, npart = UINT_MAX;
1078 BVRef bvr;
1079
1080 map->biosdev = biosdev;
1081 map->bvr = NULL;
1082 map->bvrcnt = 0;
1083 map->next = gDiskBVMap;
1084 gDiskBVMap = map;
1085
1086 for (i=0; i<npart; i++) {
1087 error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1088
1089 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
1090 break;
1091 }
1092
1093 if (i==0) {
1094 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1095 }
1096 /*
1097 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1098 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1099 dpme.dpme_pblock_start, dpme.dpme_pblocks,
1100 dpme.dpme_lblock_start, dpme.dpme_lblocks,
1101 dpme.dpme_boot_block);
1102 */
1103
1104 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
1105 bvr = newAPMBVRef(biosdev,
1106 i,
1107 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1108 dpme_p,
1109 HFSInitPartition,
1110 HFSLoadFile,
1111 HFSReadFile,
1112 HFSGetDirEntry,
1113 HFSGetFileBlock,
1114 HFSGetUUID,
1115 HFSGetDescription,
1116 HFSFree,
1117 0,
1118 kBIOSDevTypeHardDrive, 0);
1119 bvr->next = map->bvr;
1120 map->bvr = bvr;
1121 map->bvrcnt++;
1122 }
1123 }
1124 }
1125 } while (0);
1126
1127 free(buffer);
1128
1129 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1130
1131 return map ? map->bvr : NULL;
1132}
1133
1134//==========================================================================
1135
1136// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1137
1138/*
1139 * Trying to figure out the filsystem type of a given partition.
1140 */
1141static int probeFileSystem(int biosdev, unsigned int blkoff)
1142{
1143 // detected filesystem type;
1144 int result = -1;
1145 int fatbits;
1146
1147 // Allocating buffer for 4 sectors.
1148 const void * probeBuffer = malloc(PROBEFS_SIZE);
1149 if (probeBuffer == NULL)
1150 goto exit;
1151
1152 // Reading first 4 sectors of current partition
1153 int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
1154 if (error)
1155 goto exit;
1156
1157 if (HFSProbe(probeBuffer))
1158 result = FDISK_HFS;
1159 else if (EX2Probe(probeBuffer))
1160 result = FDISK_LINUX;
1161 else if (FreeBSDProbe(probeBuffer))
1162 result = FDISK_FREEBSD;
1163 else if (OpenBSDProbe(probeBuffer))
1164 result = FDISK_OPENBSD;
1165 else if (NTFSProbe(probeBuffer))
1166 result = FDISK_NTFS;
1167 else if (BeFSProbe(probeBuffer))
1168 result = FDISK_BEFS;
1169 else if ( (fatbits = MSDOSProbe(probeBuffer)) )
1170 {
1171 switch (fatbits)
1172 {
1173 case 32:
1174 default:
1175 result = FDISK_FAT32;
1176 break;
1177 case 16:
1178 result = FDISK_DOS16B;
1179 break;
1180 case 12:
1181 result = FDISK_DOS12;
1182 break;
1183 }
1184 }
1185 else
1186 // Couldn't detect filesystem type
1187 result = 0;
1188
1189exit:
1190 if (probeBuffer != NULL) free((void *)probeBuffer);
1191 return result;
1192}
1193
1194static bool isPartitionUsed(gpt_ent * partition)
1195{
1196 //
1197 // Ask whether the given partition is used.
1198 //
1199
1200 return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1201}
1202
1203// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1204
1205static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )
1206{
1207 struct DiskBVMap * map = NULL;
1208 void *buffer = malloc(BPS);
1209 int error;
1210 if ( (error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer )) != 0) {
1211 verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1212 goto scanErr;
1213 }
1214 struct REAL_disk_blk0 *fdiskMap = buffer;
1215 if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1216 {
1217 verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1218 goto scanErr;
1219 }
1220
1221 int fdiskID = 0;
1222 unsigned index;
1223 for ( index = 0; index < FDISK_NPART; index++ )
1224 {
1225 if ( fdiskMap->parts[index].systid )
1226 {
1227 if ( fdiskMap->parts[index].systid == 0xEE )
1228 {
1229 // Fail if two 0xEE partitions are present which
1230 // means the FDISK code will wind up parsing it.
1231 if ( fdiskID ) goto scanErr;
1232
1233 fdiskID = index + 1;
1234 }
1235 }
1236 }
1237
1238 if ( fdiskID == 0 ) goto scanErr;
1239 verbose("Attempting to read GPT\n");
1240
1241 if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1242 goto scanErr;
1243
1244 gpt_hdr *headerMap = buffer;
1245
1246 // Determine whether the partition header signature is present.
1247
1248 if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1249 {
1250 goto scanErr;
1251 }
1252
1253 // Determine whether the partition header size is valid.
1254
1255 UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1256 UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1257
1258 if ( headerSize < offsetof(gpt_hdr, padding) )
1259 {
1260 goto scanErr;
1261 }
1262
1263 if ( headerSize > BPS )
1264 {
1265 goto scanErr;
1266 }
1267
1268 // Determine whether the partition header checksum is valid.
1269
1270 headerMap->hdr_crc_self = 0;
1271
1272 if ( crc32(0, headerMap, headerSize) != headerCheck )
1273 {
1274 goto scanErr;
1275 }
1276
1277 // Determine whether the partition entry size is valid.
1278
1279 UInt64 gptBlock = 0;
1280 UInt32 gptCheck = 0;
1281 UInt32 gptCount = 0;
1282 UInt32 gptID = 0;
1283 gpt_ent * gptMap = 0;
1284 UInt32 gptSize = 0;
1285
1286 gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1287 gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1288 gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1289 gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1290
1291 if ( gptSize < sizeof(gpt_ent) )
1292 {
1293 goto scanErr;
1294 }
1295
1296 // Allocate a buffer large enough to hold one map, rounded to a media block.
1297 free(buffer);
1298 buffer = NULL;
1299
1300 UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1301 if(bufferSize == 0)
1302 goto scanErr;
1303 buffer = malloc(bufferSize);
1304
1305 if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1306 goto scanErr;
1307
1308 verbose("Read GPT\n");
1309
1310 // Allocate a new map for this BIOS device and insert it into the chain
1311 map = malloc(sizeof(*map));
1312 map->biosdev = biosdev;
1313 map->bvr = NULL;
1314 map->bvrcnt = 0;
1315 map->next = gDiskBVMap;
1316 gDiskBVMap = map;
1317
1318 // fdisk like partition type id.
1319 int fsType = 0;
1320
1321 for(gptID = 1; gptID <= gptCount; ++gptID)
1322 {
1323BVRef bvr = NULL;
1324unsigned int bvrFlags = 0;
1325
1326 // size on disk can be larger than sizeof(gpt_ent)
1327 gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1328
1329 // NOTE: EFI_GUID's are in LE and we know we're on an x86.
1330 // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1331
1332 if (isPartitionUsed(gptMap))
1333 {
1334 char stringuuid[100];
1335 efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1336 verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1337
1338 // Getting fdisk like partition type.
1339 fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1340
1341 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1342 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1343 {
1344 bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1345 bvr = newGPTBVRef(biosdev,
1346 gptID,
1347 gptMap->ent_lba_start,
1348 gptMap,
1349 HFSInitPartition,
1350 HFSLoadFile,
1351 HFSReadFile,
1352 HFSGetDirEntry,
1353 HFSGetFileBlock,
1354 HFSGetUUID,
1355 HFSGetDescription,
1356 HFSFree,
1357 0,
1358 kBIOSDevTypeHardDrive, bvrFlags);
1359 }
1360
1361// zef - foreign OS support
1362 if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1363 (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1364 {
1365switch (fsType)
1366 {
1367 case FDISK_NTFS:
1368 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1369 0, 0, 0, 0, 0, 0, NTFSGetDescription,
1370 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1371break;
1372 case FDISK_LINUX:
1373 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1374 0, 0, 0, 0, 0, 0, EX2GetDescription,
1375 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1376break;
1377
1378 default:
1379 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1380 0, 0, 0, 0, 0, 0, 0,
1381 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1382 break;
1383 }
1384
1385 }
1386
1387 // turbo - save our booter partition
1388 // zef - only on original boot device
1389 if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1390 {
1391switch (fsType)
1392 {
1393 case FDISK_HFS:
1394 if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1395 {
1396 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1397 HFSInitPartition,
1398 HFSLoadFile,
1399 HFSReadFile,
1400 HFSGetDirEntry,
1401 HFSGetFileBlock,
1402 HFSGetUUID,
1403 HFSGetDescription,
1404 HFSFree,
1405 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1406 }
1407 break;
1408
1409 case FDISK_FAT32:
1410 if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1411 {
1412 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1413 MSDOSInitPartition,
1414 MSDOSLoadFile,
1415 MSDOSReadFile,
1416 MSDOSGetDirEntry,
1417 MSDOSGetFileBlock,
1418 MSDOSGetUUID,
1419 MSDOSGetDescription,
1420 MSDOSFree,
1421 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1422 }
1423 break;
1424
1425 if (biosdev == gBIOSDev)
1426 gBIOSBootVolume = bvr;
1427 }
1428 }
1429
1430if (bvr)
1431{
1432 // Fixup bvr with the fake fdisk partition type.
1433 if (fsType > 0) bvr->part_type = fsType;
1434
1435bvr->next = map->bvr;
1436map->bvr = bvr;
1437++map->bvrcnt;
1438}
1439
1440 }
1441 }
1442
1443scanErr:
1444 free(buffer);
1445
1446 if(map)
1447 {
1448 if(countPtr) *countPtr = map->bvrcnt;
1449 return map->bvr;
1450 }
1451 else
1452 {
1453 if(countPtr) *countPtr = 0;
1454 return NULL;
1455 }
1456}
1457
1458static bool getOSVersion(BVRef bvr, char *str)
1459{
1460bool valid = false;
1461config_file_t systemVersion;
1462char dirSpec[512];
1463
1464sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1465
1466if (!loadConfigFile(dirSpec, &systemVersion))
1467{
1468valid = true;
1469}
1470else
1471{
1472sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1473
1474if (!loadConfigFile(dirSpec, &systemVersion))
1475{
1476 bvr->OSisServer = true;
1477valid = true;
1478}
1479}
1480
1481if (valid)
1482{
1483const char *val;
1484int len;
1485
1486if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1487{
1488// getValueForKey uses const char for val
1489// so copy it and trim
1490*str = '\0';
1491strncat(str, val, MIN(len, 4));
1492}
1493else
1494valid = false;
1495}
1496
1497return valid;
1498}
1499
1500//==========================================================================
1501
1502static void scanFSLevelBVRSettings(BVRef chain)
1503{
1504 BVRef bvr;
1505 char dirSpec[512], fileSpec[512];
1506 char label[BVSTRLEN];
1507 int ret;
1508 long flags, time;
1509 int fh, fileSize, error;
1510
1511 for (bvr = chain; bvr; bvr = bvr->next)
1512 {
1513 ret = -1;
1514 error = 0;
1515
1516 //
1517 // Check for alternate volume label on boot helper partitions.
1518 //
1519 if (bvr->flags & kBVFlagBooter)
1520 {
1521 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1522 strcpy(fileSpec, ".disk_label.contentDetails");
1523 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1524 if (!ret)
1525 {
1526 fh = open(strcat(dirSpec, fileSpec), 0);
1527 fileSize = file_size(fh);
1528 if (fileSize > 0 && fileSize < BVSTRLEN)
1529 {
1530 if (read(fh, label, fileSize) != fileSize)
1531 error = -1;
1532 }
1533 else
1534 error = -1;
1535
1536 close(fh);
1537
1538 if (!error)
1539 {
1540 label[fileSize] = '\0';
1541 strcpy(bvr->altlabel, label);
1542 }
1543 }
1544 }
1545
1546 //
1547 // Check for SystemVersion.plist or ServerVersion.plist
1548 // to determine if a volume hosts an installed system.
1549 //
1550 if (bvr->flags & kBVFlagNativeBoot)
1551 {
1552 if (getOSVersion(bvr,bvr->OSVersion) == true)
1553 {
1554 bvr->flags |= kBVFlagSystemVolume;
1555 }
1556 }
1557
1558 }
1559}
1560
1561void rescanBIOSDevice(int biosdev)
1562{
1563struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1564CacheReset();
1565diskFreeMap(oldMap);
1566oldMap = NULL;
1567scanBootVolumes(biosdev, 0);
1568}
1569
1570struct DiskBVMap* diskResetBootVolumes(int biosdev)
1571{
1572 struct DiskBVMap * map;
1573 struct DiskBVMap *prevMap = NULL;
1574 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1575 if ( biosdev == map->biosdev ) {
1576 break;
1577 }
1578 }
1579 if(map != NULL)
1580 {
1581 verbose("Resetting BIOS device %xh\n", biosdev);
1582 // Reset the biosbuf cache
1583 cache_valid = false;
1584 if(map == gDiskBVMap)
1585 gDiskBVMap = map->next;
1586 else if(prevMap != NULL)
1587 prevMap->next = map->next;
1588 else
1589 stop("");
1590 }
1591 // Return the old map, either to be freed, or reinserted later
1592 return map;
1593}
1594
1595// Frees a DiskBVMap and all of its BootVolume's
1596void diskFreeMap(struct DiskBVMap *map)
1597{
1598 if(map != NULL)
1599 {
1600 while(map->bvr != NULL)
1601 {
1602 BVRef bvr = map->bvr;
1603 map->bvr = bvr->next;
1604 (*bvr->bv_free)(bvr);
1605 }
1606 free(map);
1607 }
1608}
1609
1610BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1611{
1612 struct DiskBVMap * map = NULL;
1613 BVRef bvr;
1614 int count = 0;
1615
1616 // Find an existing mapping for this device.
1617
1618 for ( map = gDiskBVMap; map; map = map->next ) {
1619 if ( biosdev == map->biosdev ) {
1620 count = map->bvrcnt;
1621 break;
1622 }
1623 }
1624
1625 if (map == NULL) {
1626 bvr = diskScanGPTBootVolumes(biosdev, &count);
1627 if (bvr == NULL) {
1628 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1629 }
1630 if (bvr == NULL) {
1631 bvr = diskScanAPMBootVolumes(biosdev, &count);
1632 }
1633 if (bvr)
1634 {
1635 scanFSLevelBVRSettings(bvr);
1636 }
1637 } else {
1638 bvr = map->bvr;
1639 }
1640 if (countPtr) *countPtr += count;
1641 return bvr;
1642}
1643
1644BVRef getBVChainForBIOSDev(int biosdev)
1645{
1646 BVRef chain = NULL;
1647 struct DiskBVMap * map = NULL;
1648
1649 for (map = gDiskBVMap; map; map = map->next)
1650 {
1651 if (map->biosdev == biosdev)
1652 {
1653 chain = map->bvr;
1654 break;
1655 }
1656 }
1657
1658 return chain;
1659}
1660
1661BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1662{
1663 BVRef chain = NULL;
1664 BVRef bvr = NULL;
1665 BVRef newBVR = NULL;
1666 BVRef prevBVR = NULL;
1667
1668 struct DiskBVMap * map = NULL;
1669 int bvCount = 0;
1670
1671 const char *raw = 0;
1672 char* val = 0;
1673 int len;
1674
1675 getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1676 if(raw)
1677 {
1678 val = XMLDecode(raw);
1679 }
1680
1681 /*
1682 * Traverse gDISKBVmap to get references for
1683 * individual bvr chains of each drive.
1684 */
1685 for (map = gDiskBVMap; map; map = map->next)
1686 {
1687 for (bvr = map->bvr; bvr; bvr = bvr->next)
1688 {
1689 /*
1690 * Save the last bvr.
1691 */
1692 if (newBVR) prevBVR = newBVR;
1693
1694 /*
1695 * Allocate and copy the matched bvr entry into a new one.
1696 */
1697 newBVR = (BVRef) malloc(sizeof(*newBVR));
1698 bcopy(bvr, newBVR, sizeof(*newBVR));
1699
1700 /*
1701 * Adjust the new bvr's fields.
1702 */
1703 newBVR->next = NULL;
1704 newBVR->filtered = true;
1705
1706 if ( (!allowFlags || newBVR->flags & allowFlags)
1707 && (!denyFlags || !(newBVR->flags & denyFlags) )
1708 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1709 )
1710 newBVR->visible = true;
1711
1712 /*
1713 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1714 * to be able to hide foreign partitions from the boot menu.
1715 *
1716 */
1717 if ( (newBVR->flags & kBVFlagForeignBoot) )
1718 {
1719 char *start, *next = val;
1720 long len = 0;
1721 do
1722 {
1723 start = strbreak(next, &next, &len);
1724 if(len && matchVolumeToString(newBVR, start, len) )
1725 newBVR->visible = false;
1726 }
1727 while ( next && *next );
1728 }
1729
1730 /*
1731 * Use the first bvr entry as the starting chain pointer.
1732 */
1733 if (!chain)
1734 chain = newBVR;
1735
1736 /*
1737 * Update the previous bvr's link pointer to use the new memory area.
1738 */
1739 if (prevBVR)
1740 prevBVR->next = newBVR;
1741
1742 if (newBVR->visible)
1743 bvCount++;
1744 }
1745 }
1746
1747#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1748 for (bvr = chain; bvr; bvr = bvr->next)
1749 {
1750 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1751 }
1752 printf("count: %d\n", bvCount);
1753 getchar();
1754#endif
1755
1756 *count = bvCount;
1757
1758 free(val);
1759 return chain;
1760}
1761
1762int freeFilteredBVChain(const BVRef chain)
1763{
1764 int ret = 1;
1765 BVRef bvr = chain;
1766 BVRef nextBVR = NULL;
1767
1768 while (bvr)
1769 {
1770 nextBVR = bvr->next;
1771
1772 if (bvr->filtered)
1773 {
1774 free(bvr);
1775 }
1776 else
1777 {
1778 ret = 0;
1779 break;
1780 }
1781
1782 bvr = nextBVR;
1783 }
1784
1785 return ret;
1786}
1787
1788//==========================================================================
1789
1790static const struct NamedValue fdiskTypes[] =
1791{
1792{ FDISK_NTFS,"Windows NTFS" },
1793{ FDISK_DOS12,"Windows FAT12" },
1794{ FDISK_DOS16B,"Windows FAT16" },
1795{ FDISK_DOS16S,"Windows FAT16" },
1796{ FDISK_DOS16SLBA,"Windows FAT16" },
1797{ FDISK_SMALLFAT32,"Windows FAT32" },
1798{ FDISK_FAT32,"Windows FAT32" },
1799{ FDISK_FREEBSD,"FreeBSD" },
1800{ FDISK_OPENBSD,"OpenBSD" },
1801{ FDISK_LINUX,"Linux" },
1802{ FDISK_UFS,"Apple UFS" },
1803{ FDISK_HFS,"Apple HFS" },
1804{ FDISK_BOOTER,"Apple Boot/UFS" },
1805{ FDISK_BEFS,"Haiku" },
1806{ 0xCD,"CD-ROM" },
1807{ 0x00,0 } /* must be last */
1808};
1809
1810//==========================================================================
1811
1812bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1813{
1814char testStr[128];
1815
1816if ( !bvr || !match || !*match)
1817return 0;
1818
1819if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1820 return 0;
1821
1822 // Try to match hd(x,y) first.
1823 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1824 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1825 return true;
1826
1827 // Try to match volume UUID.
1828 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1829 {
1830 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1831 return true;
1832 }
1833
1834 // Try to match volume label (always quoted).
1835 if ( bvr->description )
1836 {
1837 bvr->description(bvr, testStr, sizeof(testStr)-1);
1838 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1839 return true;
1840 }
1841
1842 return false;
1843}
1844
1845/* If Rename Partition has defined an alias, then extract it for description purpose.
1846 * The format for the rename string is the following:
1847 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
1848 */
1849
1850bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
1851{
1852 char *aliasList, *entryStart, *entryNext;
1853
1854 if ( !str || strMaxLen <= 0)
1855 return false;
1856
1857 aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
1858 if ( !aliasList )
1859 return false;
1860
1861 for ( entryStart = entryNext = aliasList;
1862 entryNext && *entryNext;
1863 entryStart = entryNext )
1864 {
1865 char *volStart, *volEnd, *aliasStart;
1866 long volLen, aliasLen;
1867
1868 // Delimit current entry
1869 entryNext = strchr(entryStart, ';');
1870 if ( entryNext )
1871 {
1872 *entryNext = '\0';
1873 entryNext++;
1874 }
1875
1876 volStart = strbreak(entryStart, &volEnd, &volLen);
1877 if(!volLen)
1878 continue;
1879
1880 aliasStart = strbreak(volEnd, 0, &aliasLen);
1881 if(!aliasLen)
1882 continue;
1883
1884 if ( matchVolumeToString(bvr, volStart, volLen) )
1885 {
1886 strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
1887 free(aliasList);
1888
1889 return true;
1890 }
1891 }
1892
1893 free(aliasList);
1894 return false;
1895}
1896
1897void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1898{
1899 unsigned char type;
1900 char *p = str;
1901
1902 if(!bvr || !p || strMaxLen <= 0)
1903 return;
1904
1905 type = (unsigned char) bvr->part_type;
1906
1907 if (useDeviceDescription)
1908 {
1909 int len = getDeviceDescription(bvr, str);
1910 if(len >= strMaxLen)
1911 return;
1912
1913 strcpy(str + len, " ");
1914 len++;
1915 strMaxLen -= len;
1916 p += len;
1917 }
1918
1919 /* See if a partition rename is preferred */
1920 if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
1921 strncpy(bvr->label, p, strMaxLen);
1922 return; // we're done here no need to seek for real name
1923 }
1924
1925 //
1926 // Get the volume label using filesystem specific functions
1927 // or use the alternate volume label if available.
1928 //
1929if (*bvr->altlabel != '\0')
1930 strncpy(p, bvr->altlabel, strMaxLen);
1931else if (bvr->description)
1932 bvr->description(bvr, p, strMaxLen);
1933
1934 if (*p == '\0') {
1935 const char * name = getNameForValue( fdiskTypes, type );
1936 if (name == NULL) {
1937 name = bvr->type_name;
1938 }
1939 if (name == NULL) {
1940 sprintf(p, "TYPE %02x", type);
1941 } else {
1942 strncpy(p, name, strMaxLen);
1943 }
1944 }
1945
1946 // Set the devices label
1947 sprintf(bvr->label, p);
1948}
1949
1950//==========================================================================
1951int readBootSector(int biosdev, unsigned int secno, void * buffer)
1952{
1953int error;
1954struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
1955
1956if (bootSector == NULL)
1957{
1958if (gBootSector == NULL)
1959{
1960gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1961
1962if (gBootSector == NULL)
1963{
1964return -1;
1965}
1966}
1967
1968 bootSector = gBootSector;
1969}
1970
1971error = readBytes(biosdev, secno, 0, BPS, bootSector);
1972
1973if (error || bootSector->signature != DISK_SIGNATURE)
1974{
1975return -1;
1976}
1977return 0;
1978}
1979
1980/*
1981 * Format of boot1f32 block.
1982 */
1983
1984#define BOOT1F32_MAGIC "BOOT "
1985#define BOOT1F32_MAGICLEN 11
1986
1987struct disk_boot1f32_blk {
1988 unsigned char init[3];
1989 unsigned char fsheader[87];
1990 unsigned char magic[BOOT1F32_MAGICLEN];
1991 unsigned char bootcode[409];
1992 unsigned short signature;
1993};
1994
1995int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
1996{
1997 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
1998 int error;
1999
2000 if ( bootSector == NULL )
2001 {
2002 if ( gBootSector == NULL )
2003 {
2004 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
2005 if ( gBootSector == NULL ) return -1;
2006 }
2007 bootSector = (struct disk_boot1f32_blk *) gBootSector;
2008 }
2009
2010 error = readBytes( biosdev, secno, 0, BPS, bootSector );
2011 if ( error || bootSector->signature != DISK_SIGNATURE
2012 || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2013 return -1;
2014
2015 return 0;
2016}
2017
2018//==========================================================================
2019// Handle seek request from filesystem modules.
2020
2021void diskSeek(BVRef bvr, long long position)
2022{
2023 bvr->fs_boff = position / BPS;
2024 bvr->fs_byteoff = position % BPS;
2025}
2026
2027//==========================================================================
2028// Handle read request from filesystem modules.
2029
2030int diskRead( BVRef bvr, long addr, long length )
2031{
2032 return readBytes( bvr->biosdev,
2033 bvr->fs_boff + bvr->part_boff,
2034 bvr->fs_byteoff,
2035 length,
2036 (void *) addr );
2037}
2038
2039int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2040{
2041 int secs;
2042 unsigned char *cbuf = (unsigned char *)buffer;
2043 unsigned int copy_len;
2044 int rc;
2045
2046 if ((len & (BPS-1)) != 0) {
2047 error("raw disk read not sector aligned");
2048 return -1;
2049 }
2050 secno += bvr->part_boff;
2051
2052 cache_valid = false;
2053
2054 while (len > 0) {
2055 secs = len / BPS;
2056 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2057 copy_len = secs * BPS;
2058
2059 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2060 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
2061 /* Ignore corrected ECC errors */
2062 if (rc != ECC_CORRECTED_ERR) {
2063 error(" EBIOS read error: %s\n", bios_error(rc), rc);
2064 error(" Block %d Sectors %d\n", secno, secs);
2065 return rc;
2066 }
2067 }
2068 bcopy( trackbuf, cbuf, copy_len );
2069 len -= copy_len;
2070 cbuf += copy_len;
2071 secno += secs;
2072 spinActivityIndicator(secs);
2073 }
2074
2075 return 0;
2076}
2077
2078int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2079{
2080 int secs;
2081 unsigned char *cbuf = (unsigned char *)buffer;
2082 unsigned int copy_len;
2083 int rc;
2084
2085 if ((len & (BPS-1)) != 0) {
2086 error("raw disk write not sector aligned");
2087 return -1;
2088 }
2089 secno += bvr->part_boff;
2090
2091 cache_valid = false;
2092
2093 while (len > 0) {
2094 secs = len / BPS;
2095 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2096 copy_len = secs * BPS;
2097
2098 bcopy( cbuf, trackbuf, copy_len );
2099 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2100 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
2101 error(" EBIOS write error: %s\n", bios_error(rc), rc);
2102 error(" Block %d Sectors %d\n", secno, secs);
2103 return rc;
2104 }
2105 len -= copy_len;
2106 cbuf += copy_len;
2107 secno += secs;
2108 spinActivityIndicator(secs);
2109 }
2110
2111 return 0;
2112}
2113
2114int diskIsCDROM(BVRef bvr)
2115{
2116 struct driveInfo di;
2117
2118 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
2119return 1;
2120 }
2121 return 0;
2122}
2123
2124int biosDevIsCDROM(int biosdev)
2125{
2126 struct driveInfo di;
2127
2128 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2129 {
2130 return 1;
2131 }
2132 return 0;
2133}
2134

Archive Download this file

Revision: 1993