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/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1538
1539if (!loadConfigFile(dirSpec, &systemVersion))
1540{
1541 bvr->OSisServer = true;
1542valid = true;
1543}
1544else
1545{
1546sprintf(dirSpec, "hd(%d,%d)/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1547
1548if (GetFileInfo(dirSpec, "Mac OS X Install Data", &flags, &time) == 0)
1549{
1550*str = '\0';
1551strncat(str, "10.7", 4);
1552return true;
1553}
1554}
1555}
1556
1557if (valid)
1558{
1559const char *val;
1560int len;
1561
1562if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1563{
1564// getValueForKey uses const char for val
1565// so copy it and trim
1566*str = '\0';
1567strncat(str, val, MIN(len, 4));
1568}
1569else
1570valid = false;
1571}
1572
1573return valid;
1574}
1575
1576//==========================================================================
1577
1578static void scanFSLevelBVRSettings(BVRef chain)
1579{
1580BVRef bvr;
1581int ret;
1582#ifdef BOOT_HELPER_SUPPORT
1583char label[BVSTRLEN];
1584int fh, fileSize, error;
1585#endif
1586for (bvr = chain; bvr; bvr = bvr->next)
1587{
1588ret = -1;
1589#ifdef BOOT_HELPER_SUPPORT
1590error = 0;
1591
1592//
1593// Check for alternate volume label on boot helper partitions.
1594//
1595if (bvr->flags & kBVFlagBooter)
1596{
1597sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1598strcpy(fileSpec, ".disk_label.contentDetails");
1599ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1600if (!ret)
1601{
1602fh = open(strcat(dirSpec, fileSpec));
1603fileSize = file_size(fh);
1604if (fileSize > 0 && fileSize < BVSTRLEN)
1605{
1606if (read(fh, label, fileSize) != fileSize)
1607error = -1;
1608}
1609else
1610error = -1;
1611
1612close(fh);
1613
1614if (!error)
1615{
1616label[fileSize] = '\0';
1617strcpy(bvr->altlabel, label);
1618}
1619}
1620}
1621#endif
1622//
1623// Check for SystemVersion.plist or ServerVersion.plist
1624// to determine if a volume hosts an installed system.
1625//
1626if (bvr->flags & kBVFlagNativeBoot)
1627{
1628if (getOSVersion(bvr,bvr->OSVersion) == true)
1629{
1630bvr->flags |= kBVFlagSystemVolume;
1631}
1632}
1633
1634}
1635}
1636#ifndef OPTION_ROM
1637void rescanBIOSDevice(int biosdev)
1638{
1639struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1640CacheReset();
1641diskFreeMap(oldMap);
1642oldMap = NULL;
1643scanBootVolumes(biosdev, 0);
1644}
1645#endif
1646
1647struct DiskBVMap* diskResetBootVolumes(int biosdev)
1648{
1649 struct DiskBVMap * map;
1650 struct DiskBVMap *prevMap = NULL;
1651 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1652 if ( biosdev == map->biosdev ) {
1653 break;
1654 }
1655 }
1656 if(map != NULL)
1657 {
1658 verbose("Resetting BIOS device %xh\n", biosdev);
1659 // Reset the biosbuf cache
1660 cache_valid = false;
1661 if(map == gDiskBVMap)
1662 gDiskBVMap = map->next;
1663 else if(prevMap != NULL)
1664 prevMap->next = map->next;
1665 else
1666 stop("");
1667 }
1668 // Return the old map, either to be freed, or reinserted later
1669 return map;
1670}
1671
1672// Frees a DiskBVMap and all of its BootVolume's
1673void diskFreeMap(struct DiskBVMap *map)
1674{
1675 if(map != NULL)
1676 {
1677 while(map->bvr != NULL)
1678 {
1679 BVRef bvr = map->bvr;
1680 map->bvr = bvr->next;
1681 (*bvr->bv_free)(bvr);
1682 }
1683 free(map);
1684 }
1685}
1686
1687BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1688{
1689 struct DiskBVMap * map;
1690 BVRef bvr;
1691 int count = 0;
1692
1693 // Find an existing mapping for this device.
1694
1695 for ( map = gDiskBVMap; map; map = map->next ) {
1696 if ( biosdev == map->biosdev ) {
1697 count = map->bvrcnt;
1698 break;
1699 }
1700 }
1701
1702 if (map == NULL) {
1703 bvr = diskScanGPTBootVolumes(biosdev, &count);
1704 if (bvr == NULL) {
1705bvr = diskScanFDiskBootVolumes(biosdev, &count);
1706 }
1707#ifdef APPLE_PARTITION_MAP_SUPPORT
1708 if (bvr == NULL) {
1709bvr = diskScanAPMBootVolumes(biosdev, &count);
1710 }
1711#endif
1712 if (bvr)
1713 {
1714scanFSLevelBVRSettings(bvr);
1715 }
1716 } else {
1717 bvr = map->bvr;
1718 }
1719 if (countPtr) *countPtr += count;
1720 return bvr;
1721}
1722
1723BVRef getBVChainForBIOSDev(int biosdev)
1724{
1725BVRef chain = NULL;
1726struct DiskBVMap * map = NULL;
1727
1728for (map = gDiskBVMap; map; map = map->next)
1729{
1730if (map->biosdev == biosdev)
1731{
1732chain = map->bvr;
1733break;
1734}
1735}
1736
1737return chain;
1738}
1739
1740BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1741{
1742BVRef chain = NULL;
1743BVRef bvr = NULL;
1744BVRef newBVR = NULL;
1745BVRef prevBVR = NULL;
1746
1747struct DiskBVMap * map = NULL;
1748int bvCount = 0;
1749
1750const char *raw = 0;
1751char* val = 0;
1752int len;
1753
1754getValueForKey(kHidePartition, &raw, &len, &bootInfo->bootConfig);
1755if(raw)
1756{
1757val = XMLDecode(raw);
1758}
1759
1760/*
1761 * Traverse gDISKBVmap to get references for
1762 * individual bvr chains of each drive.
1763 */
1764for (map = gDiskBVMap; map; map = map->next)
1765{
1766for (bvr = map->bvr; bvr; bvr = bvr->next)
1767{
1768/*
1769 * Save the last bvr.
1770 */
1771if (newBVR) prevBVR = newBVR;
1772
1773/*
1774 * Allocate and copy the matched bvr entry into a new one.
1775 */
1776newBVR = (BVRef) malloc(sizeof(*newBVR));
1777bcopy(bvr, newBVR, sizeof(*newBVR));
1778
1779/*
1780 * Adjust the new bvr's fields.
1781 */
1782newBVR->next = NULL;
1783newBVR->filtered = true;
1784
1785if ( (!allowFlags || newBVR->flags & allowFlags)
1786&& (!denyFlags || !(newBVR->flags & denyFlags) )
1787&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1788)
1789newBVR->visible = true;
1790
1791/* Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format
1792 * to be able to hide foreign partitions from the boot menu.
1793 */
1794if ( (newBVR->flags & kBVFlagForeignBoot) )
1795{
1796char *start, *next = val;
1797long len = 0;
1798do
1799{
1800start = strbreak(next, &next, &len);
1801if(len && matchVolumeToString(newBVR, start, len) )
1802newBVR->visible = false;
1803}
1804while ( next && *next );
1805}
1806
1807/*
1808 * Use the first bvr entry as the starting chain pointer.
1809 */
1810if (!chain)
1811chain = newBVR;
1812
1813/*
1814 * Update the previous bvr's link pointer to use the new memory area.
1815 */
1816if (prevBVR)
1817prevBVR->next = newBVR;
1818
1819if (newBVR->visible)
1820bvCount++;
1821}
1822}
1823
1824#if DEBUG
1825for (bvr = chain; bvr; bvr = bvr->next)
1826{
1827printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1828}
1829printf("count: %d\n", bvCount);
1830getc();
1831#endif
1832
1833*count = bvCount;
1834
1835free(val);
1836return chain;
1837}
1838
1839int freeFilteredBVChain(const BVRef chain)
1840{
1841int ret = 1;
1842BVRef bvr = chain;
1843BVRef nextBVR = NULL;
1844
1845while (bvr)
1846{
1847nextBVR = bvr->next;
1848
1849if (bvr->filtered)
1850{
1851free(bvr);
1852}
1853else
1854{
1855ret = 0;
1856break;
1857}
1858
1859bvr = nextBVR;
1860}
1861
1862return ret;
1863}
1864
1865//==========================================================================
1866
1867static const struct NamedValue fdiskTypes[] =
1868{
1869#ifndef NO_WIN_SUPPORT
1870 { FDISK_NTFS, "Windows NTFS" },
1871{ FDISK_DOS12, "Windows FAT12" },
1872{ FDISK_DOS16B, "Windows FAT16" },
1873{ FDISK_DOS16S, "Windows FAT16" },
1874{ FDISK_DOS16SLBA, "Windows FAT16" },
1875{ FDISK_SMALLFAT32, "Windows FAT32" },
1876{ FDISK_FAT32, "Windows FAT32" },
1877#endif
1878#ifndef NO_OTHERS_BSD_SUPPORT
1879{ FDISK_FREEBSD, "FreeBSD" },
1880 { FDISK_OPENBSD, "OpenBSD" },
1881#endif
1882#ifndef NO_LINUX_SUPPORT
1883 { FDISK_LINUX, "Linux" },
1884#endif
1885#ifdef UFS_SUPPORT
1886 { FDISK_UFS, "Apple UFS" },
1887#endif
1888 { FDISK_HFS, "Apple HFS" },
1889 { FDISK_BOOTER, "Apple Boot/UFS" },
1890#ifndef NO_HAIKU_SUPPORT
1891{ FDISK_BEFS, "Haiku" },
1892#endif
1893 { 0xCD, "CD-ROM" },
1894 { 0x00, 0 } /* must be last */
1895};
1896
1897//==========================================================================
1898
1899bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1900{
1901char testStr[128];
1902
1903if ( !bvr || !match || !*match)
1904return 0;
1905
1906if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1907 return 0;
1908
1909 // Try to match hd(x,y) first.
1910 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1911 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1912 return true;
1913
1914 // Try to match volume UUID.
1915 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1916 {
1917 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1918 return true;
1919 }
1920
1921 // Try to match volume label (always quoted).
1922 if ( bvr->description )
1923 {
1924 bvr->description(bvr, testStr, sizeof(testStr)-1);
1925 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1926 return true;
1927 }
1928
1929 return false;
1930}
1931
1932/* If Rename Partition has defined an alias, then extract it for description purpose
1933 * The format for the rename string is the following:
1934 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" etc; ...
1935 */
1936
1937bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
1938{
1939 char *aliasList, *entryStart, *entryNext;
1940
1941 if ( !str || strMaxLen <= 0)
1942 return false;
1943
1944 aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->bootConfig));
1945 if ( !aliasList )
1946 return false;
1947
1948 for ( entryStart = entryNext = aliasList;
1949 entryNext && *entryNext;
1950 entryStart = entryNext )
1951 {
1952 char *volStart, *volEnd, *aliasStart;
1953 long volLen, aliasLen;
1954
1955 // Delimit current entry
1956 entryNext = strchr(entryStart, ';');
1957 if ( entryNext )
1958 {
1959 *entryNext = '\0';
1960 entryNext++;
1961 }
1962
1963 volStart = strbreak(entryStart, &volEnd, &volLen);
1964 if(!volLen)
1965 continue;
1966
1967 aliasStart = strbreak(volEnd, 0, &aliasLen);
1968 if(!aliasLen)
1969 continue;
1970
1971 if ( matchVolumeToString(bvr, volStart, volLen) )
1972 {
1973 strncat(str, aliasStart, min(strMaxLen, aliasLen));
1974 free(aliasList);
1975
1976 return true;
1977 }
1978 }
1979
1980 free(aliasList);
1981 return false;
1982}
1983
1984void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1985{
1986 unsigned char type;
1987 char *p = str;
1988
1989 if(!bvr || !p || strMaxLen <= 0)
1990 return;
1991
1992 type = (unsigned char) bvr->part_type;
1993
1994 if (useDeviceDescription)
1995 {
1996 int len = getDeviceDescription(bvr, str);
1997 if(len >= strMaxLen)
1998 return;
1999
2000 strcpy(str + len, " ");
2001 len++;
2002 strMaxLen -= len;
2003 p += len;
2004 }
2005
2006 /* See if a partition rename is preferred */
2007 if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
2008 strncpy(bvr->label, p, strMaxLen);
2009 return; // we're done here no need to seek for real name
2010 }
2011
2012 //
2013 // Get the volume label using filesystem specific functions
2014 // or use the alternate volume label if available.
2015 //
2016if (*bvr->altlabel != '\0')
2017 strncpy(p, bvr->altlabel, strMaxLen);
2018else if (bvr->description)
2019 bvr->description(bvr, p, strMaxLen);
2020
2021 if (*p == '\0') {
2022 const char * name = getNameForValue( fdiskTypes, type );
2023 if (name == NULL) {
2024 name = bvr->type_name;
2025 }
2026 if (name == NULL) {
2027 sprintf(p, "TYPE %02x", type);
2028 } else {
2029 strncpy(p, name, strMaxLen);
2030 }
2031 }
2032
2033 // Set the devices label
2034 sprintf(bvr->label, p);
2035}
2036
2037//==========================================================================
2038int readBootSector( int biosdev, unsigned int secno, void * buffer )
2039{
2040 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
2041 int error;
2042
2043 if ( bootSector == NULL )
2044 {
2045 if ( gBootSector == NULL )
2046 {
2047 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
2048 if ( gBootSector == NULL ) return -1;
2049 }
2050 bootSector = gBootSector;
2051 }
2052
2053 error = readBytes( biosdev, secno, 0, BPS, bootSector );
2054 if ( error || bootSector->signature != DISK_SIGNATURE )
2055 return -1;
2056
2057 return 0;
2058}
2059
2060#ifndef NO_WIN_SUPPORT
2061/*
2062 * Format of boot1f32 block.
2063 */
2064
2065#define BOOT1F32_MAGIC "BOOT "
2066#define BOOT1F32_MAGICLEN 11
2067
2068struct disk_boot1f32_blk {
2069 unsigned char init[3];
2070 unsigned char fsheader[87];
2071 unsigned char magic[BOOT1F32_MAGICLEN];
2072 unsigned char bootcode[409];
2073 unsigned short signature;
2074};
2075
2076int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
2077{
2078 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
2079 int error;
2080
2081 if ( bootSector == NULL )
2082 {
2083 if ( gBootSector == NULL )
2084 {
2085 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
2086 if ( gBootSector == NULL ) return -1;
2087 }
2088 bootSector = (struct disk_boot1f32_blk *) gBootSector;
2089 }
2090
2091 error = readBytes( biosdev, secno, 0, BPS, bootSector );
2092 if ( error || bootSector->signature != DISK_SIGNATURE
2093|| strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
2094return -1;
2095
2096 return 0;
2097}
2098#endif
2099//==========================================================================
2100// Handle seek request from filesystem modules.
2101
2102void diskSeek( BVRef bvr, long long position )
2103{
2104 bvr->fs_boff = position / BPS;
2105 bvr->fs_byteoff = position % BPS;
2106}
2107
2108//==========================================================================
2109// Handle read request from filesystem modules.
2110
2111int diskRead( BVRef bvr, long addr, long length )
2112{
2113 return readBytes( bvr->biosdev,
2114 bvr->fs_boff + bvr->part_boff,
2115 bvr->fs_byteoff,
2116 length,
2117 (void *) addr );
2118}
2119
2120#if UNUSED
2121int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2122{
2123 int secs;
2124 unsigned char *cbuf = (unsigned char *)buffer;
2125 unsigned int copy_len;
2126 int rc;
2127
2128 if ((len & (BPS-1)) != 0) {
2129 error("raw disk read not sector aligned");
2130 return -1;
2131 }
2132 secno += bvr->part_boff;
2133
2134 cache_valid = false;
2135
2136 while (len > 0) {
2137 secs = len / BPS;
2138 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2139 copy_len = secs * BPS;
2140
2141 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2142 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
2143 /* Ignore corrected ECC errors */
2144 if (rc != ECC_CORRECTED_ERR) {
2145 error(" EBIOS read error: %s\n", bios_error(rc), rc);
2146 error(" Block %d Sectors %d\n", secno, secs);
2147 return rc;
2148 }
2149 }
2150 bcopy( trackbuf, cbuf, copy_len );
2151 len -= copy_len;
2152 cbuf += copy_len;
2153 secno += secs;
2154#if TEXT_SPINNER
2155spinActivityIndicator(secs);
2156#endif
2157 }
2158
2159 return 0;
2160}
2161
2162int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2163{
2164 int secs;
2165 unsigned char *cbuf = (unsigned char *)buffer;
2166 unsigned int copy_len;
2167 int rc;
2168
2169 if ((len & (BPS-1)) != 0) {
2170 error("raw disk write not sector aligned");
2171 return -1;
2172 }
2173 secno += bvr->part_boff;
2174
2175 cache_valid = false;
2176
2177 while (len > 0) {
2178 secs = len / BPS;
2179 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2180 copy_len = secs * BPS;
2181
2182 bcopy( cbuf, trackbuf, copy_len );
2183 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2184 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
2185 error(" EBIOS write error: %s\n", bios_error(rc), rc);
2186 error(" Block %d Sectors %d\n", secno, secs);
2187 return rc;
2188 }
2189 len -= copy_len;
2190 cbuf += copy_len;
2191 secno += secs;
2192#if TEXT_SPINNER
2193spinActivityIndicator(secs);
2194#endif
2195 }
2196
2197 return 0;
2198}
2199#endif
2200
2201int diskIsCDROM(BVRef bvr)
2202{
2203 struct driveInfo di;
2204
2205 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
2206return 1;
2207 }
2208 return 0;
2209}
2210
2211int biosDevIsCDROM(int biosdev)
2212{
2213 struct driveInfo di;
2214
2215 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2216 {
2217 return 1;
2218 }
2219 return 0;
2220}
2221

Archive Download this file

Revision: 1736