317 lines
7.9 KiB
C
317 lines
7.9 KiB
C
#include "arccodes.h"
|
|
#include "bootx86.h"
|
|
#include "flop.h"
|
|
|
|
#ifdef FLOPPY_CACHE
|
|
|
|
//#define FLOPPY_CACHE_DEBUG
|
|
#ifdef FLOPPY_CACHE_DEBUG
|
|
#define DBGOUT(x) BlPrint x
|
|
#else
|
|
#define DBGOUT(x)
|
|
#endif
|
|
|
|
|
|
#define MAX_FLOPPY_LEN 1474560
|
|
|
|
UCHAR CachedDiskImage[MAX_FLOPPY_LEN];
|
|
UCHAR CachedDiskBadSectorMap[(MAX_FLOPPY_LEN/512)];
|
|
UCHAR CachedDiskCylinderMap[80];
|
|
USHORT CachedDiskBytesPerSector;
|
|
USHORT CachedDiskSectorsPerTrack;
|
|
USHORT CachedDiskSectorsPerCylinder;
|
|
USHORT CachedDiskBytesPerTrack;
|
|
ULONG CachedDiskLastSector;
|
|
|
|
BOOLEAN DiskInCache = FALSE;
|
|
|
|
|
|
VOID
|
|
FcpCacheOneCylinder(
|
|
IN USHORT Cylinder
|
|
)
|
|
{
|
|
PUCHAR pCache;
|
|
unsigned track,sector;
|
|
ULONG AbsoluteSector;
|
|
ARC_STATUS Status;
|
|
unsigned retry;
|
|
|
|
//
|
|
// Calculate the location in the cache image where this cylinder should go.
|
|
//
|
|
AbsoluteSector = Cylinder * CachedDiskSectorsPerCylinder;
|
|
pCache = CachedDiskImage + (AbsoluteSector * CachedDiskBytesPerSector);
|
|
|
|
//
|
|
// Read track 0 and 1 of this cylinder.
|
|
//
|
|
for(track=0; track<2; track++) {
|
|
|
|
DBGOUT(("FcCacheFloppyDisk: Cylinder %u head %u: ",Cylinder,track));
|
|
|
|
retry = 0;
|
|
|
|
do {
|
|
|
|
Status = GET_SECTOR(
|
|
2, // int13 request = read
|
|
0, // disk number (a:)
|
|
(USHORT)track, // head (0 or 1)
|
|
Cylinder, // track (usually 0-79)
|
|
1, // sector number (1-based)
|
|
CachedDiskSectorsPerTrack, // number of sectors to read
|
|
LocalBuffer // buffer
|
|
);
|
|
|
|
if(Status) {
|
|
retry++;
|
|
RESET_DISK(0,0,0,0,0,0,0);
|
|
}
|
|
|
|
} while(Status && (retry <= 3));
|
|
|
|
if(Status) {
|
|
|
|
DBGOUT(("Error!\n"));
|
|
|
|
//
|
|
// One or more sectors in the track were bad -- read individually.
|
|
//
|
|
for(sector=1; sector<=CachedDiskSectorsPerTrack; sector++) {
|
|
|
|
DBGOUT((" Sector %u: ",sector));
|
|
|
|
retry = 0;
|
|
|
|
do {
|
|
|
|
Status = GET_SECTOR(
|
|
2, // int13 request = read
|
|
0, // disk number (a:)
|
|
(USHORT)track, // head (0 or 1)
|
|
Cylinder, // cylinder (usually 0-79)
|
|
(USHORT)sector, // sector number (1-based)
|
|
1, // number of sectors to read
|
|
LocalBuffer // buffer
|
|
);
|
|
|
|
if(Status) {
|
|
retry++;
|
|
RESET_DISK(0,0,0,0,0,0,0);
|
|
}
|
|
|
|
} while(Status && (retry <= 2));
|
|
|
|
if(Status) {
|
|
|
|
//
|
|
// Sector is bad.
|
|
//
|
|
CachedDiskBadSectorMap[AbsoluteSector] = TRUE;
|
|
|
|
DBGOUT(("bad\n"));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Sector is good. Transfer the data into the cache buffer.
|
|
//
|
|
RtlMoveMemory(pCache,LocalBuffer,CachedDiskBytesPerSector);
|
|
|
|
DBGOUT(("OK\n"));
|
|
}
|
|
|
|
//
|
|
// Advance to the next sector in the cache buffer.
|
|
//
|
|
pCache += CachedDiskBytesPerSector;
|
|
AbsoluteSector++;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Transfer the whole track we just successfully read
|
|
// into the cached disk buffer.
|
|
//
|
|
RtlMoveMemory(pCache,LocalBuffer,CachedDiskBytesPerTrack);
|
|
pCache += CachedDiskBytesPerTrack;
|
|
AbsoluteSector += CachedDiskSectorsPerTrack;
|
|
|
|
DBGOUT(("OK\n"));
|
|
}
|
|
}
|
|
|
|
CachedDiskCylinderMap[Cylinder] = TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FcIsThisFloppyCached(
|
|
IN PUCHAR Buffer
|
|
)
|
|
{
|
|
if(!DiskInCache) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Compare the first 512 bytes of the cached disk
|
|
// to the buffer passed in. If they are equal,
|
|
// then the disk is already cached.
|
|
//
|
|
if(RtlCompareMemory(CachedDiskImage,Buffer,512) == 512) {
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Disk is not cached.
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
FcUncacheFloppyDisk(
|
|
VOID
|
|
)
|
|
{
|
|
DiskInCache = FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FcCacheFloppyDisk(
|
|
PBIOS_PARAMETER_BLOCK Bpb
|
|
)
|
|
{
|
|
//
|
|
// Indicate that the cache is invalid.
|
|
//
|
|
DiskInCache = FALSE;
|
|
|
|
//
|
|
// Sanity check the bpb.
|
|
// Ensure it's a standard 1.2 meg or 1.44 meg disk.
|
|
//
|
|
if((Bpb->Heads != 2) || (Bpb->BytesPerSector != 512)
|
|
|| ((Bpb->SectorsPerTrack != 15) && (Bpb->SectorsPerTrack != 18))
|
|
|| ((Bpb->Sectors != 2880) && (Bpb->Sectors != 2400)))
|
|
{
|
|
DBGOUT(("FcCacheFloppyDisk: floppy not standard 1.2 or 1.44 meg disk\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Grab a buffer under the 1 meg line.
|
|
// The buffer must be big enough to hold one whole track of
|
|
// a 1.44 meg floppy.
|
|
//
|
|
|
|
if(LocalBuffer == NULL) {
|
|
LocalBuffer = FwAllocateHeap(18 * 512);
|
|
if(LocalBuffer == NULL) {
|
|
DBGOUT(("FcCacheFloppyDisk: Couldn't allocate local buffer\n"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
DBGOUT(("FcCacheFloppyDisk: LocalBuffer @ %lx\n",LocalBuffer));
|
|
|
|
//
|
|
// The disk is one we can cache. Indicate that a disk is cached
|
|
// and mark all sectors good and all tracks not present.
|
|
//
|
|
DiskInCache = TRUE;
|
|
RtlZeroMemory(CachedDiskBadSectorMap,sizeof(CachedDiskBadSectorMap));
|
|
RtlZeroMemory(CachedDiskCylinderMap,sizeof(CachedDiskCylinderMap));
|
|
CachedDiskSectorsPerTrack = Bpb->SectorsPerTrack;
|
|
CachedDiskSectorsPerCylinder = Bpb->Heads * Bpb->SectorsPerTrack;
|
|
CachedDiskBytesPerSector = Bpb->BytesPerSector;
|
|
|
|
//
|
|
// Calculate the number of bytes in a Track on the floppy.
|
|
//
|
|
CachedDiskBytesPerTrack = CachedDiskSectorsPerTrack * Bpb->BytesPerSector;
|
|
|
|
//
|
|
// Calculate the number of tracks.
|
|
//
|
|
CachedDiskLastSector = Bpb->Sectors-1;
|
|
|
|
DBGOUT(("FcCacheFloppyDisk: Caching disk, %u sectors per track\n",CachedDiskSectorsPerTrack));
|
|
|
|
FcpCacheOneCylinder(0);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
FcReadFromCache(
|
|
IN ULONG Offset,
|
|
IN ULONG Length,
|
|
OUT PUCHAR Buffer
|
|
)
|
|
{
|
|
ULONG FirstSector,LastSector,Sector;
|
|
ULONG FirstCyl,LastCyl,cyl;
|
|
|
|
if(!Length) {
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
if(!DiskInCache) {
|
|
return(EINVAL);
|
|
}
|
|
|
|
//
|
|
// Determine the first sector in the transfer.
|
|
//
|
|
FirstSector = Offset / 512;
|
|
|
|
//
|
|
// Determine and validate the last sector in the transfer.
|
|
//
|
|
LastSector = FirstSector + ((Length-1)/512);
|
|
|
|
if(LastSector > CachedDiskLastSector) {
|
|
return(E2BIG);
|
|
}
|
|
|
|
//
|
|
// Determine the first and last cylinders involved in the transfer.
|
|
//
|
|
FirstCyl = FirstSector / CachedDiskSectorsPerCylinder;
|
|
LastCyl = LastSector / CachedDiskSectorsPerCylinder;
|
|
|
|
//
|
|
// Make sure all these cylinders are cached.
|
|
//
|
|
for(cyl=FirstCyl; cyl<=LastCyl; cyl++) {
|
|
if(!CachedDiskCylinderMap[cyl]) {
|
|
FcpCacheOneCylinder((USHORT)cyl);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determine if any of the sectors in the transfer range
|
|
// are marked bad in the sector map.
|
|
//
|
|
// If so, return an i/o error.
|
|
//
|
|
for(Sector=FirstSector; Sector<=LastSector; Sector++) {
|
|
if(CachedDiskBadSectorMap[Sector]) {
|
|
return(EIO);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Transfer the data into the caller's buffer.
|
|
//
|
|
RtlMoveMemory(Buffer,CachedDiskImage+Offset,Length);
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
#endif // def FLOPPY_CACHE
|