Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2456