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

Archive Download this file

Revision: 2115