Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2118