mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-08 19:32:39 +08:00
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:
parent
43b0dc2d25
commit
9a76485bb0
377
src/dos/dos.cpp
377
src/dos/dos.cpp
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user