Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 495