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

Archive Download this file

Revision: 994