Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2225