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

Archive Download this file

Revision: 789