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

Archive Download this file

Revision: 1119