Chameleon

Chameleon Svn Source Tree

Root/branches/valv/AnVAL/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));
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
632// HFS+ GUID in LE form
633EFI_GUID const GPT_HFS_GUID= { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
634// turbo - also our booter partition
635EFI_GUID const GPT_BOOT_GUID= { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
636// turbo - or an efi system partition
637EFI_GUID const GPT_EFISYS_GUID= { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };
638// zef - basic data partition EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support
639EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };
640EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };
641
642
643BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,
644 const gpt_ent * part,
645 FSInit initFunc, FSLoadFile loadFunc,
646 FSReadFile readFunc,
647 FSGetDirEntry getdirFunc,
648 FSGetFileBlock getBlockFunc,
649 FSGetUUID getUUIDFunc,
650 BVGetDescription getDescriptionFunc,
651 BVFree bvFreeFunc,
652 int probe, int type, unsigned int bvrFlags )
653{
654 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
655 if ( bvr )
656 {
657 bzero(bvr, sizeof(*bvr));
658
659 bvr->biosdev = biosdev;
660 bvr->part_no = partno;
661 bvr->part_boff = blkoff;
662 bvr->fs_loadfile = loadFunc;
663 bvr->fs_readfile = readFunc;
664 bvr->fs_getdirentry = getdirFunc;
665 bvr->fs_getfileblock= getBlockFunc;
666 bvr->fs_getuuid = getUUIDFunc;
667 bvr->description = getDescriptionFunc;
668 bvr->type = type;
669 bvr->bv_free = bvFreeFunc;
670 // FIXME: UCS-2 -> UTF-8 the name
671 strlcpy(bvr->name, "----", DPISTRLEN);
672 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)part->ent_type) == 0) ||
673 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)part->ent_type) == 0) )
674 strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);
675 else
676 strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);
677
678 /*
679 if ( part->bootid & FDISK_ACTIVE )
680 bvr->flags |= kBVFlagPrimary;
681 */
682
683 // Probe the filesystem.
684
685 if ( initFunc )
686 {
687 bvr->flags |= kBVFlagNativeBoot;
688
689 if ( probe && initFunc( bvr ) != 0 )
690 {
691 // filesystem probe failed.
692
693 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
694 __FUNCTION__, biosdev, partno));
695
696 (*bvr->bv_free)(bvr);
697 bvr = NULL;
698 }
699 if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
700 {
701 bvr->flags |= kBVFlagBootable;
702 }
703 }
704 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
705 {
706 bvr->flags |= kBVFlagForeignBoot;
707 }
708 else
709 {
710 (*bvr->bv_free)(bvr);
711 bvr = NULL;
712 }
713 }
714 if (bvr) bvr->flags |= bvrFlags;
715 return bvr;
716}
717
718//==========================================================================
719
720/* A note on partition numbers:
721 * IOKit makes the primary partitions numbers 1-4, and then
722 * extended partitions are numbered consecutively 5 and up.
723 * So, for example, if you have two primary partitions and
724 * one extended partition they will be numbered 1, 2, 5.
725 */
726
727static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
728{
729 const struct fdisk_part * part;
730 struct DiskBVMap * map;
731 int partno = -1;
732 BVRef bvr;
733#if UFS_SUPPORT
734 BVRef booterUFS = NULL;
735#endif
736 int spc;
737 struct driveInfo di;
738 boot_drive_info_t *dp;
739
740 /* Initialize disk info */
741 if (getDriveInfo(biosdev, &di) != 0) {
742return NULL;
743 }
744 dp = &di.di;
745 spc = (dp->params.phys_spt * dp->params.phys_heads);
746 if (spc == 0) {
747/* This is probably a CD-ROM; punt on the geometry. */
748spc = 1;
749 }
750
751 do {
752 // Create a new mapping.
753
754 map = (struct DiskBVMap *) malloc( sizeof(*map) );
755 if ( map )
756 {
757 map->biosdev = biosdev;
758 map->bvr = NULL;
759 map->bvrcnt = 0;
760 map->next = gDiskBVMap;
761 gDiskBVMap = map;
762
763 // Create a record for each partition found on the disk.
764
765 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
766 {
767 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
768 partno, part->systid));
769 bvr = 0;
770
771 switch ( part->systid )
772 {
773#if UFS_SUPPORT
774 case FDISK_UFS:
775 bvr = newFDiskBVRef(
776 biosdev, partno,
777 part->relsect + UFS_FRONT_PORCH/BPS,
778 part,
779 UFSInitPartition,
780 UFSLoadFile,
781 UFSReadFile,
782 UFSGetDirEntry,
783 UFSGetFileBlock,
784 UFSGetUUID,
785 UFSGetDescription,
786 UFSFree,
787 0,
788 kBIOSDevTypeHardDrive, 0);
789 break;
790#endif
791
792 case FDISK_HFS:
793 bvr = newFDiskBVRef(
794 biosdev, partno,
795 part->relsect,
796 part,
797 HFSInitPartition,
798 HFSLoadFile,
799 HFSReadFile,
800 HFSGetDirEntry,
801 HFSGetFileBlock,
802 HFSGetUUID,
803 HFSGetDescription,
804 HFSFree,
805 0,
806 kBIOSDevTypeHardDrive, 0);
807 break;
808
809 // turbo - we want the booter type scanned also
810 case FDISK_BOOTER:
811 if (part->bootid & FDISK_ACTIVE)
812 gBIOSBootVolume = newFDiskBVRef(
813 biosdev, partno,
814 part->relsect,
815 part,
816 HFSInitPartition,
817 HFSLoadFile,
818 HFSReadFile,
819 HFSGetDirEntry,
820 HFSGetFileBlock,
821 HFSGetUUID,
822 HFSGetDescription,
823 HFSFree,
824 0,
825 kBIOSDevTypeHardDrive, 0);
826 break;
827
828#if UFS_SUPPORT
829 case FDISK_BOOTER:
830 booterUFS = newFDiskBVRef(
831 biosdev, partno,
832 ((part->relsect + spc - 1) / spc) * spc,
833 part,
834 UFSInitPartition,
835 UFSLoadFile,
836 UFSReadFile,
837 UFSGetDirEntry,
838 UFSGetFileBlock,
839 UFSGetUUID,
840 UFSGetDescription,
841 UFSFree,
842 0,
843 kBIOSDevTypeHardDrive, 0);
844 break;
845#endif
846
847 case FDISK_FAT32:
848 case FDISK_DOS12:
849 case FDISK_DOS16S:
850 case FDISK_DOS16B:
851 case FDISK_SMALLFAT32:
852 case FDISK_DOS16SLBA:
853 bvr = newFDiskBVRef(
854 biosdev, partno,
855 part->relsect,
856 part,
857 MSDOSInitPartition,
858 MSDOSLoadFile,
859 MSDOSReadFile,
860 MSDOSGetDirEntry,
861 MSDOSGetFileBlock,
862 MSDOSGetUUID,
863 MSDOSGetDescription,
864 MSDOSFree,
865 0,
866 kBIOSDevTypeHardDrive, 0);
867 break;
868
869 case FDISK_NTFS:
870 bvr = newFDiskBVRef(
871 biosdev, partno,
872 part->relsect,
873 part,
874 0, 0, 0, 0, 0, 0,
875 NTFSGetDescription,
876 (BVFree)free,
877 0, kBIOSDevTypeHardDrive, 0);
878 break;
879
880 case FDISK_LINUX:
881 bvr = newFDiskBVRef(
882 biosdev, partno,
883 part->relsect,
884 part,
885 0, 0, 0, 0, 0, 0,
886 EX2GetDescription,
887 (BVFree)free,
888 0, kBIOSDevTypeHardDrive, 0);
889 break;
890
891 default:
892 bvr = newFDiskBVRef(
893 biosdev, partno,
894 part->relsect,
895 part,
896 0, 0, 0, 0, 0, 0, 0,
897 (BVFree)free,
898 0,
899 kBIOSDevTypeHardDrive, 0);
900 break;
901 }
902
903 if ( bvr )
904 {
905 bvr->next = map->bvr;
906 map->bvr = bvr;
907 map->bvrcnt++;
908 }
909 }
910
911#if UFS_SUPPORT
912 // Booting from a CD with an UFS filesystem embedded
913 // in a booter partition.
914
915 if ( booterUFS )
916 {
917 if ( map->bvrcnt == 0 )
918 {
919 map->bvr = booterUFS;
920 map->bvrcnt++;
921 }
922 else free( booterUFS );
923 }
924#endif
925 }
926 } while (0);
927
928 /*
929 * If no FDisk partition, then we will check for
930 * an Apple partition map elsewhere.
931 */
932#if UNUSED
933 if (map->bvrcnt == 0) {
934static struct fdisk_part cdpart;
935cdpart.systid = 0xCD;
936
937/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
938bvr = newFDiskBVRef(
939 biosdev, 0,
940 0,
941 &cdpart,
942 HFSInitPartition,
943 HFSLoadFile,
944 HFSReadFile,
945 HFSGetDirEntry,
946 HFSGetFileBlock,
947 HFSGetUUID,
948 0,
949 kBIOSDevTypeHardDrive);
950bvr->next = map->bvr;
951map->bvr = bvr;
952map->bvrcnt++;
953 }
954#endif
955 // Actually this should always be true given the above code
956 if(map == gDiskBVMap)
957 {
958 // Don't leave a null map in the chain
959 if(map->bvrcnt == 0 && map->bvr == NULL)
960 {
961 gDiskBVMap = map->next;
962 free(map);
963 map = NULL;
964 }
965 }
966
967 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
968
969 return map ? map->bvr : NULL;
970}
971
972//==========================================================================
973
974static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
975{
976 struct DiskBVMap * map;
977 struct Block0 *block0_p;
978 unsigned int blksize;
979 unsigned int factor;
980 void *buffer = malloc(BPS);
981
982 /* Check for alternate block size */
983 if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
984 return NULL;
985 }
986 block0_p = buffer;
987 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
988 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
989 if (blksize != BPS) {
990 free(buffer);
991 buffer = malloc(blksize);
992 }
993 factor = blksize / BPS;
994 } else {
995 blksize = BPS;
996 factor = 1;
997 }
998
999 do {
1000 // Create a new mapping.
1001
1002 map = (struct DiskBVMap *) malloc( sizeof(*map) );
1003 if ( map )
1004 {
1005 int error;
1006 DPME *dpme_p = (DPME *)buffer;
1007 UInt32 i, npart = UINT_MAX;
1008 BVRef bvr;
1009
1010 map->biosdev = biosdev;
1011 map->bvr = NULL;
1012 map->bvrcnt = 0;
1013 map->next = gDiskBVMap;
1014 gDiskBVMap = map;
1015
1016 for (i=0; i<npart; i++) {
1017 error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1018
1019 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
1020 break;
1021 }
1022
1023 if (i==0) {
1024 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1025 }
1026 /*
1027 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1028 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1029 dpme.dpme_pblock_start, dpme.dpme_pblocks,
1030 dpme.dpme_lblock_start, dpme.dpme_lblocks,
1031 dpme.dpme_boot_block);
1032 */
1033
1034 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
1035 bvr = newAPMBVRef(biosdev,
1036 i,
1037 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1038 dpme_p,
1039 HFSInitPartition,
1040 HFSLoadFile,
1041 HFSReadFile,
1042 HFSGetDirEntry,
1043 HFSGetFileBlock,
1044 HFSGetUUID,
1045 HFSGetDescription,
1046 HFSFree,
1047 0,
1048 kBIOSDevTypeHardDrive, 0);
1049 bvr->next = map->bvr;
1050 map->bvr = bvr;
1051 map->bvrcnt++;
1052 }
1053 }
1054 }
1055 } while (0);
1056
1057 free(buffer);
1058
1059 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1060
1061 return map ? map->bvr : NULL;
1062}
1063
1064//==========================================================================
1065
1066// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1067
1068/*
1069 * Trying to figure out the filsystem type of a given partition.
1070 */
1071static int probeFileSystem(int biosdev, unsigned int blkoff)
1072{
1073 // detected filesystem type;
1074 int result = -1;
1075 int fatbits;
1076
1077 // Allocating buffer for 4 sectors.
1078 const void * probeBuffer = malloc(PROBEFS_SIZE);
1079 if (probeBuffer == NULL)
1080 goto exit;
1081
1082 // Reading first 4 sectors of current partition
1083 int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
1084 if (error)
1085 goto exit;
1086
1087 if (HFSProbe(probeBuffer))
1088 result = FDISK_HFS;
1089 else if (EX2Probe(probeBuffer))
1090 result = FDISK_LINUX;
1091 else if (NTFSProbe(probeBuffer))
1092 result = FDISK_NTFS;
1093 else if (fatbits=MSDOSProbe(probeBuffer))
1094 {
1095 switch (fatbits)
1096 {
1097 case 32:
1098 default:
1099 result = FDISK_FAT32;
1100 break;
1101 case 16:
1102 result = FDISK_DOS16B;
1103 break;
1104 case 12:
1105 result = FDISK_DOS12;
1106 break;
1107 }
1108 }
1109 else
1110 // Couldn't detect filesystem type
1111 result = 0;
1112
1113exit:
1114 if (probeBuffer != NULL) free((void *)probeBuffer);
1115 return result;
1116}
1117
1118static bool isPartitionUsed(gpt_ent * partition)
1119{
1120 //
1121 // Ask whether the given partition is used.
1122 //
1123
1124 return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1125}
1126
1127// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1128
1129static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )
1130{
1131 struct DiskBVMap * map = NULL;
1132 void *buffer = malloc(BPS);
1133 int error;
1134 if ( error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer ) != 0) {
1135 verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1136 goto scanErr;
1137 }
1138 struct REAL_disk_blk0 *fdiskMap = buffer;
1139 if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1140 {
1141 verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1142 goto scanErr;
1143 }
1144
1145 int fdiskID = 0;
1146 unsigned index;
1147 for ( index = 0; index < FDISK_NPART; index++ )
1148 {
1149 if ( fdiskMap->parts[index].systid )
1150 {
1151 if ( fdiskMap->parts[index].systid == 0xEE )
1152 {
1153 // Fail if two 0xEE partitions are present which
1154 // means the FDISK code will wind up parsing it.
1155 if ( fdiskID ) goto scanErr;
1156
1157 fdiskID = index + 1;
1158 }
1159 }
1160 }
1161
1162 if ( fdiskID == 0 ) goto scanErr;
1163 verbose("Attempting to read GPT\n");
1164
1165 if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1166 goto scanErr;
1167
1168 gpt_hdr *headerMap = buffer;
1169
1170 // Determine whether the partition header signature is present.
1171
1172 if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1173 {
1174 goto scanErr;
1175 }
1176
1177 // Determine whether the partition header size is valid.
1178
1179 UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1180 UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1181
1182 if ( headerSize < offsetof(gpt_hdr, padding) )
1183 {
1184 goto scanErr;
1185 }
1186
1187 if ( headerSize > BPS )
1188 {
1189 goto scanErr;
1190 }
1191
1192 // Determine whether the partition header checksum is valid.
1193
1194 headerMap->hdr_crc_self = 0;
1195
1196 if ( crc32(0, headerMap, headerSize) != headerCheck )
1197 {
1198 goto scanErr;
1199 }
1200
1201 // Determine whether the partition entry size is valid.
1202
1203 UInt64 gptBlock = 0;
1204 UInt32 gptCheck = 0;
1205 UInt32 gptCount = 0;
1206 UInt32 gptID = 0;
1207 gpt_ent * gptMap = 0;
1208 UInt32 gptSize = 0;
1209
1210 gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1211 gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1212 gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1213 gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1214
1215 if ( gptSize < sizeof(gpt_ent) )
1216 {
1217 goto scanErr;
1218 }
1219
1220 // Allocate a buffer large enough to hold one map, rounded to a media block.
1221 free(buffer);
1222 buffer = NULL;
1223
1224 UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1225 if(bufferSize == 0)
1226 goto scanErr;
1227 buffer = malloc(bufferSize);
1228
1229 if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1230 goto scanErr;
1231
1232 verbose("Read GPT\n");
1233
1234 // Allocate a new map for this BIOS device and insert it into the chain
1235 map = malloc(sizeof(*map));
1236 map->biosdev = biosdev;
1237 map->bvr = NULL;
1238 map->bvrcnt = 0;
1239 map->next = gDiskBVMap;
1240 gDiskBVMap = map;
1241
1242 // fdisk like partition type id.
1243 int fsType = 0;
1244
1245 for(gptID = 1; gptID <= gptCount; ++gptID)
1246 {
1247BVRef bvr = NULL;
1248unsigned int bvrFlags = 0;
1249
1250 // size on disk can be larger than sizeof(gpt_ent)
1251 gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1252
1253 // NOTE: EFI_GUID's are in LE and we know we're on an x86.
1254 // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1255
1256 if(isPartitionUsed(gptMap))
1257 {
1258 char stringuuid[100];
1259 efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1260 verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1261
1262 // Getting fdisk like partition type.
1263 fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1264
1265 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1266 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1267 {
1268 bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1269 bvr = newGPTBVRef(biosdev,
1270 gptID,
1271 gptMap->ent_lba_start,
1272 gptMap,
1273 HFSInitPartition,
1274 HFSLoadFile,
1275 HFSReadFile,
1276 HFSGetDirEntry,
1277 HFSGetFileBlock,
1278 HFSGetUUID,
1279 HFSGetDescription,
1280 HFSFree,
1281 0,
1282 kBIOSDevTypeHardDrive, bvrFlags);
1283 }
1284
1285// zef - foreign OS support
1286 if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1287 (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1288 {
1289switch (fsType)
1290 {
1291 case FDISK_NTFS:
1292 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1293 0, 0, 0, 0, 0, 0, NTFSGetDescription,
1294 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1295break;
1296
1297 default:
1298 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1299 0, 0, 0, 0, 0, 0, 0,
1300 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1301 break;
1302 }
1303
1304 }
1305
1306 // turbo - save our booter partition
1307 // zef - only on original boot device
1308 if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1309 {
1310switch (fsType)
1311 {
1312 case FDISK_HFS:
1313 if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1314 {
1315 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1316 HFSInitPartition,
1317 HFSLoadFile,
1318 HFSReadFile,
1319 HFSGetDirEntry,
1320 HFSGetFileBlock,
1321 HFSGetUUID,
1322 HFSGetDescription,
1323 HFSFree,
1324 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1325 }
1326 break;
1327
1328 case FDISK_FAT32:
1329 if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1330 {
1331 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1332 MSDOSInitPartition,
1333 MSDOSLoadFile,
1334 MSDOSReadFile,
1335 MSDOSGetDirEntry,
1336 MSDOSGetFileBlock,
1337 MSDOSGetUUID,
1338 MSDOSGetDescription,
1339 MSDOSFree,
1340 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1341 }
1342 break;
1343
1344 if (biosdev == gBIOSDev)
1345 gBIOSBootVolume = bvr;
1346 }
1347 }
1348
1349if (bvr)
1350{
1351 // Fixup bvr with the fake fdisk partition type.
1352 if (fsType > 0) bvr->part_type = fsType;
1353
1354bvr->next = map->bvr;
1355map->bvr = bvr;
1356++map->bvrcnt;
1357}
1358
1359 }
1360 }
1361
1362scanErr:
1363 free(buffer);
1364
1365 if(map)
1366 {
1367 if(countPtr) *countPtr = map->bvrcnt;
1368 return map->bvr;
1369 }
1370 else
1371 {
1372 if(countPtr) *countPtr = 0;
1373 return NULL;
1374 }
1375}
1376
1377//==========================================================================
1378
1379static void scanFSLevelBVRSettings(BVRef chain)
1380{
1381 BVRef bvr;
1382 char dirSpec[512], fileSpec[512];
1383 char label[BVSTRLEN];
1384 int ret;
1385 long flags, time;
1386 int fh, fileSize, error;
1387
1388 for (bvr = chain; bvr; bvr = bvr->next)
1389 {
1390 ret = -1;
1391 error = 0;
1392
1393 //
1394 // Check for alternate volume label on boot helper partitions.
1395 //
1396 if (bvr->flags & kBVFlagBooter)
1397 {
1398 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1399 strcpy(fileSpec, ".disk_label.contentDetails");
1400 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1401 if (!ret)
1402 {
1403 fh = open(strcat(dirSpec, fileSpec), 0);
1404 fileSize = file_size(fh);
1405 if (fileSize > 0 && fileSize < BVSTRLEN)
1406 {
1407 if (read(fh, label, fileSize) != fileSize)
1408 error = -1;
1409 }
1410 else
1411 error = -1;
1412
1413 close(fh);
1414
1415 if (!error)
1416 {
1417 label[fileSize] = '\0';
1418 strcpy(bvr->altlabel, label);
1419 }
1420 }
1421 }
1422
1423 //
1424 // Check for SystemVersion.plist or ServerVersion.plist
1425 // to determine if a volume hosts an installed system.
1426 //
1427 if (bvr->flags & kBVFlagNativeBoot)
1428 {
1429 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1430 strcpy(fileSpec, "SystemVersion.plist");
1431 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1432
1433 if (ret == -1)
1434 {
1435 strcpy(fileSpec, "ServerVersion.plist");
1436 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1437 }
1438
1439 if (!ret)
1440 bvr->flags |= kBVFlagSystemVolume;
1441 }
1442
1443 }
1444}
1445
1446void rescanBIOSDevice(int biosdev)
1447{
1448 struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1449 CacheReset();
1450 diskFreeMap(oldMap);
1451 oldMap = NULL;
1452
1453 scanBootVolumes(biosdev, 0);
1454}
1455
1456struct DiskBVMap* diskResetBootVolumes(int biosdev)
1457{
1458 struct DiskBVMap * map;
1459 struct DiskBVMap *prevMap = NULL;
1460 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1461 if ( biosdev == map->biosdev ) {
1462 break;
1463 }
1464 }
1465 if(map != NULL)
1466 {
1467 verbose("Resetting BIOS device %xh\n", biosdev);
1468 // Reset the biosbuf cache
1469 cache_valid = false;
1470 if(map == gDiskBVMap)
1471 gDiskBVMap = map->next;
1472 else if(prevMap != NULL)
1473 prevMap->next = map->next;
1474 else
1475 stop("");
1476 }
1477 // Return the old map, either to be freed, or reinserted later
1478 return map;
1479}
1480
1481// Frees a DiskBVMap and all of its BootVolume's
1482void diskFreeMap(struct DiskBVMap *map)
1483{
1484 if(map != NULL)
1485 {
1486 while(map->bvr != NULL)
1487 {
1488 BVRef bvr = map->bvr;
1489 map->bvr = bvr->next;
1490 (*bvr->bv_free)(bvr);
1491 }
1492 free(map);
1493 }
1494}
1495
1496BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1497{
1498 struct DiskBVMap * map;
1499 BVRef bvr;
1500 int count = 0;
1501
1502 // Find an existing mapping for this device.
1503
1504 for ( map = gDiskBVMap; map; map = map->next ) {
1505 if ( biosdev == map->biosdev ) {
1506 count = map->bvrcnt;
1507 break;
1508 }
1509 }
1510
1511 if (map == NULL) {
1512 bvr = diskScanGPTBootVolumes(biosdev, &count);
1513 if (bvr == NULL) {
1514 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1515 }
1516 if (bvr == NULL) {
1517 bvr = diskScanAPMBootVolumes(biosdev, &count);
1518 }
1519 if (bvr)
1520 {
1521 scanFSLevelBVRSettings(bvr);
1522 }
1523 } else {
1524 bvr = map->bvr;
1525 }
1526 if (countPtr) *countPtr += count;
1527 return bvr;
1528}
1529
1530BVRef getBVChainForBIOSDev(int biosdev)
1531{
1532 BVRef chain = NULL;
1533 struct DiskBVMap * map = NULL;
1534
1535 for (map = gDiskBVMap; map; map = map->next)
1536 {
1537 if (map->biosdev == biosdev)
1538 {
1539 chain = map->bvr;
1540 break;
1541 }
1542 }
1543
1544 return chain;
1545}
1546
1547BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1548{
1549 BVRef chain = NULL;
1550 BVRef bvr = NULL;
1551 BVRef newBVR = NULL;
1552 BVRef prevBVR = NULL;
1553
1554 struct DiskBVMap * map = NULL;
1555 int bvCount = 0;
1556
1557 const char *val;
1558 char devsw[12];
1559 int len;
1560
1561 /*
1562 * Traverse gDISKBVmap to get references for
1563 * individual bvr chains of each drive.
1564 */
1565 for (map = gDiskBVMap; map; map = map->next)
1566 {
1567 for (bvr = map->bvr; bvr; bvr = bvr->next)
1568 {
1569 /*
1570 * Save the last bvr.
1571 */
1572 if (newBVR) prevBVR = newBVR;
1573
1574 /*
1575 * Allocate and copy the matched bvr entry into a new one.
1576 */
1577 newBVR = (BVRef) malloc(sizeof(*newBVR));
1578 bcopy(bvr, newBVR, sizeof(*newBVR));
1579
1580 /*
1581 * Adjust the new bvr's fields.
1582 */
1583 newBVR->next = NULL;
1584 newBVR->filtered = true;
1585
1586 if ( (!allowFlags || newBVR->flags & allowFlags)
1587 && (!denyFlags || !(newBVR->flags & denyFlags) )
1588 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1589 )
1590 newBVR->visible = true;
1591
1592 /*
1593 * Looking for "Hide Partition" entries in "hd(x,y) hd(n,m)" format
1594 * to be able to hide foreign partitions from the boot menu.
1595 */
1596if ( (newBVR->flags & kBVFlagForeignBoot)
1597&& getValueForKey(kHidePartition, &val, &len, &bootInfo->bootConfig)
1598 )
1599 {
1600 sprintf(devsw, "hd(%d,%d)", BIOS_DEV_UNIT(newBVR), newBVR->part_no);
1601 if (strstr(val, devsw) != NULL)
1602 newBVR->visible = false;
1603 }
1604
1605 /*
1606 * Use the first bvr entry as the starting chain pointer.
1607 */
1608 if (!chain)
1609 chain = newBVR;
1610
1611 /*
1612 * Update the previous bvr's link pointer to use the new memory area.
1613 */
1614 if (prevBVR)
1615 prevBVR->next = newBVR;
1616
1617 if (newBVR->visible)
1618 bvCount++;
1619 }
1620 }
1621
1622#if DEBUG
1623 for (bvr = chain; bvr; bvr = bvr->next)
1624 {
1625 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1626 }
1627 printf("count: %d\n", bvCount);
1628 getc();
1629#endif
1630
1631 *count = bvCount;
1632 return chain;
1633}
1634
1635int freeFilteredBVChain(const BVRef chain)
1636{
1637 int ret = 1;
1638 BVRef bvr = chain;
1639 BVRef nextBVR = NULL;
1640
1641 while (bvr)
1642 {
1643 nextBVR = bvr->next;
1644
1645 if (bvr->filtered)
1646 {
1647 free(bvr);
1648 }
1649 else
1650 {
1651 ret = 0;
1652 break;
1653 }
1654
1655 bvr = nextBVR;
1656 }
1657
1658 return ret;
1659}
1660
1661//==========================================================================
1662
1663static const struct NamedValue fdiskTypes[] =
1664{
1665 { FDISK_NTFS, "Windows NTFS" },
1666{ FDISK_DOS12, "Windows FAT12" },
1667{ FDISK_DOS16B, "Windows FAT16" },
1668{ FDISK_DOS16S, "Windows FAT16" },
1669{ FDISK_DOS16SLBA, "Windows FAT16" },
1670{ FDISK_SMALLFAT32, "Windows FAT32" },
1671{ FDISK_FAT32, "Windows FAT32" },
1672 { FDISK_LINUX, "Linux" },
1673 { FDISK_UFS, "Apple UFS" },
1674 { FDISK_HFS, "Apple HFS" },
1675 { FDISK_BOOTER, "Apple Boot/UFS" },
1676 { 0xCD, "CD-ROM" },
1677 { 0x00, 0 } /* must be last */
1678};
1679
1680//==========================================================================
1681
1682/* If Rename Partition has defined an alias, then extract it for description purpose */
1683static const char * getVolumeLabelAlias( BVRef bvr, const char * str, long strMaxLen)
1684{
1685 const int MAX_ALIAS_SIZE=31;
1686 static char szAlias[MAX_ALIAS_SIZE+1];
1687 char *q=szAlias;
1688 const char * szAliases = getStringForKey(kRenamePartition, &bootInfo->bootConfig);
1689
1690 if (!str || !*str || !szAliases) return 0; // no renaming wanted
1691
1692 const char * p = strstr(szAliases, str);
1693 if(!p || !(*p)) return 0; // this volume must not be renamed, or option is malformed
1694
1695 p+= strlen(str); // skip the "hd(n,m) " field
1696 // multiple aliases can be found separated by a semi-column
1697 while(*p && *p != ';' && q<(szAlias+MAX_ALIAS_SIZE)) *q++=*p++;
1698 *q='\0';
1699
1700 return szAlias;
1701}
1702
1703void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool verbose )
1704{
1705 unsigned char type = (unsigned char) bvr->part_type;
1706 char *p;
1707
1708 p = str;
1709 if (verbose) {
1710 sprintf( str, "hd(%d,%d) ", BIOS_DEV_UNIT(bvr), bvr->part_no);
1711 for (; strMaxLen > 0 && *p != '\0'; p++, strMaxLen--);
1712 }
1713
1714 // See if we should get the renamed alias name for this partion:
1715 const char * szAliasName = getVolumeLabelAlias(bvr, str, strMaxLen);
1716 if (szAliasName && *szAliasName)
1717 {
1718strncpy(bvr->label, szAliasName, strMaxLen);
1719return; // we're done here no need to seek for real name
1720 }
1721
1722 //
1723 // Get the volume label using filesystem specific functions
1724 // or use the alternate volume label if available.
1725 //
1726 if (*bvr->altlabel == '\0')
1727 {
1728 if (bvr->description)
1729 bvr->description(bvr, p, strMaxLen);
1730 }
1731 else
1732 strncpy(p, bvr->altlabel, strMaxLen);
1733
1734 if (*p == '\0') {
1735 const char * name = getNameForValue( fdiskTypes, type );
1736 if (name == NULL) {
1737 name = bvr->type_name;
1738 }
1739 if (name == NULL) {
1740 sprintf(p, "TYPE %02x", type);
1741 } else {
1742 strncpy(p, name, strMaxLen);
1743 }
1744 }
1745
1746 /* See if a partion rename is wanted: */
1747
1748 // Set the devices label
1749 sprintf(bvr->label, p);
1750}
1751
1752//==========================================================================
1753int readBootSector( int biosdev, unsigned int secno, void * buffer )
1754{
1755 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
1756 int error;
1757
1758 if ( bootSector == NULL )
1759 {
1760 if ( gBootSector == NULL )
1761 {
1762 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1763 if ( gBootSector == NULL ) return -1;
1764 }
1765 bootSector = gBootSector;
1766 }
1767
1768 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1769 if ( error || bootSector->signature != DISK_SIGNATURE )
1770 return -1;
1771
1772 return 0;
1773}
1774
1775/*
1776 * Format of boot1f32 block.
1777 */
1778
1779#define BOOT1F32_MAGIC "BOOT "
1780#define BOOT1F32_MAGICLEN 11
1781
1782struct disk_boot1f32_blk {
1783 unsigned char init[3];
1784 unsigned char fsheader[87];
1785 unsigned char magic[BOOT1F32_MAGICLEN];
1786 unsigned char bootcode[409];
1787 unsigned short signature;
1788};
1789
1790int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
1791{
1792 struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
1793 int error;
1794
1795 if ( bootSector == NULL )
1796 {
1797 if ( gBootSector == NULL )
1798 {
1799 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1800 if ( gBootSector == NULL ) return -1;
1801 }
1802 bootSector = (struct disk_boot1f32_blk *) gBootSector;
1803 }
1804
1805 error = readBytes( biosdev, secno, 0, BPS, bootSector );
1806 if ( error || bootSector->signature != DISK_SIGNATURE
1807 || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
1808 return -1;
1809
1810 return 0;
1811}
1812
1813//==========================================================================
1814// Handle seek request from filesystem modules.
1815
1816void diskSeek( BVRef bvr, long long position )
1817{
1818 bvr->fs_boff = position / BPS;
1819 bvr->fs_byteoff = position % BPS;
1820}
1821
1822//==========================================================================
1823// Handle read request from filesystem modules.
1824
1825int diskRead( BVRef bvr, long addr, long length )
1826{
1827 return readBytes( bvr->biosdev,
1828 bvr->fs_boff + bvr->part_boff,
1829 bvr->fs_byteoff,
1830 length,
1831 (void *) addr );
1832}
1833
1834int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1835{
1836 int secs;
1837 unsigned char *cbuf = (unsigned char *)buffer;
1838 unsigned int copy_len;
1839 int rc;
1840
1841 if ((len & (BPS-1)) != 0) {
1842 error("raw disk read not sector aligned");
1843 return -1;
1844 }
1845 secno += bvr->part_boff;
1846
1847 cache_valid = false;
1848
1849 while (len > 0) {
1850 secs = len / BPS;
1851 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1852 copy_len = secs * BPS;
1853
1854 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1855 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
1856 /* Ignore corrected ECC errors */
1857 if (rc != ECC_CORRECTED_ERR) {
1858 error(" EBIOS read error: %s\n", bios_error(rc), rc);
1859 error(" Block %d Sectors %d\n", secno, secs);
1860 return rc;
1861 }
1862 }
1863 bcopy( trackbuf, cbuf, copy_len );
1864 len -= copy_len;
1865 cbuf += copy_len;
1866 secno += secs;
1867 spinActivityIndicator(secs);
1868 }
1869
1870 return 0;
1871}
1872
1873int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1874{
1875 int secs;
1876 unsigned char *cbuf = (unsigned char *)buffer;
1877 unsigned int copy_len;
1878 int rc;
1879
1880 if ((len & (BPS-1)) != 0) {
1881 error("raw disk write not sector aligned");
1882 return -1;
1883 }
1884 secno += bvr->part_boff;
1885
1886 cache_valid = false;
1887
1888 while (len > 0) {
1889 secs = len / BPS;
1890 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1891 copy_len = secs * BPS;
1892
1893 bcopy( cbuf, trackbuf, copy_len );
1894 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1895 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
1896 error(" EBIOS write error: %s\n", bios_error(rc), rc);
1897 error(" Block %d Sectors %d\n", secno, secs);
1898 return rc;
1899 }
1900 len -= copy_len;
1901 cbuf += copy_len;
1902 secno += secs;
1903 spinActivityIndicator(secs);
1904 }
1905
1906 return 0;
1907}
1908
1909
1910int diskIsCDROM(BVRef bvr)
1911{
1912 struct driveInfo di;
1913
1914 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
1915return 1;
1916 }
1917 return 0;
1918}
1919
1920int biosDevIsCDROM(int biosdev)
1921{
1922 struct driveInfo di;
1923
1924 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
1925 {
1926 return 1;
1927 }
1928 return 0;
1929}
1930

Archive Download this file

Revision: 169