Chameleon

Chameleon Svn Source Tree

Root/branches/JrCs/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, 0,
901 EX2GetDescription,
902 (BVFree)free,
903 0, kBIOSDevTypeHardDrive, 0);
904 break;
905
906 case FDISK_BEFS:
907 bvr = newFDiskBVRef(
908 biosdev, partno,
909 part->relsect,
910 part,
911 0, 0, 0, 0, 0, 0,
912 BeFSGetDescription,
913 (BVFree)free,
914 0, kBIOSDevTypeHardDrive, 0);
915 break;
916
917 case FDISK_FREEBSD:
918 bvr = newFDiskBVRef(
919 biosdev, partno,
920 part->relsect,
921 part,
922 0, 0, 0, 0, 0, 0,
923 FreeBSDGetDescription,
924 (BVFree)free,
925 0, kBIOSDevTypeHardDrive, 0);
926 break;
927
928 case FDISK_OPENBSD:
929 bvr = newFDiskBVRef(
930 biosdev, partno,
931 part->relsect,
932 part,
933 0, 0, 0, 0, 0, 0,
934 OpenBSDGetDescription,
935 (BVFree)free,
936 0, kBIOSDevTypeHardDrive, 0);
937 break;
938
939 default:
940 bvr = newFDiskBVRef(
941 biosdev, partno,
942 part->relsect,
943 part,
944 0, 0, 0, 0, 0, 0, 0,
945 (BVFree)free,
946 0,
947 kBIOSDevTypeHardDrive, 0);
948 break;
949 }
950
951 if ( bvr )
952 {
953 bvr->next = map->bvr;
954 map->bvr = bvr;
955 map->bvrcnt++;
956 }
957 }
958
959#if UFS_SUPPORT
960 // Booting from a CD with an UFS filesystem embedded
961 // in a booter partition.
962
963 if ( booterUFS )
964 {
965 if ( map->bvrcnt == 0 )
966 {
967 map->bvr = booterUFS;
968 map->bvrcnt++;
969 }
970 else free( booterUFS );
971 }
972#endif
973 }
974 } while (0);
975
976 /*
977 * If no FDisk partition, then we will check for
978 * an Apple partition map elsewhere.
979 */
980#if UNUSED
981 if (map->bvrcnt == 0) {
982static struct fdisk_part cdpart;
983cdpart.systid = 0xCD;
984
985/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
986bvr = newFDiskBVRef(
987 biosdev, 0,
988 0,
989 &cdpart,
990 HFSInitPartition,
991 HFSLoadFile,
992 HFSReadFile,
993 HFSGetDirEntry,
994 HFSGetFileBlock,
995 HFSGetUUID,
996 0,
997 kBIOSDevTypeHardDrive);
998bvr->next = map->bvr;
999map->bvr = bvr;
1000map->bvrcnt++;
1001 }
1002#endif
1003 // Actually this should always be true given the above code
1004 if(map == gDiskBVMap)
1005 {
1006 // Don't leave a null map in the chain
1007 if(map->bvrcnt == 0 && map->bvr == NULL)
1008 {
1009 gDiskBVMap = map->next;
1010 free(map);
1011 map = NULL;
1012 }
1013 }
1014
1015 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1016
1017 return map ? map->bvr : NULL;
1018}
1019
1020//==========================================================================
1021
1022static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
1023{
1024 struct DiskBVMap * map;
1025 struct Block0 *block0_p;
1026 unsigned int blksize;
1027 unsigned int factor;
1028 void *buffer = malloc(BPS);
1029
1030 /* Check for alternate block size */
1031 if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
1032 return NULL;
1033 }
1034 block0_p = buffer;
1035 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
1036 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
1037 if (blksize != BPS) {
1038 free(buffer);
1039 buffer = malloc(blksize);
1040 }
1041 factor = blksize / BPS;
1042 } else {
1043 blksize = BPS;
1044 factor = 1;
1045 }
1046
1047 do {
1048 // Create a new mapping.
1049
1050 map = (struct DiskBVMap *) malloc( sizeof(*map) );
1051 if ( map )
1052 {
1053 int error;
1054 DPME *dpme_p = (DPME *)buffer;
1055 UInt32 i, npart = UINT_MAX;
1056 BVRef bvr;
1057
1058 map->biosdev = biosdev;
1059 map->bvr = NULL;
1060 map->bvrcnt = 0;
1061 map->next = gDiskBVMap;
1062 gDiskBVMap = map;
1063
1064 for (i=0; i<npart; i++) {
1065 error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1066
1067 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
1068 break;
1069 }
1070
1071 if (i==0) {
1072 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1073 }
1074 /*
1075 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1076 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1077 dpme.dpme_pblock_start, dpme.dpme_pblocks,
1078 dpme.dpme_lblock_start, dpme.dpme_lblocks,
1079 dpme.dpme_boot_block);
1080 */
1081
1082 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
1083 bvr = newAPMBVRef(biosdev,
1084 i,
1085 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1086 dpme_p,
1087 HFSInitPartition,
1088 HFSLoadFile,
1089 HFSReadFile,
1090 HFSGetDirEntry,
1091 HFSGetFileBlock,
1092 HFSGetUUID,
1093 HFSGetDescription,
1094 HFSFree,
1095 0,
1096 kBIOSDevTypeHardDrive, 0);
1097 bvr->next = map->bvr;
1098 map->bvr = bvr;
1099 map->bvrcnt++;
1100 }
1101 }
1102 }
1103 } while (0);
1104
1105 free(buffer);
1106
1107 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1108
1109 return map ? map->bvr : NULL;
1110}
1111
1112//==========================================================================
1113
1114// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1115
1116/*
1117 * Trying to figure out the filsystem type of a given partition.
1118 */
1119static int probeFileSystem(int biosdev, unsigned int blkoff)
1120{
1121 // detected filesystem type;
1122 int result = -1;
1123 int fatbits;
1124
1125 // Allocating buffer for 4 sectors.
1126 const void * probeBuffer = malloc(PROBEFS_SIZE);
1127 if (probeBuffer == NULL)
1128 goto exit;
1129
1130 // Reading first 4 sectors of current partition
1131 int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
1132 if (error)
1133 goto exit;
1134
1135 if (HFSProbe(probeBuffer))
1136 result = FDISK_HFS;
1137 else if (EX2Probe(probeBuffer))
1138 result = FDISK_LINUX;
1139 else if (FreeBSDProbe(probeBuffer))
1140 result = FDISK_FREEBSD;
1141 else if (OpenBSDProbe(probeBuffer))
1142 result = FDISK_OPENBSD;
1143 else if (NTFSProbe(probeBuffer))
1144 result = FDISK_NTFS;
1145 else if (BeFSProbe(probeBuffer))
1146 result = FDISK_BEFS;
1147 else if ( (fatbits = MSDOSProbe(probeBuffer)) )
1148 {
1149 switch (fatbits)
1150 {
1151 case 32:
1152 default:
1153 result = FDISK_FAT32;
1154 break;
1155 case 16:
1156 result = FDISK_DOS16B;
1157 break;
1158 case 12:
1159 result = FDISK_DOS12;
1160 break;
1161 }
1162 }
1163 else
1164 // Couldn't detect filesystem type
1165 result = 0;
1166
1167exit:
1168 if (probeBuffer != NULL) free((void *)probeBuffer);
1169 return result;
1170}
1171
1172static bool isPartitionUsed(gpt_ent * partition)
1173{
1174 //
1175 // Ask whether the given partition is used.
1176 //
1177
1178 return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1179}
1180
1181// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1182
1183static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )
1184{
1185 struct DiskBVMap * map = NULL;
1186 void *buffer = malloc(BPS);
1187 int error;
1188 if ( (error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer )) != 0) {
1189 verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1190 goto scanErr;
1191 }
1192 struct REAL_disk_blk0 *fdiskMap = buffer;
1193 if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1194 {
1195 verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1196 goto scanErr;
1197 }
1198
1199 int fdiskID = 0;
1200 unsigned index;
1201 for ( index = 0; index < FDISK_NPART; index++ )
1202 {
1203 if ( fdiskMap->parts[index].systid )
1204 {
1205 if ( fdiskMap->parts[index].systid == 0xEE )
1206 {
1207 // Fail if two 0xEE partitions are present which
1208 // means the FDISK code will wind up parsing it.
1209 if ( fdiskID ) goto scanErr;
1210
1211 fdiskID = index + 1;
1212 }
1213 }
1214 }
1215
1216 if ( fdiskID == 0 ) goto scanErr;
1217 verbose("Attempting to read GPT\n");
1218
1219 if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1220 goto scanErr;
1221
1222 gpt_hdr *headerMap = buffer;
1223
1224 // Determine whether the partition header signature is present.
1225
1226 if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1227 {
1228 goto scanErr;
1229 }
1230
1231 // Determine whether the partition header size is valid.
1232
1233 UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1234 UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1235
1236 if ( headerSize < offsetof(gpt_hdr, padding) )
1237 {
1238 goto scanErr;
1239 }
1240
1241 if ( headerSize > BPS )
1242 {
1243 goto scanErr;
1244 }
1245
1246 // Determine whether the partition header checksum is valid.
1247
1248 headerMap->hdr_crc_self = 0;
1249
1250 if ( crc32(0, headerMap, headerSize) != headerCheck )
1251 {
1252 goto scanErr;
1253 }
1254
1255 // Determine whether the partition entry size is valid.
1256
1257 UInt64 gptBlock = 0;
1258 UInt32 gptCheck = 0;
1259 UInt32 gptCount = 0;
1260 UInt32 gptID = 0;
1261 gpt_ent * gptMap = 0;
1262 UInt32 gptSize = 0;
1263
1264 gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1265 gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1266 gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1267 gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1268
1269 if ( gptSize < sizeof(gpt_ent) )
1270 {
1271 goto scanErr;
1272 }
1273
1274 // Allocate a buffer large enough to hold one map, rounded to a media block.
1275 free(buffer);
1276 buffer = NULL;
1277
1278 UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1279 if(bufferSize == 0)
1280 goto scanErr;
1281 buffer = malloc(bufferSize);
1282
1283 if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1284 goto scanErr;
1285
1286 verbose("Read GPT\n");
1287
1288 // Allocate a new map for this BIOS device and insert it into the chain
1289 map = malloc(sizeof(*map));
1290 map->biosdev = biosdev;
1291 map->bvr = NULL;
1292 map->bvrcnt = 0;
1293 map->next = gDiskBVMap;
1294 gDiskBVMap = map;
1295
1296 // fdisk like partition type id.
1297 int fsType = 0;
1298
1299 for(gptID = 1; gptID <= gptCount; ++gptID)
1300 {
1301BVRef bvr = NULL;
1302unsigned int bvrFlags = 0;
1303
1304 // size on disk can be larger than sizeof(gpt_ent)
1305 gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1306
1307 // NOTE: EFI_GUID's are in LE and we know we're on an x86.
1308 // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1309
1310 if (isPartitionUsed(gptMap))
1311 {
1312 char stringuuid[100];
1313 efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1314 verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1315
1316 // Getting fdisk like partition type.
1317 fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1318
1319 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1320 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1321 {
1322 bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1323 bvr = newGPTBVRef(biosdev,
1324 gptID,
1325 gptMap->ent_lba_start,
1326 gptMap,
1327 HFSInitPartition,
1328 HFSLoadFile,
1329 HFSReadFile,
1330 HFSGetDirEntry,
1331 HFSGetFileBlock,
1332 HFSGetUUID,
1333 HFSGetDescription,
1334 HFSFree,
1335 0,
1336 kBIOSDevTypeHardDrive, bvrFlags);
1337 }
1338
1339// zef - foreign OS support
1340 if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1341 (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1342 {
1343switch (fsType)
1344 {
1345 case FDISK_NTFS:
1346 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1347 0, 0, 0, 0, 0, 0, NTFSGetDescription,
1348 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1349break;
1350
1351 default:
1352 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1353 0, 0, 0, 0, 0, 0, 0,
1354 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1355 break;
1356 }
1357
1358 }
1359
1360 // turbo - save our booter partition
1361 // zef - only on original boot device
1362 if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1363 {
1364switch (fsType)
1365 {
1366 case FDISK_HFS:
1367 if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1368 {
1369 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1370 HFSInitPartition,
1371 HFSLoadFile,
1372 HFSReadFile,
1373 HFSGetDirEntry,
1374 HFSGetFileBlock,
1375 HFSGetUUID,
1376 HFSGetDescription,
1377 HFSFree,
1378 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1379 }
1380 break;
1381
1382 case FDISK_FAT32:
1383 if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1384 {
1385 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1386 MSDOSInitPartition,
1387 MSDOSLoadFile,
1388 MSDOSReadFile,
1389 MSDOSGetDirEntry,
1390 MSDOSGetFileBlock,
1391 MSDOSGetUUID,
1392 MSDOSGetDescription,
1393 MSDOSFree,
1394 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1395 }
1396 break;
1397
1398 if (biosdev == gBIOSDev)
1399 gBIOSBootVolume = bvr;
1400 }
1401 }
1402
1403if (bvr)
1404{
1405 // Fixup bvr with the fake fdisk partition type.
1406 if (fsType > 0) bvr->part_type = fsType;
1407
1408bvr->next = map->bvr;
1409map->bvr = bvr;
1410++map->bvrcnt;
1411}
1412
1413 }
1414 }
1415
1416scanErr:
1417 free(buffer);
1418
1419 if(map)
1420 {
1421 if(countPtr) *countPtr = map->bvrcnt;
1422 return map->bvr;
1423 }
1424 else
1425 {
1426 if(countPtr) *countPtr = 0;
1427 return NULL;
1428 }
1429}
1430
1431static bool getOSVersion(BVRef bvr, char *str)
1432{
1433bool valid = false;
1434config_file_t systemVersion;
1435char dirSpec[512];
1436
1437sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1438
1439if (!loadConfigFile(dirSpec, &systemVersion))
1440{
1441valid = true;
1442}
1443else
1444{
1445sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);
1446
1447if (!loadConfigFile(dirSpec, &systemVersion))
1448{
1449 bvr->OSisServer = true;
1450valid = true;
1451}
1452}
1453
1454if (valid)
1455{
1456const char *val;
1457int len;
1458
1459if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1460{
1461// getValueForKey uses const char for val
1462// so copy it and trim
1463*str = '\0';
1464strncat(str, val, MIN(len, 4));
1465}
1466else
1467valid = false;
1468}
1469
1470return valid;
1471}
1472
1473//==========================================================================
1474
1475static void scanFSLevelBVRSettings(BVRef chain)
1476{
1477 BVRef bvr;
1478 char dirSpec[512], fileSpec[512];
1479 char label[BVSTRLEN];
1480 int ret;
1481 long flags, time;
1482 int fh, fileSize, error;
1483
1484 for (bvr = chain; bvr; bvr = bvr->next)
1485 {
1486 ret = -1;
1487 error = 0;
1488
1489 //
1490 // Check for alternate volume label on boot helper partitions.
1491 //
1492 if (bvr->flags & kBVFlagBooter)
1493 {
1494 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1495 strcpy(fileSpec, ".disk_label.contentDetails");
1496 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1497 if (!ret)
1498 {
1499 fh = open(strcat(dirSpec, fileSpec), 0);
1500 fileSize = file_size(fh);
1501 if (fileSize > 0 && fileSize < BVSTRLEN)
1502 {
1503 if (read(fh, label, fileSize) != fileSize)
1504 error = -1;
1505 }
1506 else
1507 error = -1;
1508
1509 close(fh);
1510
1511 if (!error)
1512 {
1513 label[fileSize] = '\0';
1514 strcpy(bvr->altlabel, label);
1515 }
1516 }
1517 }
1518
1519 //
1520 // Check for SystemVersion.plist or ServerVersion.plist
1521 // to determine if a volume hosts an installed system.
1522 //
1523 if (bvr->flags & kBVFlagNativeBoot)
1524 {
1525 if (getOSVersion(bvr,bvr->OSVersion) == true)
1526 {
1527 bvr->flags |= kBVFlagSystemVolume;
1528 }
1529 }
1530
1531 }
1532}
1533
1534void rescanBIOSDevice(int biosdev)
1535{
1536struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1537CacheReset();
1538diskFreeMap(oldMap);
1539oldMap = NULL;
1540scanBootVolumes(biosdev, 0);
1541}
1542
1543struct DiskBVMap* diskResetBootVolumes(int biosdev)
1544{
1545 struct DiskBVMap * map;
1546 struct DiskBVMap *prevMap = NULL;
1547 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1548 if ( biosdev == map->biosdev ) {
1549 break;
1550 }
1551 }
1552 if(map != NULL)
1553 {
1554 verbose("Resetting BIOS device %xh\n", biosdev);
1555 // Reset the biosbuf cache
1556 cache_valid = false;
1557 if(map == gDiskBVMap)
1558 gDiskBVMap = map->next;
1559 else if(prevMap != NULL)
1560 prevMap->next = map->next;
1561 else
1562 stop("");
1563 }
1564 // Return the old map, either to be freed, or reinserted later
1565 return map;
1566}
1567
1568// Frees a DiskBVMap and all of its BootVolume's
1569void diskFreeMap(struct DiskBVMap *map)
1570{
1571 if(map != NULL)
1572 {
1573 while(map->bvr != NULL)
1574 {
1575 BVRef bvr = map->bvr;
1576 map->bvr = bvr->next;
1577 (*bvr->bv_free)(bvr);
1578 }
1579 free(map);
1580 }
1581}
1582
1583BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1584{
1585 struct DiskBVMap * map;
1586 BVRef bvr;
1587 int count = 0;
1588
1589 // Find an existing mapping for this device.
1590
1591 for ( map = gDiskBVMap; map; map = map->next ) {
1592 if ( biosdev == map->biosdev ) {
1593 count = map->bvrcnt;
1594 break;
1595 }
1596 }
1597
1598 if (map == NULL) {
1599 bvr = diskScanGPTBootVolumes(biosdev, &count);
1600 if (bvr == NULL) {
1601 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1602 }
1603 if (bvr == NULL) {
1604 bvr = diskScanAPMBootVolumes(biosdev, &count);
1605 }
1606 if (bvr)
1607 {
1608 scanFSLevelBVRSettings(bvr);
1609 }
1610 } else {
1611 bvr = map->bvr;
1612 }
1613 if (countPtr) *countPtr += count;
1614 return bvr;
1615}
1616
1617BVRef getBVChainForBIOSDev(int biosdev)
1618{
1619 BVRef chain = NULL;
1620 struct DiskBVMap * map = NULL;
1621
1622 for (map = gDiskBVMap; map; map = map->next)
1623 {
1624 if (map->biosdev == biosdev)
1625 {
1626 chain = map->bvr;
1627 break;
1628 }
1629 }
1630
1631 return chain;
1632}
1633
1634BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1635{
1636 BVRef chain = NULL;
1637 BVRef bvr = NULL;
1638 BVRef newBVR = NULL;
1639 BVRef prevBVR = NULL;
1640
1641 struct DiskBVMap * map = NULL;
1642 int bvCount = 0;
1643
1644 const char *raw = 0;
1645 char* val = 0;
1646 int len;
1647
1648 getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);
1649 if(raw)
1650 {
1651 val = XMLDecode(raw);
1652 }
1653
1654 /*
1655 * Traverse gDISKBVmap to get references for
1656 * individual bvr chains of each drive.
1657 */
1658 for (map = gDiskBVMap; map; map = map->next)
1659 {
1660 for (bvr = map->bvr; bvr; bvr = bvr->next)
1661 {
1662 /*
1663 * Save the last bvr.
1664 */
1665 if (newBVR) prevBVR = newBVR;
1666
1667 /*
1668 * Allocate and copy the matched bvr entry into a new one.
1669 */
1670 newBVR = (BVRef) malloc(sizeof(*newBVR));
1671 bcopy(bvr, newBVR, sizeof(*newBVR));
1672
1673 /*
1674 * Adjust the new bvr's fields.
1675 */
1676 newBVR->next = NULL;
1677 newBVR->filtered = true;
1678
1679 if ( (!allowFlags || newBVR->flags & allowFlags)
1680 && (!denyFlags || !(newBVR->flags & denyFlags) )
1681 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1682 )
1683 newBVR->visible = true;
1684
1685 /*
1686 * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
1687 * to be able to hide foreign partitions from the boot menu.
1688 *
1689 */
1690 if ( (newBVR->flags & kBVFlagForeignBoot) )
1691 {
1692 char *start, *next = val;
1693 long len = 0;
1694 do
1695 {
1696 start = strbreak(next, &next, &len);
1697 if(len && matchVolumeToString(newBVR, start, len) )
1698 newBVR->visible = false;
1699 }
1700 while ( next && *next );
1701 }
1702
1703 /*
1704 * Use the first bvr entry as the starting chain pointer.
1705 */
1706 if (!chain)
1707 chain = newBVR;
1708
1709 /*
1710 * Update the previous bvr's link pointer to use the new memory area.
1711 */
1712 if (prevBVR)
1713 prevBVR->next = newBVR;
1714
1715 if (newBVR->visible)
1716 bvCount++;
1717 }
1718 }
1719
1720#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1721 for (bvr = chain; bvr; bvr = bvr->next)
1722 {
1723 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1724 }
1725 printf("count: %d\n", bvCount);
1726 getchar();
1727#endif
1728
1729 *count = bvCount;
1730
1731 free(val);
1732 return chain;
1733}
1734
1735int freeFilteredBVChain(const BVRef chain)
1736{
1737 int ret = 1;
1738 BVRef bvr = chain;
1739 BVRef nextBVR = NULL;
1740
1741 while (bvr)
1742 {
1743 nextBVR = bvr->next;
1744
1745 if (bvr->filtered)
1746 {
1747 free(bvr);
1748 }
1749 else
1750 {
1751 ret = 0;
1752 break;
1753 }
1754
1755 bvr = nextBVR;
1756 }
1757
1758 return ret;
1759}
1760
1761//==========================================================================
1762
1763static const struct NamedValue fdiskTypes[] =
1764{
1765{ FDISK_NTFS,"Windows NTFS" },
1766{ FDISK_DOS12,"Windows FAT12" },
1767{ FDISK_DOS16B,"Windows FAT16" },
1768{ FDISK_DOS16S,"Windows FAT16" },
1769{ FDISK_DOS16SLBA,"Windows FAT16" },
1770{ FDISK_SMALLFAT32,"Windows FAT32" },
1771{ FDISK_FAT32,"Windows FAT32" },
1772{ FDISK_FREEBSD,"FreeBSD" },
1773{ FDISK_OPENBSD,"OpenBSD" },
1774{ FDISK_LINUX,"Linux" },
1775{ FDISK_UFS,"Apple UFS" },
1776{ FDISK_HFS,"Apple HFS" },
1777{ FDISK_BOOTER,"Apple Boot/UFS" },
1778{ FDISK_BEFS,"Haiku" },
1779{ 0xCD,"CD-ROM" },
1780{ 0x00,0 } /* must be last */
1781};
1782
1783//==========================================================================
1784
1785bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1786{
1787char testStr[128];
1788
1789if ( !bvr || !match || !*match)
1790return 0;
1791
1792if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1793 return 0;
1794
1795 // Try to match hd(x,y) first.
1796 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1797 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1798 return true;
1799
1800 // Try to match volume UUID.
1801 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1802 {
1803 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1804 return true;
1805 }
1806
1807 // Try to match volume label (always quoted).
1808 if ( bvr->description )
1809 {
1810 bvr->description(bvr, testStr, sizeof(testStr)-1);
1811 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1812 return true;
1813 }
1814
1815 return false;
1816}
1817
1818/* If Rename Partition has defined an alias, then extract it for description purpose.
1819 * The format for the rename string is the following:
1820 * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
1821 */
1822
1823bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
1824{
1825 char *aliasList, *entryStart, *entryNext;
1826
1827 if ( !str || strMaxLen <= 0)
1828 return false;
1829
1830 aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));
1831 if ( !aliasList )
1832 return false;
1833
1834 for ( entryStart = entryNext = aliasList;
1835 entryNext && *entryNext;
1836 entryStart = entryNext )
1837 {
1838 char *volStart, *volEnd, *aliasStart;
1839 long volLen, aliasLen;
1840
1841 // Delimit current entry
1842 entryNext = strchr(entryStart, ';');
1843 if ( entryNext )
1844 {
1845 *entryNext = '\0';
1846 entryNext++;
1847 }
1848
1849 volStart = strbreak(entryStart, &volEnd, &volLen);
1850 if(!volLen)
1851 continue;
1852
1853 aliasStart = strbreak(volEnd, 0, &aliasLen);
1854 if(!aliasLen)
1855 continue;
1856
1857 if ( matchVolumeToString(bvr, volStart, volLen) )
1858 {
1859 strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
1860 free(aliasList);
1861
1862 return true;
1863 }
1864 }
1865
1866 free(aliasList);
1867 return false;
1868}
1869
1870void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1871{
1872 unsigned char type;
1873 char *p = str;
1874
1875 if(!bvr || !p || strMaxLen <= 0)
1876 return;
1877
1878 type = (unsigned char) bvr->part_type;
1879
1880 if (useDeviceDescription)
1881 {
1882 int len = getDeviceDescription(bvr, str);
1883 if(len >= strMaxLen)
1884 return;
1885
1886 strcpy(str + len, " ");
1887 len++;
1888 strMaxLen -= len;
1889 p += len;
1890 }
1891
1892 /* See if a partition rename is preferred */
1893 if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
1894 strncpy(bvr->label, p, strMaxLen);
1895 return; // we're done here no need to seek for real name
1896 }
1897
1898 //
1899 // Get the volume label using filesystem specific functions
1900 // or use the alternate volume label if available.
1901 //
1902if (*bvr->altlabel != '\0')
1903 strncpy(p, bvr->altlabel, strMaxLen);
1904else if (bvr->description)
1905 bvr->description(bvr, p, strMaxLen);
1906
1907 if (*p == '\0') {
1908 const char * name = getNameForValue( fdiskTypes, type );
1909 if (name == NULL) {
1910 name = bvr->type_name;
1911 }
1912 if (name == NULL) {
1913 sprintf(p, "TYPE %02x", type);
1914 } else {
1915 strncpy(p, name, strMaxLen);
1916 }
1917 }
1918
1919 // Set the devices label
1920 sprintf(bvr->label, p);
1921}
1922
1923//==========================================================================
1924int readBootSector( int biosdev, unsigned int secno, void * buffer )
1925{
1926 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
1927 int error;
1928
1929 if ( bootSector == NULL )
1930 {
1931 if ( gBootSector == NULL )
1932 {
1933 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1934 if ( gBootSector == NULL ) return -1;
1935 }
1936 bootSector = gBootSector;
1937 }
1938
1939 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1940 if ( error || bootSector->signature != DISK_SIGNATURE )
1941 return -1;
1942
1943 return 0;
1944}
1945
1946/*
1947 * Format of boot1f32 block.
1948 */
1949
1950#define BOOT1F32_MAGIC "BOOT "
1951#define BOOT1F32_MAGICLEN 11
1952
1953struct disk_boot1f32_blk {
1954 unsigned char init[3];
1955 unsigned char fsheader[87];
1956 unsigned char magic[BOOT1F32_MAGICLEN];
1957 unsigned char bootcode[409];
1958 unsigned short signature;
1959};
1960
1961int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
1962{
1963 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
1964 int error;
1965
1966 if ( bootSector == NULL )
1967 {
1968 if ( gBootSector == NULL )
1969 {
1970 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1971 if ( gBootSector == NULL ) return -1;
1972 }
1973 bootSector = (struct disk_boot1f32_blk *) gBootSector;
1974 }
1975
1976 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1977 if ( error || bootSector->signature != DISK_SIGNATURE
1978 || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
1979 return -1;
1980
1981 return 0;
1982}
1983
1984//==========================================================================
1985// Handle seek request from filesystem modules.
1986
1987void diskSeek( BVRef bvr, long long position )
1988{
1989 bvr->fs_boff = position / BPS;
1990 bvr->fs_byteoff = position % BPS;
1991}
1992
1993//==========================================================================
1994// Handle read request from filesystem modules.
1995
1996int diskRead( BVRef bvr, long addr, long length )
1997{
1998 return readBytes( bvr->biosdev,
1999 bvr->fs_boff + bvr->part_boff,
2000 bvr->fs_byteoff,
2001 length,
2002 (void *) addr );
2003}
2004
2005int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2006{
2007 int secs;
2008 unsigned char *cbuf = (unsigned char *)buffer;
2009 unsigned int copy_len;
2010 int rc;
2011
2012 if ((len & (BPS-1)) != 0) {
2013 error("raw disk read not sector aligned");
2014 return -1;
2015 }
2016 secno += bvr->part_boff;
2017
2018 cache_valid = false;
2019
2020 while (len > 0) {
2021 secs = len / BPS;
2022 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2023 copy_len = secs * BPS;
2024
2025 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2026 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
2027 /* Ignore corrected ECC errors */
2028 if (rc != ECC_CORRECTED_ERR) {
2029 error(" EBIOS read error: %s\n", bios_error(rc), rc);
2030 error(" Block %d Sectors %d\n", secno, secs);
2031 return rc;
2032 }
2033 }
2034 bcopy( trackbuf, cbuf, copy_len );
2035 len -= copy_len;
2036 cbuf += copy_len;
2037 secno += secs;
2038 spinActivityIndicator(secs);
2039 }
2040
2041 return 0;
2042}
2043
2044int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
2045{
2046 int secs;
2047 unsigned char *cbuf = (unsigned char *)buffer;
2048 unsigned int copy_len;
2049 int rc;
2050
2051 if ((len & (BPS-1)) != 0) {
2052 error("raw disk write not sector aligned");
2053 return -1;
2054 }
2055 secno += bvr->part_boff;
2056
2057 cache_valid = false;
2058
2059 while (len > 0) {
2060 secs = len / BPS;
2061 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
2062 copy_len = secs * BPS;
2063
2064 bcopy( cbuf, trackbuf, copy_len );
2065 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
2066 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
2067 error(" EBIOS write error: %s\n", bios_error(rc), rc);
2068 error(" Block %d Sectors %d\n", secno, secs);
2069 return rc;
2070 }
2071 len -= copy_len;
2072 cbuf += copy_len;
2073 secno += secs;
2074 spinActivityIndicator(secs);
2075 }
2076
2077 return 0;
2078}
2079
2080int diskIsCDROM(BVRef bvr)
2081{
2082 struct driveInfo di;
2083
2084 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
2085return 1;
2086 }
2087 return 0;
2088}
2089
2090int biosDevIsCDROM(int biosdev)
2091{
2092 struct driveInfo di;
2093
2094 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
2095 {
2096 return 1;
2097 }
2098 return 0;
2099}
2100

Archive Download this file

Revision: HEAD