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

Archive Download this file

Revision: 300