Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 290