Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 293