Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 515