]> git.saurik.com Git - apple/boot.git/blame - i386/libsaio/disk.c
boot-132.tar.gz
[apple/boot.git] / i386 / libsaio / disk.c
CommitLineData
14c7c974 1/*
57c72a9a 2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
14c7c974
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
57c72a9a 6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
4f6e3300
A
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
57c72a9a 9 * Source License Version 2.0 (the "License"). You may not use this file
4f6e3300
A
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.
14c7c974
A
13 *
14 * The Original Code and all software distributed under the License are
4f6e3300 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
4f6e3300
A
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.
14c7c974
A
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
bba600dd
A
47#define UFS_SUPPORT 1
48
f083c6c3 49#include "bootstruct.h"
14c7c974 50#include "libsaio.h"
75b89a82 51#include "fdisk.h"
bba600dd 52#if UFS_SUPPORT
f083c6c3 53#include "ufs.h"
bba600dd 54#endif
f083c6c3 55#include "hfs.h"
57c72a9a
A
56#include "ntfs.h"
57#include "msdos.h"
14c7c974 58
f083c6c3
A
59#include <limits.h>
60#include <IOKit/storage/IOApplePartitionScheme.h>
14c7c974 61
75b89a82 62#define BPS 512 /* sector size of the device */
f083c6c3
A
63#define CD_BPS 2048 /* CD-ROM block size */
64#define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */
75b89a82 65#define UFS_FRONT_PORCH 0
f083c6c3
A
66#define kAPMSector 2 /* Sector number of Apple partition map */
67#define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
14c7c974
A
68
69/*
75b89a82
A
70 * trackbuf points to the start of the track cache. Biosread()
71 * will store the sectors read from disk to this memory area.
14c7c974 72 *
75b89a82
A
73 * biosbuf points to a sector within the track cache, and is
74 * updated by Biosread().
14c7c974 75 */
57c72a9a
A
76static char * const trackbuf = (char *) ptov(BIOS_ADDR);
77static char * biosbuf;
14c7c974 78
75b89a82
A
79/*
80 * Map a disk drive to bootable volumes contained within.
14c7c974 81 */
75b89a82
A
82struct DiskBVMap {
83 int biosdev; // BIOS device number (unique)
84 BVRef bvr; // chain of boot volumes on the disk
85 int bvrcnt; // number of boot volumes
86 struct DiskBVMap * next; // linkage to next mapping
87};
14c7c974 88
75b89a82
A
89static struct DiskBVMap * gDiskBVMap = NULL;
90static struct disk_blk0 * gBootSector = NULL;
14c7c974 91
75b89a82 92extern void spinActivityIndicator();
14c7c974 93
75b89a82 94static void getVolumeDescription(BVRef bvr, char * str, long strMaxLen);
14c7c974 95
75b89a82 96//==========================================================================
14c7c974 97
f083c6c3 98static int getDriveInfo( int biosdev, struct driveInfo *dip )
14c7c974 99{
f083c6c3
A
100 static struct driveInfo cached_di;
101 int cc;
75b89a82 102
f083c6c3 103 if ( !cached_di.valid || biosdev != cached_di.biosdev )
75b89a82 104 {
f083c6c3
A
105 cc = get_drive_info(biosdev, &cached_di);
106 if (cc < 0) {
107 cached_di.valid = 0;
bba600dd 108 DEBUG_DISK(("get_drive_info returned error\n"));
f083c6c3
A
109 return (-1); // BIOS call error
110 }
75b89a82 111 }
14c7c974 112
f083c6c3 113 bcopy(&cached_di, dip, sizeof(cached_di));
14c7c974 114
75b89a82
A
115 return 0;
116}
14c7c974 117
75b89a82
A
118//==========================================================================
119// Maps (E)BIOS return codes to message strings.
14c7c974 120
75b89a82
A
121struct NamedValue {
122 unsigned char value;
123 const char * name;
124};
14c7c974 125
75b89a82
A
126static const char * getNameForValue( const struct NamedValue * nameTable,
127 unsigned char value )
128{
129 const struct NamedValue * np;
14c7c974 130
75b89a82
A
131 for ( np = nameTable; np->value; np++)
132 if (np->value == value)
133 return np->name;
14c7c974 134
75b89a82 135 return NULL;
14c7c974
A
136}
137
14c7c974
A
138#define ECC_CORRECTED_ERR 0x11
139
75b89a82
A
140static const struct NamedValue bios_errors[] = {
141 { 0x10, "Media error" },
142 { 0x11, "Corrected ECC error" },
143 { 0x20, "Controller or device error" },
144 { 0x40, "Seek failed" },
145 { 0x80, "Device timeout" },
146 { 0xAA, "Drive not ready" },
147 { 0x00, 0 }
14c7c974
A
148};
149
75b89a82 150static const char * bios_error(int errnum)
14c7c974 151{
75b89a82
A
152 static char errorstr[] = "Error 0x00";
153 const char * errname;
154
155 errname = getNameForValue( bios_errors, errnum );
156 if ( errname ) return errname;
157
158 sprintf(errorstr, "Error 0x%02x", errnum);
159 return errorstr; // No string, print error code only
14c7c974
A
160}
161
75b89a82
A
162//==========================================================================
163// Use BIOS INT13 calls to read the sector specified. This function will
164// also perform read-ahead to cache a few subsequent sector to the sector
165// cache.
166//
167// Return:
168// 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
169
57c72a9a
A
170static BOOL cache_valid = FALSE;
171
75b89a82 172static int Biosread( int biosdev, unsigned int secno )
14c7c974 173{
75b89a82
A
174 static int xbiosdev, xcyl, xhead;
175 static unsigned int xsec, xnsecs;
f083c6c3 176 struct driveInfo di;
14c7c974 177
75b89a82 178 int rc = -1;
14c7c974 179 int cyl, head, sec;
14c7c974 180 int tries = 0;
f083c6c3 181 int bps, divisor;
14c7c974 182
f083c6c3
A
183 if (getDriveInfo(biosdev, &di) < 0) {
184 return -1;
185 }
186 if (di.no_emulation) {
187 /* Always assume 2k block size; BIOS may lie about geometry */
188 bps = 2048;
189 } else {
190 bps = di.di.params.phys_nbps;
57c72a9a
A
191 if (bps == 0) {
192 return -1;
193 }
f083c6c3
A
194 }
195 divisor = bps / BPS;
196
197 DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));
14c7c974
A
198
199 // To read the disk sectors, use EBIOS if we can. Otherwise,
200 // revert to the standard BIOS calls.
75b89a82
A
201
202 if ((biosdev >= kBIOSDevTypeHardDrive) &&
f083c6c3 203 (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))
75b89a82 204 {
14c7c974
A
205 if (cache_valid &&
206 (biosdev == xbiosdev) &&
207 (secno >= xsec) &&
f083c6c3 208 ((unsigned int)secno < (xsec + xnsecs)))
14c7c974 209 {
75b89a82 210 biosbuf = trackbuf + (BPS * (secno - xsec));
14c7c974
A
211 return 0;
212 }
213
214 xnsecs = N_CACHE_SECS;
f083c6c3 215 xsec = (secno / divisor) * divisor;
75b89a82 216 cache_valid = FALSE;
14c7c974 217
f083c6c3 218 while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))
14c7c974
A
219 {
220 if (rc == ECC_CORRECTED_ERR) {
221 /* Ignore corrected ECC errors */
75b89a82 222 rc = 0;
14c7c974
A
223 break;
224 }
225 error(" EBIOS read error: %s\n", bios_error(rc), rc);
226 error(" Block %d Sectors %d\n", secno, xnsecs);
227 sleep(1);
228 }
229 }
f083c6c3 230 else
75b89a82 231 {
f083c6c3
A
232 /* spc = spt * heads */
233 int spc = (di.di.params.phys_spt * di.di.params.phys_heads);
14c7c974 234 cyl = secno / spc;
f083c6c3
A
235 head = (secno % spc) / di.di.params.phys_spt;
236 sec = secno % di.di.params.phys_spt;
14c7c974
A
237
238 if (cache_valid &&
239 (biosdev == xbiosdev) &&
240 (cyl == xcyl) &&
241 (head == xhead) &&
f083c6c3
A
242 ((unsigned int)sec >= xsec) &&
243 ((unsigned int)sec < (xsec + xnsecs)))
14c7c974 244 {
75b89a82
A
245 // this sector is in trackbuf cache
246 biosbuf = trackbuf + (BPS * (sec - xsec));
14c7c974
A
247 return 0;
248 }
249
250 // Cache up to a track worth of sectors, but do not cross a
251 // track boundary.
75b89a82 252
14c7c974
A
253 xcyl = cyl;
254 xhead = head;
255 xsec = sec;
f083c6c3 256 xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;
75b89a82 257 cache_valid = FALSE;
14c7c974
A
258
259 while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) &&
260 (++tries < 5))
261 {
262 if (rc == ECC_CORRECTED_ERR) {
263 /* Ignore corrected ECC errors */
75b89a82 264 rc = 0;
14c7c974
A
265 break;
266 }
267 error(" BIOS read error: %s\n", bios_error(rc), rc);
268 error(" Block %d, Cyl %d Head %d Sector %d\n",
269 secno, cyl, head, sec);
270 sleep(1);
271 }
272 }
273
274 // If the BIOS reported success, mark the sector cache as valid.
75b89a82 275
14c7c974
A
276 if (rc == 0) {
277 cache_valid = TRUE;
278 }
f083c6c3 279 biosbuf = trackbuf + (secno % divisor) * BPS;
14c7c974
A
280 xbiosdev = biosdev;
281
75b89a82 282 spinActivityIndicator();
14c7c974
A
283
284 return rc;
285}
286
75b89a82
A
287//==========================================================================
288
289static int readBytes( int biosdev, unsigned int blkno,
bba600dd 290 unsigned int byteoff,
75b89a82 291 unsigned int byteCount, void * buffer )
14c7c974 292{
75b89a82
A
293
294 char * cbuf = (char *) buffer;
295 int error;
296 int copy_len;
297
298 DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__,
299 biosdev, blkno, byteCount, (unsigned)cbuf));
300
bba600dd 301 for ( ; byteCount; cbuf += copy_len, blkno++ )
75b89a82
A
302 {
303 error = Biosread( biosdev, blkno );
304 if ( error )
305 {
306 DEBUG_DISK(("error\n"));
307 return (-1);
308 }
309
bba600dd
A
310 copy_len = ((byteCount + byteoff) > BPS) ? (BPS - byteoff) : byteCount;
311 bcopy( biosbuf + byteoff, cbuf, copy_len );
75b89a82 312 byteCount -= copy_len;
bba600dd 313 byteoff = 0;
75b89a82
A
314 }
315
316 DEBUG_DISK(("done\n"));
317
318 return 0;
14c7c974
A
319}
320
75b89a82
A
321//==========================================================================
322
323static int isExtendedFDiskPartition( const struct fdisk_part * part )
14c7c974 324{
75b89a82
A
325 static unsigned char extParts[] =
326 {
327 0x05, /* Extended */
328 0x0f, /* Win95 extended */
329 0x85, /* Linux extended */
330 };
331
f083c6c3 332 unsigned int i;
75b89a82
A
333
334 for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)
335 {
336 if (extParts[i] == part->systid) return 1;
337 }
338 return 0;
14c7c974
A
339}
340
75b89a82
A
341//==========================================================================
342
343static int getNextFDiskPartition( int biosdev, int * partno,
344 const struct fdisk_part ** outPart )
14c7c974 345{
75b89a82
A
346 static int sBiosdev = -1;
347 static int sNextPartNo;
57c72a9a 348 static unsigned int sFirstBase;
75b89a82
A
349 static unsigned int sExtBase;
350 static unsigned int sExtDepth;
351 static struct fdisk_part * sExtPart;
352 struct fdisk_part * part;
353
354 if ( sBiosdev != biosdev || *partno < 0 )
355 {
356 // Fetch MBR.
357 if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0;
358
359 sBiosdev = biosdev;
360 sNextPartNo = 0;
57c72a9a 361 sFirstBase = 0;
75b89a82
A
362 sExtBase = 0;
363 sExtDepth = 0;
364 sExtPart = NULL;
365 }
14c7c974 366
75b89a82
A
367 while (1)
368 {
369 part = NULL;
14c7c974 370
75b89a82
A
371 if ( sNextPartNo < FDISK_NPART )
372 {
373 part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];
374 }
375 else if ( sExtPart )
376 {
57c72a9a 377 unsigned int blkno = sExtPart->relsect + sFirstBase;
14c7c974 378
75b89a82
A
379 // Save the block offset of the first extended partition.
380
57c72a9a
A
381 if (sExtDepth == 0) {
382 sFirstBase = blkno;
383 }
384 sExtBase = blkno;
75b89a82
A
385
386 // Load extended partition table.
387
388 if ( readBootSector( biosdev, blkno, 0 ) == 0 )
389 {
390 sNextPartNo = 0;
391 sExtDepth++;
392 sExtPart = NULL;
393 continue;
394 }
57c72a9a 395 // Fall through to part == NULL
75b89a82
A
396 }
397
398 if ( part == NULL ) break; // Reached end of partition chain.
399
400 // Advance to next partition number.
401
402 sNextPartNo++;
403
75b89a82
A
404 if ( isExtendedFDiskPartition(part) )
405 {
406 sExtPart = part;
407 continue;
408 }
409
410 // Skip empty slots.
411
412 if ( part->systid == 0x00 )
413 {
414 continue;
415 }
416
417 // Change relative offset to an absolute offset.
75b89a82
A
418 part->relsect += sExtBase;
419
420 *outPart = part;
57c72a9a 421 *partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;
75b89a82
A
422
423 break;
14c7c974
A
424 }
425
75b89a82
A
426 return (part != NULL);
427}
428
429//==========================================================================
14c7c974 430
75b89a82
A
431static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,
432 const struct fdisk_part * part,
433 FSInit initFunc, FSLoadFile loadFunc,
57c72a9a
A
434 FSReadFile readFunc,
435 FSGetDirEntry getdirFunc,
436 FSGetFileBlock getBlockFunc,
bba600dd 437 FSGetUUID getUUIDFunc,
57c72a9a
A
438 BVGetDescription getDescriptionFunc,
439 int probe, int type )
75b89a82
A
440{
441 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
442 if ( bvr )
14c7c974 443 {
75b89a82 444 bzero(bvr, sizeof(*bvr));
14c7c974 445
75b89a82
A
446 bvr->biosdev = biosdev;
447 bvr->part_no = partno;
448 bvr->part_boff = blkoff;
449 bvr->part_type = part->systid;
450 bvr->fs_loadfile = loadFunc;
57c72a9a 451 bvr->fs_readfile = readFunc;
75b89a82 452 bvr->fs_getdirentry = getdirFunc;
57c72a9a 453 bvr->fs_getfileblock= getBlockFunc;
bba600dd 454 bvr->fs_getuuid = getUUIDFunc;
57c72a9a
A
455 bvr->description = getDescriptionFunc ?
456 getDescriptionFunc : getVolumeDescription;
f083c6c3 457 bvr->type = type;
75b89a82
A
458
459 if ( part->bootid & FDISK_ACTIVE )
460 bvr->flags |= kBVFlagPrimary;
461
462 // Probe the filesystem.
463
464 if ( initFunc )
465 {
466 bvr->flags |= kBVFlagNativeBoot;
14c7c974 467
75b89a82
A
468 if ( probe && initFunc( bvr ) != 0 )
469 {
470 // filesystem probe failed.
14c7c974 471
75b89a82
A
472 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
473 __FUNCTION__, biosdev, partno));
14c7c974 474
75b89a82
A
475 free(bvr);
476 bvr = NULL;
477 }
478 }
479 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
480 {
481 bvr->flags |= kBVFlagForeignBoot;
482 }
483 else
484 {
485 free(bvr);
486 bvr = NULL;
14c7c974
A
487 }
488 }
75b89a82
A
489 return bvr;
490}
14c7c974 491
75b89a82
A
492//==========================================================================
493
f083c6c3
A
494BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,
495 const DPME * part,
496 FSInit initFunc, FSLoadFile loadFunc,
57c72a9a
A
497 FSReadFile readFunc,
498 FSGetDirEntry getdirFunc,
499 FSGetFileBlock getBlockFunc,
bba600dd 500 FSGetUUID getUUIDFunc,
57c72a9a
A
501 BVGetDescription getDescriptionFunc,
502 int probe, int type )
f083c6c3
A
503{
504 BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
505 if ( bvr )
506 {
507 bzero(bvr, sizeof(*bvr));
508
509 bvr->biosdev = biosdev;
510 bvr->part_no = partno;
511 bvr->part_boff = blkoff;
512 bvr->fs_loadfile = loadFunc;
57c72a9a 513 bvr->fs_readfile = readFunc;
f083c6c3 514 bvr->fs_getdirentry = getdirFunc;
57c72a9a 515 bvr->fs_getfileblock= getBlockFunc;
bba600dd 516 bvr->fs_getuuid = getUUIDFunc;
57c72a9a
A
517 bvr->description = getDescriptionFunc ?
518 getDescriptionFunc : getVolumeDescription;
f083c6c3
A
519 bvr->type = type;
520 strlcpy(bvr->name, part->dpme_name, DPISTRLEN);
521 strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);
522
523 /*
524 if ( part->bootid & FDISK_ACTIVE )
525 bvr->flags |= kBVFlagPrimary;
526 */
527
528 // Probe the filesystem.
529
530 if ( initFunc )
531 {
532 bvr->flags |= kBVFlagNativeBoot;
533
534 if ( probe && initFunc( bvr ) != 0 )
535 {
536 // filesystem probe failed.
537
538 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
539 __FUNCTION__, biosdev, partno));
540
541 free(bvr);
542 bvr = NULL;
543 }
544 }
545 /*
546 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
547 {
548 bvr->flags |= kBVFlagForeignBoot;
549 }
550 */
551 else
552 {
553 free(bvr);
554 bvr = NULL;
555 }
556 }
557 return bvr;
558}
559
560//==========================================================================
561
57c72a9a
A
562/* A note on partition numbers:
563 * IOKit makes the primary partitions numbers 1-4, and then
564 * extended partitions are numbered consecutively 5 and up.
565 * So, for example, if you have two primary partitions and
566 * one extended partition they will be numbered 1, 2, 5.
567 */
568
f083c6c3 569static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
75b89a82
A
570{
571 const struct fdisk_part * part;
572 struct DiskBVMap * map;
573 int partno = -1;
574 BVRef bvr;
bba600dd 575#if UFS_SUPPORT
75b89a82 576 BVRef booterUFS = NULL;
bba600dd 577#endif
f083c6c3
A
578 int spc;
579 struct driveInfo di;
580 boot_drive_info_t *dp;
75b89a82 581
f083c6c3
A
582 /* Initialize disk info */
583 if (getDriveInfo(biosdev, &di) != 0) {
584 return NULL;
585 }
586 dp = &di.di;
587 spc = (dp->params.phys_spt * dp->params.phys_heads);
588 if (spc == 0) {
589 /* This is probably a CD-ROM; punt on the geometry. */
590 spc = 1;
591 }
14c7c974 592
f083c6c3 593 do {
75b89a82 594 // Create a new mapping.
14c7c974 595
75b89a82
A
596 map = (struct DiskBVMap *) malloc( sizeof(*map) );
597 if ( map )
598 {
599 map->biosdev = biosdev;
600 map->bvr = NULL;
601 map->bvrcnt = 0;
602 map->next = gDiskBVMap;
603 gDiskBVMap = map;
14c7c974 604
75b89a82
A
605 // Create a record for each partition found on the disk.
606
607 while ( getNextFDiskPartition( biosdev, &partno, &part ) )
14c7c974 608 {
75b89a82
A
609 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
610 partno, part->systid));
75b89a82
A
611 bvr = 0;
612
613 switch ( part->systid )
614 {
bba600dd 615#if UFS_SUPPORT
75b89a82 616 case FDISK_UFS:
f083c6c3 617 bvr = newFDiskBVRef(
75b89a82
A
618 biosdev, partno,
619 part->relsect + UFS_FRONT_PORCH/BPS,
620 part,
621 UFSInitPartition,
622 UFSLoadFile,
57c72a9a 623 UFSReadFile,
75b89a82 624 UFSGetDirEntry,
57c72a9a 625 UFSGetFileBlock,
bba600dd 626 UFSGetUUID,
57c72a9a 627 UFSGetDescription,
f083c6c3
A
628 0,
629 kBIOSDevTypeHardDrive);
75b89a82 630 break;
bba600dd 631#endif
75b89a82
A
632
633 case FDISK_HFS:
634 bvr = newFDiskBVRef(
635 biosdev, partno,
636 part->relsect,
637 part,
638 HFSInitPartition,
639 HFSLoadFile,
57c72a9a 640 HFSReadFile,
75b89a82 641 HFSGetDirEntry,
57c72a9a 642 HFSGetFileBlock,
bba600dd 643 HFSGetUUID,
57c72a9a 644 HFSGetDescription,
f083c6c3
A
645 0,
646 kBIOSDevTypeHardDrive);
75b89a82
A
647 break;
648
bba600dd 649#if UFS_SUPPORT
75b89a82 650 case FDISK_BOOTER:
75b89a82
A
651 booterUFS = newFDiskBVRef(
652 biosdev, partno,
653 ((part->relsect + spc - 1) / spc) * spc,
654 part,
655 UFSInitPartition,
656 UFSLoadFile,
57c72a9a 657 UFSReadFile,
75b89a82 658 UFSGetDirEntry,
57c72a9a 659 UFSGetFileBlock,
bba600dd 660 UFSGetUUID,
57c72a9a 661 UFSGetDescription,
f083c6c3
A
662 0,
663 kBIOSDevTypeHardDrive);
75b89a82 664 break;
bba600dd 665#endif
75b89a82 666
57c72a9a
A
667 case FDISK_NTFS:
668 bvr = newFDiskBVRef(
669 biosdev, partno,
670 part->relsect,
671 part,
bba600dd 672 0, 0, 0, 0, 0, 0,
57c72a9a
A
673 NTFSGetDescription,
674 0,
675 kBIOSDevTypeHardDrive);
676 break;
677
75b89a82
A
678 default:
679 bvr = newFDiskBVRef(
680 biosdev, partno,
681 part->relsect,
682 part,
bba600dd 683 0, 0, 0, 0, 0, 0, 0, 0,
f083c6c3 684 kBIOSDevTypeHardDrive);
75b89a82
A
685 break;
686 }
687
688 if ( bvr )
689 {
690 bvr->next = map->bvr;
691 map->bvr = bvr;
692 map->bvrcnt++;
693 }
14c7c974 694 }
14c7c974 695
bba600dd 696#if UFS_SUPPORT
75b89a82
A
697 // Booting from a CD with an UFS filesystem embedded
698 // in a booter partition.
699
700 if ( booterUFS )
701 {
702 if ( map->bvrcnt == 0 )
703 {
704 map->bvr = booterUFS;
705 map->bvrcnt++;
706 }
707 else free( booterUFS );
708 }
bba600dd 709#endif
75b89a82
A
710 }
711 } while (0);
712
f083c6c3
A
713 /*
714 * If no FDisk partition, then we will check for
715 * an Apple partition map elsewhere.
716 */
57c72a9a 717#if UNUSED
f083c6c3
A
718 if (map->bvrcnt == 0) {
719 static struct fdisk_part cdpart;
720 cdpart.systid = 0xCD;
721
722 /* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
723 bvr = newFDiskBVRef(
724 biosdev, 0,
725 0,
726 &cdpart,
727 HFSInitPartition,
728 HFSLoadFile,
57c72a9a 729 HFSReadFile,
f083c6c3 730 HFSGetDirEntry,
57c72a9a 731 HFSGetFileBlock,
bba600dd 732 HFSGetUUID,
f083c6c3
A
733 0,
734 kBIOSDevTypeHardDrive);
735 bvr->next = map->bvr;
736 map->bvr = bvr;
737 map->bvrcnt++;
738 }
739#endif
740
75b89a82
A
741 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
742
743 return map ? map->bvr : NULL;
744}
745
f083c6c3
A
746//==========================================================================
747
748static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
749{
750 struct DiskBVMap * map;
751 struct Block0 *block0_p;
752 unsigned int blksize;
753 unsigned int factor;
754 void *buffer = malloc(BPS);
755
756 /* Check for alternate block size */
bba600dd 757 if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
f083c6c3
A
758 return NULL;
759 }
760 block0_p = buffer;
57c72a9a
A
761 if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
762 blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
f083c6c3
A
763 if (blksize != BPS) {
764 free(buffer);
765 buffer = malloc(blksize);
766 }
767 factor = blksize / BPS;
768 } else {
769 blksize = BPS;
770 factor = 1;
771 }
772
773 do {
774 // Create a new mapping.
775
776 map = (struct DiskBVMap *) malloc( sizeof(*map) );
777 if ( map )
778 {
779 int error;
780 DPME *dpme_p = (DPME *)buffer;
781 UInt32 i, npart = UINT_MAX;
782 BVRef bvr;
783
784 map->biosdev = biosdev;
785 map->bvr = NULL;
786 map->bvrcnt = 0;
787 map->next = gDiskBVMap;
788 gDiskBVMap = map;
789
790 for (i=0; i<npart; i++) {
bba600dd 791 error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
f083c6c3 792
57c72a9a 793 if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
f083c6c3
A
794 break;
795 }
796
797 if (i==0) {
57c72a9a 798 npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
f083c6c3
A
799 }
800 /*
801 printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
802 dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
803 dpme.dpme_pblock_start, dpme.dpme_pblocks,
804 dpme.dpme_lblock_start, dpme.dpme_lblocks,
805 dpme.dpme_boot_block);
806 */
807
808 if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
809 bvr = newAPMBVRef(biosdev,
810 i,
57c72a9a 811 OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
f083c6c3
A
812 dpme_p,
813 HFSInitPartition,
814 HFSLoadFile,
57c72a9a 815 HFSReadFile,
f083c6c3 816 HFSGetDirEntry,
57c72a9a 817 HFSGetFileBlock,
bba600dd 818 HFSGetUUID,
57c72a9a 819 HFSGetDescription,
f083c6c3
A
820 0,
821 kBIOSDevTypeHardDrive);
822 bvr->next = map->bvr;
823 map->bvr = bvr;
824 map->bvrcnt++;
825 }
826 }
827 }
828 } while (0);
829
830 free(buffer);
831
832 if (countPtr) *countPtr = map ? map->bvrcnt : 0;
833
834 return map ? map->bvr : NULL;
835}
836
837//==========================================================================
838
839BVRef diskScanBootVolumes( int biosdev, int * countPtr )
840{
841 struct DiskBVMap * map;
842 BVRef bvr;
843 int count = 0;
844
845 // Find an existing mapping for this device.
846
847 for ( map = gDiskBVMap; map; map = map->next ) {
848 if ( biosdev == map->biosdev ) {
849 count = map->bvrcnt;
850 break;
851 }
852 }
853
854 if (map == NULL) {
855 bvr = diskScanFDiskBootVolumes(biosdev, &count);
856 if (bvr == NULL) {
857 bvr = diskScanAPMBootVolumes(biosdev, &count);
858 }
859 } else {
860 bvr = map->bvr;
861 }
862 if (countPtr) *countPtr = count;
863 return bvr;
864}
865
866
75b89a82
A
867//==========================================================================
868
869static const struct NamedValue fdiskTypes[] =
870{
57c72a9a
A
871 { FDISK_NTFS, "Windows NTFS" },
872 { FDISK_FAT32, "Windows FAT32" },
75b89a82
A
873 { 0x83, "Linux" },
874 { FDISK_UFS, "Apple UFS" },
875 { FDISK_HFS, "Apple HFS" },
876 { FDISK_BOOTER, "Apple Boot/UFS" },
f083c6c3 877 { 0xCD, "CD-ROM" },
75b89a82
A
878 { 0x00, 0 } /* must be last */
879};
880
57c72a9a
A
881//==========================================================================
882
883void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, BOOL verbose )
75b89a82
A
884{
885 unsigned char type = (unsigned char) bvr->part_type;
886 const char * name = getNameForValue( fdiskTypes, type );
57c72a9a
A
887 char *p;
888
889 if (name == NULL)
890 name = bvr->type_name;
891
892 p = str;
893 if ( name && verbose ) {
894 sprintf( str, "hd(%d,%d) ",
895 BIOS_DEV_UNIT(bvr), bvr->part_no);
896 for (; strMaxLen > 0 && *p != '\0'; p++, strMaxLen--);
897 } else {
898 *p = '\0';
899 }
900 bvr->description(bvr, p, strMaxLen);
901 if (*p == '\0') {
902 const char * name = getNameForValue( fdiskTypes, type );
903 if (name == NULL) {
904 name = bvr->type_name;
905 }
906 if (name == NULL) {
907 sprintf(p, "TYPE %02x", type);
908 } else {
909 strncpy(p, name, strMaxLen);
910 }
911 }
912}
913
914#if UNUSED
915//==========================================================================
916
917static int
918getFAT32VolumeDescription( BVRef bvr, char *str, long strMaxLen)
919{
920 struct fat32_header {
921 unsigned char code[3];
922 unsigned char oem_id[8];
923 unsigned char data[56];
924 unsigned long serial;
925 unsigned char label[11];
926 unsigned char fsid[8];
927 unsigned char reserved[420];
928 unsigned short signature;
929 } __attribute__((packed));
930
931 char *buf, *name;
932 struct fat32_header *fat32_p;
933 int label_len = sizeof(fat32_p->label);
934 int error;
935
936 buf = (char *)malloc(BPS);
937 name = (char *)malloc(label_len + 1);
938 fat32_p = (struct fat32_header *)buf;
939
940 diskSeek(bvr, 0ULL);
941 error = diskRead(bvr, (long)buf, BPS);
942 if ( error ) return 0;
943
944 if (fat32_p->signature != 0xaa55) return 0;
945
946 if (strMaxLen < label_len) label_len = strMaxLen;
947 strncpy(str, fat32_p->label, label_len);
948 str[label_len] = '\0';
949 return 1;
950}
951#endif
952
953//==========================================================================
954
955static void getVolumeDescription( BVRef bvr, char * str, long strMaxLen )
956{
957 unsigned char type = (unsigned char) bvr->part_type;
958 const char * name = NULL;
959
960 /* First try a few types that we can figure out the
961 * volume description.
962 */
963 switch(type) {
964 case FDISK_FAT32:
965 str[0] = '\0';
966 MSDOSGetDescription(bvr, str, strMaxLen);
967 if (str[0] != '\0')
968 return;
969 break;
970
971 default: // Not one of our known types
972 break;
973 }
974
975 if (name == NULL)
976 name = getNameForValue( fdiskTypes, type );
75b89a82 977
f083c6c3
A
978 if (name == NULL)
979 name = bvr->type_name;
980
75b89a82 981 if ( name )
57c72a9a 982 strncpy( str, name, strMaxLen);
75b89a82 983 else
57c72a9a 984 sprintf( str, "TYPE %02x", type);
75b89a82
A
985}
986
f083c6c3 987
75b89a82
A
988//==========================================================================
989
990int readBootSector( int biosdev, unsigned int secno, void * buffer )
991{
992 struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
993 int error;
994
995 if ( bootSector == NULL )
996 {
997 if ( gBootSector == NULL )
998 {
999 gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
1000 if ( gBootSector == NULL ) return -1;
14c7c974 1001 }
75b89a82 1002 bootSector = gBootSector;
14c7c974 1003 }
75b89a82 1004
bba600dd 1005 error = readBytes( biosdev, secno, 0, BPS, bootSector );
75b89a82
A
1006 if ( error || bootSector->signature != DISK_SIGNATURE )
1007 return -1;
1008
1009 return 0;
1010}
1011
1012//==========================================================================
1013// Handle seek request from filesystem modules.
1014
1015void diskSeek( BVRef bvr, long long position )
1016{
1017 bvr->fs_boff = position / BPS;
bba600dd 1018 bvr->fs_byteoff = position % BPS;
75b89a82
A
1019}
1020
1021//==========================================================================
1022// Handle read request from filesystem modules.
1023
1024int diskRead( BVRef bvr, long addr, long length )
1025{
1026 return readBytes( bvr->biosdev,
1027 bvr->fs_boff + bvr->part_boff,
bba600dd 1028 bvr->fs_byteoff,
75b89a82
A
1029 length,
1030 (void *) addr );
14c7c974 1031}
f083c6c3 1032
57c72a9a
A
1033int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1034{
1035 int secs;
1036 unsigned char *cbuf = (unsigned char *)buffer;
1037 unsigned int copy_len;
1038 int rc;
1039
1040 if ((len & (BPS-1)) != 0) {
1041 error("raw disk read not sector aligned");
1042 return -1;
1043 }
1044 secno += bvr->part_boff;
1045
1046 cache_valid = FALSE;
1047
1048 while (len > 0) {
1049 secs = len / BPS;
1050 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1051 copy_len = secs * BPS;
1052
1053 //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1054 if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
1055 /* Ignore corrected ECC errors */
1056 if (rc != ECC_CORRECTED_ERR) {
1057 error(" EBIOS read error: %s\n", bios_error(rc), rc);
1058 error(" Block %d Sectors %d\n", secno, secs);
1059 return rc;
1060 }
1061 }
1062 bcopy( trackbuf, cbuf, copy_len );
1063 len -= copy_len;
1064 cbuf += copy_len;
1065 secno += secs;
1066 spinActivityIndicator();
1067 }
1068
1069 return 0;
1070}
1071
1072int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
1073{
1074 int secs;
1075 unsigned char *cbuf = (unsigned char *)buffer;
1076 unsigned int copy_len;
1077 int rc;
1078
1079 if ((len & (BPS-1)) != 0) {
1080 error("raw disk write not sector aligned");
1081 return -1;
1082 }
1083 secno += bvr->part_boff;
1084
1085 cache_valid = FALSE;
1086
1087 while (len > 0) {
1088 secs = len / BPS;
1089 if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
1090 copy_len = secs * BPS;
1091
1092 bcopy( cbuf, trackbuf, copy_len );
1093 //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
1094 if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
1095 error(" EBIOS write error: %s\n", bios_error(rc), rc);
1096 error(" Block %d Sectors %d\n", secno, secs);
1097 return rc;
1098 }
1099 len -= copy_len;
1100 cbuf += copy_len;
1101 secno += secs;
1102 spinActivityIndicator();
1103 }
1104
1105 return 0;
1106}
1107
bba600dd
A
1108
1109int diskIsCDROM(BVRef bvr)
f083c6c3 1110{
bba600dd
A
1111 struct driveInfo di;
1112
1113 if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
1114 return 1;
1115 }
1116 return 0;
f083c6c3 1117}