Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Chazileon/i386/libsaio/disk.c

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

Archive Download this file

Revision: 418