DOS: Add INT 21h AX=7305h extended absolute disk read/write to satisfy FORMAT.COM and SCANDISK.EXE shipped with Windows 98

This commit is contained in:
Jonathan Campbell 2020-05-12 20:55:06 -07:00
parent 43b0dc2d25
commit 9a76485bb0

View File

@ -74,6 +74,9 @@ char * shiftjis_upcase(char * str) {
return str;
}
static Bitu DOS_25Handler_Actual(bool fat32);
static Bitu DOS_26Handler_Actual(bool fat32);
unsigned char cpm_compat_mode = CPM_COMPAT_MSDOS5;
bool dos_in_hma = true;
@ -2025,6 +2028,17 @@ static Bitu DOS_21Handler(void) {
}
rsize=false;
}
else if (reg_al == 5 && reg_cx == 0xFFFF && (dos.version.major > 7 || (dos.version.major == 7 && dos.version.minor >= 10))) {
/* Windows 9x FAT32 extended disk read/write */
reg_al = reg_dl - 1; /* INT 25h AL 0=A: 1=B: This interface DL 1=A: 2=B: */
if (reg_si & 1)
DOS_26Handler_Actual(true/*fat32*/); /* writing */
else
DOS_25Handler_Actual(true/*fat32*/); /* reading */
/* CF needs to be returned on stack or else it's lost */
CALLBACK_SCF(!!(reg_flags & FLAG_CF));
}
else {
LOG(LOG_DOSMISC,LOG_ERROR)("DOS:Unhandled call %02X al=%02X (MS-DOS 7.x function)",reg_ah,reg_al);
CALLBACK_SCF(true);
@ -2100,194 +2114,235 @@ static Bitu DOS_27Handler(void) {
return CBRET_NONE;
}
static Bitu DOS_25Handler(void) {
static Bitu DOS_25Handler_Actual(bool fat32) {
if (reg_al >= DOS_DRIVES || !Drives[reg_al] || Drives[reg_al]->isRemovable()) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
} else {
DOS_Drive *drv = Drives[reg_al];
/* assume drv != NULL */
Bit32u sector_size = drv->GetSectorSize();
Bit32u sector_count = drv->GetSectorCount();
PhysPt ptr = PhysMake(SegValue(ds),reg_bx);
Bit32u req_count = reg_cx;
Bit32u sector_num = reg_dx;
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
} else {
DOS_Drive *drv = Drives[reg_al];
/* assume drv != NULL */
Bit32u sector_size = drv->GetSectorSize();
Bit32u sector_count = drv->GetSectorCount();
PhysPt ptr = PhysMake(SegValue(ds),reg_bx);
Bit32u req_count = reg_cx;
Bit32u sector_num = reg_dx;
/* For < 32MB drives.
* AL = drive
* CX = sector count (not 0xFFFF)
* DX = sector number
* DS:BX = pointer to disk transfer area
*
* For >= 32MB drives.
*
* AL = drive
* CX = 0xFFFF
* DS:BX = disk read packet
*
* Disk read packet:
* +0 DWORD = sector number
* +4 WORD = sector count
* +6 DWORD = disk tranfer area
*/
if (sector_count != 0 && sector_size != 0) {
unsigned char tmp[2048];
const char *method;
/* For < 32MB drives.
* AL = drive
* CX = sector count (not 0xFFFF)
* DX = sector number
* DS:BX = pointer to disk transfer area
*
* For >= 32MB drives.
*
* AL = drive
* CX = 0xFFFF
* DS:BX = disk read packet
*
* Disk read packet:
* +0 DWORD = sector number
* +4 WORD = sector count
* +6 DWORD = disk tranfer area
*/
if (sector_count != 0 && sector_size != 0) {
unsigned char tmp[2048];
const char *method;
if (sector_size > sizeof(tmp)) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (sector_size > sizeof(tmp)) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (sector_count > 0xFFFF && req_count != 0xFFFF) {
reg_ax = 0x0207; // must use CX=0xFFFF API for > 64KB segment partitions
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (sector_count > 0xFFFF && req_count != 0xFFFF) {
reg_ax = 0x0207; // must use CX=0xFFFF API for > 64KB segment partitions
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (req_count == 0xFFFF) {
sector_num = mem_readd(ptr+0);
req_count = mem_readw(ptr+4);
Bit32u p = mem_readd(ptr+6);
ptr = PhysMake(p >> 16u,p & 0xFFFFu);
method = ">=32MB";
}
else {
method = "<32MB";
}
if (fat32) {
sector_num = mem_readd(ptr+0);
req_count = mem_readw(ptr+4);
Bit32u p = mem_readd(ptr+6);
ptr = PhysMake(p >> 16u,p & 0xFFFFu);
method = "Win95/FAT32";
}
else if (req_count == 0xFFFF) {
sector_num = mem_readd(ptr+0);
req_count = mem_readw(ptr+4);
Bit32u p = mem_readd(ptr+6);
ptr = PhysMake(p >> 16u,p & 0xFFFFu);
method = ">=32MB";
}
else {
method = "<32MB";
}
LOG(LOG_MISC,LOG_DEBUG)("INT 25h READ: sector=%lu count=%lu ptr=%lx method='%s'",
(unsigned long)sector_num,
(unsigned long)req_count,
(unsigned long)ptr,
method);
if (fat32) {
LOG(LOG_MISC,LOG_DEBUG)("INT 21h AX=7305h READ: sector=%lu count=%lu ptr=%lx method='%s'",
(unsigned long)sector_num,
(unsigned long)req_count,
(unsigned long)ptr,
method);
}
else {
LOG(LOG_MISC,LOG_DEBUG)("INT 25h READ: sector=%lu count=%lu ptr=%lx method='%s'",
(unsigned long)sector_num,
(unsigned long)req_count,
(unsigned long)ptr,
method);
}
SETFLAGBIT(CF,false);
reg_ax = 0;
SETFLAGBIT(CF,false);
reg_ax = 0;
while (req_count > 0) {
Bit8u res = drv->Read_AbsoluteSector_INT25(sector_num,tmp);
if (res != 0) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
break;
}
while (req_count > 0) {
Bit8u res = drv->Read_AbsoluteSector_INT25(sector_num,tmp);
if (res != 0) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
break;
}
for (unsigned int i=0;i < (unsigned int)sector_size;i++)
mem_writeb(ptr+i,tmp[i]);
for (unsigned int i=0;i < (unsigned int)sector_size;i++)
mem_writeb(ptr+i,tmp[i]);
req_count--;
sector_num++;
ptr += sector_size;
}
req_count--;
sector_num++;
ptr += sector_size;
}
return CBRET_NONE;
}
return CBRET_NONE;
}
/* MicroProse installer hack, inherited from DOSBox SVN, as a fallback if INT 25h emulation is not available for the drive. */
if (reg_cx == 1 && reg_dx == 0 && reg_al >= 2) {
// write some BPB data into buffer for MicroProse installers
mem_writew(ptr+0x1c,0x3f); // hidden sectors
SETFLAGBIT(CF,false);
reg_ax = 0;
} else {
LOG(LOG_DOSMISC,LOG_NORMAL)("int 25 called but not as disk detection drive %u",reg_al);
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
}
}
return CBRET_NONE;
/* MicroProse installer hack, inherited from DOSBox SVN, as a fallback if INT 25h emulation is not available for the drive. */
if (reg_cx == 1 && reg_dx == 0 && reg_al >= 2) {
// write some BPB data into buffer for MicroProse installers
mem_writew(ptr+0x1c,0x3f); // hidden sectors
SETFLAGBIT(CF,false);
reg_ax = 0;
} else {
LOG(LOG_DOSMISC,LOG_NORMAL)("int 25 called but not as disk detection drive %u",reg_al);
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
}
}
return CBRET_NONE;
}
static Bitu DOS_26Handler(void) {
static Bitu DOS_25Handler(void) {
return DOS_25Handler_Actual(false);
}
static Bitu DOS_26Handler_Actual(bool fat32) {
if (reg_al >= DOS_DRIVES || !Drives[reg_al] || Drives[reg_al]->isRemovable()) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
} else {
DOS_Drive *drv = Drives[reg_al];
/* assume drv != NULL */
Bit32u sector_size = drv->GetSectorSize();
Bit32u sector_count = drv->GetSectorCount();
PhysPt ptr = PhysMake(SegValue(ds),reg_bx);
Bit32u req_count = reg_cx;
Bit32u sector_num = reg_dx;
} else {
DOS_Drive *drv = Drives[reg_al];
/* assume drv != NULL */
Bit32u sector_size = drv->GetSectorSize();
Bit32u sector_count = drv->GetSectorCount();
PhysPt ptr = PhysMake(SegValue(ds),reg_bx);
Bit32u req_count = reg_cx;
Bit32u sector_num = reg_dx;
/* For < 32MB drives.
* AL = drive
* CX = sector count (not 0xFFFF)
* DX = sector number
* DS:BX = pointer to disk transfer area
*
* For >= 32MB drives.
*
* AL = drive
* CX = 0xFFFF
* DS:BX = disk read packet
*
* Disk read packet:
* +0 DWORD = sector number
* +4 WORD = sector count
* +6 DWORD = disk tranfer area
*/
if (sector_count != 0 && sector_size != 0) {
unsigned char tmp[2048];
const char *method;
/* For < 32MB drives.
* AL = drive
* CX = sector count (not 0xFFFF)
* DX = sector number
* DS:BX = pointer to disk transfer area
*
* For >= 32MB drives.
*
* AL = drive
* CX = 0xFFFF
* DS:BX = disk read packet
*
* Disk read packet:
* +0 DWORD = sector number
* +4 WORD = sector count
* +6 DWORD = disk tranfer area
*/
if (sector_count != 0 && sector_size != 0) {
unsigned char tmp[2048];
const char *method;
if (sector_size > sizeof(tmp)) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (sector_size > sizeof(tmp)) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (sector_count > 0xFFFF && req_count != 0xFFFF) {
reg_ax = 0x0207; // must use CX=0xFFFF API for > 64KB segment partitions
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (sector_count > 0xFFFF && req_count != 0xFFFF) {
reg_ax = 0x0207; // must use CX=0xFFFF API for > 64KB segment partitions
SETFLAGBIT(CF,true);
return CBRET_NONE;
}
if (req_count == 0xFFFF) {
sector_num = mem_readd(ptr+0);
req_count = mem_readw(ptr+4);
Bit32u p = mem_readd(ptr+6);
ptr = PhysMake(p >> 16u,p & 0xFFFFu);
method = ">=32MB";
}
else {
method = "<32MB";
}
if (fat32) {
sector_num = mem_readd(ptr+0);
req_count = mem_readw(ptr+4);
Bit32u p = mem_readd(ptr+6);
ptr = PhysMake(p >> 16u,p & 0xFFFFu);
method = "Win95/FAT32";
}
else if (req_count == 0xFFFF) {
sector_num = mem_readd(ptr+0);
req_count = mem_readw(ptr+4);
Bit32u p = mem_readd(ptr+6);
ptr = PhysMake(p >> 16u,p & 0xFFFFu);
method = ">=32MB";
}
else {
method = "<32MB";
}
LOG(LOG_MISC,LOG_DEBUG)("INT 26h WRITE: sector=%lu count=%lu ptr=%lx method='%s'",
(unsigned long)sector_num,
(unsigned long)req_count,
(unsigned long)ptr,
method);
if (fat32) {
LOG(LOG_MISC,LOG_DEBUG)("INT 21h AX=7305h WRITE: sector=%lu count=%lu ptr=%lx method='%s'",
(unsigned long)sector_num,
(unsigned long)req_count,
(unsigned long)ptr,
method);
}
else {
LOG(LOG_MISC,LOG_DEBUG)("INT 26h WRITE: sector=%lu count=%lu ptr=%lx method='%s'",
(unsigned long)sector_num,
(unsigned long)req_count,
(unsigned long)ptr,
method);
}
SETFLAGBIT(CF,false);
reg_ax = 0;
SETFLAGBIT(CF,false);
reg_ax = 0;
while (req_count > 0) {
for (unsigned int i=0;i < (unsigned int)sector_size;i++)
tmp[i] = mem_readb(ptr+i);
while (req_count > 0) {
for (unsigned int i=0;i < (unsigned int)sector_size;i++)
tmp[i] = mem_readb(ptr+i);
Bit8u res = drv->Write_AbsoluteSector_INT25(sector_num,tmp);
if (res != 0) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
break;
}
Bit8u res = drv->Write_AbsoluteSector_INT25(sector_num,tmp);
if (res != 0) {
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
break;
}
req_count--;
sector_num++;
ptr += sector_size;
}
req_count--;
sector_num++;
ptr += sector_size;
}
return CBRET_NONE;
}
return CBRET_NONE;
}
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
}
return CBRET_NONE;
reg_ax = 0x8002;
SETFLAGBIT(CF,true);
}
return CBRET_NONE;
}
static Bitu DOS_26Handler(void) {
return DOS_26Handler_Actual(false);
}
bool enable_collating_uppercase = true;