/* * demdasd.c - module for direct disk access related support functions * * Williamh 09-Dec-1992 Created * Revision 24-Mar-1993 added fdisk support */ #include "io.h" #include "dem.h" #include "stdio.h" #include "windows.h" #include "demdasd.h" #include "softpc.h" PBDS demBDS; BYTE NumberOfFloppy; BYTE NumberOfFdisk; #if defined(NEC_98) #define LPTBL_adr 0x0066c #define EXLPTBL_adr 0x03286 #define FLOPY_LPTBL 0x90 // Floppy #define FDISK_LPTBL 0xA0 // Shown as SCSI #endif // NEC_98 extern WORD int13h_vector_off, int13h_vector_seg; extern WORD int13h_caller_off, int13h_caller_seg; #if defined(NEC_98) extern void sas_store(char*,unsigned char); #endif // NEC_98 BPB StdBpb[MAX_FLOPPY_TYPE] = { {512, 2, 1, 2, 112, 2*9*40, 0xFD, 2, 9, 2, 0, 0}, // 360KB {512, 1, 1, 2, 224, 2*15*80, 0xF9, 7, 15, 2, 0, 0}, // 1.2MB {512, 2, 1, 2, 112, 2*9*80, 0xF9, 3, 9, 2, 0, 0}, // 720KB {512, 1, 1, 2, 224, 2*18*80, 0xF0, 9, 18, 2, 0, 0}, // 1.44MB {512, 2, 1, 2, 240, 2*36*80, 0xF0, 9, 36, 2, 0, 0} // 2.88MB #if defined(NEC_98) , {1024, 1, 1, 2, 192, 2*8*77, 0xFE, 2, 8, 2, 0, 0}, // 1.2MB {512, 2, 1, 2, 112, 2*8*80, 0xFB, 2, 8, 2, 0, 0} // 640KB #endif // !NEC_98 }; BYTE FormFactorTable[MAX_FLOPPY_TYPE] = { FF_360, FF_120, FF_720, FF_144, #if defined(NEC_98) FF_288, FF_125, FF_640 #else // !NEC_98 FF_288 #endif // !NEC_98 }; /* demDasdInit - dem diskette system Initialiazation * * Entry * none * * * Exit * None */ VOID demDasdInit(VOID) { demBDS = NULL; NumberOfFloppy = NumberOfFdisk = 0; demFloppyInit(); demFdiskInit(); } /* demAbsRead - int 25, absolute read * * Entry * Client (AL) = drive number (0 based) * (DS:BX) = pointer to the buffer to receive the read data * or pointer to the DISKIO structure * (CX) = number of sectors to read * if (0FFFFh) then DS:DX points to DISKIO * DX contents are discarded * (DX) = starting sector number * * * Exit * Client (CY) = 0 if operation succeed * (AX) = 0 * * (CY) = 1 if operation failed * (AX) = error code */ VOID demAbsRead (VOID) { #if DBG if (fShowSVCMsg & DEM_ABSDRD) OutputDebugStringOem("DEM: INT 25 Called \n"); #endif demAbsReadWrite(FALSE); } /* demAbsWrite - int 26, absolute read * * * Entry * Client (AL) = drive number (0 based) * (DS:BX) = pointer to the buffer to receive the read data * or pointer to the DISKIO structure * (CX) = number of sectors to read * if (0FFFFh) then DS:DX points to DISKIO * DX contents are discarded * (DX) = starting sector number * * * Exit * Client (CY) = 0 if operation succeed * (AX) = 0 * * (CY) = 1 if operation failed * (AX) = error code */ VOID demAbsWrite(VOID) { #if DBG if (fShowSVCMsg & DEM_ABSWRT) OutputDebugStringOem("DEM: INT 26 Called \n"); #endif demAbsReadWrite(TRUE); } extern BOOL (*DosWowDoDirectHDPopup)(VOID); // defined in demlfn.c VOID demAbsReadWrite(BOOL IsWrite) { BYTE Drive; DWORD LastError; DWORD Sectors; DWORD StartSector; PDISKIO DiskIo; DWORD SectorsReturned; PBDS pBDS; WORD BufferOff, BufferSeg; Drive = getAL(); if ((Sectors = getCX()) == 0xFFFF) { DiskIo = (PDISKIO) GetVDMAddr(getDS(), getBX()); Sectors = DiskIo->Sectors; StartSector = DiskIo->StartSector; BufferOff = DiskIo->BufferOff; BufferSeg = DiskIo->BufferSeg; } else { StartSector = getDX(); BufferOff = getBX(); BufferSeg = getDS(); } if ((pBDS = demGetBDS(Drive)) == NULL) { if (!demIsDriveFloppy(Drive) && Drive < 26) { if (NULL == DosWowDoDirectHDPopup || (*DosWowDoDirectHDPopup)()) { host_direct_access_error(NOSUPPORT_HARDDISK); } } setAX(DOS_DRIVE_NOT_READY); setCF(1); return; } #if DBG if (fShowSVCMsg & (DEM_ABSDRD | DEM_ABSWRT)) { sprintf(demDebugBuffer, "Drive Number: %d\n", Drive); OutputDebugStringOem(demDebugBuffer); sprintf(demDebugBuffer, "StartSector: %d\n", StartSector); OutputDebugStringOem(demDebugBuffer); sprintf(demDebugBuffer, "Total Sectors: %d\n", Sectors); OutputDebugStringOem(demDebugBuffer); sprintf(demDebugBuffer, "Buffer: %x:%x\n", BufferSeg, BufferOff); } #endif if (IsWrite) SectorsReturned = demDasdWrite(pBDS, StartSector, Sectors, BufferOff, BufferSeg ); else SectorsReturned = demDasdRead(pBDS, StartSector, Sectors, BufferOff, BufferSeg ); if (SectorsReturned != Sectors) { LastError = GetLastError(); #if DBG if (fShowSVCMsg & (DEM_ABSDRD | DEM_ABSWRT)) { sprintf(demDebugBuffer, "dem: AbsRDWR Failed, error=%lx\n", LastError); OutputDebugStringOem(demDebugBuffer); } #endif setAX(demWinErrorToDosError(LastError)); setCF(1); return; } setCF(0); return; } DWORD demDasdRead( PBDS pbds, DWORD StartSector, DWORD Sectors, WORD BufferOff, WORD BufferSeg ) { ULONG SizeReturned; LARGE_INTEGER LargeInteger; DWORD Size; DWORD SectorSize; WORD CurBiosDiskIoOff, CurBiosDiskIoSeg; PBYTE Buffer; // if this is the first time we access the BDS or // the media has been changed, build the bds -- floppy if (!(pbds->Flags & NON_REMOVABLE) && ((pbds->Flags & UNFORMATTED_MEDIA) || !nt_floppy_media_check(pbds->DrivePhys))) { if (!demGetBPB(pbds)) return 0; } if (StartSector >= pbds->TotalSectors || StartSector + Sectors > pbds->TotalSectors) { SetLastError(ERROR_SECTOR_NOT_FOUND); return 0 ; } SectorSize = pbds->bpb.SectorSize; LargeInteger.QuadPart = Int32x32To64(Sectors, SectorSize); // size must fit in ulong if (LargeInteger.HighPart != 0) { SetLastError(ERROR_SECTOR_NOT_FOUND); return 0; } Size = LargeInteger.LowPart; Buffer = (PBYTE) GetVDMAddr(BufferSeg, BufferOff); if (pbds->Flags & NON_REMOVABLE) { LargeInteger.QuadPart = Int32x32To64(StartSector, SectorSize); SizeReturned = nt_fdisk_read( pbds->DrivePhys, &LargeInteger, Size, Buffer ); } else { // floppy need special care beacuse application may hook // bios disk interrupt. We dont' do this for hard disks because // we don't allow int13 to them sas_loadw(0x13*4, &CurBiosDiskIoOff); sas_loadw(0x13* 4 + 2, &CurBiosDiskIoSeg); #if defined(NEC_98) if ( 1 ) // if NEC_98, always TRUE #else // !NEC_98 if (int13h_vector_off == CurBiosDiskIoOff && int13h_vector_seg == CurBiosDiskIoSeg) #endif // !NEC_98 SizeReturned = nt_floppy_read( pbds->DrivePhys, StartSector * SectorSize, Size, Buffer ); else return (demBiosDiskIoRW(pbds, StartSector, Sectors, BufferOff, BufferSeg, FALSE )); } if (SizeReturned == Size) return Sectors; else return SizeReturned / SectorSize; } DWORD demDasdWrite( PBDS pbds, DWORD StartSector, DWORD Sectors, WORD BufferOff, WORD BufferSeg ) { ULONG SizeReturned; LARGE_INTEGER LargeInteger; DWORD Size; DWORD SectorSize; WORD CurBiosDiskIoOff, CurBiosDiskIoSeg; PBYTE Buffer; // if this is the first time we access the BDS or // the media has been changed, build the bds if (!(pbds->Flags & NON_REMOVABLE) && ((pbds->Flags & UNFORMATTED_MEDIA) || !nt_floppy_media_check(pbds->DrivePhys))) { if (!demGetBPB(pbds)) return 0; } if (StartSector >= pbds->TotalSectors || StartSector + Sectors > pbds->TotalSectors) { SetLastError(ERROR_SECTOR_NOT_FOUND); return 0 ; } SectorSize = pbds->bpb.SectorSize; LargeInteger.QuadPart = Int32x32To64(Sectors, SectorSize); // size must fit in ulong if (LargeInteger.HighPart != 0) { SetLastError(ERROR_SECTOR_NOT_FOUND); return 0; } Size = LargeInteger.LowPart; Buffer = (PBYTE) GetVDMAddr(BufferSeg, BufferOff); if (pbds->Flags & NON_REMOVABLE) { LargeInteger.QuadPart = Int32x32To64(StartSector, SectorSize); SizeReturned = nt_fdisk_write( pbds->DrivePhys, &LargeInteger, Size, Buffer ); } else { // floppy need special care beacuse application may hook // bios disk interrupt. We dont' do this for hard disks because // we don't allow int13 to them sas_loadw(0x13*4, &CurBiosDiskIoOff); sas_loadw(0x13* 4 + 2, &CurBiosDiskIoSeg); #if defined(NEC_98) if ( 1 ) // if NEC_98, always TRUE #else // !NEC_98 if (int13h_vector_off == CurBiosDiskIoOff && int13h_vector_seg == CurBiosDiskIoSeg) #endif // !NEC_98 SizeReturned = nt_floppy_write( pbds->DrivePhys, StartSector * SectorSize, Size, Buffer ); else return(demBiosDiskIoRW(pbds, StartSector, Sectors, BufferOff, BufferSeg, TRUE )); } if (Size == SizeReturned) return Sectors; else return SizeReturned / SectorSize; } BOOL demDasdFormat(PBDS pbds, DWORD Head, DWORD Cylinder, MEDIA_TYPE * Media) { BOOL Result; if (pbds->Flags & NON_REMOVABLE) Result = demDasdVerify(pbds, Head, Cylinder); else { if (*Media == Unknown) { *Media = nt_floppy_get_media_type(pbds->DrivePhys, pbds->Cylinders, pbds->bpb.TrackSize, pbds->bpb.Heads ); return TRUE; } else { Result = nt_floppy_format(pbds->DrivePhys, (WORD)Cylinder, (WORD)Head, *Media ); } } return (Result); } BOOL demDasdVerify(PBDS pbds, DWORD Head, DWORD Cylinder) { DWORD Size, StartSector; LARGE_INTEGER LargeInteger; // if floppy, make sure we have up-to-date BPB and a valid media is in if (!(pbds->Flags & NON_REMOVABLE)) { if (!demGetBPB(pbds)) return FALSE; Size = pbds->bpb.TrackSize * pbds->bpb.SectorSize; StartSector = pbds->bpb.TrackSize * (Cylinder * pbds->bpb.Heads + Head) + 1; return (nt_floppy_verify(pbds->DrivePhys, StartSector * pbds->bpb.SectorSize, Size)); } // hard disk needs special care because of their size Size = pbds->bpb.TrackSize * pbds->bpb.SectorSize; StartSector = pbds->bpb.TrackSize * (Cylinder * pbds->bpb.Heads + Head) + 1; LargeInteger.QuadPart = Int32x32To64(StartSector, pbds->bpb.SectorSize); return (nt_fdisk_verify(pbds->DrivePhys, &LargeInteger, Size )); } PBDS demGetBDS(BYTE DriveLog) { PBDS pbds; pbds = demBDS; while (pbds != NULL && pbds->DriveLog != DriveLog) pbds = pbds->Next; return pbds; } BOOL demGetBPB(PBDS pbds) { PBOOTSECTOR pbs; BYTE SectorBuffer[BYTES_PER_SECTOR]; // when RETURN_FAKE_BPB is set(set by Set Device Parameter IOCTL, // the appplication has set a new BPB, we simply return it if (!(pbds->Flags & RETURN_FAKE_BPB) && !(pbds->Flags & NON_REMOVABLE) && ((pbds->Flags & UNFORMATTED_MEDIA) || !nt_floppy_media_check(pbds->DrivePhys)) ) { pbds->Flags &= ~(UNFORMATTED_MEDIA); nt_floppy_close(pbds->DrivePhys); if (nt_floppy_read(pbds->DrivePhys, 0, BYTES_PER_SECTOR, SectorBuffer ) != BYTES_PER_SECTOR) return FALSE; pbs = (PBOOTSECTOR)SectorBuffer; if ((pbs->Jump == 0x69 || pbs->Jump == 0xE9 || (pbs->Jump == 0xEB && pbs->Target[1] == 0x90)) && (pbs->bpb.MediaID & 0xF0) == 0xF0) { pbds->bpb = pbs->bpb; pbds->TotalSectors = (pbs->bpb.Sectors) ? pbs->bpb.Sectors : pbs->bpb.BigSectors; return TRUE; } // an unknown media found else { pbds->Flags |= UNFORMATTED_MEDIA; // What should we do here? The diskette has strange boot sector // should we guess it or what? // #if DEVL if (fShowSVCMsg & (DEM_ABSDRD | DEM_ABSWRT)) { sprintf(demDebugBuffer, "Invalid Boot Sector Found\n"); OutputDebugStringOem(demDebugBuffer); } #endif host_direct_access_error(NOSUPPORT_FLOPPY); return FALSE; } } return TRUE; } DWORD demBiosDiskIoRW( PBDS pbds, DWORD StartSector, DWORD Sectors, WORD BufferOff, WORD BufferSeg, BOOL IsWrite ) { BYTE CurHead, CurSector, BiosErrorCode; WORD CurTrack, TrackSize, Heads, SectorTrack; WORD AX, BX, CX, DX, ES, CS, IP; BYTE SectorsRead, SectorsToRead; WORD wRetry = 3; AX = getAX(); BX = getBX(); CX = getCX(); DX = getDX(); ES = getES(); CS = getCS(); IP = getIP(); TrackSize = pbds->bpb.TrackSize; Heads = pbds->bpb.Heads; SectorsRead = 0; CurSector = (BYTE) ((StartSector % TrackSize) + 1); CurTrack = (WORD) (StartSector / TrackSize); CurHead = CurTrack % Heads; CurTrack /= Heads; SectorsToRead = TrackSize - CurSector + 1; while (Sectors != 0) { if (Sectors < SectorsToRead) SectorsToRead = (BYTE) Sectors; // low byte: bit 6 and 7 are high bits of track, // bit 0 - 5 are sector number // high byte: bit 0 - bit 7 ->track lower 8 bits SectorTrack = ((CurTrack & 0x300) >> 2) | (CurSector & 0x3f) | ((CurTrack &0xFF) << 8); wRetry = 3; BiosRetry: setAH((BYTE) ((IsWrite) ? DISKIO_WRITE : DISKIO_READ)); setAL(SectorsToRead); setBX(BufferOff); setES(BufferSeg); setDH(CurHead); setDL(pbds->DrivePhys); setCX(SectorTrack); setCS(int13h_caller_seg); setIP(int13h_caller_off); host_simulate(); if (getCF() == 0) { SectorsRead += SectorsToRead; if ((Sectors -= SectorsToRead) == 0) break; CurSector = 1; if (++CurHead == Heads) { CurHead = 0; CurTrack++; } SectorsToRead = (BYTE) TrackSize; } else { BiosErrorCode = getAH(); // reset the disk setAH(DISKIO_RESET); setDL(pbds->DrivePhys); setCS(int13h_caller_seg); setIP(int13h_caller_off); host_simulate(); // NOTE that we dont' handle DMA boundary here // because it shouldn't happen. -- the NT disk DD // will take care of that. if (BiosErrorCode & BIOS_TIME_OUT) { SetLastError(ERROR_NO_MEDIA_IN_DRIVE); break; } if (wRetry--) goto BiosRetry; SetLastError(BiosErrorToNTError(BiosErrorCode)); break; } } setAX(AX); setBX(BX); setCX(CX); setDX(DX); setES(ES); setCS(CS); setIP(IP); return SectorsRead; } DWORD BiosErrorToNTError(BYTE BiosErrorCode) { DWORD NtErrorCode; switch (BiosErrorCode) { case BIOS_INVALID_FUNCTION: NtErrorCode = ERROR_BAD_COMMAND; break; case BIOS_BAD_ADDRESS_MARK: NtErrorCode = ERROR_FLOPPY_ID_MARK_NOT_FOUND; break; case BIOS_WRITE_PROTECTED: NtErrorCode = ERROR_WRITE_PROTECT; break; case BIOS_BAD_SECTOR: case BIOS_CRC_ERROR: NtErrorCode = ERROR_SECTOR_NOT_FOUND; break; case BIOS_DISK_CHANGED: NtErrorCode = ERROR_DISK_CHANGE; break; case BIOS_NO_MEDIA: NtErrorCode = ERROR_NO_MEDIA_IN_DRIVE; break; case BIOS_SEEK_ERROR: NtErrorCode = ERROR_SEEK; break; default: NtErrorCode = ERROR_FLOPPY_UNKNOWN_ERROR; } return NtErrorCode; } WORD demWinErrorToDosError(DWORD LastError) { WORD DosError; switch(LastError) { case ERROR_SEEK: DosError = DOS_SEEK_ERROR; break; case ERROR_BAD_UNIT: DosError = DOS_UNKNOWN_UNIT; break; case ERROR_NO_MEDIA_IN_DRIVE: case ERROR_NOT_READY: DosError = DOS_DRIVE_NOT_READY; break; case ERROR_NOT_DOS_DISK: DosError = DOS_UNKNOWN_MEDIA; break; case ERROR_SECTOR_NOT_FOUND: case ERROR_FLOPPY_WRONG_CYLINDER: DosError = DOS_SECTOR_NOT_FOUND; break; case ERROR_READ_FAULT: DosError = DOS_READ_FAULT; break; case ERROR_WRITE_FAULT: DosError = DOS_WRITE_FAULT; break; case ERROR_WRONG_DISK: case ERROR_DISK_CHANGE: case ERROR_MEDIA_CHANGED: DosError = DOS_INVALID_MEDIA_CHANGE; break; case ERROR_WRITE_PROTECT: DosError = DOS_WRITE_PROTECTION; break; default: DosError = DOS_GEN_FAILURE; } return (DosError); } VOID demFdiskInit(VOID) { PBDS pbds; UCHAR Drive; DISK_GEOMETRY DiskGeometry; BPB bpb; #if defined(NEC_98) CHAR numFlop = 0; CHAR numFdisk = 0; #endif // NEC_98 Drive = 0; do { // first, the drive must be valid // second, the drive must be a hard disk(fixed) // third, the drive must be a FAT if (demGetPhysicalDriveType(Drive) == DRIVE_FIXED && nt_fdisk_init(Drive, &bpb, &DiskGeometry)) { #if defined(NEC_98) sas_store( LPTBL_adr+Drive , (FDISK_LPTBL+numFdisk) ); sas_store( EXLPTBL_adr+Drive*2, 0 ); sas_store( EXLPTBL_adr+Drive*2+1, (FDISK_LPTBL+numFdisk++) ); #endif // NEC_98 pbds = (PBDS) malloc(sizeof(BDS)); if (pbds != NULL) { pbds->bpb = bpb; pbds->rbpb = bpb; pbds->DrivePhys = NumberOfFdisk++; pbds->DriveLog = Drive; pbds->DriveType = DRIVETYPE_FDISK; pbds->FormFactor = FF_FDISK; pbds->TotalSectors = (bpb.Sectors) ? bpb.Sectors : bpb.BigSectors; pbds->Cylinders = (WORD) DiskGeometry.Cylinders.LowPart; pbds->Next = demBDS; pbds->Flags = NON_REMOVABLE | PHYS_OWNER; demBDS = pbds; } } #if defined(NEC_98) else if (demGetPhysicalDriveType(Drive) == DRIVE_REMOVABLE ) { sas_store( LPTBL_adr+Drive, (FLOPY_LPTBL+numFlop) ); sas_store( EXLPTBL_adr+Drive*2, 0 ); sas_store( EXLPTBL_adr+Drive*2+1, (FLOPY_LPTBL+numFlop++) ); } #endif // NEC_98 } while (++Drive < 26); } VOID demFloppyInit(VOID) { WORD AX, BX, CX, DX, DI, ES; #if defined(NEC_98) // BUG???: NumberOfFloppy is defined before. BYTE i; #else // !NEC_98 BYTE i, NumberOfFloppy; #endif // NEC_98 PBDS pbds; BYTE DriveType; #if defined(NEC_98) DWORD DriveMask; CHAR achRoot[] = "A:\\"; #endif // NEC_98 AX = getAX(); BX = getBX(); CX = getCX(); DX = getDX(); DI = getDI(); ES = getES(); // reset the floppy system #if defined(NEC_98) DriveMask = GetLogicalDrives(); i=0; if ( DriveMask ) { while (DriveMask != 0) { achRoot[0] = i + 'A'; if ((DriveMask & 1) &&(GetDriveType(achRoot) == DRIVE_REMOVABLE)){ pbds = (PBDS) malloc(sizeof(BDS)); if (pbds == NULL) { OutputDebugStringOem("dem: not enough memory for BDS\n"); break; } pbds->DrivePhys = pbds->DriveLog = i; pbds->DriveType = DriveType = 6; // 1.2 MB 2HD pbds->fd = NULL; // pbds->Cylinders = 77; // pbds->Sectors = 8; // pbds->rbpb = StdBpb[DriveType - 1]; pbds->TotalSectors = 0; pbds->Next = demBDS; pbds->FormFactor = FormFactorTable[DriveType - 1]; demBDS = pbds; pbds->Flags = UNFORMATTED_MEDIA | PHYS_OWNER; pbds->Flags |= HAS_CHANGELINE; } DriveMask>>=1; i++; NumberOfFloppy++; } } #else // !NEC_98 setDL(0); setAH(DISKIO_RESET); diskette_io(); setDL(0); setAH(DISKIO_GETPARAMS); diskette_io(); if (getCF() == 0 && (NumberOfFloppy = getDL()) != 0) { for(i = 0; i < NumberOfFloppy; i++) { setDL(i); setAH(DISKIO_GETPARAMS); diskette_io(); if (getCF() == 0) { pbds = (PBDS) malloc(sizeof(BDS)); if (pbds == NULL) { OutputDebugStringOem("dem: not enough memory for BDS\n"); break; } pbds->DrivePhys = pbds->DriveLog = i; pbds->DriveType = DriveType = getBL() & 0x0F; pbds->fd = NULL; pbds->Cylinders = getCH() + 1; pbds->Sectors = getCL(); pbds->rbpb = StdBpb[DriveType - 1]; pbds->TotalSectors = 0; pbds->Next = demBDS; pbds->FormFactor = FormFactorTable[DriveType - 1]; demBDS = pbds; pbds->Flags = UNFORMATTED_MEDIA | PHYS_OWNER; setAH(DISKIO_DRIVETYPE); setDL(i); diskette_io(); if (getAH() == 2 ) pbds->Flags |= HAS_CHANGELINE; } } } #endif //NEC_98 setAX(AX); setBX(BX); setCX(CX); setDX(DX); setDI(DI); setES(ES); } #if defined(NEC_98) BOOL demIsDriveFloppy(BYTE DriveLog){ CHAR achRoot[] = "A:\\"; achRoot[0]='A'+DriveLog; return (GetDriveType(achRoot) == DRIVE_REMOVABLE ); } #endif // NEC_98