2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
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.
33 * INTEL CORPORATION PROPRIETARY INFORMATION
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.
39 * Copyright 1988, 1989 Intel Corporation
43 * Copyright 1993 NeXT Computer, Inc.
44 * All rights reserved.
49 #include "bootstruct.h"
60 #include <IOKit/storage/IOApplePartitionScheme.h>
62 #define BPS 512 /* sector size of the device */
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 */
65 #define UFS_FRONT_PORCH 0
66 #define kAPMSector 2 /* Sector number of Apple partition map */
67 #define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
70 * trackbuf points to the start of the track cache. Biosread()
71 * will store the sectors read from disk to this memory area.
73 * biosbuf points to a sector within the track cache, and is
74 * updated by Biosread().
76 static char * const trackbuf
= (char *) ptov(BIOS_ADDR
);
77 static char * biosbuf
;
80 * Map a disk drive to bootable volumes contained within.
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
89 static struct DiskBVMap
* gDiskBVMap
= NULL
;
90 static struct disk_blk0
* gBootSector
= NULL
;
92 extern void spinActivityIndicator();
94 static void getVolumeDescription(BVRef bvr
, char * str
, long strMaxLen
);
96 //==========================================================================
98 static int getDriveInfo( int biosdev
, struct driveInfo
*dip
)
100 static struct driveInfo cached_di
;
103 if ( !cached_di
.valid
|| biosdev
!= cached_di
.biosdev
)
105 cc
= get_drive_info(biosdev
, &cached_di
);
108 DEBUG_DISK(("get_drive_info returned error\n"));
109 return (-1); // BIOS call error
113 bcopy(&cached_di
, dip
, sizeof(cached_di
));
118 //==========================================================================
119 // Maps (E)BIOS return codes to message strings.
126 static const char * getNameForValue( const struct NamedValue
* nameTable
,
127 unsigned char value
)
129 const struct NamedValue
* np
;
131 for ( np
= nameTable
; np
->value
; np
++)
132 if (np
->value
== value
)
138 #define ECC_CORRECTED_ERR 0x11
140 static 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" },
150 static const char * bios_error(int errnum
)
152 static char errorstr
[] = "Error 0x00";
153 const char * errname
;
155 errname
= getNameForValue( bios_errors
, errnum
);
156 if ( errname
) return errname
;
158 sprintf(errorstr
, "Error 0x%02x", errnum
);
159 return errorstr
; // No string, print error code only
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
168 // 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
170 static BOOL cache_valid
= FALSE
;
172 static int Biosread( int biosdev
, unsigned int secno
)
174 static int xbiosdev
, xcyl
, xhead
;
175 static unsigned int xsec
, xnsecs
;
183 if (getDriveInfo(biosdev
, &di
) < 0) {
186 if (di
.no_emulation
) {
187 /* Always assume 2k block size; BIOS may lie about geometry */
190 bps
= di
.di
.params
.phys_nbps
;
197 DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev
, secno
, bps
));
199 // To read the disk sectors, use EBIOS if we can. Otherwise,
200 // revert to the standard BIOS calls.
202 if ((biosdev
>= kBIOSDevTypeHardDrive
) &&
203 (di
.uses_ebios
& EBIOS_FIXED_DISK_ACCESS
))
206 (biosdev
== xbiosdev
) &&
208 ((unsigned int)secno
< (xsec
+ xnsecs
)))
210 biosbuf
= trackbuf
+ (BPS
* (secno
- xsec
));
214 xnsecs
= N_CACHE_SECS
;
215 xsec
= (secno
/ divisor
) * divisor
;
218 while ((rc
= ebiosread(biosdev
, secno
/ divisor
, xnsecs
/ divisor
)) && (++tries
< 5))
220 if (rc
== ECC_CORRECTED_ERR
) {
221 /* Ignore corrected ECC errors */
225 error(" EBIOS read error: %s\n", bios_error(rc
), rc
);
226 error(" Block %d Sectors %d\n", secno
, xnsecs
);
232 /* spc = spt * heads */
233 int spc
= (di
.di
.params
.phys_spt
* di
.di
.params
.phys_heads
);
235 head
= (secno
% spc
) / di
.di
.params
.phys_spt
;
236 sec
= secno
% di
.di
.params
.phys_spt
;
239 (biosdev
== xbiosdev
) &&
242 ((unsigned int)sec
>= xsec
) &&
243 ((unsigned int)sec
< (xsec
+ xnsecs
)))
245 // this sector is in trackbuf cache
246 biosbuf
= trackbuf
+ (BPS
* (sec
- xsec
));
250 // Cache up to a track worth of sectors, but do not cross a
256 xnsecs
= ((unsigned int)(sec
+ N_CACHE_SECS
) > di
.di
.params
.phys_spt
) ? (di
.di
.params
.phys_spt
- sec
) : N_CACHE_SECS
;
259 while ((rc
= biosread(biosdev
, cyl
, head
, sec
, xnsecs
)) &&
262 if (rc
== ECC_CORRECTED_ERR
) {
263 /* Ignore corrected ECC errors */
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
);
274 // If the BIOS reported success, mark the sector cache as valid.
279 biosbuf
= trackbuf
+ (secno
% divisor
) * BPS
;
282 spinActivityIndicator();
287 //==========================================================================
289 static int readBytes( int biosdev
, unsigned int blkno
,
290 unsigned int byteoff
,
291 unsigned int byteCount
, void * buffer
)
294 char * cbuf
= (char *) buffer
;
298 DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__
,
299 biosdev
, blkno
, byteCount
, (unsigned)cbuf
));
301 for ( ; byteCount
; cbuf
+= copy_len
, blkno
++ )
303 error
= Biosread( biosdev
, blkno
);
306 DEBUG_DISK(("error\n"));
310 copy_len
= ((byteCount
+ byteoff
) > BPS
) ? (BPS
- byteoff
) : byteCount
;
311 bcopy( biosbuf
+ byteoff
, cbuf
, copy_len
);
312 byteCount
-= copy_len
;
316 DEBUG_DISK(("done\n"));
321 //==========================================================================
323 static int isExtendedFDiskPartition( const struct fdisk_part
* part
)
325 static unsigned char extParts
[] =
328 0x0f, /* Win95 extended */
329 0x85, /* Linux extended */
334 for (i
= 0; i
< sizeof(extParts
)/sizeof(extParts
[0]); i
++)
336 if (extParts
[i
] == part
->systid
) return 1;
341 //==========================================================================
343 static int getNextFDiskPartition( int biosdev
, int * partno
,
344 const struct fdisk_part
** outPart
)
346 static int sBiosdev
= -1;
347 static int sNextPartNo
;
348 static unsigned int sFirstBase
;
349 static unsigned int sExtBase
;
350 static unsigned int sExtDepth
;
351 static struct fdisk_part
* sExtPart
;
352 struct fdisk_part
* part
;
354 if ( sBiosdev
!= biosdev
|| *partno
< 0 )
357 if ( readBootSector( biosdev
, DISK_BLK0
, 0 ) ) return 0;
371 if ( sNextPartNo
< FDISK_NPART
)
373 part
= (struct fdisk_part
*) gBootSector
->parts
[sNextPartNo
];
377 unsigned int blkno
= sExtPart
->relsect
+ sFirstBase
;
379 // Save the block offset of the first extended partition.
381 if (sExtDepth
== 0) {
386 // Load extended partition table.
388 if ( readBootSector( biosdev
, blkno
, 0 ) == 0 )
395 // Fall through to part == NULL
398 if ( part
== NULL
) break; // Reached end of partition chain.
400 // Advance to next partition number.
404 if ( isExtendedFDiskPartition(part
) )
412 if ( part
->systid
== 0x00 )
417 // Change relative offset to an absolute offset.
418 part
->relsect
+= sExtBase
;
421 *partno
= sExtDepth
? (int)(sExtDepth
+ FDISK_NPART
) : sNextPartNo
;
426 return (part
!= NULL
);
429 //==========================================================================
431 static BVRef
newFDiskBVRef( int biosdev
, int partno
, unsigned int blkoff
,
432 const struct fdisk_part
* part
,
433 FSInit initFunc
, FSLoadFile loadFunc
,
435 FSGetDirEntry getdirFunc
,
436 FSGetFileBlock getBlockFunc
,
437 FSGetUUID getUUIDFunc
,
438 BVGetDescription getDescriptionFunc
,
439 int probe
, int type
)
441 BVRef bvr
= (BVRef
) malloc( sizeof(*bvr
) );
444 bzero(bvr
, sizeof(*bvr
));
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
;
451 bvr
->fs_readfile
= readFunc
;
452 bvr
->fs_getdirentry
= getdirFunc
;
453 bvr
->fs_getfileblock
= getBlockFunc
;
454 bvr
->fs_getuuid
= getUUIDFunc
;
455 bvr
->description
= getDescriptionFunc
?
456 getDescriptionFunc
: getVolumeDescription
;
459 if ( part
->bootid
& FDISK_ACTIVE
)
460 bvr
->flags
|= kBVFlagPrimary
;
462 // Probe the filesystem.
466 bvr
->flags
|= kBVFlagNativeBoot
;
468 if ( probe
&& initFunc( bvr
) != 0 )
470 // filesystem probe failed.
472 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
473 __FUNCTION__
, biosdev
, partno
));
479 else if ( readBootSector( biosdev
, blkoff
, (void *)0x7e00 ) == 0 )
481 bvr
->flags
|= kBVFlagForeignBoot
;
492 //==========================================================================
494 BVRef
newAPMBVRef( int biosdev
, int partno
, unsigned int blkoff
,
496 FSInit initFunc
, FSLoadFile loadFunc
,
498 FSGetDirEntry getdirFunc
,
499 FSGetFileBlock getBlockFunc
,
500 FSGetUUID getUUIDFunc
,
501 BVGetDescription getDescriptionFunc
,
502 int probe
, int type
)
504 BVRef bvr
= (BVRef
) malloc( sizeof(*bvr
) );
507 bzero(bvr
, sizeof(*bvr
));
509 bvr
->biosdev
= biosdev
;
510 bvr
->part_no
= partno
;
511 bvr
->part_boff
= blkoff
;
512 bvr
->fs_loadfile
= loadFunc
;
513 bvr
->fs_readfile
= readFunc
;
514 bvr
->fs_getdirentry
= getdirFunc
;
515 bvr
->fs_getfileblock
= getBlockFunc
;
516 bvr
->fs_getuuid
= getUUIDFunc
;
517 bvr
->description
= getDescriptionFunc
?
518 getDescriptionFunc
: getVolumeDescription
;
520 strlcpy(bvr
->name
, part
->dpme_name
, DPISTRLEN
);
521 strlcpy(bvr
->type_name
, part
->dpme_type
, DPISTRLEN
);
524 if ( part->bootid & FDISK_ACTIVE )
525 bvr->flags |= kBVFlagPrimary;
528 // Probe the filesystem.
532 bvr
->flags
|= kBVFlagNativeBoot
;
534 if ( probe
&& initFunc( bvr
) != 0 )
536 // filesystem probe failed.
538 DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
539 __FUNCTION__
, biosdev
, partno
));
546 else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
548 bvr->flags |= kBVFlagForeignBoot;
560 //==========================================================================
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.
569 static BVRef
diskScanFDiskBootVolumes( int biosdev
, int * countPtr
)
571 const struct fdisk_part
* part
;
572 struct DiskBVMap
* map
;
576 BVRef booterUFS
= NULL
;
580 boot_drive_info_t
*dp
;
582 /* Initialize disk info */
583 if (getDriveInfo(biosdev
, &di
) != 0) {
587 spc
= (dp
->params
.phys_spt
* dp
->params
.phys_heads
);
589 /* This is probably a CD-ROM; punt on the geometry. */
594 // Create a new mapping.
596 map
= (struct DiskBVMap
*) malloc( sizeof(*map
) );
599 map
->biosdev
= biosdev
;
602 map
->next
= gDiskBVMap
;
605 // Create a record for each partition found on the disk.
607 while ( getNextFDiskPartition( biosdev
, &partno
, &part
) )
609 DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__
,
610 partno
, part
->systid
));
613 switch ( part
->systid
)
619 part
->relsect
+ UFS_FRONT_PORCH
/BPS
,
629 kBIOSDevTypeHardDrive
);
646 kBIOSDevTypeHardDrive
);
651 booterUFS
= newFDiskBVRef(
653 ((part
->relsect
+ spc
- 1) / spc
) * spc
,
663 kBIOSDevTypeHardDrive
);
675 kBIOSDevTypeHardDrive
);
683 0, 0, 0, 0, 0, 0, 0, 0,
684 kBIOSDevTypeHardDrive
);
690 bvr
->next
= map
->bvr
;
697 // Booting from a CD with an UFS filesystem embedded
698 // in a booter partition.
702 if ( map
->bvrcnt
== 0 )
704 map
->bvr
= booterUFS
;
707 else free( booterUFS
);
714 * If no FDisk partition, then we will check for
715 * an Apple partition map elsewhere.
718 if (map
->bvrcnt
== 0) {
719 static struct fdisk_part cdpart
;
720 cdpart
.systid
= 0xCD;
722 /* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
734 kBIOSDevTypeHardDrive
);
735 bvr
->next
= map
->bvr
;
741 if (countPtr
) *countPtr
= map
? map
->bvrcnt
: 0;
743 return map
? map
->bvr
: NULL
;
746 //==========================================================================
748 static BVRef
diskScanAPMBootVolumes( int biosdev
, int * countPtr
)
750 struct DiskBVMap
* map
;
751 struct Block0
*block0_p
;
752 unsigned int blksize
;
754 void *buffer
= malloc(BPS
);
756 /* Check for alternate block size */
757 if (readBytes( biosdev
, 0, 0, BPS
, buffer
) != 0) {
761 if (OSSwapBigToHostInt16(block0_p
->sbSig
) == BLOCK0_SIGNATURE
) {
762 blksize
= OSSwapBigToHostInt16(block0_p
->sbBlkSize
);
763 if (blksize
!= BPS
) {
765 buffer
= malloc(blksize
);
767 factor
= blksize
/ BPS
;
774 // Create a new mapping.
776 map
= (struct DiskBVMap
*) malloc( sizeof(*map
) );
780 DPME
*dpme_p
= (DPME
*)buffer
;
781 UInt32 i
, npart
= UINT_MAX
;
784 map
->biosdev
= biosdev
;
787 map
->next
= gDiskBVMap
;
790 for (i
=0; i
<npart
; i
++) {
791 error
= readBytes( biosdev
, (kAPMSector
+ i
) * factor
, 0, blksize
, buffer
);
793 if (error
|| OSSwapBigToHostInt16(dpme_p
->dpme_signature
) != DPME_SIGNATURE
) {
798 npart
= OSSwapBigToHostInt32(dpme_p
->dpme_map_entries
);
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);
808 if (strcmp(dpme_p
->dpme_type
, "Apple_HFS") == 0) {
809 bvr
= newAPMBVRef(biosdev
,
811 OSSwapBigToHostInt32(dpme_p
->dpme_pblock_start
) * factor
,
821 kBIOSDevTypeHardDrive
);
822 bvr
->next
= map
->bvr
;
832 if (countPtr
) *countPtr
= map
? map
->bvrcnt
: 0;
834 return map
? map
->bvr
: NULL
;
837 //==========================================================================
839 BVRef
diskScanBootVolumes( int biosdev
, int * countPtr
)
841 struct DiskBVMap
* map
;
845 // Find an existing mapping for this device.
847 for ( map
= gDiskBVMap
; map
; map
= map
->next
) {
848 if ( biosdev
== map
->biosdev
) {
855 bvr
= diskScanFDiskBootVolumes(biosdev
, &count
);
857 bvr
= diskScanAPMBootVolumes(biosdev
, &count
);
862 if (countPtr
) *countPtr
= count
;
867 //==========================================================================
869 static const struct NamedValue fdiskTypes
[] =
871 { FDISK_NTFS
, "Windows NTFS" },
872 { FDISK_FAT32
, "Windows FAT32" },
874 { FDISK_UFS
, "Apple UFS" },
875 { FDISK_HFS
, "Apple HFS" },
876 { FDISK_BOOTER
, "Apple Boot/UFS" },
878 { 0x00, 0 } /* must be last */
881 //==========================================================================
883 void getBootVolumeDescription( BVRef bvr
, char * str
, long strMaxLen
, BOOL verbose
)
885 unsigned char type
= (unsigned char) bvr
->part_type
;
886 const char * name
= getNameForValue( fdiskTypes
, type
);
890 name
= bvr
->type_name
;
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
--);
900 bvr
->description(bvr
, p
, strMaxLen
);
902 const char * name
= getNameForValue( fdiskTypes
, type
);
904 name
= bvr
->type_name
;
907 sprintf(p
, "TYPE %02x", type
);
909 strncpy(p
, name
, strMaxLen
);
915 //==========================================================================
918 getFAT32VolumeDescription( BVRef bvr
, char *str
, long strMaxLen
)
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
));
932 struct fat32_header
*fat32_p
;
933 int label_len
= sizeof(fat32_p
->label
);
936 buf
= (char *)malloc(BPS
);
937 name
= (char *)malloc(label_len
+ 1);
938 fat32_p
= (struct fat32_header
*)buf
;
941 error
= diskRead(bvr
, (long)buf
, BPS
);
942 if ( error
) return 0;
944 if (fat32_p
->signature
!= 0xaa55) return 0;
946 if (strMaxLen
< label_len
) label_len
= strMaxLen
;
947 strncpy(str
, fat32_p
->label
, label_len
);
948 str
[label_len
] = '\0';
953 //==========================================================================
955 static void getVolumeDescription( BVRef bvr
, char * str
, long strMaxLen
)
957 unsigned char type
= (unsigned char) bvr
->part_type
;
958 const char * name
= NULL
;
960 /* First try a few types that we can figure out the
961 * volume description.
966 MSDOSGetDescription(bvr
, str
, strMaxLen
);
971 default: // Not one of our known types
976 name
= getNameForValue( fdiskTypes
, type
);
979 name
= bvr
->type_name
;
982 strncpy( str
, name
, strMaxLen
);
984 sprintf( str
, "TYPE %02x", type
);
988 //==========================================================================
990 int readBootSector( int biosdev
, unsigned int secno
, void * buffer
)
992 struct disk_blk0
* bootSector
= (struct disk_blk0
*) buffer
;
995 if ( bootSector
== NULL
)
997 if ( gBootSector
== NULL
)
999 gBootSector
= (struct disk_blk0
*) malloc(sizeof(*gBootSector
));
1000 if ( gBootSector
== NULL
) return -1;
1002 bootSector
= gBootSector
;
1005 error
= readBytes( biosdev
, secno
, 0, BPS
, bootSector
);
1006 if ( error
|| bootSector
->signature
!= DISK_SIGNATURE
)
1012 //==========================================================================
1013 // Handle seek request from filesystem modules.
1015 void diskSeek( BVRef bvr
, long long position
)
1017 bvr
->fs_boff
= position
/ BPS
;
1018 bvr
->fs_byteoff
= position
% BPS
;
1021 //==========================================================================
1022 // Handle read request from filesystem modules.
1024 int diskRead( BVRef bvr
, long addr
, long length
)
1026 return readBytes( bvr
->biosdev
,
1027 bvr
->fs_boff
+ bvr
->part_boff
,
1033 int rawDiskRead( BVRef bvr
, unsigned int secno
, void *buffer
, unsigned int len
)
1036 unsigned char *cbuf
= (unsigned char *)buffer
;
1037 unsigned int copy_len
;
1040 if ((len
& (BPS
-1)) != 0) {
1041 error("raw disk read not sector aligned");
1044 secno
+= bvr
->part_boff
;
1046 cache_valid
= FALSE
;
1050 if (secs
> N_CACHE_SECS
) secs
= N_CACHE_SECS
;
1051 copy_len
= secs
* BPS
;
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
);
1062 bcopy( trackbuf
, cbuf
, copy_len
);
1066 spinActivityIndicator();
1072 int rawDiskWrite( BVRef bvr
, unsigned int secno
, void *buffer
, unsigned int len
)
1075 unsigned char *cbuf
= (unsigned char *)buffer
;
1076 unsigned int copy_len
;
1079 if ((len
& (BPS
-1)) != 0) {
1080 error("raw disk write not sector aligned");
1083 secno
+= bvr
->part_boff
;
1085 cache_valid
= FALSE
;
1089 if (secs
> N_CACHE_SECS
) secs
= N_CACHE_SECS
;
1090 copy_len
= secs
* BPS
;
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
);
1102 spinActivityIndicator();
1109 int diskIsCDROM(BVRef bvr
)
1111 struct driveInfo di
;
1113 if (getDriveInfo(bvr
->biosdev
, &di
) == 0 && di
.no_emulation
) {