Chameleon

Chameleon Svn Source Tree

Root/trunk/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;
1481}
1482else
1483{
1484close(fh);
1485}
1486}
1487
1488return valid;
1489}
1490
1491//==========================================================================
1492
1493static void scanFSLevelBVRSettings(BVRef chain)
1494{
1495 BVRef bvr;
1496 char dirSpec[512], fileSpec[512];
1497 char label[BVSTRLEN];
1498 int ret;
1499 long flags, time;
1500 int fh, fileSize, error;
1501
1502 for (bvr = chain; bvr; bvr = bvr->next)
1503 {
1504 ret = -1;
1505 error = 0;
1506
1507 //
1508 // Check for alternate volume label on boot helper partitions.
1509 //
1510 if (bvr->flags & kBVFlagBooter)
1511 {
1512 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1513 strcpy(fileSpec, ".disk_label.contentDetails");
1514 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1515 if (!ret)
1516 {
1517 fh = open(strcat(dirSpec, fileSpec), 0);
1518 fileSize = file_size(fh);
1519 if (fileSize > 0 && fileSize < BVSTRLEN)
1520 {
1521 if (read(fh, label, fileSize) != fileSize)
1522 error = -1;
1523 }
1524 else
1525 error = -1;
1526
1527 close(fh);
1528
1529 if (!error)
1530 {
1531 label[fileSize] = '\0';
1532 strcpy(bvr->altlabel, label);
1533 }
1534 }
1535 }
1536
1537 //
1538 // Check for SystemVersion.plist or ServerVersion.plist
1539 // to determine if a volume hosts an installed system.
1540 //
1541 if (bvr->flags & kBVFlagNativeBoot)
1542 {
1543 if (getOSVersion(bvr,bvr->OSVersion) == true)
1544 {
1545 bvr->flags |= kBVFlagSystemVolume;
1546 }
1547 }
1548
1549 }
1550}
1551
1552void rescanBIOSDevice(int biosdev)
1553{
1554struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1555CacheReset();
1556diskFreeMap(oldMap);
1557oldMap = NULL;
1558scanBootVolumes(biosdev, 0);
1559}
1560
1561struct DiskBVMap* diskResetBootVolumes(int biosdev)
1562{
1563 struct DiskBVMap * map;
1564 struct DiskBVMap *prevMap = NULL;
1565 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1566 if ( biosdev == map->biosdev ) {
1567 break;
1568 }
1569 }
1570 if(map != NULL)
1571 {
1572 verbose("Resetting BIOS device %xh\n", biosdev);
1573 // Reset the biosbuf cache
1574 cache_valid = false;
1575 if(map == gDiskBVMap)
1576 gDiskBVMap = map->next;
1577 else if(prevMap != NULL)
1578 prevMap->next = map->next;
1579 else
1580 stop("");
1581 }
1582 // Return the old map, either to be freed, or reinserted later
1583 return map;
1584}
1585
1586// Frees a DiskBVMap and all of its BootVolume's
1587void diskFreeMap(struct DiskBVMap *map)
1588{
1589 if(map != NULL)
1590 {
1591 while(map->bvr != NULL)
1592 {
1593 BVRef bvr = map->bvr;
1594 map->bvr = bvr->next;
1595 (*bvr->bv_free)(bvr);
1596 }
1597 free(map);
1598 }
1599}
1600
1601BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1602{
1603 struct DiskBVMap * map;
1604 BVRef bvr;
1605 int count = 0;
1606
1607 // Find an existing mapping for this device.
1608
1609 for ( map = gDiskBVMap; map; map = map->next ) {
1610 if ( biosdev == map->biosdev ) {
1611 count = map->bvrcnt;
1612 break;
1613 }
1614 }
1615
1616 if (map == NULL) {
1617 bvr = diskScanGPTBootVolumes(biosdev, &count);
1618 if (bvr == NULL) {
1619 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1620 }
1621 if (bvr == NULL) {
1622 bvr = diskScanAPMBootVolumes(biosdev, &count);
1623 }
1624 if (bvr)
1625 {
1626 scanFSLevelBVRSettings(bvr);
1627 }
1628 } else {
1629 bvr = map->bvr;
1630 }
1631 if (countPtr) *countPtr += count;
1632 return bvr;
1633}
1634
1635BVRef getBVChainForBIOSDev(int biosdev)
1636{
1637 BVRef chain = NULL;
1638 struct DiskBVMap * map = NULL;
1639
1640 for (map = gDiskBVMap; map; map = map->next)
1641 {
1642 if (map->biosdev == biosdev)
1643 {
1644 chain = map->bvr;
1645 break;
1646 }
1647 }
1648
1649 return chain;
1650}
1651
1652BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1653{
1654 BVRef chain = NULL;
1655 BVRef bvr = NULL;
1656 BVRef newBVR = NULL;
1657 BVRef prevBVR = NULL;
1658
1659 struct DiskBVMap * map = NULL;
1660 int bvCount = 0;
1661
1662 const char *raw = 0;
1663 char* val = 0;
1664 int len;
1665
1666 getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1667 if(raw)
1668 {
1669 val = XMLDecode(raw);
1670 }
1671
1672 /*
1673 * Traverse gDISKBVmap to get references for
1674 * individual bvr chains of each drive.
1675 */
1676 for (map = gDiskBVMap; map; map = map->next)
1677 {
1678 for (bvr = map->bvr; bvr; bvr = bvr->next)
1679 {
1680 /*
1681 * Save the last bvr.
1682 */
1683 if (newBVR) prevBVR = newBVR;
1684
1685 /*
1686 * Allocate and copy the matched bvr entry into a new one.
1687 */
1688 newBVR = (BVRef) malloc(sizeof(*newBVR));
1689 bcopy(bvr, newBVR, sizeof(*newBVR));
1690
1691 /*
1692 * Adjust the new bvr's fields.
1693 */
1694 newBVR->next = NULL;
1695 newBVR->filtered = true;
1696
1697 if ( (!allowFlags || newBVR->flags & allowFlags)
1698 && (!denyFlags || !(newBVR->flags & denyFlags) )
1699 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1700 )
1701 newBVR->visible = true;
1702
1703 /*
1704 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1705 * to be able to hide foreign partitions from the boot menu.
1706 *
1707 */
1708 if ( (newBVR->flags & kBVFlagForeignBoot) )
1709 {
1710 char *start, *next = val;
1711 long len = 0;
1712 do
1713 {
1714 start = strbreak(next, &next, &len);
1715 if(len && matchVolumeToString(newBVR, start, len) )
1716 newBVR->visible = false;
1717 }
1718 while ( next && *next );
1719 }
1720
1721 /*
1722 * Use the first bvr entry as the starting chain pointer.
1723 */
1724 if (!chain)
1725 chain = newBVR;
1726
1727 /*
1728 * Update the previous bvr's link pointer to use the new memory area.
1729 */
1730 if (prevBVR)
1731 prevBVR->next = newBVR;
1732
1733 if (newBVR->visible)
1734 bvCount++;
1735 }
1736 }
1737
1738#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1739 for (bvr = chain; bvr; bvr = bvr->next)
1740 {
1741 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1742 }
1743 printf("count: %d\n", bvCount);
1744 getchar();
1745#endif
1746
1747 *count = bvCount;
1748
1749 free(val);
1750 return chain;
1751}
1752
1753int freeFilteredBVChain(const BVRef chain)
1754{
1755 int ret = 1;
1756 BVRef bvr = chain;
1757 BVRef nextBVR = NULL;
1758
1759 while (bvr)
1760 {
1761 nextBVR = bvr->next;
1762
1763 if (bvr->filtered)
1764 {
1765 free(bvr);
1766 }
1767 else
1768 {
1769 ret = 0;
1770 break;
1771 }
1772
1773 bvr = nextBVR;
1774 }
1775
1776 return ret;
1777}
1778
1779//==========================================================================
1780
1781static const struct NamedValue fdiskTypes[] =
1782{
1783{ FDISK_NTFS,"Windows NTFS" },
1784{ FDISK_DOS12,"Windows FAT12" },
1785{ FDISK_DOS16B,"Windows FAT16" },
1786{ FDISK_DOS16S,"Windows FAT16" },
1787{ FDISK_DOS16SLBA,"Windows FAT16" },
1788{ FDISK_SMALLFAT32,"Windows FAT32" },
1789{ FDISK_FAT32,"Windows FAT32" },
1790{ FDISK_FREEBSD,"FreeBSD" },
1791{ FDISK_OPENBSD,"OpenBSD" },
1792{ FDISK_LINUX,"Linux" },
1793{ FDISK_UFS,"Apple UFS" },
1794{ FDISK_HFS,"Apple HFS" },
1795{ FDISK_BOOTER,"Apple Boot/UFS" },
1796{ FDISK_BEFS,"Haiku" },
1797{ 0xCD,"CD-ROM" },
1798{ 0x00,0 } /* must be last */
1799};
1800
1801//==========================================================================
1802
1803bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1804{
1805char testStr[128];
1806
1807if ( !bvr || !match || !*match)
1808return 0;
1809
1810if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1811 return 0;
1812
1813 // Try to match hd(x,y) first.
1814 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1815 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1816 return true;
1817
1818 // Try to match volume UUID.
1819 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1820 {
1821 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1822 return true;
1823 }
1824
1825 // Try to match volume label (always quoted).
1826 if ( bvr->description )
1827 {
1828 bvr->description(bvr, testStr, sizeof(testStr)-1);
1829 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1830 return true;
1831 }
1832
1833 return false;
1834}
1835
1836/* If Rename Partition has defined an alias, then extract it for description purpose.
1837 * The format for the rename string is the following:
1838 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
1839 */
1840
1841bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
1842{
1843 char *aliasList, *entryStart, *entryNext;
1844
1845 if ( !str || strMaxLen <= 0)
1846 return false;
1847
1848 aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
1849 if ( !aliasList )
1850 return false;
1851
1852 for ( entryStart = entryNext = aliasList;
1853 entryNext && *entryNext;
1854 entryStart = entryNext )
1855 {
1856 char *volStart, *volEnd, *aliasStart;
1857 long volLen, aliasLen;
1858
1859 // Delimit current entry
1860 entryNext = strchr(entryStart, ';');
1861 if ( entryNext )
1862 {
1863 *entryNext = '\0';
1864 entryNext++;
1865 }
1866
1867 volStart = strbreak(entryStart, &volEnd, &volLen);
1868 if(!volLen)
1869 continue;
1870
1871 aliasStart = strbreak(volEnd, 0, &aliasLen);
1872 if(!aliasLen)
1873 continue;
1874
1875 if ( matchVolumeToString(bvr, volStart, volLen) )
1876 {
1877 strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
1878 free(aliasList);
1879
1880 return true;
1881 }
1882 }
1883
1884 free(aliasList);
1885 return false;
1886}
1887
1888void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1889{
1890 unsigned char type;
1891 char *p = str;
1892
1893 if(!bvr || !p || strMaxLen <= 0)
1894 return;
1895
1896 type = (unsigned char) bvr->part_type;
1897
1898 if (useDeviceDescription)
1899 {
1900 int len = getDeviceDescription(bvr, str);
1901 if(len >= strMaxLen)
1902 return;
1903
1904 strcpy(str + len, bvr->OSisInstaller ? " (Installer) " : " ");
1905 len += bvr->OSisInstaller ? 13 : 1;
1906 strMaxLen -= len;
1907 p += len;
1908 }
1909
1910 /* See if a partition rename is preferred */
1911 if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
1912 strncpy(bvr->label, p, strMaxLen);
1913 return; // we're done here no need to seek for real name
1914 }
1915
1916 //
1917 // Get the volume label using filesystem specific functions
1918 // or use the alternate volume label if available.
1919 //
1920if (*bvr->altlabel != '\0')
1921 strncpy(p, bvr->altlabel, strMaxLen);
1922else if (bvr->description)
1923 bvr->description(bvr, p, strMaxLen);
1924
1925 if (*p == '\0') {
1926 const char * name = getNameForValue( fdiskTypes, type );
1927 if (name == NULL) {
1928 name = bvr->type_name;
1929 }
1930 if (name == NULL) {
1931 sprintf(p, "TYPE %02x", type);
1932 } else {
1933 strncpy(p, name, strMaxLen);
1934 }
1935 }
1936
1937 // Set the devices label
1938 sprintf(bvr->label, p);
1939}
1940
1941//==========================================================================
1942int readBootSector( int biosdev, unsigned int secno, void * buffer )
1943{
1944 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
1945 int error;
1946
1947 if ( bootSector == NULL )
1948 {
1949 if ( gBootSector == NULL )
1950 {
1951 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1952 if ( gBootSector == NULL ) return -1;
1953 }
1954 bootSector = gBootSector;
1955 }
1956
1957 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1958 if ( error || bootSector->signature != DISK_SIGNATURE )
1959 return -1;
1960
1961 return 0;
1962}
1963
1964/*
1965 * Format of boot1f32 block.
1966 */
1967
1968#define BOOT1F32_MAGIC "BOOT "
1969#define BOOT1F32_MAGICLEN 11
1970
1971struct disk_boot1f32_blk {
1972 unsigned char init[3];
1973 unsigned char fsheader[87];
1974 unsigned char magic[BOOT1F32_MAGICLEN];
1975 unsigned char bootcode[409];
1976 unsigned short signature;
1977};
1978
1979int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
1980{
1981 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
1982 int error;
1983
1984 if ( bootSector == NULL )
1985 {
1986 if ( gBootSector == NULL )
1987 {
1988 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1989 if ( gBootSector == NULL ) return -1;
1990 }
1991 bootSector = (struct disk_boot1f32_blk *) gBootSector;
1992 }
1993
1994 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1995 if ( error || bootSector->signature != DISK_SIGNATURE
1996 || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
1997 return -1;
1998
1999 return 0;
2000}
2001
2002//==========================================================================
2003// Handle seek request from filesystem modules.
2004
2005void diskSeek( BVRef bvr, long long position )
2006{
2007 bvr->fs_boff = position / BPS;
2008 bvr->fs_byteoff = position % BPS;
2009}
2010
2011//==========================================================================
2012// Handle read request from filesystem modules.
2013
2014int diskRead( BVRef bvr, long addr, long length )
2015{
2016 return readBytes( bvr->biosdev,
2017 bvr->fs_boff + bvr->part_boff,
2018 bvr->fs_byteoff,
2019 length,
2020 (void *) addr );
2021}
2022
2023int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2024{
2025 int secs;
2026 unsigned char *cbuf = (unsigned char *)buffer;
2027 unsigned int copy_len;
2028 int rc;
2029
2030 if ((len & (BPS-1)) != 0) {
2031 error("raw disk read not sector aligned");
2032 return -1;
2033 }
2034 secno += bvr->part_boff;
2035
2036 cache_valid = false;
2037
2038 while (len > 0) {
2039 secs = len / BPS;
2040 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2041 copy_len = secs * BPS;
2042
2043 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2044 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
2045 /* Ignore corrected ECC errors */
2046 if (rc != ECC_CORRECTED_ERR) {
2047 error(" EBIOS read error: %s\n", bios_error(rc), rc);
2048 error(" Block %d Sectors %d\n", secno, secs);
2049 return rc;
2050 }
2051 }
2052 bcopy( trackbuf, cbuf, copy_len );
2053 len -= copy_len;
2054 cbuf += copy_len;
2055 secno += secs;
2056 spinActivityIndicator(secs);
2057 }
2058
2059 return 0;
2060}
2061
2062int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2063{
2064 int secs;
2065 unsigned char *cbuf = (unsigned char *)buffer;
2066 unsigned int copy_len;
2067 int rc;
2068
2069 if ((len & (BPS-1)) != 0) {
2070 error("raw disk write not sector aligned");
2071 return -1;
2072 }
2073 secno += bvr->part_boff;
2074
2075 cache_valid = false;
2076
2077 while (len > 0) {
2078 secs = len / BPS;
2079 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2080 copy_len = secs * BPS;
2081
2082 bcopy( cbuf, trackbuf, copy_len );
2083 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2084 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
2085 error(" EBIOS write error: %s\n", bios_error(rc), rc);
2086 error(" Block %d Sectors %d\n", secno, secs);
2087 return rc;
2088 }
2089 len -= copy_len;
2090 cbuf += copy_len;
2091 secno += secs;
2092 spinActivityIndicator(secs);
2093 }
2094
2095 return 0;
2096}
2097
2098int diskIsCDROM(BVRef bvr)
2099{
2100 struct driveInfo di;
2101
2102 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
2103return 1;
2104 }
2105 return 0;
2106}
2107
2108int biosDevIsCDROM(int biosdev)
2109{
2110 struct driveInfo di;
2111
2112 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2113 {
2114 return 1;
2115 }
2116 return 0;
2117}
2118

Archive Download this file

Revision: 2102