Chameleon

Chameleon Svn Source Tree

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

Source at commit 1066 created 12 years 10 months ago.
By meklort, Removing even more code...
1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * All rights reserved. The CMU software License Agreement specifies
29 * the terms and conditions for use and redistribution.
30 */
31
32/*
33 * INTEL CORPORATION PROPRIETARY INFORMATION
34 *
35 * This software is supplied under the terms of a license agreement or
36 * nondisclosure agreement with Intel Corporation and may not be copied
37 * nor disclosed except in accordance with the terms of that agreement.
38 *
39 * Copyright 1988, 1989 Intel Corporation
40 */
41
42/*
43 * Copyright 1993 NeXT Computer, Inc.
44 * All rights reserved.
45 */
46
47/*
48 * Copyright 2007 VMware Inc.
49 * "Preboot" ramdisk support added by David Elliott
50 * GPT support added by David Elliott. Based on IOGUIDPartitionScheme.cpp.
51 */
52
53//Azi: style the rest later...
54
55// Allow UFS_SUPPORT to be overridden with preprocessor option.
56#ifndef UFS_SUPPORT
57// zef: Disabled UFS support
58#define UFS_SUPPORT 0
59#endif
60
61#if UFS_SUPPORT
62#include "ufs.h"
63#endif
64#include <limits.h>
65#include <IOKit/storage/IOApplePartitionScheme.h>
66#include <IOKit/storage/IOGUIDPartitionScheme.h>
67#include "libsaio.h"
68#include "boot.h"
69#include "memory.h"
70#include "fdisk.h"
71#include "hfs.h"
72#include "ntfs.h"
73#include "msdos.h"
74#include "ext2fs.h"
75#include "xml.h"
76#include "disk.h"
77// For EFI_GUID
78#include "efi.h"
79#include "efi_tables.h"
80
81typedef struct gpt_hdr gpt_hdr;
82typedef struct gpt_ent gpt_ent;
83
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
131//==========================================================================
132
133static int getDriveInfo( int biosdev, struct driveInfo *dip )
134{
135 static struct driveInfo cached_di;
136 int cc;
137
138 // Real BIOS devices are 8-bit, so anything above that is for internal use.
139 // Don't cache ramdisk drive info since it doesn't require several BIOS
140 // calls and is thus not worth it.
141 if(biosdev >= 0x100)
142 {
143 if(p_get_ramdisk_info != NULL)
144 cc = (*p_get_ramdisk_info)(biosdev, dip);
145 else
146 cc = -1;
147 if(cc < 0)
148 {
149 dip->valid = 0;
150 return -1;
151 }
152 else
153 return 0;
154 }
155
156 if ( !cached_di.valid || biosdev != cached_di.biosdev )
157 {
158cc = get_drive_info(biosdev, &cached_di);
159 if (cc < 0) {
160 cached_di.valid = 0;
161 DEBUG_DISK(("get_drive_info returned error\n"));
162 return (-1); // BIOS call error
163}
164 }
165
166 bcopy(&cached_di, dip, sizeof(cached_di));
167
168 return 0;
169}
170
171//==========================================================================
172// Maps (E)BIOS return codes to message strings.
173
174struct NamedValue {
175 unsigned char value;
176 const char * name;
177};
178
179static const char * getNameForValue( const struct NamedValue * nameTable,
180 unsigned char value )
181{
182 const struct NamedValue * np;
183
184 for ( np = nameTable; np->value; np++)
185 if (np->value == value)
186 return np->name;
187
188 return NULL;
189}
190
191#define ECC_CORRECTED_ERR 0x11
192
193static const struct NamedValue bios_errors[] = {
194 { 0x10, "Media error" },
195 { 0x11, "Corrected ECC error" },
196 { 0x20, "Controller or device error" },
197 { 0x40, "Seek failed" },
198 { 0x80, "Device timeout" },
199 { 0xAA, "Drive not ready" },
200 { 0x00, 0 }
201};
202
203static const char * bios_error(int errnum)
204{
205 static char errorstr[] = "Error 0x00";
206 const char * errname;
207
208 errname = getNameForValue( bios_errors, errnum );
209 if ( errname ) return errname;
210
211 sprintf(errorstr, "Error 0x%02x", errnum);
212 return errorstr; // No string, print error code only
213}
214
215//==========================================================================
216// Use BIOS INT13 calls to read the sector specified. This function will
217// also perform read-ahead to cache a few subsequent sector to the sector
218// cache.
219//
220// Return:
221// 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
222
223static bool cache_valid = false;
224
225static int Biosread( int biosdev, unsigned long long secno )
226{
227 static int xbiosdev, xcyl, xhead;
228 static unsigned int xsec, xnsecs;
229 struct driveInfo di;
230
231 int rc = -1;
232 int cyl, head, sec;
233 int tries = 0;
234 int bps, divisor;
235
236 if (getDriveInfo(biosdev, &di) < 0) {
237return -1;
238 }
239 if (di.no_emulation) {
240/* Always assume 2k block size; BIOS may lie about geometry */
241bps = 2048;
242 } else {
243bps = di.di.params.phys_nbps;
244 if (bps == 0) {
245 return -1;
246 }
247 }
248 divisor = bps / BPS;
249
250 DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));
251
252 // To read the disk sectors, use EBIOS if we can. Otherwise,
253 // revert to the standard BIOS calls.
254
255 if ((biosdev >= kBIOSDevTypeHardDrive) &&
256 (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))
257 {
258 if (cache_valid &&
259 (biosdev == xbiosdev) &&
260 (secno >= xsec) &&
261 ((unsigned int)secno < (xsec + xnsecs)))
262 {
263 biosbuf = trackbuf + (BPS * (secno - xsec));
264 return 0;
265 }
266
267 xnsecs = N_CACHE_SECS;
268 xsec = (secno / divisor) * divisor;
269 cache_valid = false;
270
271 while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))
272 {
273 if (rc == ECC_CORRECTED_ERR) {
274 /* Ignore corrected ECC errors */
275 rc = 0;
276 break;
277 }
278 error(" EBIOS read error: %s\n", bios_error(rc), rc);
279 error(" Block 0x%x Sectors %d\n", secno, xnsecs);
280 sleep(1);
281 }
282 }
283 else
284 {
285/* spc = spt * heads */
286int spc = (di.di.params.phys_spt * di.di.params.phys_heads);
287 cyl = secno / spc;
288 head = (secno % spc) / di.di.params.phys_spt;
289 sec = secno % di.di.params.phys_spt;
290
291 if (cache_valid &&
292 (biosdev == xbiosdev) &&
293 (cyl == xcyl) &&
294 (head == xhead) &&
295 ((unsigned int)sec >= xsec) &&
296 ((unsigned int)sec < (xsec + xnsecs)))
297 {
298 // this sector is in trackbuf cache
299 biosbuf = trackbuf + (BPS * (sec - xsec));
300 return 0;
301 }
302
303 // Cache up to a track worth of sectors, but do not cross a
304 // track boundary.
305
306 xcyl = cyl;
307 xhead = head;
308 xsec = sec;
309 xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;
310 cache_valid = false;
311
312 while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) &&
313 (++tries < 5))
314 {
315 if (rc == ECC_CORRECTED_ERR) {
316 /* Ignore corrected ECC errors */
317 rc = 0;
318 break;
319 }
320 error(" BIOS read error: %s\n", bios_error(rc), rc);
321 error(" Block %d, Cyl %d Head %d Sector %d\n",
322 secno, cyl, head, sec);
323 sleep(1);
324 }
325 }
326
327 // If the BIOS reported success, mark the sector cache as valid.
328
329 if (rc == 0) {
330 cache_valid = true;
331 }
332 biosbuf = trackbuf + (secno % divisor) * BPS;
333 xbiosdev = biosdev;
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// GUID's in LE form:
632// HFS+ partition - 48465300-0000-11AA-AA11-00306543ECAC
633EFI_GUID const GPT_HFS_GUID = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
634
635// turbo - Apple Boot Partition - 426F6F74-0000-11AA-AA11-00306543ECAC
636EFI_GUID const GPT_BOOT_GUID = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
637
638// turbo - or an EFI System Partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B
639EFI_GUID const GPT_EFISYS_GUID = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };
640
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 } };
643
644// Microsoft Reserved Partition - E3C9E316-0B5C-4DB8-817DF92DF00215AE
645EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };
646
647
648BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,
649 const gpt_ent * part,
650 FSInit initFunc, FSLoadFile loadFunc,
651 FSReadFile readFunc,
652 FSGetDirEntry getdirFunc,
653 FSGetFileBlock getBlockFunc,
654 FSGetUUID getUUIDFunc,
655 BVGetDescription getDescriptionFunc,
656 BVFree bvFreeFunc,
657 int probe, int type, unsigned int bvrFlags )
658{
659 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
660 if ( bvr )
661 {
662 bzero(bvr, sizeof(*bvr));
663
664 bvr->biosdev = biosdev;
665 bvr->part_no = partno;
666 bvr->part_boff = blkoff;
667 bvr->fs_loadfile = loadFunc;
668 bvr->fs_readfile = readFunc;
669 bvr->fs_getdirentry = getdirFunc;
670 bvr->fs_getfileblock= getBlockFunc;
671 bvr->fs_getuuid = getUUIDFunc;
672 bvr->description = getDescriptionFunc;
673 bvr->type = type;
674 bvr->bv_free = bvFreeFunc;
675 // FIXME: UCS-2 -> UTF-8 the name
676 strlcpy(bvr->name, "----", DPISTRLEN);
677 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)part->ent_type) == 0) ||
678 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)part->ent_type) == 0) )
679 strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);
680 else
681 strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);
682
683 /*
684 if ( part->bootid & FDISK_ACTIVE )
685 bvr->flags |= kBVFlagPrimary;
686 */
687
688 // Probe the filesystem.
689
690 if ( initFunc )
691 {
692 bvr->flags |= kBVFlagNativeBoot;
693
694 if ( probe && initFunc( bvr ) != 0 )
695 {
696 // filesystem probe failed.
697
698 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
699 __FUNCTION__, biosdev, partno));
700
701 (*bvr->bv_free)(bvr);
702 bvr = NULL;
703 }
704 if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
705 {
706 bvr->flags |= kBVFlagBootable;
707 }
708 }
709 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
710 {
711 bvr->flags |= kBVFlagForeignBoot;
712 }
713 else
714 {
715 (*bvr->bv_free)(bvr);
716 bvr = NULL;
717 }
718 }
719 if (bvr) bvr->flags |= bvrFlags;
720 return bvr;
721}
722
723//==========================================================================
724
725/* A note on partition numbers:
726 * IOKit makes the primary partitions numbers 1-4, and then
727 * extended partitions are numbered consecutively 5 and up.
728 * So, for example, if you have two primary partitions and
729 * one extended partition they will be numbered 1, 2, 5.
730 */
731
732static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
733{
734 const struct fdisk_part * part;
735 struct DiskBVMap * map;
736 int partno = -1;
737 BVRef bvr;
738#if UFS_SUPPORT
739 BVRef booterUFS = NULL;
740#endif
741 int spc;
742 struct driveInfo di;
743 boot_drive_info_t *dp;
744
745 /* Initialize disk info */
746 if (getDriveInfo(biosdev, &di) != 0) {
747return NULL;
748 }
749 dp = &di.di;
750 spc = (dp->params.phys_spt * dp->params.phys_heads);
751 if (spc == 0) {
752/* This is probably a CD-ROM; punt on the geometry. */
753spc = 1;
754 }
755
756 do {
757 // Create a new mapping.
758
759 map = (struct DiskBVMap *) malloc( sizeof(*map) );
760 if ( map )
761 {
762 map->biosdev = biosdev;
763 map->bvr = NULL;
764 map->bvrcnt = 0;
765 map->next = gDiskBVMap;
766 gDiskBVMap = map;
767
768 // Create a record for each partition found on the disk.
769
770 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
771 {
772 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
773 partno, part->systid));
774 bvr = 0;
775
776 switch ( part->systid )
777 {
778#if UFS_SUPPORT
779 case FDISK_UFS:
780 bvr = newFDiskBVRef(
781 biosdev, partno,
782 part->relsect + UFS_FRONT_PORCH/BPS,
783 part,
784 UFSInitPartition,
785 UFSLoadFile,
786 UFSReadFile,
787 UFSGetDirEntry,
788 UFSGetFileBlock,
789 UFSGetUUID,
790 UFSGetDescription,
791 UFSFree,
792 0,
793 kBIOSDevTypeHardDrive, 0);
794 break;
795#endif
796
797 case FDISK_HFS:
798 bvr = newFDiskBVRef(
799 biosdev, partno,
800 part->relsect,
801 part,
802 HFSInitPartition,
803 HFSLoadFile,
804 HFSReadFile,
805 HFSGetDirEntry,
806 HFSGetFileBlock,
807 HFSGetUUID,
808 HFSGetDescription,
809 HFSFree,
810 0,
811 kBIOSDevTypeHardDrive, 0);
812 break;
813
814 // turbo - we want the booter type scanned also
815 case FDISK_BOOTER:
816 if (part->bootid & FDISK_ACTIVE)
817 gBIOSBootVolume = newFDiskBVRef(
818 biosdev, partno,
819 part->relsect,
820 part,
821 HFSInitPartition,
822 HFSLoadFile,
823 HFSReadFile,
824 HFSGetDirEntry,
825 HFSGetFileBlock,
826 HFSGetUUID,
827 HFSGetDescription,
828 HFSFree,
829 0,
830 kBIOSDevTypeHardDrive, 0);
831 break;
832
833#if UFS_SUPPORT
834 case FDISK_BOOTER:
835 booterUFS = newFDiskBVRef(
836 biosdev, partno,
837 ((part->relsect + spc - 1) / spc) * spc,
838 part,
839 UFSInitPartition,
840 UFSLoadFile,
841 UFSReadFile,
842 UFSGetDirEntry,
843 UFSGetFileBlock,
844 UFSGetUUID,
845 UFSGetDescription,
846 UFSFree,
847 0,
848 kBIOSDevTypeHardDrive, 0);
849 break;
850#endif
851
852 case FDISK_FAT32:
853 case FDISK_DOS12:
854 case FDISK_DOS16S:
855 case FDISK_DOS16B:
856 case FDISK_SMALLFAT32:
857 case FDISK_DOS16SLBA:
858 bvr = newFDiskBVRef(
859 biosdev, partno,
860 part->relsect,
861 part,
862 MSDOSInitPartition,
863 MSDOSLoadFile,
864 MSDOSReadFile,
865 MSDOSGetDirEntry,
866 MSDOSGetFileBlock,
867 MSDOSGetUUID,
868 MSDOSGetDescription,
869 MSDOSFree,
870 0,
871 kBIOSDevTypeHardDrive, 0);
872 break;
873
874 case FDISK_NTFS:
875 bvr = newFDiskBVRef(
876 biosdev, partno,
877 part->relsect,
878 part,
879 0, 0, 0, 0, 0,
880 NTFSGetUUID,
881 NTFSGetDescription,
882 (BVFree)free,
883 0, kBIOSDevTypeHardDrive, 0);
884 break;
885
886 case FDISK_LINUX:
887 bvr = newFDiskBVRef(
888 biosdev, partno,
889 part->relsect,
890 part,
891 0, 0, 0, 0, 0, 0,
892 EX2GetDescription,
893 (BVFree)free,
894 0, kBIOSDevTypeHardDrive, 0);
895 break;
896
897 default:
898 bvr = newFDiskBVRef(
899 biosdev, partno,
900 part->relsect,
901 part,
902 0, 0, 0, 0, 0, 0, 0,
903 (BVFree)free,
904 0,
905 kBIOSDevTypeHardDrive, 0);
906 break;
907 }
908
909 if ( bvr )
910 {
911 bvr->next = map->bvr;
912 map->bvr = bvr;
913 map->bvrcnt++;
914 }
915 }
916
917#if UFS_SUPPORT
918 // Booting from a CD with an UFS filesystem embedded
919 // in a booter partition.
920
921 if ( booterUFS )
922 {
923 if ( map->bvrcnt == 0 )
924 {
925 map->bvr = booterUFS;
926 map->bvrcnt++;
927 }
928 else free( booterUFS );
929 }
930#endif
931 }
932 } while (0);
933
934 /*
935 * If no FDisk partition, then we will check for
936 * an Apple partition map elsewhere.
937 */
938#if UNUSED
939 if (map->bvrcnt == 0) {
940static struct fdisk_part cdpart;
941cdpart.systid = 0xCD;
942
943/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
944bvr = newFDiskBVRef(
945 biosdev, 0,
946 0,
947 &cdpart,
948 HFSInitPartition,
949 HFSLoadFile,
950 HFSReadFile,
951 HFSGetDirEntry,
952 HFSGetFileBlock,
953 HFSGetUUID,
954 0,
955 kBIOSDevTypeHardDrive);
956bvr->next = map->bvr;
957map->bvr = bvr;
958map->bvrcnt++;
959 }
960#endif
961 // Actually this should always be true given the above code
962 if(map == gDiskBVMap)
963 {
964 // Don't leave a null map in the chain
965 if(map->bvrcnt == 0 && map->bvr == NULL)
966 {
967 gDiskBVMap = map->next;
968 free(map);
969 map = NULL;
970 }
971 }
972
973 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
974
975 return map ? map->bvr : NULL;
976}
977
978//==========================================================================
979
980static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
981{
982 struct DiskBVMap * map;
983 struct Block0 *block0_p;
984 unsigned int blksize;
985 unsigned int factor;
986 void *buffer = malloc(BPS);
987
988 /* Check for alternate block size */
989 if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
990 return NULL;
991 }
992 block0_p = buffer;
993 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
994 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
995 if (blksize != BPS) {
996 free(buffer);
997 buffer = malloc(blksize);
998 }
999 factor = blksize / BPS;
1000 } else {
1001 blksize = BPS;
1002 factor = 1;
1003 }
1004
1005 do {
1006 // Create a new mapping.
1007
1008 map = (struct DiskBVMap *) malloc( sizeof(*map) );
1009 if ( map )
1010 {
1011 int error;
1012 DPME *dpme_p = (DPME *)buffer;
1013 UInt32 i, npart = UINT_MAX;
1014 BVRef bvr;
1015
1016 map->biosdev = biosdev;
1017 map->bvr = NULL;
1018 map->bvrcnt = 0;
1019 map->next = gDiskBVMap;
1020 gDiskBVMap = map;
1021
1022 for (i=0; i<npart; i++) {
1023 error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
1024
1025 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
1026 break;
1027 }
1028
1029 if (i==0) {
1030 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
1031 }
1032 /*
1033 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
1034 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
1035 dpme.dpme_pblock_start, dpme.dpme_pblocks,
1036 dpme.dpme_lblock_start, dpme.dpme_lblocks,
1037 dpme.dpme_boot_block);
1038 */
1039
1040 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
1041 bvr = newAPMBVRef(biosdev,
1042 i,
1043 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
1044 dpme_p,
1045 HFSInitPartition,
1046 HFSLoadFile,
1047 HFSReadFile,
1048 HFSGetDirEntry,
1049 HFSGetFileBlock,
1050 HFSGetUUID,
1051 HFSGetDescription,
1052 HFSFree,
1053 0,
1054 kBIOSDevTypeHardDrive, 0);
1055 bvr->next = map->bvr;
1056 map->bvr = bvr;
1057 map->bvrcnt++;
1058 }
1059 }
1060 }
1061 } while (0);
1062
1063 free(buffer);
1064
1065 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
1066
1067 return map ? map->bvr : NULL;
1068}
1069
1070//==========================================================================
1071
1072// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1073
1074/*
1075 * Trying to figure out the filsystem type of a given partition.
1076 */
1077static int probeFileSystem(int biosdev, unsigned int blkoff)
1078{
1079 // detected filesystem type;
1080 int result = -1;
1081 int fatbits;
1082
1083 // Allocating buffer for 4 sectors.
1084 const void * probeBuffer = malloc(PROBEFS_SIZE);
1085 if (probeBuffer == NULL)
1086 goto exit;
1087
1088 // Reading first 4 sectors of current partition
1089 int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
1090 if (error)
1091 goto exit;
1092
1093 if (HFSProbe(probeBuffer))
1094 result = FDISK_HFS;
1095 else if (EX2Probe(probeBuffer))
1096 result = FDISK_LINUX;
1097 else if (NTFSProbe(probeBuffer))
1098 result = FDISK_NTFS;
1099 else if (fatbits=MSDOSProbe(probeBuffer))
1100 {
1101 switch (fatbits)
1102 {
1103 case 32:
1104 default:
1105 result = FDISK_FAT32;
1106 break;
1107 case 16:
1108 result = FDISK_DOS16B;
1109 break;
1110 case 12:
1111 result = FDISK_DOS12;
1112 break;
1113 }
1114 }
1115 else
1116 // Couldn't detect filesystem type
1117 result = 0;
1118
1119exit:
1120 if (probeBuffer != NULL) free((void *)probeBuffer);
1121 return result;
1122}
1123
1124static bool isPartitionUsed(gpt_ent * partition)
1125{
1126 //
1127 // Ask whether the given partition is used.
1128 //
1129
1130 return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
1131}
1132
1133// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1134
1135static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )
1136{
1137 struct DiskBVMap * map = NULL;
1138 void *buffer = malloc(BPS);
1139 int error;
1140 if ( error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer ) != 0) {
1141 verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
1142 goto scanErr;
1143 }
1144 struct REAL_disk_blk0 *fdiskMap = buffer;
1145 if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
1146 {
1147 verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
1148 goto scanErr;
1149 }
1150
1151 int fdiskID = 0;
1152 unsigned index;
1153 for ( index = 0; index < FDISK_NPART; index++ )
1154 {
1155 if ( fdiskMap->parts[index].systid )
1156 {
1157 if ( fdiskMap->parts[index].systid == 0xEE )
1158 {
1159 // Fail if two 0xEE partitions are present which
1160 // means the FDISK code will wind up parsing it.
1161 if ( fdiskID ) goto scanErr;
1162
1163 fdiskID = index + 1;
1164 }
1165 }
1166 }
1167
1168 if ( fdiskID == 0 ) goto scanErr;
1169 verbose("Attempting to read GPT\n");
1170
1171 if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
1172 goto scanErr;
1173
1174 gpt_hdr *headerMap = buffer;
1175
1176 // Determine whether the partition header signature is present.
1177
1178 if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
1179 {
1180 goto scanErr;
1181 }
1182
1183 // Determine whether the partition header size is valid.
1184
1185 UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
1186 UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
1187
1188 if ( headerSize < offsetof(gpt_hdr, padding) )
1189 {
1190 goto scanErr;
1191 }
1192
1193 if ( headerSize > BPS )
1194 {
1195 goto scanErr;
1196 }
1197
1198 // Determine whether the partition header checksum is valid.
1199
1200 headerMap->hdr_crc_self = 0;
1201
1202 if ( crc32(0, headerMap, headerSize) != headerCheck )
1203 {
1204 goto scanErr;
1205 }
1206
1207 // Determine whether the partition entry size is valid.
1208
1209 UInt64 gptBlock = 0;
1210 UInt32 gptCheck = 0;
1211 UInt32 gptCount = 0;
1212 UInt32 gptID = 0;
1213 gpt_ent * gptMap = 0;
1214 UInt32 gptSize = 0;
1215
1216 gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
1217 gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
1218 gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
1219 gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
1220
1221 if ( gptSize < sizeof(gpt_ent) )
1222 {
1223 goto scanErr;
1224 }
1225
1226 // Allocate a buffer large enough to hold one map, rounded to a media block.
1227 free(buffer);
1228 buffer = NULL;
1229
1230 UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
1231 if(bufferSize == 0)
1232 goto scanErr;
1233 buffer = malloc(bufferSize);
1234
1235 if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
1236 goto scanErr;
1237
1238 verbose("Read GPT\n");
1239
1240 // Allocate a new map for this BIOS device and insert it into the chain
1241 map = malloc(sizeof(*map));
1242 map->biosdev = biosdev;
1243 map->bvr = NULL;
1244 map->bvrcnt = 0;
1245 map->next = gDiskBVMap;
1246 gDiskBVMap = map;
1247
1248 // fdisk like partition type id.
1249 int fsType = 0;
1250
1251 for(gptID = 1; gptID <= gptCount; ++gptID)
1252 {
1253BVRef bvr = NULL;
1254unsigned int bvrFlags = 0;
1255
1256 // size on disk can be larger than sizeof(gpt_ent)
1257 gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
1258
1259 // NOTE: EFI_GUID's are in LE and we know we're on an x86.
1260 // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
1261
1262 if (isPartitionUsed(gptMap))
1263 {
1264 char stringuuid[100];
1265 efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
1266 verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
1267
1268 // Getting fdisk like partition type.
1269 fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
1270
1271 if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1272 (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1273 {
1274 bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
1275 bvr = newGPTBVRef(biosdev,
1276 gptID,
1277 gptMap->ent_lba_start,
1278 gptMap,
1279 HFSInitPartition,
1280 HFSLoadFile,
1281 HFSReadFile,
1282 HFSGetDirEntry,
1283 HFSGetFileBlock,
1284 HFSGetUUID,
1285 HFSGetDescription,
1286 HFSFree,
1287 0,
1288 kBIOSDevTypeHardDrive, bvrFlags);
1289 }
1290
1291// zef - foreign OS support
1292 if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
1293 (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1294 {
1295switch (fsType)
1296 {
1297 case FDISK_NTFS:
1298 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1299 0, 0, 0, 0, 0, 0, NTFSGetDescription,
1300 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1301break;
1302
1303 default:
1304 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1305 0, 0, 0, 0, 0, 0, 0,
1306 (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
1307 break;
1308 }
1309
1310 }
1311
1312 // turbo - save our booter partition
1313 // zef - only on original boot device
1314 if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
1315 {
1316switch (fsType)
1317 {
1318 case FDISK_HFS:
1319 if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1320 {
1321 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1322 HFSInitPartition,
1323 HFSLoadFile,
1324 HFSReadFile,
1325 HFSGetDirEntry,
1326 HFSGetFileBlock,
1327 HFSGetUUID,
1328 HFSGetDescription,
1329 HFSFree,
1330 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1331 }
1332 break;
1333
1334 case FDISK_FAT32:
1335 if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
1336 {
1337 bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
1338 MSDOSInitPartition,
1339 MSDOSLoadFile,
1340 MSDOSReadFile,
1341 MSDOSGetDirEntry,
1342 MSDOSGetFileBlock,
1343 MSDOSGetUUID,
1344 MSDOSGetDescription,
1345 MSDOSFree,
1346 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
1347 }
1348 break;
1349
1350 if (biosdev == gBIOSDev)
1351 gBIOSBootVolume = bvr;
1352 }
1353 }
1354
1355if (bvr)
1356{
1357 // Fixup bvr with the fake fdisk partition type.
1358 if (fsType > 0) bvr->part_type = fsType;
1359
1360bvr->next = map->bvr;
1361map->bvr = bvr;
1362++map->bvrcnt;
1363}
1364
1365 }
1366 }
1367
1368scanErr:
1369 free(buffer);
1370
1371 if(map)
1372 {
1373 if(countPtr) *countPtr = map->bvrcnt;
1374 return map->bvr;
1375 }
1376 else
1377 {
1378 if(countPtr) *countPtr = 0;
1379 return NULL;
1380 }
1381}
1382
1383//==========================================================================
1384
1385static void scanFSLevelBVRSettings(BVRef chain)
1386{
1387 BVRef bvr;
1388 char dirSpec[512], fileSpec[512];
1389 char label[BVSTRLEN];
1390 int ret;
1391 long flags, time;
1392 int fh, fileSize, error;
1393
1394 for (bvr = chain; bvr; bvr = bvr->next)
1395 {
1396 ret = -1;
1397 error = 0;
1398
1399 //
1400 // Check for alternate volume label on boot helper partitions.
1401 //
1402 if (bvr->flags & kBVFlagBooter)
1403 {
1404 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1405 strcpy(fileSpec, ".disk_label.contentDetails");
1406 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1407 if (!ret)
1408 {
1409 fh = open(strcat(dirSpec, fileSpec), 0);
1410 fileSize = file_size(fh);
1411 if (fileSize > 0 && fileSize < BVSTRLEN)
1412 {
1413 if (read(fh, label, fileSize) != fileSize)
1414 error = -1;
1415 }
1416 else
1417 error = -1;
1418
1419 close(fh);
1420
1421 if (!error)
1422 {
1423 label[fileSize] = '\0';
1424 strcpy(bvr->altlabel, label);
1425 }
1426 }
1427 }
1428
1429 //
1430 // Check for SystemVersion.plist or ServerVersion.plist
1431 // to determine if a volume hosts an installed system.
1432 //
1433 if (bvr->flags & kBVFlagNativeBoot)
1434 {
1435 sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1436 strcpy(fileSpec, "SystemVersion.plist");
1437 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1438
1439 if (ret == -1)
1440 {
1441 strcpy(fileSpec, "ServerVersion.plist");
1442 ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
1443 }
1444
1445 if (!ret)
1446 bvr->flags |= kBVFlagSystemVolume;
1447 }
1448
1449 }
1450}
1451
1452void rescanBIOSDevice(int biosdev)
1453{
1454struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
1455CacheReset();
1456diskFreeMap(oldMap);
1457oldMap = NULL;
1458scanBootVolumes(biosdev, 0);
1459}
1460
1461struct DiskBVMap* diskResetBootVolumes(int biosdev)
1462{
1463 struct DiskBVMap * map;
1464 struct DiskBVMap *prevMap = NULL;
1465 for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
1466 if ( biosdev == map->biosdev ) {
1467 break;
1468 }
1469 }
1470 if(map != NULL)
1471 {
1472 verbose("Resetting BIOS device %xh\n", biosdev);
1473 // Reset the biosbuf cache
1474 cache_valid = false;
1475 if(map == gDiskBVMap)
1476 gDiskBVMap = map->next;
1477 else if(prevMap != NULL)
1478 prevMap->next = map->next;
1479 else
1480 stop("");
1481 }
1482 // Return the old map, either to be freed, or reinserted later
1483 return map;
1484}
1485
1486// Frees a DiskBVMap and all of its BootVolume's
1487void diskFreeMap(struct DiskBVMap *map)
1488{
1489 if(map != NULL)
1490 {
1491 while(map->bvr != NULL)
1492 {
1493 BVRef bvr = map->bvr;
1494 map->bvr = bvr->next;
1495 (*bvr->bv_free)(bvr);
1496 }
1497 free(map);
1498 }
1499}
1500
1501BVRef diskScanBootVolumes( int biosdev, int * countPtr )
1502{
1503 struct DiskBVMap * map;
1504 BVRef bvr;
1505 int count = 0;
1506
1507 // Find an existing mapping for this device.
1508
1509 for ( map = gDiskBVMap; map; map = map->next ) {
1510 if ( biosdev == map->biosdev ) {
1511 count = map->bvrcnt;
1512 break;
1513 }
1514 }
1515
1516 if (map == NULL) {
1517 bvr = diskScanGPTBootVolumes(biosdev, &count);
1518 if (bvr == NULL) {
1519 bvr = diskScanFDiskBootVolumes(biosdev, &count);
1520 }
1521 if (bvr == NULL) {
1522 bvr = diskScanAPMBootVolumes(biosdev, &count);
1523 }
1524 if (bvr)
1525 {
1526 scanFSLevelBVRSettings(bvr);
1527 }
1528 } else {
1529 bvr = map->bvr;
1530 }
1531 if (countPtr) *countPtr += count;
1532 return bvr;
1533}
1534
1535BVRef getBVChainForBIOSDev(int biosdev)
1536{
1537 BVRef chain = NULL;
1538 struct DiskBVMap * map = NULL;
1539
1540 for (map = gDiskBVMap; map; map = map->next)
1541 {
1542 if (map->biosdev == biosdev)
1543 {
1544 chain = map->bvr;
1545 break;
1546 }
1547 }
1548
1549 return chain;
1550}
1551
1552BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
1553{
1554 BVRef chain = NULL;
1555 BVRef bvr = NULL;
1556 BVRef newBVR = NULL;
1557 BVRef prevBVR = NULL;
1558
1559 struct DiskBVMap * map = NULL;
1560 int bvCount = 0;
1561
1562 /*
1563 * Traverse gDISKBVmap to get references for
1564 * individual bvr chains of each drive.
1565 */
1566 for (map = gDiskBVMap; map; map = map->next)
1567 {
1568 for (bvr = map->bvr; bvr; bvr = bvr->next)
1569 {
1570 /*
1571 * Save the last bvr.
1572 */
1573 if (newBVR) prevBVR = newBVR;
1574
1575 /*
1576 * Allocate and copy the matched bvr entry into a new one.
1577 */
1578 newBVR = (BVRef) malloc(sizeof(*newBVR));
1579 bcopy(bvr, newBVR, sizeof(*newBVR));
1580
1581 /*
1582 * Adjust the new bvr's fields.
1583 */
1584 newBVR->next = NULL;
1585 newBVR->filtered = true;
1586
1587 if ( (!allowFlags || newBVR->flags & allowFlags)
1588 && (!denyFlags || !(newBVR->flags & denyFlags) )
1589 && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
1590 )
1591 newBVR->visible = true;
1592
1593 /*
1594 * Use the first bvr entry as the starting chain pointer.
1595 */
1596 if (!chain)
1597 chain = newBVR;
1598
1599 /*
1600 * Update the previous bvr's link pointer to use the new memory area.
1601 */
1602 if (prevBVR)
1603 prevBVR->next = newBVR;
1604
1605 if (newBVR->visible)
1606 bvCount++;
1607 }
1608 }
1609
1610#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
1611 for (bvr = chain; bvr; bvr = bvr->next)
1612 {
1613 printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
1614 }
1615 printf("count: %d\n", bvCount);
1616 getchar();
1617#endif
1618
1619 *count = bvCount;
1620
1621 return chain;
1622}
1623
1624int freeFilteredBVChain(const BVRef chain)
1625{
1626 int ret = 1;
1627 BVRef bvr = chain;
1628 BVRef nextBVR = NULL;
1629
1630 while (bvr)
1631 {
1632 nextBVR = bvr->next;
1633
1634 if (bvr->filtered)
1635 {
1636 free(bvr);
1637 }
1638 else
1639 {
1640 ret = 0;
1641 break;
1642 }
1643
1644 bvr = nextBVR;
1645 }
1646
1647 return ret;
1648}
1649
1650//==========================================================================
1651
1652static const struct NamedValue fdiskTypes[] =
1653{
1654 { FDISK_NTFS, "Windows NTFS" },
1655{ FDISK_DOS12, "Windows FAT12" },
1656{ FDISK_DOS16B, "Windows FAT16" },
1657{ FDISK_DOS16S, "Windows FAT16" },
1658{ FDISK_DOS16SLBA, "Windows FAT16" },
1659{ FDISK_SMALLFAT32, "Windows FAT32" },
1660{ FDISK_FAT32, "Windows FAT32" },
1661 { FDISK_LINUX, "Linux" },
1662 { FDISK_UFS, "Apple UFS" },
1663 { FDISK_HFS, "Apple HFS" },
1664 { FDISK_BOOTER, "Apple Boot/UFS" },
1665 { 0xCD, "CD-ROM" },
1666 { 0x00, 0 } /* must be last */
1667};
1668
1669//==========================================================================
1670
1671bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
1672{
1673char testStr[128];
1674
1675if ( !bvr || !match || !*match)
1676return 0;
1677
1678if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
1679 return 0;
1680
1681 // Try to match hd(x,y) first.
1682 sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
1683 if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1684 return true;
1685
1686 // Try to match volume UUID.
1687 if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
1688 {
1689 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1690 return true;
1691 }
1692
1693 // Try to match volume label (always quoted).
1694 if ( bvr->description )
1695 {
1696 bvr->description(bvr, testStr, sizeof(testStr)-1);
1697 if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
1698 return true;
1699 }
1700
1701 return false;
1702}
1703
1704void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
1705{
1706 unsigned char type;
1707 char *p = str;
1708
1709 if(!bvr || !p || strMaxLen <= 0)
1710 return;
1711
1712 type = (unsigned char) bvr->part_type;
1713
1714 if (useDeviceDescription)
1715 {
1716 int len = getDeviceDescription(bvr, str);
1717 if(len >= strMaxLen)
1718 return;
1719
1720 strcpy(str + len, " ");
1721 len++;
1722 strMaxLen -= len;
1723 p += len;
1724 }
1725
1726 //
1727 // Get the volume label using filesystem specific functions
1728 // or use the alternate volume label if available.
1729 //
1730if (*bvr->altlabel != '\0')
1731 strncpy(p, bvr->altlabel, strMaxLen);
1732else if (bvr->description)
1733 bvr->description(bvr, p, strMaxLen);
1734
1735 if (*p == '\0') {
1736 const char * name = getNameForValue( fdiskTypes, type );
1737 if (name == NULL) {
1738 name = bvr->type_name;
1739 }
1740 if (name == NULL) {
1741 sprintf(p, "TYPE %02x", type);
1742 } else {
1743 strncpy(p, name, strMaxLen);
1744 }
1745 }
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 }
1867
1868 return 0;
1869}
1870
1871int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1872{
1873 int secs;
1874 unsigned char *cbuf = (unsigned char *)buffer;
1875 unsigned int copy_len;
1876 int rc;
1877
1878 if ((len & (BPS-1)) != 0) {
1879 error("raw disk write not sector aligned");
1880 return -1;
1881 }
1882 secno += bvr->part_boff;
1883
1884 cache_valid = false;
1885
1886 while (len > 0) {
1887 secs = len / BPS;
1888 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1889 copy_len = secs * BPS;
1890
1891 bcopy( cbuf, trackbuf, copy_len );
1892 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1893 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
1894 error(" EBIOS write error: %s\n", bios_error(rc), rc);
1895 error(" Block %d Sectors %d\n", secno, secs);
1896 return rc;
1897 }
1898 len -= copy_len;
1899 cbuf += copy_len;
1900 secno += secs;
1901 }
1902
1903 return 0;
1904}
1905
1906int diskIsCDROM(BVRef bvr)
1907{
1908 struct driveInfo di;
1909
1910 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
1911return 1;
1912 }
1913 return 0;
1914}
1915
1916int biosDevIsCDROM(int biosdev)
1917{
1918 struct driveInfo di;
1919
1920 if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
1921 {
1922 return 1;
1923 }
1924 return 0;
1925}
1926

Archive Download this file

Revision: 1066