Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 296