DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include <string.h> 00021 #include "dosbox.h" 00022 #include "callback.h" 00023 #include "mem.h" 00024 #include "regs.h" 00025 #include "bios_disk.h" 00026 #include "dos_inc.h" 00027 #include "drives.h" 00028 00029 bool DOS_IOCTL_AX440D_CH08(Bit8u drive,bool query) { 00030 PhysPt ptr = SegPhys(ds)+reg_dx; 00031 switch (reg_cl) { 00032 case 0x40: /* Set device parameters */ 00033 { 00034 if (strncmp(Drives[drive]->GetInfo(),"fatDrive ",9)) { 00035 DOS_SetError(DOSERR_ACCESS_DENIED); 00036 return false; 00037 } 00038 fatDrive *fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00039 if (fdp == NULL || fdp->readonly) { 00040 DOS_SetError(DOSERR_ACCESS_DENIED); 00041 return false; 00042 } 00043 00044 if (query) break; 00045 00046 FAT_BootSector::bpb_union_t bpb=fdp->GetBPB(); 00047 if (fdp->loadedDisk != NULL) 00048 fdp->loadedDisk->cylinders = mem_readw(ptr+4); // number of cylinders 00049 00050 if (mem_readw(ptr+0xd) == 0 && mem_readw(ptr+0xf) == 0 && mem_readw(ptr+0x12) == 0) { // FAT32 BPB? 00051 bpb.v32.BPB_BytsPerSec = mem_readw(ptr+7); // bytes per sector (Win3 File Mgr. uses it) 00052 bpb.v32.BPB_SecPerClus = mem_readb(ptr+9); // sectors per cluster 00053 bpb.v32.BPB_RsvdSecCnt = mem_readw(ptr+0xa); // number of reserved sectors 00054 bpb.v32.BPB_NumFATs = mem_readb(ptr+0xc); // number of FATs 00055 bpb.v32.BPB_RootEntCnt = mem_readw(ptr+0xd); // number of root entries (Fake, the real BPB value is zero) 00056 bpb.v32.BPB_TotSec16 = mem_readw(ptr+0xf); // number of small sectors (always zero on BPB and returned by Win98) 00057 bpb.v32.BPB_Media = mem_readb(ptr+0x11); // media type 00058 bpb.v32.BPB_FATSz32 = (uint16_t)mem_readw(ptr+0x12); // sectors per FAT (FIXME: What does Win98 do if this value > 0xFFFF?) 00059 bpb.v32.BPB_SecPerTrk = (uint16_t)mem_readw(ptr+0x14); // sectors per track 00060 bpb.v32.BPB_NumHeads = (uint16_t)mem_readw(ptr+0x16); // number of heads 00061 bpb.v32.BPB_HiddSec = (uint32_t)mem_readd(ptr+0x18); // number of hidden sectors 00062 bpb.v32.BPB_TotSec32 = (uint32_t)mem_readd(ptr+0x1c); // number of big sectors 00063 } else { 00064 bpb.v.BPB_BytsPerSec = mem_readw(ptr+7); // bytes per sector (Win3 File Mgr. uses it) 00065 bpb.v.BPB_SecPerClus = mem_readb(ptr+9); // sectors per cluster 00066 bpb.v.BPB_RsvdSecCnt = mem_readw(ptr+0xa); // number of reserved sectors 00067 bpb.v.BPB_NumFATs = mem_readb(ptr+0xc); // number of FATs 00068 bpb.v.BPB_RootEntCnt = mem_readw(ptr+0xd); // number of root entries 00069 bpb.v.BPB_TotSec16 = mem_readw(ptr+0xf); // number of small sectors 00070 bpb.v.BPB_Media = mem_readb(ptr+0x11); // media type 00071 bpb.v.BPB_FATSz16 = (uint16_t)mem_readw(ptr+0x12); // sectors per FAT 00072 bpb.v.BPB_SecPerTrk = (uint16_t)mem_readw(ptr+0x14); // sectors per track 00073 bpb.v.BPB_NumHeads = (uint16_t)mem_readw(ptr+0x16); // number of heads 00074 bpb.v.BPB_HiddSec = (uint32_t)mem_readd(ptr+0x18); // number of hidden sectors 00075 bpb.v.BPB_TotSec32 = (uint32_t)mem_readd(ptr+0x1c); // number of big sectors 00076 } 00077 fdp->SetBPB(bpb); 00078 break; 00079 } 00080 case 0x60: /* Get device parameters */ 00081 if (query) break; 00082 { 00083 //mem_writeb(ptr+0,0); // special functions (call value) 00084 mem_writeb(ptr+1,(drive>=2)?0x05:0x07); // type: hard disk(5), 1.44 floppy(7) 00085 mem_writew(ptr+2,(drive>=2)?0x01:0x00); // attributes: bit 0 set for nonremovable 00086 mem_writew(ptr+4,(drive>=2)?0x3FF:0x50);// number of cylinders 00087 mem_writeb(ptr+6,0x00); // media type (00=other type) 00088 // bios parameter block following 00089 fatDrive *fdp; 00090 FAT_BootSector::bpb_union_t bpb; 00091 bool usereal=false; 00092 if (!strncmp(Drives[drive]->GetInfo(),"fatDrive ",9)) { 00093 fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00094 if (fdp != NULL) { 00095 bpb=fdp->GetBPB(); 00096 if (bpb.v.BPB_BytsPerSec && bpb.v.BPB_Media) 00097 usereal=true; 00098 } 00099 } 00100 if (usereal) { 00101 if (fdp->loadedDisk != NULL) 00102 mem_writew(ptr+4,fdp->loadedDisk->cylinders); // number of cylinders 00103 00104 if (bpb.is_fat32()) { 00105 /* Windows 98 behavior: Some of the FAT32 BPB fields are translated into FAT16 BPB fields even though those fields are zero in the actual BPB */ 00106 mem_writew(ptr+7,bpb.v32.BPB_BytsPerSec); // bytes per sector (Win3 File Mgr. uses it) 00107 mem_writeb(ptr+9,bpb.v32.BPB_SecPerClus); // sectors per cluster 00108 mem_writew(ptr+0xa,bpb.v32.BPB_RsvdSecCnt); // number of reserved sectors 00109 mem_writeb(ptr+0xc,bpb.v32.BPB_NumFATs); // number of FATs 00110 mem_writew(ptr+0xd,0x200); // number of root entries (Fake, the real BPB value is zero) 00111 mem_writew(ptr+0xf,0); // number of small sectors (always zero on BPB and returned by Win98) 00112 mem_writeb(ptr+0x11,bpb.v32.BPB_Media); // media type 00113 mem_writew(ptr+0x12,(uint16_t)bpb.v32.BPB_FATSz32); // sectors per FAT (FIXME: What does Win98 do if this value > 0xFFFF?) 00114 mem_writew(ptr+0x14,(uint16_t)bpb.v32.BPB_SecPerTrk); // sectors per track 00115 mem_writew(ptr+0x16,(uint16_t)bpb.v32.BPB_NumHeads); // number of heads 00116 mem_writed(ptr+0x18,(uint32_t)bpb.v32.BPB_HiddSec); // number of hidden sectors 00117 mem_writed(ptr+0x1c,(uint32_t)bpb.v32.BPB_TotSec32); // number of big sectors 00118 } 00119 else { 00120 mem_writew(ptr+7,bpb.v.BPB_BytsPerSec); // bytes per sector (Win3 File Mgr. uses it) 00121 mem_writeb(ptr+9,bpb.v.BPB_SecPerClus); // sectors per cluster 00122 mem_writew(ptr+0xa,bpb.v.BPB_RsvdSecCnt); // number of reserved sectors 00123 mem_writeb(ptr+0xc,bpb.v.BPB_NumFATs); // number of FATs 00124 mem_writew(ptr+0xd,bpb.v.BPB_RootEntCnt); // number of root entries 00125 mem_writew(ptr+0xf,bpb.v.BPB_TotSec16); // number of small sectors 00126 mem_writeb(ptr+0x11,bpb.v.BPB_Media); // media type 00127 mem_writew(ptr+0x12,(uint16_t)bpb.v.BPB_FATSz16); // sectors per FAT 00128 mem_writew(ptr+0x14,(uint16_t)bpb.v.BPB_SecPerTrk); // sectors per track 00129 mem_writew(ptr+0x16,(uint16_t)bpb.v.BPB_NumHeads); // number of heads 00130 mem_writed(ptr+0x18,(uint32_t)bpb.v.BPB_HiddSec); // number of hidden sectors 00131 mem_writed(ptr+0x1c,(uint32_t)bpb.v.BPB_TotSec32); // number of big sectors 00132 } 00133 } else { 00134 mem_writew(ptr+7,0x0200); // bytes per sector (Win3 File Mgr. uses it) 00135 mem_writew(ptr+9,(drive>=2)?0x20:0x01); // sectors per cluster 00136 mem_writew(ptr+0xa,0x0001); // number of reserved sectors 00137 mem_writew(ptr+0xc,0x02); // number of FATs 00138 mem_writew(ptr+0xd,(drive>=2)?0x0200:0x00E0); // number of root entries 00139 mem_writew(ptr+0xf,(drive>=2)?0x0000:0x0B40); // number of small sectors 00140 mem_writew(ptr+0x11,(drive>=2)?0xF8:0xF0); // media type 00141 mem_writew(ptr+0x12,(drive>=2)?0x00C9:0x0009); // sectors per FAT 00142 mem_writew(ptr+0x14,(drive>=2)?0x003F:0x0012); // sectors per track 00143 mem_writew(ptr+0x16,(drive>=2)?0x10:0x02); // number of heads 00144 mem_writed(ptr+0x18,0); // number of hidden sectors 00145 mem_writed(ptr+0x1c,(drive>=2)?0x31F11:0x00); // number of big sectors 00146 } 00147 for (int i=0x20; i<0x22; i++) 00148 mem_writeb(ptr+i,0); 00149 break; 00150 } 00151 case 0x42: /* Format and verify logical device track (FORMAT.COM) */ 00152 { 00153 /* 01h WORD number of disk head 00154 * 03h WORD number of disk cylinder 00155 * ---BYTE 00h bit 1 set--- 00156 * 05h WORD number of tracks to format */ 00157 Bit8u flags = mem_readb(ptr+0); 00158 Bit16u head = mem_readw(ptr+1); 00159 Bit16u cyl = mem_readw(ptr+3); 00160 Bit16u ntracks = (flags & 0x1) ? mem_readw(ptr+5) : 1; 00161 Bit16u sect = 0; 00162 00163 fatDrive *fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00164 if (fdp == NULL || fdp->readonly) { 00165 DOS_SetError(DOSERR_ACCESS_DENIED); 00166 return false; 00167 } 00168 00169 if (query) break; 00170 00171 /* BUT: These are C/H/S values relative to the partition! 00172 * FIXME: MS-DOS may not adjust sector value, or maybe it does... 00173 * perhaps there is a reason Linux fdisk warns about sector alignment to sect/track for MS-DOS partitions? */ 00174 { 00175 Bit32u adj = fdp->GetPartitionOffset(); 00176 sect += adj % fdp->loadedDisk->sectors; 00177 adj /= fdp->loadedDisk->sectors; 00178 head += adj % fdp->loadedDisk->heads; 00179 adj /= fdp->loadedDisk->heads; 00180 cyl += adj; 00181 00182 while (sect >= fdp->loadedDisk->sectors) { 00183 sect -= fdp->loadedDisk->sectors; 00184 head++; 00185 } 00186 while (head >= fdp->loadedDisk->heads) { 00187 head -= fdp->loadedDisk->heads; 00188 cyl++; 00189 } 00190 00191 /* finally, MS-DOS counts sectors from 0 and BIOS INT 13h counts from 1 */ 00192 sect++; 00193 } 00194 00195 // STUB! 00196 LOG(LOG_IOCTL,LOG_DEBUG)("DOS:IOCTL Call 0D:42 Drive %2X pretending to format device track C/H/S=%u/%u/%u ntracks=%u",drive,cyl,head,sect,ntracks); 00197 } 00198 break; 00199 case 0x62: /* Verify logical device track (FORMAT.COM) */ 00200 { 00201 /* 01h WORD number of disk head 00202 * 03h WORD number of disk cylinder 00203 * 05h WORD number of tracks to verify */ 00204 Bit16u head = mem_readw(ptr+1); 00205 Bit16u cyl = mem_readw(ptr+3); 00206 Bit16u ntracks = mem_readw(ptr+5); 00207 Bit16u sect = 0; 00208 00209 fatDrive *fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00210 if (fdp == NULL) { 00211 DOS_SetError(DOSERR_ACCESS_DENIED); 00212 return false; 00213 } 00214 00215 if (query) break; 00216 00217 /* BUT: These are C/H/S values relative to the partition! 00218 * FIXME: MS-DOS may not adjust sector value, or maybe it does... 00219 * perhaps there is a reason Linux fdisk warns about sector alignment to sect/track for MS-DOS partitions? */ 00220 { 00221 Bit32u adj = fdp->GetPartitionOffset(); 00222 sect += adj % fdp->loadedDisk->sectors; 00223 adj /= fdp->loadedDisk->sectors; 00224 head += adj % fdp->loadedDisk->heads; 00225 adj /= fdp->loadedDisk->heads; 00226 cyl += adj; 00227 00228 while (sect >= fdp->loadedDisk->sectors) { 00229 sect -= fdp->loadedDisk->sectors; 00230 head++; 00231 } 00232 while (head >= fdp->loadedDisk->heads) { 00233 head -= fdp->loadedDisk->heads; 00234 cyl++; 00235 } 00236 00237 /* finally, MS-DOS counts sectors from 0 and BIOS INT 13h counts from 1 */ 00238 sect++; 00239 } 00240 00241 // STUB! 00242 LOG(LOG_IOCTL,LOG_DEBUG)("DOS:IOCTL Call 0D:62 Drive %2X pretending to verify device track C/H/S=%u/%u/%u ntracks=%u",drive,cyl,head,sect,ntracks); 00243 } 00244 break; 00245 case 0x46: /* Set volume serial number */ 00246 if (query) break; 00247 { 00248 fatDrive* fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00249 if (fdp == NULL || fdp->readonly) { 00250 DOS_SetError(DOSERR_ACCESS_DENIED); 00251 return false; 00252 } 00253 00254 FAT_BootSector::bpb_union_t bpb=fdp->GetBPB(); 00255 unsigned long serial_number=mem_readd(ptr+2)?mem_readd(ptr+2):0x1234; 00256 if (bpb.is_fat32()) 00257 bpb.v32.BS_VolID=serial_number; 00258 else 00259 bpb.v.BPB_VolID=serial_number; 00260 fdp->SetBPB(bpb); 00261 } 00262 break; 00263 case 0x66: /* Get volume serial number */ 00264 if (query) break; 00265 { 00266 char const* bufin=Drives[drive]->GetLabel(); 00267 char buffer[11];memset(buffer,' ',11); 00268 00269 char const* find_ext=strchr(bufin,'.'); 00270 if (find_ext) { 00271 Bitu size=(Bitu)(find_ext-bufin); 00272 if (size>8) size=8; 00273 memcpy(buffer,bufin,size); 00274 find_ext++; 00275 memcpy(buffer+8,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); 00276 } else { 00277 memcpy(buffer,bufin,(strlen(bufin) > 8) ? 8 : strlen(bufin)); 00278 } 00279 00280 char buf2[8]={ 'F','A','T','1','6',' ',' ',' '}; 00281 if(drive<2) buf2[4] = '2'; //FAT12 for floppies 00282 00283 //mem_writew(ptr+0,0); //Info level (call value) 00284 unsigned long serial_number=0x1234; 00285 if (!strncmp(Drives[drive]->GetInfo(),"fatDrive ",9)) { 00286 fatDrive* fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00287 if (fdp != NULL) serial_number=fdp->GetSerial(); 00288 } 00289 #if defined (WIN32) 00290 if (!strncmp(Drives[drive]->GetInfo(),"local ",6) || !strncmp(Drives[drive]->GetInfo(),"CDRom ",6)) { 00291 localDrive* ldp = !strncmp(Drives[drive]->GetInfo(),"local ",6)?dynamic_cast<localDrive*>(Drives[drive]):dynamic_cast<cdromDrive*>(Drives[drive]); 00292 if (ldp != NULL) serial_number=ldp->GetSerial(); 00293 } 00294 #endif 00295 mem_writed(ptr+2,serial_number);//Serial number 00296 MEM_BlockWrite(ptr+6,buffer,11);//volumename 00297 MEM_BlockWrite(ptr+0x11,buf2,8);//filesystem 00298 } 00299 break; 00300 case 0x41: /* Write logical device track */ 00301 { 00302 fatDrive *fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00303 if (fdp == NULL || fdp->readonly) { 00304 DOS_SetError(DOSERR_ACCESS_DENIED); 00305 return false; 00306 } 00307 00308 Bit8u sectbuf[SECTOR_SIZE_MAX]; 00309 00310 if (fdp->loadedDisk == NULL) { 00311 DOS_SetError(DOSERR_ACCESS_DENIED); 00312 return false; 00313 } 00314 00315 if (query) break; 00316 00317 /* (RBIL) [http://www.ctyme.com/intr/rb-2896.htm] 00318 * Offset Size Description (Table 01562) 00319 * 00h BYTE special functions (reserved, must be zero) 00320 * 01h WORD number of disk head 00321 * 03h WORD number of disk cylinder 00322 * 05h WORD number of first sector to read/write 00323 * 07h WORD number of sectors 00324 * 09h DWORD transfer address */ 00325 Bit16u head = mem_readw(ptr+1); 00326 Bit16u cyl = mem_readw(ptr+3); 00327 Bit16u sect = mem_readw(ptr+5); 00328 Bit16u nsect = mem_readw(ptr+7); 00329 Bit32u xfer_addr = mem_readd(ptr+9); 00330 PhysPt xfer_ptr = ((xfer_addr>>16u)<<4u)+(xfer_addr&0xFFFFu); 00331 Bit16u sectsize = fdp->loadedDisk->getSectSize(); 00332 00333 /* BUT: These are C/H/S values relative to the partition! 00334 * FIXME: MS-DOS may not adjust sector value, or maybe it does... 00335 * perhaps there is a reason Linux fdisk warns about sector alignment to sect/track for MS-DOS partitions? */ 00336 { 00337 Bit32u adj = fdp->GetPartitionOffset(); 00338 sect += adj % fdp->loadedDisk->sectors; 00339 adj /= fdp->loadedDisk->sectors; 00340 head += adj % fdp->loadedDisk->heads; 00341 adj /= fdp->loadedDisk->heads; 00342 cyl += adj; 00343 00344 while (sect >= fdp->loadedDisk->sectors) { 00345 sect -= fdp->loadedDisk->sectors; 00346 head++; 00347 } 00348 while (head >= fdp->loadedDisk->heads) { 00349 head -= fdp->loadedDisk->heads; 00350 cyl++; 00351 } 00352 00353 /* finally, MS-DOS counts sectors from 0 and BIOS INT 13h counts from 1 */ 00354 sect++; 00355 } 00356 00357 LOG(LOG_IOCTL,LOG_DEBUG)("DOS:IOCTL Call 0D:41 Write Logical Device Track from Drive %2X C/H/S=%u/%u/%u num=%u from %04x:%04x sz=%u", 00358 drive,cyl,head,sect,nsect,xfer_addr >> 16,xfer_addr & 0xFFFF,sectsize); 00359 00360 while (nsect > 0) { 00361 MEM_BlockRead(xfer_ptr,sectbuf,sectsize); 00362 00363 Bit8u status = fdp->loadedDisk->Write_Sector(head,cyl,sect,sectbuf); 00364 if (status != 0) { 00365 LOG(LOG_IOCTL,LOG_DEBUG)("IOCTL 0D:61 write error at C/H/S %u/%u/%u",cyl,head,sect); 00366 DOS_SetError(DOSERR_ACCESS_DENIED);//FIXME 00367 return false; 00368 } 00369 00370 xfer_ptr += sectsize; 00371 nsect--; 00372 sect++; 00373 } 00374 } 00375 break; 00376 case 0x61: /* Read logical device track */ 00377 { 00378 fatDrive *fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00379 if (fdp == NULL) { 00380 DOS_SetError(DOSERR_ACCESS_DENIED); 00381 return false; 00382 } 00383 00384 Bit8u sectbuf[SECTOR_SIZE_MAX]; 00385 00386 if (fdp->loadedDisk == NULL) { 00387 DOS_SetError(DOSERR_ACCESS_DENIED); 00388 return false; 00389 } 00390 00391 if (query) break; 00392 00393 /* (RBIL) [http://www.ctyme.com/intr/rb-2896.htm] 00394 * Offset Size Description (Table 01562) 00395 * 00h BYTE special functions (reserved, must be zero) 00396 * 01h WORD number of disk head 00397 * 03h WORD number of disk cylinder 00398 * 05h WORD number of first sector to read/write 00399 * 07h WORD number of sectors 00400 * 09h DWORD transfer address */ 00401 Bit16u head = mem_readw(ptr+1); 00402 Bit16u cyl = mem_readw(ptr+3); 00403 Bit16u sect = mem_readw(ptr+5); 00404 Bit16u nsect = mem_readw(ptr+7); 00405 Bit32u xfer_addr = mem_readd(ptr+9); 00406 PhysPt xfer_ptr = ((xfer_addr>>16u)<<4u)+(xfer_addr&0xFFFFu); 00407 Bit16u sectsize = fdp->loadedDisk->getSectSize(); 00408 00409 /* BUT: These are C/H/S values relative to the partition! 00410 * FIXME: MS-DOS may not adjust sector value, or maybe it does... 00411 * perhaps there is a reason Linux fdisk warns about sector alignment to sect/track for MS-DOS partitions? */ 00412 { 00413 Bit32u adj = fdp->GetPartitionOffset();; 00414 sect += adj % fdp->loadedDisk->sectors; 00415 adj /= fdp->loadedDisk->sectors; 00416 head += adj % fdp->loadedDisk->heads; 00417 adj /= fdp->loadedDisk->heads; 00418 cyl += adj; 00419 00420 while (sect >= fdp->loadedDisk->sectors) { 00421 sect -= fdp->loadedDisk->sectors; 00422 head++; 00423 } 00424 while (head >= fdp->loadedDisk->heads) { 00425 head -= fdp->loadedDisk->heads; 00426 cyl++; 00427 } 00428 00429 /* finally, MS-DOS counts sectors from 0 and BIOS INT 13h counts from 1 */ 00430 sect++; 00431 } 00432 00433 LOG(LOG_IOCTL,LOG_DEBUG)("DOS:IOCTL Call 0D:61 Read Logical Device Track from Drive %2X C/H/S=%u/%u/%u num=%u to %04x:%04x sz=%u", 00434 drive,cyl,head,sect,nsect,xfer_addr >> 16,xfer_addr & 0xFFFF,sectsize); 00435 00436 while (nsect > 0) { 00437 Bit8u status = fdp->loadedDisk->Read_Sector(head,cyl,sect,sectbuf); 00438 if (status != 0) { 00439 LOG(LOG_IOCTL,LOG_DEBUG)("IOCTL 0D:61 read error at C/H/S %u/%u/%u",cyl,head,sect); 00440 DOS_SetError(DOSERR_ACCESS_DENIED);//FIXME 00441 return false; 00442 } 00443 00444 MEM_BlockWrite(xfer_ptr,sectbuf,sectsize); 00445 xfer_ptr += sectsize; 00446 nsect--; 00447 sect++; 00448 } 00449 } 00450 break; 00451 case 0x4A: 00452 case 0x4B: 00453 case 0x6A: 00454 case 0x6B: 00455 if (query) break; 00456 LOG(LOG_IOCTL,LOG_ERROR)("DOS:IOCTL Call 0D:%2X Drive %2X volume/drive locking IOCTL, faking it",reg_cl,drive); 00457 break; 00458 case 0x67: /* Get access flag (whether allowed by driver) */ 00459 if (query) break; 00460 /* In DOSBox-X, disk access is always allowed. 00461 * Real MS-DOS might be more restrictive, especially Windows 95 which requires volume locking before disk access is allowed */ 00462 /* FDISK.EXE needs this IOCTL to determine whether it can read the partition and therefore whether the "system type" is "FAT16", "FAT12", "unknown" etc. */ 00463 /* ptr+0 = special function (always zero) 00464 * ptr+1 = return whether access allowed */ 00465 mem_writeb(ptr+1,0x01); 00466 break; 00467 default: 00468 LOG(LOG_IOCTL,LOG_ERROR)("DOS:IOCTL %s %2X:%2X Drive %2X unhandled (CH=08h)",query?"Query":"Call",reg_al,reg_cl,drive); 00469 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00470 return false; 00471 } 00472 reg_ax=0; 00473 return true; 00474 } 00475 00476 bool DOS_IOCTL_AX440D_CH48(Bit8u drive,bool query) { 00477 PhysPt ptr = SegPhys(ds)+reg_dx; 00478 switch (reg_cl) { 00479 case 0x40: /* Set device parameters */ 00480 { 00481 if (strncmp(Drives[drive]->GetInfo(),"fatDrive ",9)) { 00482 DOS_SetError(DOSERR_ACCESS_DENIED); 00483 return false; 00484 } 00485 fatDrive *fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00486 if (fdp == NULL || fdp->readonly) { 00487 DOS_SetError(DOSERR_ACCESS_DENIED); 00488 return false; 00489 } 00490 00491 if (query) break; 00492 00493 FAT_BootSector::bpb_union_t bpb=fdp->GetBPB(); 00494 if (fdp->loadedDisk != NULL) 00495 fdp->loadedDisk->cylinders = mem_readw(ptr+4); // number of cylinders 00496 00497 if (mem_readw(ptr+0xd) == 0 && mem_readw(ptr+0xf) == 0 && mem_readw(ptr+0x12) == 0) { // FAT32 BPB? 00498 bpb.v.BPB_BytsPerSec = mem_readw(ptr+7); // bytes per sector (Win3 File Mgr. uses it) 00499 bpb.v.BPB_SecPerClus = mem_readb(ptr+9); // sectors per cluster 00500 bpb.v.BPB_RsvdSecCnt = mem_readw(ptr+0xa); // number of reserved sectors 00501 bpb.v.BPB_NumFATs = mem_readb(ptr+0xc); // number of FATs 00502 bpb.v.BPB_RootEntCnt = mem_readw(ptr+0xd); // number of root entries 00503 bpb.v.BPB_TotSec16 = mem_readw(ptr+0xf); // number of small sectors 00504 bpb.v.BPB_Media = mem_readb(ptr+0x11); // media type 00505 bpb.v.BPB_FATSz16 = (uint16_t)mem_readw(ptr+0x12); // sectors per FAT 00506 bpb.v.BPB_SecPerTrk = (uint16_t)mem_readw(ptr+0x14); // sectors per track 00507 bpb.v.BPB_NumHeads = (uint16_t)mem_readw(ptr+0x16); // number of heads 00508 bpb.v.BPB_HiddSec = (uint32_t)mem_readd(ptr+0x18); // number of hidden sectors 00509 bpb.v.BPB_TotSec32 = (uint32_t)mem_readd(ptr+0x1c); // number of big sectors 00510 bpb.v32.BPB_FATSz32 = (uint32_t)mem_readd(ptr+0x20); // sectors per FAT 00511 bpb.v32.BPB_ExtFlags = (uint16_t)mem_readw(ptr+0x24); 00512 bpb.v32.BPB_FSVer = (uint16_t)mem_readw(ptr+0x26); 00513 bpb.v32.BPB_RootClus = (uint32_t)mem_readd(ptr+0x28); 00514 bpb.v32.BPB_FSInfo = (uint16_t)mem_readw(ptr+0x2C); 00515 bpb.v32.BPB_BkBootSec = (uint16_t)mem_readw(ptr+0x2E); 00516 fdp->SetBPB(bpb); 00517 } else { 00518 DOS_SetError(DOSERR_ACCESS_DENIED); 00519 return false; 00520 } 00521 break; 00522 } 00523 case 0x60: /* Get device parameters */ 00524 if (query) break; 00525 { 00526 //mem_writeb(ptr+0,0); // special functions (call value) 00527 mem_writeb(ptr+1,(drive>=2)?0x05:0x07); // type: hard disk(5), 1.44 floppy(7) 00528 mem_writew(ptr+2,(drive>=2)?0x01:0x00); // attributes: bit 0 set for nonremovable 00529 mem_writew(ptr+4,(drive>=2)?0x3FF:0x50);// num of cylinders 00530 mem_writeb(ptr+6,0x00); // media type (00=other type) 00531 // bios parameter block following 00532 fatDrive *fdp; 00533 FAT_BootSector::bpb_union_t bpb; 00534 bool usereal=false; 00535 if (!strncmp(Drives[drive]->GetInfo(),"fatDrive ",9)) { 00536 fdp = dynamic_cast<fatDrive*>(Drives[drive]); 00537 if (fdp != NULL) { 00538 bpb=fdp->GetBPB(); 00539 if (bpb.v.BPB_BytsPerSec && bpb.v.BPB_Media) 00540 usereal=true; 00541 } 00542 } 00543 if (usereal) { 00544 if (fdp->loadedDisk != NULL) 00545 mem_writew(ptr+4,fdp->loadedDisk->cylinders); // num of cylinders 00546 00547 if (bpb.is_fat32()) { 00548 mem_writew(ptr+7,bpb.v.BPB_BytsPerSec); // bytes per sector (Win3 File Mgr. uses it) 00549 mem_writeb(ptr+9,bpb.v.BPB_SecPerClus); // sectors per cluster 00550 mem_writew(ptr+0xa,bpb.v.BPB_RsvdSecCnt); // number of reserved sectors 00551 mem_writeb(ptr+0xc,bpb.v.BPB_NumFATs); // number of FATs 00552 mem_writew(ptr+0xd,bpb.v.BPB_RootEntCnt); // number of root entries 00553 mem_writew(ptr+0xf,bpb.v.BPB_TotSec16); // number of small sectors 00554 mem_writeb(ptr+0x11,bpb.v.BPB_Media); // media type 00555 mem_writew(ptr+0x12,(uint16_t)bpb.v.BPB_FATSz16); // sectors per FAT 00556 mem_writew(ptr+0x14,(uint16_t)bpb.v.BPB_SecPerTrk); // sectors per track 00557 mem_writew(ptr+0x16,(uint16_t)bpb.v.BPB_NumHeads); // number of heads 00558 mem_writed(ptr+0x18,(uint32_t)bpb.v.BPB_HiddSec); // number of hidden sectors 00559 mem_writed(ptr+0x1c,(uint32_t)bpb.v.BPB_TotSec32); // number of big sectors 00560 mem_writed(ptr+0x20,(uint32_t)bpb.v32.BPB_FATSz32); // sectors per FAT 00561 mem_writew(ptr+0x24,(uint16_t)bpb.v32.BPB_ExtFlags); 00562 mem_writew(ptr+0x26,(uint16_t)bpb.v32.BPB_FSVer); 00563 mem_writed(ptr+0x28,(uint32_t)bpb.v32.BPB_RootClus); 00564 mem_writew(ptr+0x2C,(uint16_t)bpb.v32.BPB_FSInfo); 00565 mem_writew(ptr+0x2E,(uint16_t)bpb.v32.BPB_BkBootSec); 00566 } 00567 else { 00568 DOS_SetError(DOSERR_ACCESS_DENIED); 00569 return false; 00570 } 00571 } else { 00572 DOS_SetError(DOSERR_ACCESS_DENIED); 00573 return false; 00574 } 00575 break; 00576 } 00577 case 0x42: 00578 case 0x46: 00579 case 0x4A: 00580 case 0x4B: 00581 case 0x61: 00582 case 0x62: 00583 case 0x66: 00584 case 0x6A: 00585 case 0x6B: 00586 return DOS_IOCTL_AX440D_CH08(drive,query); 00587 default: 00588 LOG(LOG_IOCTL,LOG_ERROR)("DOS:IOCTL Call %02X:%2X Drive %2X unhandled (CH=48h)",reg_al,reg_cl,drive); 00589 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00590 return false; 00591 } 00592 reg_ax=0; 00593 return true; 00594 } 00595 00596 bool DOS_IOCTL(void) { 00597 Bitu handle=0;Bit8u drive=0; 00598 /* calls 0-4,6,7,10,12,16 use a file handle */ 00599 if ((reg_al<4) || (reg_al==0x06) || (reg_al==0x07) || (reg_al==0x0a) || (reg_al==0x0c) || (reg_al==0x10)) { 00600 handle=RealHandle(reg_bx); 00601 if (handle>=DOS_FILES) { 00602 DOS_SetError(DOSERR_INVALID_HANDLE); 00603 return false; 00604 } 00605 if (!Files[handle]) { 00606 DOS_SetError(DOSERR_INVALID_HANDLE); 00607 return false; 00608 } 00609 } else if (reg_al<0x12) { /* those use a diskdrive except 0x0b */ 00610 if (reg_al!=0x0b) { 00611 drive=reg_bl; 00612 if ((reg_al==0x0D||reg_al==0x11) && (reg_cl==0x4B||reg_cl==0x6B)) drive=reg_bh; 00613 if (!drive) drive = DOS_GetDefaultDrive();else drive--; 00614 if( (drive >= 2) && !(( drive < DOS_DRIVES ) && Drives[drive]) ) { 00615 DOS_SetError(DOSERR_INVALID_DRIVE); 00616 return false; 00617 } 00618 } 00619 } else { 00620 LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al); 00621 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00622 return false; 00623 } 00624 switch(reg_al) { 00625 case 0x00: /* Get Device Information */ 00626 if (Files[handle]->GetInformation() & 0x8000) { //Check for device 00627 reg_dx=Files[handle]->GetInformation(); 00628 } else { 00629 Bit8u hdrive=Files[handle]->GetDrive(); 00630 if (hdrive==0xff) { 00631 LOG(LOG_IOCTL,LOG_NORMAL)("00:No drive set"); 00632 hdrive=2; // defaulting to C: 00633 } 00634 /* return drive number in lower 5 bits for block devices */ 00635 reg_dx=(Files[handle]->GetInformation()&0xffe0)|hdrive; 00636 } 00637 reg_ax=reg_dx; //Destroyed officially 00638 return true; 00639 case 0x01: /* Set Device Information */ 00640 if (reg_dh != 0) { 00641 DOS_SetError(DOSERR_DATA_INVALID); 00642 return false; 00643 } else { 00644 if (Files[handle]->GetInformation() & 0x8000) { //Check for device 00645 reg_al=(Bit8u)(Files[handle]->GetInformation() & 0xff); 00646 } else { 00647 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00648 return false; 00649 } 00650 } 00651 return true; 00652 case 0x02: /* Read from Device Control Channel */ 00653 if (Files[handle]->GetInformation() & 0xc000) { 00654 /* is character device with IOCTL support */ 00655 PhysPt bufptr=PhysMake(SegValue(ds),reg_dx); 00656 Bit16u retcode=0; 00657 if (((DOS_Device*)(Files[handle]))->ReadFromControlChannel(bufptr,reg_cx,&retcode)) { 00658 reg_ax=retcode; 00659 return true; 00660 } 00661 } 00662 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00663 return false; 00664 case 0x03: /* Write to Device Control Channel */ 00665 if (Files[handle]->GetInformation() & 0xc000) { 00666 /* is character device with IOCTL support */ 00667 PhysPt bufptr=PhysMake(SegValue(ds),reg_dx); 00668 Bit16u retcode=0; 00669 if (((DOS_Device*)(Files[handle]))->WriteToControlChannel(bufptr,reg_cx,&retcode)) { 00670 reg_ax=retcode; 00671 return true; 00672 } 00673 } 00674 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00675 return false; 00676 case 0x06: /* Get Input Status */ 00677 if (Files[handle]->GetInformation() & 0x8000) { //Check for device 00678 reg_al=(Files[handle]->GetInformation() & 0x40) ? 0x0 : 0xff; 00679 } else { // FILE 00680 Bit32u oldlocation=0; 00681 Files[handle]->Seek(&oldlocation, DOS_SEEK_CUR); 00682 Bit32u endlocation=0; 00683 Files[handle]->Seek(&endlocation, DOS_SEEK_END); 00684 if(oldlocation < endlocation){//Still data available 00685 reg_al=0xff; 00686 } else { 00687 reg_al=0x0; //EOF or beyond 00688 } 00689 Files[handle]->Seek(&oldlocation, DOS_SEEK_SET); //restore filelocation 00690 LOG(LOG_IOCTL,LOG_NORMAL)("06:Used Get Input Status on regular file with handle %d",(int)handle); 00691 } 00692 return true; 00693 case 0x07: /* Get Output Status */ 00694 LOG(LOG_IOCTL,LOG_NORMAL)("07:Fakes output status is ready for handle %d",(int)handle); 00695 reg_al=0xff; 00696 return true; 00697 case 0x08: /* Check if block device removable */ 00698 /* cdrom drives and drive a&b are removable */ 00699 if (drive < 2) { 00700 if (Drives[drive]) 00701 reg_ax=0; 00702 else { 00703 DOS_SetError(DOSERR_INVALID_DRIVE); 00704 return false; 00705 } 00706 } else if (!Drives[drive]->isRemovable()) reg_ax=1; 00707 else { 00708 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00709 return false; 00710 } 00711 return true; 00712 case 0x09: /* Check if block device remote */ 00713 if ((drive >= 2) && Drives[drive]->isRemote()) { 00714 reg_dx=0x1000; // device is remote 00715 // undocumented bits always clear 00716 } else { 00717 reg_dx=0x0802; // Open/Close supported; 32bit access supported (any use? fixes Fable installer) 00718 // undocumented bits from device attribute word 00719 // TODO Set bit 9 on drives that don't support direct I/O 00720 } 00721 reg_ax=0x300; 00722 return true; 00723 case 0x0A: /* Is Device of Handle Remote? */ 00724 reg_dx=0x8000; 00725 LOG(LOG_IOCTL,LOG_NORMAL)("0A:Faked output: device of handle %d is remote",(int)handle); 00726 return true; 00727 case 0x0B: /* Set sharing retry count */ 00728 if (reg_dx==0) { 00729 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00730 return false; 00731 } 00732 return true; 00733 case 0x0D: /* Generic block device request */ 00734 case 0x11: /* query generic ioctl capability */ 00735 { 00736 if (drive < 2 && !Drives[drive]) { 00737 DOS_SetError(DOSERR_ACCESS_DENIED); 00738 return false; 00739 } 00740 if (Drives[drive]->isRemovable()) { 00741 LOG(LOG_IOCTL,LOG_DEBUG)("Attempt IOCTL AX=%04x CX=%04x on removable drive",reg_ax,reg_cx); 00742 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00743 return false; 00744 } 00745 if (reg_ch == 0x08) { 00746 return DOS_IOCTL_AX440D_CH08(drive,reg_al==0x11); 00747 } 00748 else if (reg_ch == 0x48) { 00749 return DOS_IOCTL_AX440D_CH48(drive,reg_al==0x11); // Same functions as CH=08h but for FAT32 drives 00750 } 00751 else { 00752 LOG(LOG_IOCTL,LOG_DEBUG)("Attempt IOCTL AX=%04x CX=%04x",reg_ax,reg_cx); 00753 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00754 return false; 00755 } 00756 } 00757 break; 00758 case 0x0E: /* Get Logical Drive Map */ 00759 if (drive < 2) { 00760 if (Drives[drive]) reg_al=drive+1; 00761 else reg_al=1; 00762 } else if (Drives[drive]->isRemovable()) { 00763 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00764 return false; 00765 } else reg_al=0; /* Only 1 logical drive assigned */ 00766 reg_ah=0x07; 00767 return true; 00768 default: 00769 LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al); 00770 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); 00771 break; 00772 } 00773 return false; 00774 } 00775 00776 00777 bool DOS_GetSTDINStatus(void) { 00778 Bit32u handle=RealHandle(STDIN); 00779 if (handle==0xFF) return false; 00780 if (Files[handle] && (Files[handle]->GetInformation() & 64)) return false; 00781 return true; 00782 }