diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index a2f96f909..13df1876c 100644 --- a/src/dos/dos.cpp +++ b/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;