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

Archive Download this file

Revision: 1468