Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1065