Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 394