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

Archive Download this file

Revision: 1952