Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2658