Skip to content

Commit

Permalink
FAT driver, IMGMOUNT: Add code to allow directing all FAT driver acce…
Browse files Browse the repository at this point in the history
…ss through INT 13h so that if any program depends on hooking INT 13h to intercept I/O, it will work
  • Loading branch information
joncampbell123 committed Jul 9, 2024
1 parent 19421a5 commit 7e283dc
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 5 deletions.
2 changes: 2 additions & 0 deletions include/bios_disk.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,9 @@ class imageDiskINT13Drive : public imageDisk {
virtual ~imageDiskINT13Drive();

uint8_t bios_disk = 0;
bool enable_int13 = false;
imageDisk* subdisk = NULL;
bool busy = false;
};

#endif
5 changes: 5 additions & 0 deletions src/cpu/callback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,11 @@ Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress, bool use_
phys_writeb(physAddress+0x01,(uint8_t)0xCF); //An IRET Instruction
phys_writew(physAddress+0x02,(uint16_t)0x0ECD); // int 0e
phys_writeb(physAddress+0x04,(uint8_t)0xCF); //An IRET Instruction
// for the image disk support to call
phys_writew(physAddress+0x05,(uint16_t)0x13CD); // int 13
phys_writeb(physAddress+0x07,0xFE);
phys_writeb(physAddress+0x08,0x38);
phys_writew(physAddress+0x09,(uint16_t)call_idle);
return (use_cb?9:5);
case CB_VESA_WAIT:
if (use_cb) E_Exit("VESA wait must not implement a callback handler!");
Expand Down
13 changes: 10 additions & 3 deletions src/dos/dos_programs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6114,10 +6114,10 @@ class IMGMOUNT : public Program {
if ((*i) == "int13") {
char buf[32];

if (drive >= 2)
sprintf(buf,"=%u",drive+0x80-2);
if (drive >= 'C')
sprintf(buf,"=%u",drive+0x80-'C');
else
sprintf(buf,"=%u",drive);
sprintf(buf,"=%u",drive-'A');

(*i) += buf;
}
Expand Down Expand Up @@ -6344,6 +6344,13 @@ class IMGMOUNT : public Program {
}
}
}

/* now that the image is attached to INT 13h the INT 13 image can use it now */
if (image->class_id == imageDisk::ID_INT13) {
imageDiskINT13Drive *x = (imageDiskINT13Drive*)image;
x->enable_int13 = true;
LOG_MSG("INT 13 image enabling calling");
}
}
return true;
}
Expand Down
73 changes: 73 additions & 0 deletions src/dos/drive_fat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2495,6 +2495,8 @@ bool fatDrive::FileCreate(DOS_File **file, const char *name, uint16_t attributes

if (unformatted) return false;

checkDiskChange();

if (readonly) {
DOS_SetError(DOSERR_WRITE_PROTECTED);
return false;
Expand Down Expand Up @@ -2598,6 +2600,8 @@ bool fatDrive::FileCreate(DOS_File **file, const char *name, uint16_t attributes
bool fatDrive::FileExists(const char *name) {
if (unformatted) return false;

checkDiskChange();

direntry fileEntry = {};
uint32_t dummy1, dummy2;
uint16_t save_errorcode = dos.errorcode;
Expand All @@ -2609,6 +2613,8 @@ bool fatDrive::FileExists(const char *name) {
bool fatDrive::FileOpen(DOS_File **file, const char *name, uint32_t flags) {
if (unformatted) return false;

checkDiskChange();

direntry fileEntry = {};
uint32_t dirClust, subEntry;

Expand Down Expand Up @@ -2639,6 +2645,8 @@ bool fatDrive::FileStat(const char * /*name*/, FileStat_Block *const /*stat_bloc
bool fatDrive::FileUnlink(const char * name) {
if (unformatted) return false;

checkDiskChange();

if (readonly) {
DOS_SetError(DOSERR_WRITE_PROTECTED);
return false;
Expand Down Expand Up @@ -2688,6 +2696,8 @@ bool fatDrive::FileUnlink(const char * name) {
bool fatDrive::FindFirst(const char *_dir, DOS_DTA &dta,bool fcb_findfirst) {
if (unformatted) return false;

checkDiskChange();

direntry dummyClust = {};

// volume label searches always affect root directory, no matter the current directory, at least with FCBs
Expand Down Expand Up @@ -3050,6 +3060,8 @@ bool fatDrive::FindNext(DOS_DTA &dta) {
bool fatDrive::SetFileAttr(const char *name, uint16_t attr) {
if (unformatted) return false;

checkDiskChange();

if (readonly) {
DOS_SetError(DOSERR_WRITE_PROTECTED);
return false;
Expand Down Expand Up @@ -3354,6 +3366,8 @@ void fatDrive::zeroOutCluster(uint32_t clustNumber) {
bool fatDrive::MakeDir(const char *dir) {
if (unformatted) return false;

checkDiskChange();

const char *lfn = NULL;

if (readonly) {
Expand Down Expand Up @@ -3459,6 +3473,8 @@ bool fatDrive::MakeDir(const char *dir) {
bool fatDrive::RemoveDir(const char *dir) {
if (unformatted) return false;

checkDiskChange();

if (readonly) {
DOS_SetError(DOSERR_WRITE_PROTECTED);
return false;
Expand Down Expand Up @@ -3530,6 +3546,8 @@ bool fatDrive::RemoveDir(const char *dir) {
bool fatDrive::Rename(const char * oldname, const char * newname) {
if (unformatted) return false;

checkDiskChange();

const char *lfn = NULL;

if (readonly) {
Expand Down Expand Up @@ -3646,3 +3664,58 @@ void fatDrive::clusterChainMemory::clear(void) {
current_cluster_index = 0;
}

void fatDrive::checkDiskChange(void) {
bool chg = false;

if (loadedDisk->detectDiskChange() && !BPB.is_fat32()) {
LOG_MSG("FAT: disk change\n");

FAT_BootSector bootbuffer = {};
loadedDisk->Read_AbsoluteSector(0+partSectOff,&bootbuffer);

void* var = &bootbuffer.bpb.v.BPB_BytsPerSec;
bootbuffer.bpb.v.BPB_BytsPerSec = var_read((uint16_t*)var);
var = &bootbuffer.bpb.v.BPB_RsvdSecCnt;
bootbuffer.bpb.v.BPB_RsvdSecCnt = var_read((uint16_t*)var);
var = &bootbuffer.bpb.v.BPB_RootEntCnt;
bootbuffer.bpb.v.BPB_RootEntCnt = var_read((uint16_t*)var);
var = &bootbuffer.bpb.v.BPB_TotSec16;
bootbuffer.bpb.v.BPB_TotSec16 = var_read((uint16_t*)var);
var = &bootbuffer.bpb.v.BPB_FATSz16;
bootbuffer.bpb.v.BPB_FATSz16 = var_read((uint16_t*)var);
var = &bootbuffer.bpb.v.BPB_SecPerTrk;
bootbuffer.bpb.v.BPB_SecPerTrk = var_read((uint16_t*)var);
var = &bootbuffer.bpb.v.BPB_NumHeads;
bootbuffer.bpb.v.BPB_NumHeads = var_read((uint16_t*)var);
var = &bootbuffer.bpb.v.BPB_HiddSec;
bootbuffer.bpb.v.BPB_HiddSec = var_read((uint32_t*)var);
var = &bootbuffer.bpb.v.BPB_TotSec32;
bootbuffer.bpb.v.BPB_TotSec32 = var_read((uint32_t*)var);
var = &bootbuffer.bpb.v.BPB_VolID;
bootbuffer.bpb.v.BPB_VolID = var_read((uint32_t*)var);

if (BPB.v.BPB_FATSz16 == 0) {
LOG_MSG("BPB_FATSz16 == 0 and not FAT32 BPB, not valid");
return;
}

uint32_t RootDirSectors;
uint32_t DataSectors;

RootDirSectors = ((BPB.v.BPB_RootEntCnt * 32u) + (BPB.v.BPB_BytsPerSec - 1u)) / BPB.v.BPB_BytsPerSec;

if (BPB.v.BPB_TotSec16 != 0)
DataSectors = (Bitu)BPB.v.BPB_TotSec16 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
else
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);

CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
firstDataSector = ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors) + (Bitu)partSectOff;
firstRootDirSect = (Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)partSectOff;

LOG_MSG("NEW FAT: data=%llu root=%llu rootdirsect=%lu datasect=%lu",
(unsigned long long)firstDataSector,(unsigned long long)firstRootDirSect,
(unsigned long)RootDirSectors,(unsigned long)DataSectors);
}
}

2 changes: 2 additions & 0 deletions src/dos/drives.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,8 @@ class fatDrive : public DOS_Drive {
virtual uint32_t GetFirstClusterOffset(void);
virtual uint32_t GetHighestClusterNumber(void);

void checkDiskChange(void);

unsigned char bios_disk = 0;
bool unformatted = false;
};
Expand Down
3 changes: 3 additions & 0 deletions src/ints/bios.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9352,6 +9352,8 @@ void BuildACPITable(void) {
rsdt_tw.finish();
}

extern unsigned int INT13Xfer;

class BIOS:public Module_base{
private:
static Bitu cb_bios_post__func(void) {
Expand All @@ -9370,6 +9372,7 @@ class BIOS:public Module_base{
INT13_ElTorito_NoEmuDriveNumber = 0;
INT13_ElTorito_NoEmuCDROMDrive = 0;
INT13_ElTorito_IDEInterface = -1;
INT13Xfer = 0;

ACPI_mem_enable(false);
ACPI_REGION_SIZE = 0;
Expand Down
120 changes: 118 additions & 2 deletions src/ints/bios_disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "../dos/drives.h"
#include "mapper.h"
#include "ide.h"
#include "cpu.h"

#if defined(_MSC_VER)
# pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
Expand Down Expand Up @@ -3739,11 +3740,95 @@ imageDiskEmptyDrive::~imageDiskEmptyDrive() {

/////

unsigned int INT13Xfer = 0;
size_t INT13XferSize = 4096;

static void imageDiskCallINT13(void) {
unsigned int rv = CALLBACK_RealPointer(call_int13);
Bitu oldIF=GETFLAG(IF);
SETFLAGBIT(IF,true);
uint16_t oldcs=SegValue(cs);
uint32_t oldeip=reg_eip;
SegSet16(cs,rv>>16);
reg_eip=(rv&0xFFFF)+4+5;
DOSBOX_RunMachine();
reg_eip=oldeip;
SegSet16(cs,oldcs);
SETFLAGBIT(IF,oldIF);
}

uint8_t imageDiskINT13Drive::Read_Sector(uint32_t head,uint32_t cylinder,uint32_t sector,void * data,unsigned int req_sector_size) {
return subdisk->Read_Sector(head,cylinder,sector,data,req_sector_size);
if (!enable_int13 || busy) return subdisk->Read_Sector(head,cylinder,sector,data,req_sector_size);

uint8_t ret = 0x05;
unsigned int retry = 3;

if (req_sector_size == 0) req_sector_size = sector_size;

// LOG_MSG("INT13 read C/H/S %u/%u/%u busy=%u",cylinder,head,sector,busy);

if (!busy && sector_size == req_sector_size && sector_size <= INT13XferSize) {
busy = true;

if (INT13Xfer == 0) INT13Xfer = DOS_GetMemory(INT13XferSize/16u,"INT 13 transfer buffer");

unsigned int s_eax = reg_eax;
unsigned int s_ebx = reg_ebx;
unsigned int s_ecx = reg_ecx;
unsigned int s_edx = reg_edx;
unsigned int s_es = SegValue(es);
unsigned int s_fl = reg_flags;

again:
reg_eax = 0x200/*read command*/ | 1/*count*/;
reg_ebx = 0;
reg_ch = cylinder;
reg_cl = sector;
reg_dh = head;
reg_dl = bios_disk;
CPU_SetSegGeneral(es,INT13Xfer);

imageDiskCallINT13();

if (reg_flags & FLAG_CF) {
ret = reg_ah;
if (ret == 0) ret = 0x05;

if (ret == 6/*disk change*/) {
diskChangeFlag = true;
if (--retry > 0) goto again;
}
}
else {
MEM_BlockRead32(INT13Xfer<<4,data,sector_size);
data = (void*)((char*)data + sector_size);
if ((++sector) >= (sectors + 1)) {
assert(sector == (sectors + 1));
sector = 1;
if ((++head) >= heads) {
assert(head == heads);
head = 0;
cylinder++;
}
}
}

reg_eax = s_eax;
reg_ebx = s_ebx;
reg_ecx = s_ecx;
reg_edx = s_edx;
reg_flags = s_fl;
CPU_SetSegGeneral(es,s_es);

busy = false;
}

return ret;
}

uint8_t imageDiskINT13Drive::Write_Sector(uint32_t head,uint32_t cylinder,uint32_t sector,const void * data,unsigned int req_sector_size) {
if (INT13Xfer == 0) INT13Xfer = DOS_GetMemory(INT13XferSize/16u,"INT 13 transfer buffer");

return subdisk->Write_Sector(head,cylinder,sector,data,req_sector_size);
}

Expand Down Expand Up @@ -3804,7 +3889,38 @@ uint32_t imageDiskINT13Drive::getSectSize(void) {
}

bool imageDiskINT13Drive::detectDiskChange(void) {
return subdisk->detectDiskChange();
if (enable_int13 && !busy) {
busy = true;

unsigned int s_eax = reg_eax;
unsigned int s_ebx = reg_ebx;
unsigned int s_ecx = reg_ecx;
unsigned int s_edx = reg_edx;
unsigned int s_fl = reg_flags;

reg_eax = 0x1600/*disk change detect*/;
reg_dl = bios_disk;
CPU_SetSegGeneral(es,INT13Xfer);

imageDiskCallINT13();

if (reg_flags & FLAG_CF) {
if (reg_ah == 0x06) {
LOG_MSG("INT13 image disk change flag\n");
diskChangeFlag = true;
}
}

reg_eax = s_eax;
reg_ebx = s_ebx;
reg_ecx = s_ecx;
reg_edx = s_edx;
reg_flags = s_fl;

busy = false;
}

return imageDisk::detectDiskChange();
}

imageDiskINT13Drive::imageDiskINT13Drive(imageDisk *sdisk) : imageDisk(ID_INT13) {
Expand Down

0 comments on commit 7e283dc

Please sign in to comment.