Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/disk.c

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

Archive Download this file

Revision: 413