Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1735