Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/trunkAutoResolution/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;
1307
1308 default:
1309 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1310 0, 0, 0, 0, 0, 0, 0,
1311 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1312 break;
1313 }
1314
1315 }
1316
1317 // turbo - save our booter partition
1318 // zef - only on original boot device
1319 if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1320 {
1321switch (fsType)
1322 {
1323 case FDISK_HFS:
1324 if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1325 {
1326 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1327 HFSInitPartition,
1328 HFSLoadFile,
1329 HFSReadFile,
1330 HFSGetDirEntry,
1331 HFSGetFileBlock,
1332 HFSGetUUID,
1333 HFSGetDescription,
1334 HFSFree,
1335 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1336 }
1337 break;
1338
1339 case FDISK_FAT32:
1340 if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1341 {
1342 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1343 MSDOSInitPartition,
1344 MSDOSLoadFile,
1345 MSDOSReadFile,
1346 MSDOSGetDirEntry,
1347 MSDOSGetFileBlock,
1348 MSDOSGetUUID,
1349 MSDOSGetDescription,
1350 MSDOSFree,
1351 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1352 }
1353 break;
1354
1355 if (biosdev == gBIOSDev)
1356 gBIOSBootVolume = bvr;
1357 }
1358 }
1359
1360if (bvr)
1361{
1362 // Fixup bvr with the fake fdisk partition type.
1363 if (fsType > 0) bvr->part_type = fsType;
1364
1365bvr->next = map->bvr;
1366map->bvr = bvr;
1367++map->bvrcnt;
1368}
1369
1370 }
1371 }
1372
1373scanErr:
1374 free(buffer);
1375
1376 if(map)
1377 {
1378 if(countPtr) *countPtr = map->bvrcnt;
1379 return map->bvr;
1380 }
1381 else
1382 {
1383 if(countPtr) *countPtr = 0;
1384 return NULL;
1385 }
1386}
1387
1388//==========================================================================
1389
1390static void scanFSLevelBVRSettings(BVRef chain)
1391{
1392 BVRef bvr;
1393 char dirSpec[512], fileSpec[512];
1394 char label[BVSTRLEN];
1395 int ret;
1396 long flags, time;
1397 int fh, fileSize, error;
1398
1399 for (bvr = chain; bvr; bvr = bvr->next)
1400 {
1401 ret = -1;
1402 error = 0;
1403
1404 //
1405 // Check for alternate volume label on boot helper partitions.
1406 //
1407 if (bvr->flags & kBVFlagBooter)
1408 {
1409 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1410 strcpy(fileSpec, ".disk_label.contentDetails");
1411 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1412 if (!ret)
1413 {
1414 fh = open(strcat(dirSpec, fileSpec), 0);
1415 fileSize = file_size(fh);
1416 if (fileSize > 0 && fileSize < BVSTRLEN)
1417 {
1418 if (read(fh, label, fileSize) != fileSize)
1419 error = -1;
1420 }
1421 else
1422 error = -1;
1423
1424 close(fh);
1425
1426 if (!error)
1427 {
1428 label[fileSize] = '\0';
1429 strcpy(bvr->altlabel, label);
1430 }
1431 }
1432 }
1433
1434 //
1435 // Check for SystemVersion.plist or ServerVersion.plist
1436 // to determine if a volume hosts an installed system.
1437 //
1438 if (bvr->flags & kBVFlagNativeBoot)
1439 {
1440 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1441 strcpy(fileSpec, "SystemVersion.plist");
1442 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1443
1444 if (ret == -1)
1445 {
1446 strcpy(fileSpec, "ServerVersion.plist");
1447 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1448 }
1449
1450 if (!ret)
1451 bvr->flags |= kBVFlagSystemVolume;
1452 }
1453
1454 }
1455}
1456
1457void rescanBIOSDevice(int biosdev)
1458{
1459struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1460CacheReset();
1461diskFreeMap(oldMap);
1462oldMap = NULL;
1463scanBootVolumes(biosdev, 0);
1464}
1465
1466struct DiskBVMap* diskResetBootVolumes(int biosdev)
1467{
1468 struct DiskBVMap * map;
1469 struct DiskBVMap *prevMap = NULL;
1470 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1471 if ( biosdev == map->biosdev ) {
1472 break;
1473 }
1474 }
1475 if(map != NULL)
1476 {
1477 verbose("Resetting BIOS device %xh\n", biosdev);
1478 // Reset the biosbuf cache
1479 cache_valid = false;
1480 if(map == gDiskBVMap)
1481 gDiskBVMap = map->next;
1482 else if(prevMap != NULL)
1483 prevMap->next = map->next;
1484 else
1485 stop("");
1486 }
1487 // Return the old map, either to be freed, or reinserted later
1488 return map;
1489}
1490
1491// Frees a DiskBVMap and all of its BootVolume's
1492void diskFreeMap(struct DiskBVMap *map)
1493{
1494 if(map != NULL)
1495 {
1496 while(map->bvr != NULL)
1497 {
1498 BVRef bvr = map->bvr;
1499 map->bvr = bvr->next;
1500 (*bvr->bv_free)(bvr);
1501 }
1502 free(map);
1503 }
1504}
1505
1506BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1507{
1508 struct DiskBVMap * map;
1509 BVRef bvr;
1510 int count = 0;
1511
1512 // Find an existing mapping for this device.
1513
1514 for ( map = gDiskBVMap; map; map = map->next ) {
1515 if ( biosdev == map->biosdev ) {
1516 count = map->bvrcnt;
1517 break;
1518 }
1519 }
1520
1521 if (map == NULL) {
1522 bvr = diskScanGPTBootVolumes(biosdev, &count);
1523 if (bvr == NULL) {
1524 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1525 }
1526 if (bvr == NULL) {
1527 bvr = diskScanAPMBootVolumes(biosdev, &count);
1528 }
1529 if (bvr)
1530 {
1531 scanFSLevelBVRSettings(bvr);
1532 }
1533 } else {
1534 bvr = map->bvr;
1535 }
1536 if (countPtr) *countPtr += count;
1537 return bvr;
1538}
1539
1540BVRef getBVChainForBIOSDev(int biosdev)
1541{
1542 BVRef chain = NULL;
1543 struct DiskBVMap * map = NULL;
1544
1545 for (map = gDiskBVMap; map; map = map->next)
1546 {
1547 if (map->biosdev == biosdev)
1548 {
1549 chain = map->bvr;
1550 break;
1551 }
1552 }
1553
1554 return chain;
1555}
1556
1557BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1558{
1559 BVRef chain = NULL;
1560 BVRef bvr = NULL;
1561 BVRef newBVR = NULL;
1562 BVRef prevBVR = NULL;
1563
1564 struct DiskBVMap * map = NULL;
1565 int bvCount = 0;
1566
1567 const char *raw = 0;
1568 char* val = 0;
1569 int len;
1570
1571 getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1572 if(raw)
1573 {
1574 val = XMLDecode(raw);
1575 }
1576
1577 /*
1578 * Traverse gDISKBVmap to get references for
1579 * individual bvr chains of each drive.
1580 */
1581 for (map = gDiskBVMap; map; map = map->next)
1582 {
1583 for (bvr = map->bvr; bvr; bvr = bvr->next)
1584 {
1585 /*
1586 * Save the last bvr.
1587 */
1588 if (newBVR) prevBVR = newBVR;
1589
1590 /*
1591 * Allocate and copy the matched bvr entry into a new one.
1592 */
1593 newBVR = (BVRef) malloc(sizeof(*newBVR));
1594 bcopy(bvr, newBVR, sizeof(*newBVR));
1595
1596 /*
1597 * Adjust the new bvr's fields.
1598 */
1599 newBVR->next = NULL;
1600 newBVR->filtered = true;
1601
1602 if ( (!allowFlags || newBVR->flags & allowFlags)
1603 && (!denyFlags || !(newBVR->flags & denyFlags) )
1604 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1605 )
1606 newBVR->visible = true;
1607
1608 /*
1609 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1610 * to be able to hide foreign partitions from the boot menu.
1611 *
1612 */
1613 if ( (newBVR->flags & kBVFlagForeignBoot) )
1614 {
1615 char *start, *next = val;
1616 long len = 0;
1617 do
1618 {
1619 start = strbreak(next, &next, &len);
1620 if(len && matchVolumeToString(newBVR, start, len) )
1621 newBVR->visible = false;
1622 }
1623 while ( next && *next );
1624 }
1625
1626 /*
1627 * Use the first bvr entry as the starting chain pointer.
1628 */
1629 if (!chain)
1630 chain = newBVR;
1631
1632 /*
1633 * Update the previous bvr's link pointer to use the new memory area.
1634 */
1635 if (prevBVR)
1636 prevBVR->next = newBVR;
1637
1638 if (newBVR->visible)
1639 bvCount++;
1640 }
1641 }
1642
1643#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1644 for (bvr = chain; bvr; bvr = bvr->next)
1645 {
1646 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1647 }
1648 printf("count: %d\n", bvCount);
1649 getchar();
1650#endif
1651
1652 *count = bvCount;
1653
1654 free(val);
1655 return chain;
1656}
1657
1658int freeFilteredBVChain(const BVRef chain)
1659{
1660 int ret = 1;
1661 BVRef bvr = chain;
1662 BVRef nextBVR = NULL;
1663
1664 while (bvr)
1665 {
1666 nextBVR = bvr->next;
1667
1668 if (bvr->filtered)
1669 {
1670 free(bvr);
1671 }
1672 else
1673 {
1674 ret = 0;
1675 break;
1676 }
1677
1678 bvr = nextBVR;
1679 }
1680
1681 return ret;
1682}
1683
1684//==========================================================================
1685
1686static const struct NamedValue fdiskTypes[] =
1687{
1688{ FDISK_NTFS,"Windows NTFS" },
1689{ FDISK_DOS12,"Windows FAT12" },
1690{ FDISK_DOS16B,"Windows FAT16" },
1691{ FDISK_DOS16S,"Windows FAT16" },
1692{ FDISK_DOS16SLBA,"Windows FAT16" },
1693{ FDISK_SMALLFAT32,"Windows FAT32" },
1694{ FDISK_FAT32,"Windows FAT32" },
1695{ FDISK_LINUX,"Linux" },
1696{ FDISK_UFS,"Apple UFS" },
1697{ FDISK_HFS,"Apple HFS" },
1698{ FDISK_BOOTER,"Apple Boot/UFS" },
1699{ 0xCD,"CD-ROM" },
1700{ 0x00,0 } /* must be last */
1701};
1702
1703//==========================================================================
1704
1705bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1706{
1707char testStr[128];
1708
1709if ( !bvr || !match || !*match)
1710return 0;
1711
1712if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1713 return 0;
1714
1715 // Try to match hd(x,y) first.
1716 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1717 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1718 return true;
1719
1720 // Try to match volume UUID.
1721 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1722 {
1723 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1724 return true;
1725 }
1726
1727 // Try to match volume label (always quoted).
1728 if ( bvr->description )
1729 {
1730 bvr->description(bvr, testStr, sizeof(testStr)-1);
1731 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1732 return true;
1733 }
1734
1735 return false;
1736}
1737
1738/* If Rename Partition has defined an alias, then extract it for description purpose.
1739 * The format for the rename string is the following:
1740 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
1741 */
1742
1743bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
1744{
1745 char *aliasList, *entryStart, *entryNext;
1746
1747 if ( !str || strMaxLen <= 0)
1748 return false;
1749
1750 aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
1751 if ( !aliasList )
1752 return false;
1753
1754 for ( entryStart = entryNext = aliasList;
1755 entryNext && *entryNext;
1756 entryStart = entryNext )
1757 {
1758 char *volStart, *volEnd, *aliasStart;
1759 long volLen, aliasLen;
1760
1761 // Delimit current entry
1762 entryNext = strchr(entryStart, ';');
1763 if ( entryNext )
1764 {
1765 *entryNext = '\0';
1766 entryNext++;
1767 }
1768
1769 volStart = strbreak(entryStart, &volEnd, &volLen);
1770 if(!volLen)
1771 continue;
1772
1773 aliasStart = strbreak(volEnd, 0, &aliasLen);
1774 if(!aliasLen)
1775 continue;
1776
1777 if ( matchVolumeToString(bvr, volStart, volLen) )
1778 {
1779 strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
1780 free(aliasList);
1781
1782 return true;
1783 }
1784 }
1785
1786 free(aliasList);
1787 return false;
1788}
1789
1790void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1791{
1792 unsigned char type;
1793 char *p = str;
1794
1795 if(!bvr || !p || strMaxLen <= 0)
1796 return;
1797
1798 type = (unsigned char) bvr->part_type;
1799
1800 if (useDeviceDescription)
1801 {
1802 int len = getDeviceDescription(bvr, str);
1803 if(len >= strMaxLen)
1804 return;
1805
1806 strcpy(str + len, " ");
1807 len++;
1808 strMaxLen -= len;
1809 p += len;
1810 }
1811
1812 /* See if a partition rename is preferred */
1813 if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
1814 strncpy(bvr->label, p, strMaxLen);
1815 return; // we're done here no need to seek for real name
1816 }
1817
1818 //
1819 // Get the volume label using filesystem specific functions
1820 // or use the alternate volume label if available.
1821 //
1822if (*bvr->altlabel != '\0')
1823 strncpy(p, bvr->altlabel, strMaxLen);
1824else if (bvr->description)
1825 bvr->description(bvr, p, strMaxLen);
1826
1827 if (*p == '\0') {
1828 const char * name = getNameForValue( fdiskTypes, type );
1829 if (name == NULL) {
1830 name = bvr->type_name;
1831 }
1832 if (name == NULL) {
1833 sprintf(p, "TYPE %02x", type);
1834 } else {
1835 strncpy(p, name, strMaxLen);
1836 }
1837 }
1838
1839 // Set the devices label
1840 sprintf(bvr->label, p);
1841}
1842
1843//==========================================================================
1844int readBootSector( int biosdev, unsigned int secno, void * buffer )
1845{
1846 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
1847 int error;
1848
1849 if ( bootSector == NULL )
1850 {
1851 if ( gBootSector == NULL )
1852 {
1853 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1854 if ( gBootSector == NULL ) return -1;
1855 }
1856 bootSector = gBootSector;
1857 }
1858
1859 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1860 if ( error || bootSector->signature != DISK_SIGNATURE )
1861 return -1;
1862
1863 return 0;
1864}
1865
1866/*
1867 * Format of boot1f32 block.
1868 */
1869
1870#define BOOT1F32_MAGIC "BOOT "
1871#define BOOT1F32_MAGICLEN 11
1872
1873struct disk_boot1f32_blk {
1874 unsigned char init[3];
1875 unsigned char fsheader[87];
1876 unsigned char magic[BOOT1F32_MAGICLEN];
1877 unsigned char bootcode[409];
1878 unsigned short signature;
1879};
1880
1881int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
1882{
1883 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
1884 int error;
1885
1886 if ( bootSector == NULL )
1887 {
1888 if ( gBootSector == NULL )
1889 {
1890 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1891 if ( gBootSector == NULL ) return -1;
1892 }
1893 bootSector = (struct disk_boot1f32_blk *) gBootSector;
1894 }
1895
1896 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1897 if ( error || bootSector->signature != DISK_SIGNATURE
1898 || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
1899 return -1;
1900
1901 return 0;
1902}
1903
1904//==========================================================================
1905// Handle seek request from filesystem modules.
1906
1907void diskSeek( BVRef bvr, long long position )
1908{
1909 bvr->fs_boff = position / BPS;
1910 bvr->fs_byteoff = position % BPS;
1911}
1912
1913//==========================================================================
1914// Handle read request from filesystem modules.
1915
1916int diskRead( BVRef bvr, long addr, long length )
1917{
1918 return readBytes( bvr->biosdev,
1919 bvr->fs_boff + bvr->part_boff,
1920 bvr->fs_byteoff,
1921 length,
1922 (void *) addr );
1923}
1924
1925int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1926{
1927 int secs;
1928 unsigned char *cbuf = (unsigned char *)buffer;
1929 unsigned int copy_len;
1930 int rc;
1931
1932 if ((len & (BPS-1)) != 0) {
1933 error("raw disk read not sector aligned");
1934 return -1;
1935 }
1936 secno += bvr->part_boff;
1937
1938 cache_valid = false;
1939
1940 while (len > 0) {
1941 secs = len / BPS;
1942 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1943 copy_len = secs * BPS;
1944
1945 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1946 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
1947 /* Ignore corrected ECC errors */
1948 if (rc != ECC_CORRECTED_ERR) {
1949 error(" EBIOS read error: %s\n", bios_error(rc), rc);
1950 error(" Block %d Sectors %d\n", secno, secs);
1951 return rc;
1952 }
1953 }
1954 bcopy( trackbuf, cbuf, copy_len );
1955 len -= copy_len;
1956 cbuf += copy_len;
1957 secno += secs;
1958 spinActivityIndicator(secs);
1959 }
1960
1961 return 0;
1962}
1963
1964int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1965{
1966 int secs;
1967 unsigned char *cbuf = (unsigned char *)buffer;
1968 unsigned int copy_len;
1969 int rc;
1970
1971 if ((len & (BPS-1)) != 0) {
1972 error("raw disk write not sector aligned");
1973 return -1;
1974 }
1975 secno += bvr->part_boff;
1976
1977 cache_valid = false;
1978
1979 while (len > 0) {
1980 secs = len / BPS;
1981 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1982 copy_len = secs * BPS;
1983
1984 bcopy( cbuf, trackbuf, copy_len );
1985 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1986 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
1987 error(" EBIOS write error: %s\n", bios_error(rc), rc);
1988 error(" Block %d Sectors %d\n", secno, secs);
1989 return rc;
1990 }
1991 len -= copy_len;
1992 cbuf += copy_len;
1993 secno += secs;
1994 spinActivityIndicator(secs);
1995 }
1996
1997 return 0;
1998}
1999
2000int diskIsCDROM(BVRef bvr)
2001{
2002 struct driveInfo di;
2003
2004 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
2005return 1;
2006 }
2007 return 0;
2008}
2009
2010int biosDevIsCDROM(int biosdev)
2011{
2012 struct driveInfo di;
2013
2014 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2015 {
2016 return 1;
2017 }
2018 return 0;
2019}
2020

Archive Download this file

Revision: 1380