Chameleon

Chameleon Svn Source Tree

Root/branches/slice/trunkM/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/*
48 * Copyright 2007 VMware Inc.
49 * "Preboot" ramdisk support added by David Elliott
50 * GPT support added by David Elliott. Based on IOGUIDPartitionScheme.cpp.
51 */
52
53//Azi: style the rest later...
54
55// Allow UFS_SUPPORT to be overridden with preprocessor option.
56#ifndef UFS_SUPPORT
57// zef: Disabled UFS support
58#define UFS_SUPPORT 0
59#endif
60
61#if UFS_SUPPORT
62#include "ufs.h"
63#endif
64#include <limits.h>
65#include <IOKit/storage/IOApplePartitionScheme.h>
66#include <IOKit/storage/IOGUIDPartitionScheme.h>
67#include "libsaio.h"
68#include "boot.h"
69#include "bootstruct.h"
70#include "memory.h"
71#include "fdisk.h"
72#include "hfs.h"
73#include "ntfs.h"
74#include "msdos.h"
75#include "ext2fs.h"
76#include "xml.h"
77#include "disk.h"
78// For EFI_GUID
79#include "efi.h"
80#include "efi_tables.h"
81
82typedef struct gpt_hdr gpt_hdr;
83typedef struct gpt_ent gpt_ent;
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// GUID's in LE form:
637// HFS+ partition - 48465300-0000-11AA-AA11-00306543ECAC
638EFI_GUID const GPT_HFS_GUID = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
639
640// turbo - Apple Boot Partition - 426F6F74-0000-11AA-AA11-00306543ECAC
641EFI_GUID const GPT_BOOT_GUID = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
642
643// turbo - or an EFI System Partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B
644EFI_GUID const GPT_EFISYS_GUID = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };
645
646// zef - Basic Data Partition - EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support
647EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };
648
649// Microsoft Reserved Partition - E3C9E316-0B5C-4DB8-817DF92DF00215AE
650EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };
651
652
653BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,
654 const gpt_ent * part,
655 FSInit initFunc, FSLoadFile loadFunc,
656 FSReadFile readFunc,
657 FSGetDirEntry getdirFunc,
658 FSGetFileBlock getBlockFunc,
659 FSGetUUID getUUIDFunc,
660 BVGetDescription getDescriptionFunc,
661 BVFree bvFreeFunc,
662 int probe, int type, unsigned int bvrFlags )
663{
664 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
665 if ( bvr )
666 {
667 bzero(bvr, sizeof(*bvr));
668
669 bvr->biosdev = biosdev;
670 bvr->part_no = partno;
671 bvr->part_boff = blkoff;
672 bvr->fs_loadfile = loadFunc;
673 bvr->fs_readfile = readFunc;
674 bvr->fs_getdirentry = getdirFunc;
675 bvr->fs_getfileblock= getBlockFunc;
676 bvr->fs_getuuid = getUUIDFunc;
677 bvr->description = getDescriptionFunc;
678 bvr->type = type;
679 bvr->bv_free = bvFreeFunc;
680 // FIXME: UCS-2 -> UTF-8 the name
681 strlcpy(bvr->name, "----", DPISTRLEN);
682 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)part->ent_type) == 0) ||
683 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)part->ent_type) == 0) )
684 strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);
685 else
686 strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);
687
688 /*
689 if ( part->bootid & FDISK_ACTIVE )
690 bvr->flags |= kBVFlagPrimary;
691 */
692
693 // Probe the filesystem.
694
695 if ( initFunc )
696 {
697 bvr->flags |= kBVFlagNativeBoot;
698
699 if ( probe && initFunc( bvr ) != 0 )
700 {
701 // filesystem probe failed.
702
703 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
704 __FUNCTION__, biosdev, partno));
705
706 (*bvr->bv_free)(bvr);
707 bvr = NULL;
708 }
709 if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
710 {
711 bvr->flags |= kBVFlagBootable;
712 }
713 }
714 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
715 {
716 bvr->flags |= kBVFlagForeignBoot;
717 }
718 else
719 {
720 (*bvr->bv_free)(bvr);
721 bvr = NULL;
722 }
723 }
724 if (bvr) bvr->flags |= bvrFlags;
725 return bvr;
726}
727
728//==========================================================================
729
730/* A note on partition numbers:
731 * IOKit makes the primary partitions numbers 1-4, and then
732 * extended partitions are numbered consecutively 5 and up.
733 * So, for example, if you have two primary partitions and
734 * one extended partition they will be numbered 1, 2, 5.
735 */
736
737static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
738{
739 const struct fdisk_part * part;
740 struct DiskBVMap * map;
741 int partno = -1;
742 BVRef bvr;
743#if UFS_SUPPORT
744 BVRef booterUFS = NULL;
745#endif
746 int spc;
747 struct driveInfo di;
748 boot_drive_info_t *dp;
749
750 /* Initialize disk info */
751 if (getDriveInfo(biosdev, &di) != 0) {
752return NULL;
753 }
754 dp = &di.di;
755 spc = (dp->params.phys_spt * dp->params.phys_heads);
756 if (spc == 0) {
757/* This is probably a CD-ROM; punt on the geometry. */
758spc = 1;
759 }
760
761 do {
762 // Create a new mapping.
763
764 map = (struct DiskBVMap *) malloc( sizeof(*map) );
765 if ( map )
766 {
767 map->biosdev = biosdev;
768 map->bvr = NULL;
769 map->bvrcnt = 0;
770 map->next = gDiskBVMap;
771 gDiskBVMap = map;
772
773 // Create a record for each partition found on the disk.
774
775 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
776 {
777 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
778 partno, part->systid));
779 bvr = 0;
780
781 switch ( part->systid )
782 {
783#if UFS_SUPPORT
784 case FDISK_UFS:
785 bvr = newFDiskBVRef(
786 biosdev, partno,
787 part->relsect + UFS_FRONT_PORCH/BPS,
788 part,
789 UFSInitPartition,
790 UFSLoadFile,
791 UFSReadFile,
792 UFSGetDirEntry,
793 UFSGetFileBlock,
794 UFSGetUUID,
795 UFSGetDescription,
796 UFSFree,
797 0,
798 kBIOSDevTypeHardDrive, 0);
799 break;
800#endif
801
802 case FDISK_HFS:
803 bvr = newFDiskBVRef(
804 biosdev, partno,
805 part->relsect,
806 part,
807 HFSInitPartition,
808 HFSLoadFile,
809 HFSReadFile,
810 HFSGetDirEntry,
811 HFSGetFileBlock,
812 HFSGetUUID,
813 HFSGetDescription,
814 HFSFree,
815 0,
816 kBIOSDevTypeHardDrive, 0);
817 break;
818
819 // turbo - we want the booter type scanned also
820 case FDISK_BOOTER:
821 if (part->bootid & FDISK_ACTIVE)
822 gBIOSBootVolume = newFDiskBVRef(
823 biosdev, partno,
824 part->relsect,
825 part,
826 HFSInitPartition,
827 HFSLoadFile,
828 HFSReadFile,
829 HFSGetDirEntry,
830 HFSGetFileBlock,
831 HFSGetUUID,
832 HFSGetDescription,
833 HFSFree,
834 0,
835 kBIOSDevTypeHardDrive, 0);
836 break;
837
838#if UFS_SUPPORT
839 case FDISK_BOOTER:
840 booterUFS = newFDiskBVRef(
841 biosdev, partno,
842 ((part->relsect + spc - 1) / spc) * spc,
843 part,
844 UFSInitPartition,
845 UFSLoadFile,
846 UFSReadFile,
847 UFSGetDirEntry,
848 UFSGetFileBlock,
849 UFSGetUUID,
850 UFSGetDescription,
851 UFSFree,
852 0,
853 kBIOSDevTypeHardDrive, 0);
854 break;
855#endif
856
857 case FDISK_FAT32:
858 case FDISK_DOS12:
859 case FDISK_DOS16S:
860 case FDISK_DOS16B:
861 case FDISK_SMALLFAT32:
862 case FDISK_DOS16SLBA:
863 bvr = newFDiskBVRef(
864 biosdev, partno,
865 part->relsect,
866 part,
867 MSDOSInitPartition,
868 MSDOSLoadFile,
869 MSDOSReadFile,
870 MSDOSGetDirEntry,
871 MSDOSGetFileBlock,
872 MSDOSGetUUID,
873 MSDOSGetDescription,
874 MSDOSFree,
875 0,
876 kBIOSDevTypeHardDrive, 0);
877 break;
878
879 case FDISK_NTFS:
880 bvr = newFDiskBVRef(
881 biosdev, partno,
882 part->relsect,
883 part,
884 0, 0, 0, 0, 0,
885 NTFSGetUUID,
886 NTFSGetDescription,
887 (BVFree)free,
888 0, kBIOSDevTypeHardDrive, 0);
889 break;
890
891 case FDISK_LINUX:
892 bvr = newFDiskBVRef(
893 biosdev, partno,
894 part->relsect,
895 part,
896 0, 0, 0, 0, 0, 0,
897 EX2GetDescription,
898 (BVFree)free,
899 0, kBIOSDevTypeHardDrive, 0);
900 break;
901
902 default:
903 bvr = newFDiskBVRef(
904 biosdev, partno,
905 part->relsect,
906 part,
907 0, 0, 0, 0, 0, 0, 0,
908 (BVFree)free,
909 0,
910 kBIOSDevTypeHardDrive, 0);
911 break;
912 }
913
914 if ( bvr )
915 {
916 bvr->next = map->bvr;
917 map->bvr = bvr;
918 map->bvrcnt++;
919 }
920 }
921
922#if UFS_SUPPORT
923 // Booting from a CD with an UFS filesystem embedded
924 // in a booter partition.
925
926 if ( booterUFS )
927 {
928 if ( map->bvrcnt == 0 )
929 {
930 map->bvr = booterUFS;
931 map->bvrcnt++;
932 }
933 else free( booterUFS );
934 }
935#endif
936 }
937 } while (0);
938
939 /*
940 * If no FDisk partition, then we will check for
941 * an Apple partition map elsewhere.
942 */
943#if UNUSED
944 if (map->bvrcnt == 0) {
945static struct fdisk_part cdpart;
946cdpart.systid = 0xCD;
947
948/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
949bvr = newFDiskBVRef(
950 biosdev, 0,
951 0,
952 &cdpart,
953 HFSInitPartition,
954 HFSLoadFile,
955 HFSReadFile,
956 HFSGetDirEntry,
957 HFSGetFileBlock,
958 HFSGetUUID,
959 0,
960 kBIOSDevTypeHardDrive);
961bvr->next = map->bvr;
962map->bvr = bvr;
963map->bvrcnt++;
964 }
965#endif
966 // Actually this should always be true given the above code
967 if(map == gDiskBVMap)
968 {
969 // Don't leave a null map in the chain
970 if(map->bvrcnt == 0 && map->bvr == NULL)
971 {
972 gDiskBVMap = map->next;
973 free(map);
974 map = NULL;
975 }
976 }
977
978 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
979
980 return map ? map->bvr : NULL;
981}
982
983//==========================================================================
984
985static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
986{
987 struct DiskBVMap * map;
988 struct Block0 *block0_p;
989 unsigned int blksize;
990 unsigned int factor;
991 void *buffer = malloc(BPS);
992
993 /* Check for alternate block size */
994 if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
995 return NULL;
996 }
997 block0_p = buffer;
998 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
999 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1000 if (blksize != BPS) {
1001 free(buffer);
1002 buffer = malloc(blksize);
1003 }
1004 factor = blksize / BPS;
1005 } else {
1006 blksize = BPS;
1007 factor = 1;
1008 }
1009
1010 do {
1011 // Create a new mapping.
1012
1013 map = (struct DiskBVMap *) malloc( sizeof(*map) );
1014 if ( map )
1015 {
1016 int error;
1017 DPME *dpme_p = (DPME *)buffer;
1018 UInt32 i, npart = UINT_MAX;
1019 BVRef bvr;
1020
1021 map->biosdev = biosdev;
1022 map->bvr = NULL;
1023 map->bvrcnt = 0;
1024 map->next = gDiskBVMap;
1025 gDiskBVMap = map;
1026
1027 for (i=0; i<npart; i++) {
1028 error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1029
1030 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
1031 break;
1032 }
1033
1034 if (i==0) {
1035 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1036 }
1037 /*
1038 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1039 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1040 dpme.dpme_pblock_start, dpme.dpme_pblocks,
1041 dpme.dpme_lblock_start, dpme.dpme_lblocks,
1042 dpme.dpme_boot_block);
1043 */
1044
1045 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
1046 bvr = newAPMBVRef(biosdev,
1047 i,
1048 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1049 dpme_p,
1050 HFSInitPartition,
1051 HFSLoadFile,
1052 HFSReadFile,
1053 HFSGetDirEntry,
1054 HFSGetFileBlock,
1055 HFSGetUUID,
1056 HFSGetDescription,
1057 HFSFree,
1058 0,
1059 kBIOSDevTypeHardDrive, 0);
1060 bvr->next = map->bvr;
1061 map->bvr = bvr;
1062 map->bvrcnt++;
1063 }
1064 }
1065 }
1066 } while (0);
1067
1068 free(buffer);
1069
1070 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1071
1072 return map ? map->bvr : NULL;
1073}
1074
1075//==========================================================================
1076
1077// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1078
1079/*
1080 * Trying to figure out the filsystem type of a given partition.
1081 */
1082static int probeFileSystem(int biosdev, unsigned int blkoff)
1083{
1084 // detected filesystem type;
1085 int result = -1;
1086 int fatbits;
1087
1088 // Allocating buffer for 4 sectors.
1089 const void * probeBuffer = malloc(PROBEFS_SIZE);
1090 if (probeBuffer == NULL)
1091 goto exit;
1092
1093 // Reading first 4 sectors of current partition
1094 int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
1095 if (error)
1096 goto exit;
1097
1098 if (HFSProbe(probeBuffer))
1099 result = FDISK_HFS;
1100 else if (EX2Probe(probeBuffer))
1101 result = FDISK_LINUX;
1102 else if (NTFSProbe(probeBuffer))
1103 result = FDISK_NTFS;
1104 else if (fatbits=MSDOSProbe(probeBuffer))
1105 {
1106 switch (fatbits)
1107 {
1108 case 32:
1109 default:
1110 result = FDISK_FAT32;
1111 break;
1112 case 16:
1113 result = FDISK_DOS16B;
1114 break;
1115 case 12:
1116 result = FDISK_DOS12;
1117 break;
1118 }
1119 }
1120 else
1121 // Couldn't detect filesystem type
1122 result = 0;
1123
1124exit:
1125 if (probeBuffer != NULL) free((void *)probeBuffer);
1126 return result;
1127}
1128
1129static bool isPartitionUsed(gpt_ent * partition)
1130{
1131 //
1132 // Ask whether the given partition is used.
1133 //
1134
1135 return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1136}
1137
1138// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1139
1140static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )
1141{
1142 struct DiskBVMap * map = NULL;
1143 void *buffer = malloc(BPS);
1144 int error;
1145 if ( error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer ) != 0) {
1146 verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1147 goto scanErr;
1148 }
1149 struct REAL_disk_blk0 *fdiskMap = buffer;
1150 if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1151 {
1152 verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1153 goto scanErr;
1154 }
1155
1156 int fdiskID = 0;
1157 unsigned index;
1158 for ( index = 0; index < FDISK_NPART; index++ )
1159 {
1160 if ( fdiskMap->parts[index].systid )
1161 {
1162 if ( fdiskMap->parts[index].systid == 0xEE )
1163 {
1164 // Fail if two 0xEE partitions are present which
1165 // means the FDISK code will wind up parsing it.
1166 if ( fdiskID ) goto scanErr;
1167
1168 fdiskID = index + 1;
1169 }
1170 }
1171 }
1172
1173 if ( fdiskID == 0 ) goto scanErr;
1174 verbose("Attempting to read GPT\n");
1175
1176 if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1177 goto scanErr;
1178
1179 gpt_hdr *headerMap = buffer;
1180
1181 // Determine whether the partition header signature is present.
1182
1183 if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1184 {
1185 goto scanErr;
1186 }
1187
1188 // Determine whether the partition header size is valid.
1189
1190 UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1191 UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1192
1193 if ( headerSize < offsetof(gpt_hdr, padding) )
1194 {
1195 goto scanErr;
1196 }
1197
1198 if ( headerSize > BPS )
1199 {
1200 goto scanErr;
1201 }
1202
1203 // Determine whether the partition header checksum is valid.
1204
1205 headerMap->hdr_crc_self = 0;
1206
1207 if ( crc32(0, headerMap, headerSize) != headerCheck )
1208 {
1209 goto scanErr;
1210 }
1211
1212 // Determine whether the partition entry size is valid.
1213
1214 UInt64 gptBlock = 0;
1215 UInt32 gptCheck = 0;
1216 UInt32 gptCount = 0;
1217 UInt32 gptID = 0;
1218 gpt_ent * gptMap = 0;
1219 UInt32 gptSize = 0;
1220
1221 gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1222 gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1223 gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1224 gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1225
1226 if ( gptSize < sizeof(gpt_ent) )
1227 {
1228 goto scanErr;
1229 }
1230
1231 // Allocate a buffer large enough to hold one map, rounded to a media block.
1232 free(buffer);
1233 buffer = NULL;
1234
1235 UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1236 if(bufferSize == 0)
1237 goto scanErr;
1238 buffer = malloc(bufferSize);
1239
1240 if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1241 goto scanErr;
1242
1243 verbose("Read GPT\n");
1244
1245 // Allocate a new map for this BIOS device and insert it into the chain
1246 map = malloc(sizeof(*map));
1247 map->biosdev = biosdev;
1248 map->bvr = NULL;
1249 map->bvrcnt = 0;
1250 map->next = gDiskBVMap;
1251 gDiskBVMap = map;
1252
1253 // fdisk like partition type id.
1254 int fsType = 0;
1255
1256 for(gptID = 1; gptID <= gptCount; ++gptID)
1257 {
1258BVRef bvr = NULL;
1259unsigned int bvrFlags = 0;
1260
1261 // size on disk can be larger than sizeof(gpt_ent)
1262 gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1263
1264 // NOTE: EFI_GUID's are in LE and we know we're on an x86.
1265 // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1266
1267 if (isPartitionUsed(gptMap))
1268 {
1269 char stringuuid[100];
1270 efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1271 verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1272
1273 // Getting fdisk like partition type.
1274 fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1275
1276 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1277 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1278 {
1279 bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1280 bvr = newGPTBVRef(biosdev,
1281 gptID,
1282 gptMap->ent_lba_start,
1283 gptMap,
1284 HFSInitPartition,
1285 HFSLoadFile,
1286 HFSReadFile,
1287 HFSGetDirEntry,
1288 HFSGetFileBlock,
1289 HFSGetUUID,
1290 HFSGetDescription,
1291 HFSFree,
1292 0,
1293 kBIOSDevTypeHardDrive, bvrFlags);
1294 }
1295
1296// zef - foreign OS support
1297 if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1298 (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1299 {
1300switch (fsType)
1301 {
1302 case FDISK_NTFS:
1303 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1304 0, 0, 0, 0, 0, 0, NTFSGetDescription,
1305 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1306break;
1307case FDISK_LINUX:
1308bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1309 0, 0, 0, 0, 0, 0, EX2GetDescription,
1310 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1311break;
1312
1313 default:
1314 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1315 0, 0, 0, 0, 0, 0, 0,
1316 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1317 break;
1318 }
1319
1320 }
1321
1322 // turbo - save our booter partition
1323 // zef - only on original boot device
1324 if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1325 {
1326switch (fsType)
1327 {
1328 case FDISK_HFS:
1329 if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1330 {
1331 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1332 HFSInitPartition,
1333 HFSLoadFile,
1334 HFSReadFile,
1335 HFSGetDirEntry,
1336 HFSGetFileBlock,
1337 HFSGetUUID,
1338 HFSGetDescription,
1339 HFSFree,
1340 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1341 }
1342 break;
1343
1344 case FDISK_FAT32:
1345 if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1346 {
1347 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1348 MSDOSInitPartition,
1349 MSDOSLoadFile,
1350 MSDOSReadFile,
1351 MSDOSGetDirEntry,
1352 MSDOSGetFileBlock,
1353 MSDOSGetUUID,
1354 MSDOSGetDescription,
1355 MSDOSFree,
1356 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1357 }
1358 break;
1359
1360 if (biosdev == gBIOSDev)
1361 gBIOSBootVolume = bvr;
1362 }
1363 }
1364
1365if (bvr)
1366{
1367 // Fixup bvr with the fake fdisk partition type.
1368 if (fsType > 0) bvr->part_type = fsType;
1369
1370bvr->next = map->bvr;
1371map->bvr = bvr;
1372++map->bvrcnt;
1373}
1374
1375 }
1376 }
1377
1378scanErr:
1379 free(buffer);
1380
1381 if(map)
1382 {
1383 if(countPtr) *countPtr = map->bvrcnt;
1384 return map->bvr;
1385 }
1386 else
1387 {
1388 if(countPtr) *countPtr = 0;
1389 return NULL;
1390 }
1391}
1392
1393//==========================================================================
1394
1395static void scanFSLevelBVRSettings(BVRef chain)
1396{
1397 BVRef bvr;
1398 char dirSpec[512], fileSpec[512];
1399 char label[BVSTRLEN];
1400 int ret;
1401 long flags, time;
1402 int fh, fileSize, error;
1403
1404 for (bvr = chain; bvr; bvr = bvr->next)
1405 {
1406 ret = -1;
1407 error = 0;
1408
1409 //
1410 // Check for alternate volume label on boot helper partitions.
1411 //
1412 if (bvr->flags & kBVFlagBooter)
1413 {
1414 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1415 strcpy(fileSpec, ".disk_label.contentDetails");
1416 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1417 if (!ret)
1418 {
1419 fh = open(strcat(dirSpec, fileSpec), 0);
1420 fileSize = file_size(fh);
1421 if (fileSize > 0 && fileSize < BVSTRLEN)
1422 {
1423 if (read(fh, label, fileSize) != fileSize)
1424 error = -1;
1425 }
1426 else
1427 error = -1;
1428
1429 close(fh);
1430
1431 if (!error)
1432 {
1433 label[fileSize] = '\0';
1434 strcpy(bvr->altlabel, label);
1435 }
1436 }
1437 }
1438
1439 //
1440 // Check for SystemVersion.plist or ServerVersion.plist
1441 // to determine if a volume hosts an installed system.
1442 //
1443 if (bvr->flags & kBVFlagNativeBoot)
1444 {
1445 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1446 strcpy(fileSpec, "SystemVersion.plist");
1447 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1448
1449 if (ret == -1)
1450 {
1451 strcpy(fileSpec, "ServerVersion.plist");
1452 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1453 }
1454
1455 if (!ret)
1456 bvr->flags |= kBVFlagSystemVolume;
1457 }
1458
1459 }
1460}
1461
1462void rescanBIOSDevice(int biosdev)
1463{
1464struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1465CacheReset();
1466diskFreeMap(oldMap);
1467oldMap = NULL;
1468scanBootVolumes(biosdev, 0);
1469}
1470
1471struct DiskBVMap* diskResetBootVolumes(int biosdev)
1472{
1473 struct DiskBVMap * map;
1474 struct DiskBVMap *prevMap = NULL;
1475 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1476 if ( biosdev == map->biosdev ) {
1477 break;
1478 }
1479 }
1480 if(map != NULL)
1481 {
1482 verbose("Resetting BIOS device %xh\n", biosdev);
1483 // Reset the biosbuf cache
1484 cache_valid = false;
1485 if(map == gDiskBVMap)
1486 gDiskBVMap = map->next;
1487 else if(prevMap != NULL)
1488 prevMap->next = map->next;
1489 else
1490 stop("");
1491 }
1492 // Return the old map, either to be freed, or reinserted later
1493 return map;
1494}
1495
1496// Frees a DiskBVMap and all of its BootVolume's
1497void diskFreeMap(struct DiskBVMap *map)
1498{
1499 if(map != NULL)
1500 {
1501 while(map->bvr != NULL)
1502 {
1503 BVRef bvr = map->bvr;
1504 map->bvr = bvr->next;
1505 (*bvr->bv_free)(bvr);
1506 }
1507 free(map);
1508 }
1509}
1510
1511BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1512{
1513 struct DiskBVMap * map = NULL;
1514 BVRef bvr;
1515 int count = 0;
1516
1517 // Find an existing mapping for this device.
1518
1519 for ( map = gDiskBVMap; map; map = map->next ) {
1520 if ( biosdev == map->biosdev ) {
1521 count = map->bvrcnt;
1522 break;
1523 }
1524 }
1525
1526 if (map == NULL) {
1527 bvr = diskScanGPTBootVolumes(biosdev, &count);
1528 if (bvr == NULL) {
1529 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1530 }
1531 if (bvr == NULL) {
1532 bvr = diskScanAPMBootVolumes(biosdev, &count);
1533 }
1534 if (bvr)
1535 {
1536 scanFSLevelBVRSettings(bvr);
1537 }
1538 } else {
1539 bvr = map->bvr;
1540 }
1541 if (countPtr) *countPtr += count;
1542 return bvr;
1543}
1544
1545BVRef getBVChainForBIOSDev(int biosdev)
1546{
1547 BVRef chain = NULL;
1548 struct DiskBVMap * map = NULL;
1549
1550 for (map = gDiskBVMap; map; map = map->next)
1551 {
1552 if (map->biosdev == biosdev)
1553 {
1554 chain = map->bvr;
1555 break;
1556 }
1557 }
1558
1559 return chain;
1560}
1561
1562BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1563{
1564 BVRef chain = NULL;
1565 BVRef bvr = NULL;
1566 BVRef newBVR = NULL;
1567 BVRef prevBVR = NULL;
1568
1569 struct DiskBVMap * map = NULL;
1570 int bvCount = 0;
1571
1572 const char *raw = 0;
1573 char* val = 0;
1574 int len;
1575
1576 getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1577 if(raw)
1578 {
1579 val = XMLDecode(raw);
1580 }
1581
1582 /*
1583 * Traverse gDISKBVmap to get references for
1584 * individual bvr chains of each drive.
1585 */
1586 for (map = gDiskBVMap; map; map = map->next)
1587 {
1588 for (bvr = map->bvr; bvr; bvr = bvr->next)
1589 {
1590 /*
1591 * Save the last bvr.
1592 */
1593 if (newBVR) prevBVR = newBVR;
1594
1595 /*
1596 * Allocate and copy the matched bvr entry into a new one.
1597 */
1598 newBVR = (BVRef) malloc(sizeof(*newBVR));
1599 bcopy(bvr, newBVR, sizeof(*newBVR));
1600
1601 /*
1602 * Adjust the new bvr's fields.
1603 */
1604 newBVR->next = NULL;
1605 newBVR->filtered = true;
1606
1607 if ( (!allowFlags || newBVR->flags & allowFlags)
1608 && (!denyFlags || !(newBVR->flags & denyFlags) )
1609 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1610 )
1611 newBVR->visible = true;
1612
1613 /*
1614 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1615 * to be able to hide foreign partitions from the boot menu.
1616 *
1617 */
1618 if ( (newBVR->flags & kBVFlagForeignBoot) )
1619 {
1620 char *start, *next = val;
1621 long len = 0;
1622 do
1623 {
1624 start = strbreak(next, &next, &len);
1625 if(len && matchVolumeToString(newBVR, start, len) )
1626 newBVR->visible = false;
1627 }
1628 while ( next && *next );
1629 }
1630
1631 /*
1632 * Use the first bvr entry as the starting chain pointer.
1633 */
1634 if (!chain)
1635 chain = newBVR;
1636
1637 /*
1638 * Update the previous bvr's link pointer to use the new memory area.
1639 */
1640 if (prevBVR)
1641 prevBVR->next = newBVR;
1642
1643 if (newBVR->visible)
1644 bvCount++;
1645 }
1646 }
1647
1648#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1649 for (bvr = chain; bvr; bvr = bvr->next)
1650 {
1651 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1652 }
1653 printf("count: %d\n", bvCount);
1654// getchar();
1655#endif
1656
1657 *count = bvCount;
1658
1659 free(val);
1660 return chain;
1661}
1662
1663int freeFilteredBVChain(const BVRef chain)
1664{
1665 int ret = 1;
1666 BVRef bvr = chain;
1667 BVRef nextBVR = NULL;
1668
1669 while (bvr)
1670 {
1671 nextBVR = bvr->next;
1672
1673 if (bvr->filtered)
1674 {
1675 free(bvr);
1676 }
1677 else
1678 {
1679 ret = 0;
1680 break;
1681 }
1682
1683 bvr = nextBVR;
1684 }
1685
1686 return ret;
1687}
1688
1689//==========================================================================
1690
1691static const struct NamedValue fdiskTypes[] =
1692{
1693 { FDISK_NTFS, "Windows NTFS" },
1694{ FDISK_DOS12, "Windows FAT12" },
1695{ FDISK_DOS16B, "Windows FAT16" },
1696{ FDISK_DOS16S, "Windows FAT16" },
1697{ FDISK_DOS16SLBA, "Windows FAT16" },
1698{ FDISK_SMALLFAT32, "Windows FAT32" },
1699{ FDISK_FAT32, "Windows FAT32" },
1700 { FDISK_LINUX, "Linux" },
1701 { FDISK_UFS, "Apple UFS" },
1702 { FDISK_HFS, "Apple HFS" },
1703 { FDISK_BOOTER, "Apple Boot/UFS" },
1704 { 0xCD, "CD-ROM" },
1705 { 0x00, 0 } /* must be last */
1706};
1707
1708//==========================================================================
1709
1710bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1711{
1712char testStr[128];
1713
1714if ( !bvr || !match || !*match)
1715return 0;
1716
1717if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1718 return 0;
1719
1720 // Try to match hd(x,y) first.
1721 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1722 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1723 return true;
1724
1725 // Try to match volume UUID.
1726 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1727 {
1728 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1729 return true;
1730 }
1731
1732 // Try to match volume label (always quoted).
1733 if ( bvr->description )
1734 {
1735 bvr->description(bvr, testStr, sizeof(testStr)-1);
1736 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1737 return true;
1738 }
1739
1740 return false;
1741}
1742
1743/* If Rename Partition has defined an alias, then extract it for description purpose.
1744 * The format for the rename string is the following:
1745 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
1746 */
1747
1748bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
1749{
1750 char *aliasList, *entryStart, *entryNext;
1751
1752 if ( !str || strMaxLen <= 0)
1753 return false;
1754
1755 aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
1756 if ( !aliasList )
1757 return false;
1758
1759 for ( entryStart = entryNext = aliasList;
1760 entryNext && *entryNext;
1761 entryStart = entryNext )
1762 {
1763 char *volStart, *volEnd, *aliasStart;
1764 long volLen, aliasLen;
1765
1766 // Delimit current entry
1767 entryNext = strchr(entryStart, ';');
1768 if ( entryNext )
1769 {
1770 *entryNext = '\0';
1771 entryNext++;
1772 }
1773
1774 volStart = strbreak(entryStart, &volEnd, &volLen);
1775 if(!volLen)
1776 continue;
1777
1778 aliasStart = strbreak(volEnd, 0, &aliasLen);
1779 if(!aliasLen)
1780 continue;
1781
1782 if ( matchVolumeToString(bvr, volStart, volLen) )
1783 {
1784 strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
1785 free(aliasList);
1786
1787 return true;
1788 }
1789 }
1790
1791 free(aliasList);
1792 return false;
1793}
1794
1795void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1796{
1797 unsigned char type;
1798 char *p = str;
1799
1800 if(!bvr || !p || strMaxLen <= 0)
1801 return;
1802
1803 type = (unsigned char) bvr->part_type;
1804
1805 if (useDeviceDescription)
1806 {
1807 int len = getDeviceDescription(bvr, str);
1808 if(len >= strMaxLen)
1809 return;
1810
1811 strcpy(str + len, " ");
1812 len++;
1813 strMaxLen -= len;
1814 p += len;
1815 }
1816
1817 /* See if a partition rename is preferred */
1818 if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
1819 strncpy(bvr->label, p, strMaxLen);
1820 return; // we're done here no need to seek for real name
1821 }
1822
1823 //
1824 // Get the volume label using filesystem specific functions
1825 // or use the alternate volume label if available.
1826 //
1827if (*bvr->altlabel != '\0')
1828 strncpy(p, bvr->altlabel, strMaxLen);
1829else if (bvr->description)
1830 bvr->description(bvr, p, strMaxLen);
1831
1832 if (*p == '\0') {
1833 const char * name = getNameForValue( fdiskTypes, type );
1834 if (name == NULL) {
1835 name = bvr->type_name;
1836 }
1837 if (name == NULL) {
1838 sprintf(p, "TYPE %02x", type);
1839 } else {
1840 strncpy(p, name, strMaxLen);
1841 }
1842 }
1843
1844 // Set the devices label
1845 sprintf(bvr->label, p);
1846}
1847
1848//==========================================================================
1849int readBootSector( int biosdev, unsigned int secno, void * buffer )
1850{
1851 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
1852 int error;
1853
1854 if ( bootSector == NULL )
1855 {
1856 if ( gBootSector == NULL )
1857 {
1858 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1859 if ( gBootSector == NULL ) return -1;
1860 }
1861 bootSector = gBootSector;
1862 }
1863
1864 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1865 if ( error || bootSector->signature != DISK_SIGNATURE )
1866 return -1;
1867
1868 return 0;
1869}
1870
1871/*
1872 * Format of boot1f32 block.
1873 */
1874
1875#define BOOT1F32_MAGIC "BOOT "
1876#define BOOT1F32_MAGICLEN 11
1877
1878struct disk_boot1f32_blk {
1879 unsigned char init[3];
1880 unsigned char fsheader[87];
1881 unsigned char magic[BOOT1F32_MAGICLEN];
1882 unsigned char bootcode[409];
1883 unsigned short signature;
1884};
1885
1886int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
1887{
1888 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
1889 int error;
1890
1891 if ( bootSector == NULL )
1892 {
1893 if ( gBootSector == NULL )
1894 {
1895 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1896 if ( gBootSector == NULL ) return -1;
1897 }
1898 bootSector = (struct disk_boot1f32_blk *) gBootSector;
1899 }
1900
1901 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1902 if ( error || bootSector->signature != DISK_SIGNATURE
1903 || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
1904 return -1;
1905
1906 return 0;
1907}
1908
1909//==========================================================================
1910// Handle seek request from filesystem modules.
1911
1912void diskSeek( BVRef bvr, long long position )
1913{
1914 bvr->fs_boff = position / BPS;
1915 bvr->fs_byteoff = position % BPS;
1916}
1917
1918//==========================================================================
1919// Handle read request from filesystem modules.
1920
1921int diskRead( BVRef bvr, long addr, long length )
1922{
1923 return readBytes( bvr->biosdev,
1924 bvr->fs_boff + bvr->part_boff,
1925 bvr->fs_byteoff,
1926 length,
1927 (void *) addr );
1928}
1929
1930int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1931{
1932 int secs;
1933 unsigned char *cbuf = (unsigned char *)buffer;
1934 unsigned int copy_len;
1935 int rc;
1936
1937 if ((len & (BPS-1)) != 0) {
1938 error("raw disk read not sector aligned");
1939 return -1;
1940 }
1941 secno += bvr->part_boff;
1942
1943 cache_valid = false;
1944
1945 while (len > 0) {
1946 secs = len / BPS;
1947 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1948 copy_len = secs * BPS;
1949
1950 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1951 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
1952 /* Ignore corrected ECC errors */
1953 if (rc != ECC_CORRECTED_ERR) {
1954 error(" EBIOS read error: %s\n", bios_error(rc), rc);
1955 error(" Block %d Sectors %d\n", secno, secs);
1956 return rc;
1957 }
1958 }
1959 bcopy( trackbuf, cbuf, copy_len );
1960 len -= copy_len;
1961 cbuf += copy_len;
1962 secno += secs;
1963 spinActivityIndicator(secs);
1964 }
1965
1966 return 0;
1967}
1968
1969int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1970{
1971 int secs;
1972 unsigned char *cbuf = (unsigned char *)buffer;
1973 unsigned int copy_len;
1974 int rc;
1975
1976 if ((len & (BPS-1)) != 0) {
1977 error("raw disk write not sector aligned");
1978 return -1;
1979 }
1980 secno += bvr->part_boff;
1981
1982 cache_valid = false;
1983
1984 while (len > 0) {
1985 secs = len / BPS;
1986 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1987 copy_len = secs * BPS;
1988
1989 bcopy( cbuf, trackbuf, copy_len );
1990 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1991 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
1992 error(" EBIOS write error: %s\n", bios_error(rc), rc);
1993 error(" Block %d Sectors %d\n", secno, secs);
1994 return rc;
1995 }
1996 len -= copy_len;
1997 cbuf += copy_len;
1998 secno += secs;
1999 spinActivityIndicator(secs);
2000 }
2001
2002 return 0;
2003}
2004
2005int diskIsCDROM(BVRef bvr)
2006{
2007 struct driveInfo di;
2008
2009 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
2010return 1;
2011 }
2012 return 0;
2013}
2014
2015int biosDevIsCDROM(int biosdev)
2016{
2017 struct driveInfo di;
2018
2019 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2020 {
2021 return 1;
2022 }
2023 return 0;
2024}
2025

Archive Download this file

Revision: 1207