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

Archive Download this file

Revision: 1724