Chameleon

Chameleon Svn Source Tree

Root/branches/valv/i386/libsaio/disk.c

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

Archive Download this file

Revision: 665