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 #include "dosbox.h" 00020 #include "callback.h" 00021 #include "bios.h" 00022 #include "bios_disk.h" 00023 #include "regs.h" 00024 #include "mem.h" 00025 #include "dos_inc.h" /* for Drives[] */ 00026 #include "../dos/drives.h" 00027 #include "mapper.h" 00028 #include "ide.h" 00029 00030 #if defined(_MSC_VER) 00031 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */ 00032 #endif 00033 00034 extern bool int13_extensions_enable; 00035 00036 diskGeo DiskGeometryList[] = { 00037 { 160, 8, 1, 40, 0, 512, 64, 1, 0xFE}, // IBM PC double density 5.25" single-sided 160KB 00038 { 180, 9, 1, 40, 0, 512, 64, 2, 0xFC}, // IBM PC double density 5.25" single-sided 180KB 00039 { 200, 10, 1, 40, 0, 512, 0, 0, 0}, // DEC Rainbow double density 5.25" single-sided 200KB (I think...) 00040 { 320, 8, 2, 40, 1, 512, 112, 2, 0xFF}, // IBM PC double density 5.25" double-sided 320KB 00041 { 360, 9, 2, 40, 1, 512, 112, 2, 0xFD}, // IBM PC double density 5.25" double-sided 360KB 00042 { 400, 10, 2, 40, 1, 512, 0, 0, 0}, // DEC Rainbow double density 5.25" double-sided 400KB (I think...) 00043 { 640, 8, 2, 80, 3, 512, 112, 2, 0xFB}, // IBM PC double density 3.5" double-sided 640KB 00044 { 720, 9, 2, 80, 3, 512, 112, 2, 0xF9}, // IBM PC double density 3.5" double-sided 720KB 00045 {1200, 15, 2, 80, 2, 512, 224, 1, 0xF9}, // IBM PC double density 5.25" double-sided 1.2MB 00046 {1440, 18, 2, 80, 4, 512, 224, 1, 0xF0}, // IBM PC high density 3.5" double-sided 1.44MB 00047 {2880, 36, 2, 80, 6, 512, 240, 2, 0xF0}, // IBM PC high density 3.5" double-sided 2.88MB 00048 00049 {1232, 8, 2, 77, 7, 1024,192, 1, 0xFE}, // NEC PC-98 high density 3.5" double-sided 1.2MB "3-mode" 00050 00051 { 0, 0, 0, 0, 0, 0, 0, 0, 0} 00052 }; 00053 00054 Bitu call_int13 = 0; 00055 Bitu diskparm0 = 0, diskparm1 = 0; 00056 static Bit8u last_status; 00057 static Bit8u last_drive; 00058 Bit16u imgDTASeg; 00059 RealPt imgDTAPtr; 00060 DOS_DTA *imgDTA; 00061 bool killRead; 00062 static bool swapping_requested; 00063 00064 void CMOS_SetRegister(Bitu regNr, Bit8u val); //For setting equipment word 00065 00066 /* 2 floppys and 2 harddrives, max */ 00067 bool imageDiskChange[MAX_DISK_IMAGES]={false}; 00068 imageDisk *imageDiskList[MAX_DISK_IMAGES]={NULL}; 00069 imageDisk *diskSwap[MAX_SWAPPABLE_DISKS]={NULL}; 00070 Bit32s swapPosition; 00071 00072 imageDisk *GetINT13FloppyDrive(unsigned char drv) { 00073 if (drv >= 2) 00074 return NULL; 00075 return imageDiskList[drv]; 00076 } 00077 00078 imageDisk *GetINT13HardDrive(unsigned char drv) { 00079 if (drv < 0x80 || drv >= (0x80+MAX_DISK_IMAGES-2)) 00080 return NULL; 00081 00082 return imageDiskList[drv-0x80]; 00083 } 00084 00085 void FreeBIOSDiskList() { 00086 for (int i=0;i < MAX_DISK_IMAGES;i++) { 00087 if (imageDiskList[i] != NULL) { 00088 if (i >= 2) IDE_Hard_Disk_Detach(i); 00089 imageDiskList[i]->Release(); 00090 imageDiskList[i] = NULL; 00091 } 00092 } 00093 00094 for (int j=0;j < MAX_SWAPPABLE_DISKS;j++) { 00095 if (diskSwap[j] != NULL) { 00096 diskSwap[j]->Release(); 00097 diskSwap[j] = NULL; 00098 } 00099 } 00100 } 00101 00102 //update BIOS disk parameter tables for first two hard drives 00103 void updateDPT(void) { 00104 Bit32u tmpheads, tmpcyl, tmpsect, tmpsize; 00105 PhysPt dpphysaddr[2] = { CALLBACK_PhysPointer(diskparm0), CALLBACK_PhysPointer(diskparm1) }; 00106 for (int i = 0; i < 2; i++) { 00107 tmpheads = 0; tmpcyl = 0; tmpsect = 0; tmpsize = 0; 00108 if (imageDiskList[i + 2] != NULL) { 00109 imageDiskList[i + 2]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize); 00110 } 00111 phys_writew(dpphysaddr[i], (Bit16u)tmpcyl); 00112 phys_writeb(dpphysaddr[i] + 0x2, (Bit8u)tmpheads); 00113 phys_writew(dpphysaddr[i] + 0x3, 0); 00114 phys_writew(dpphysaddr[i] + 0x5, tmpcyl == 0 ? 0 : (Bit16u)-1); 00115 phys_writeb(dpphysaddr[i] + 0x7, 0); 00116 phys_writeb(dpphysaddr[i] + 0x8, tmpcyl == 0 ? 0 : (0xc0 | (((tmpheads) > 8) << 3))); 00117 phys_writeb(dpphysaddr[i] + 0x9, 0); 00118 phys_writeb(dpphysaddr[i] + 0xa, 0); 00119 phys_writeb(dpphysaddr[i] + 0xb, 0); 00120 phys_writew(dpphysaddr[i] + 0xc, (Bit16u)tmpcyl); 00121 phys_writeb(dpphysaddr[i] + 0xe, (Bit8u)tmpsect); 00122 } 00123 } 00124 00125 void incrementFDD(void) { 00126 Bit16u equipment=mem_readw(BIOS_CONFIGURATION); 00127 if(equipment&1) { 00128 Bitu numofdisks = (equipment>>6)&3; 00129 numofdisks++; 00130 if(numofdisks > 1) numofdisks=1;//max 2 floppies at the moment 00131 equipment&=~0x00C0; 00132 equipment|=(numofdisks<<6); 00133 } else equipment|=1; 00134 mem_writew(BIOS_CONFIGURATION,equipment); 00135 CMOS_SetRegister(0x14, (Bit8u)(equipment&0xff)); 00136 } 00137 00138 int swapInDisksSpecificDrive = -1; 00139 // -1 = swap across A: and B: (DOSBox / DOSBox-X default behavior) 00140 // 0 = swap across A: only 00141 // 1 = swap across B: only 00142 00143 void swapInDisks(void) { 00144 bool allNull = true; 00145 Bit32s diskcount = 0; 00146 Bits diskswapcount = 2; 00147 Bits diskswapdrive = 0; 00148 Bit32s swapPos = swapPosition; 00149 Bit32s i; 00150 00151 /* Check to make sure that there is at least one setup image */ 00152 for(i=0;i<MAX_SWAPPABLE_DISKS;i++) { 00153 if(diskSwap[i]!=NULL) { 00154 allNull = false; 00155 break; 00156 } 00157 } 00158 00159 /* No disks setup... fail */ 00160 if (allNull) return; 00161 00162 /* if a specific drive is to be swapped, then adjust to focus on it */ 00163 if (swapInDisksSpecificDrive >= 0 && swapInDisksSpecificDrive <= 1) { 00164 diskswapdrive = swapInDisksSpecificDrive; 00165 diskswapcount = 1; 00166 } 00167 00168 /* If only one disk is loaded, this loop will load the same disk in dive A and drive B */ 00169 while(diskcount < diskswapcount) { 00170 if(diskSwap[swapPos] != NULL) { 00171 LOG_MSG("Loaded drive %d disk %d from swaplist position %d - \"%s\"", (int)diskswapdrive, (int)diskcount, (int)swapPos, diskSwap[swapPos]->diskname.c_str()); 00172 00173 if (imageDiskList[diskswapdrive] != NULL) 00174 imageDiskList[diskswapdrive]->Release(); 00175 00176 imageDiskList[diskswapdrive] = diskSwap[swapPos]; 00177 imageDiskList[diskswapdrive]->Addref(); 00178 00179 imageDiskChange[diskswapdrive] = true; 00180 00181 diskcount++; 00182 diskswapdrive++; 00183 } 00184 00185 swapPos++; 00186 if(swapPos>=MAX_SWAPPABLE_DISKS) swapPos=0; 00187 } 00188 } 00189 00190 bool getSwapRequest(void) { 00191 bool sreq=swapping_requested; 00192 swapping_requested = false; 00193 return sreq; 00194 } 00195 00196 void swapInNextDisk(bool pressed) { 00197 if (!pressed) 00198 return; 00199 DriveManager::CycleAllDisks(); 00200 /* Hack/feature: rescan all disks as well */ 00201 LOG_MSG("Diskcaching reset for floppy drives."); 00202 for(Bitu i=0;i<2;i++) { /* Swap A: and B: where DOSBox mainline would run through ALL drive letters */ 00203 if (Drives[i] != NULL) { 00204 Drives[i]->EmptyCache(); 00205 Drives[i]->MediaChange(); 00206 } 00207 } 00208 swapPosition++; 00209 if(diskSwap[swapPosition] == NULL) swapPosition = 0; 00210 swapInDisks(); 00211 swapping_requested = true; 00212 } 00213 00214 void swapInNextCD(bool pressed) { 00215 if (!pressed) 00216 return; 00217 DriveManager::CycleAllCDs(); 00218 /* Hack/feature: rescan all disks as well */ 00219 LOG_MSG("Diskcaching reset for normal mounted drives."); 00220 for(Bitu i=2;i<DOS_DRIVES;i++) { /* Swap C: D: .... Z: TODO: Need to swap ONLY if a CD-ROM drive! */ 00221 if (Drives[i] != NULL) { 00222 Drives[i]->EmptyCache(); 00223 Drives[i]->MediaChange(); 00224 } 00225 } 00226 } 00227 00228 00229 Bit8u imageDisk::Read_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data,unsigned int req_sector_size) { 00230 Bit32u sectnum; 00231 00232 if (req_sector_size == 0) 00233 req_sector_size = sector_size; 00234 if (req_sector_size != sector_size) 00235 return 0x05; 00236 00237 sectnum = ( (cylinder * heads + head) * sectors ) + sector - 1L; 00238 00239 return Read_AbsoluteSector(sectnum, data); 00240 } 00241 00242 Bit8u imageDisk::Read_AbsoluteSector(Bit32u sectnum, void * data) { 00243 Bit64u bytenum,res; 00244 int got; 00245 00246 bytenum = (Bit64u)sectnum * (Bit64u)sector_size; 00247 if ((bytenum + sector_size) > this->image_length) { 00248 LOG_MSG("Attempt to read invalid sector in Read_AbsoluteSector for sector %lu.\n", (unsigned long)sectnum); 00249 return 0x05; 00250 } 00251 bytenum += image_base; 00252 00253 //LOG_MSG("Reading sectors %ld at bytenum %I64d", sectnum, bytenum); 00254 00255 fseeko64(diskimg,(fseek_ofs_t)bytenum,SEEK_SET); 00256 res = (Bit64u)ftello64(diskimg); 00257 if (res != bytenum) { 00258 LOG_MSG("fseek() failed in Read_AbsoluteSector for sector %lu. Want=%llu Got=%llu\n", 00259 (unsigned long)sectnum,(unsigned long long)bytenum,(unsigned long long)res); 00260 return 0x05; 00261 } 00262 00263 got = (int)fread(data, 1, sector_size, diskimg); 00264 if ((unsigned int)got != sector_size) { 00265 LOG_MSG("fread() failed in Read_AbsoluteSector for sector %lu. Want=%u got=%d\n", 00266 (unsigned long)sectnum,(unsigned int)sector_size,(unsigned int)got); 00267 return 0x05; 00268 } 00269 00270 return 0x00; 00271 } 00272 00273 Bit8u imageDisk::Write_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,const void * data,unsigned int req_sector_size) { 00274 Bit32u sectnum; 00275 00276 if (req_sector_size == 0) 00277 req_sector_size = sector_size; 00278 if (req_sector_size != sector_size) 00279 return 0x05; 00280 00281 sectnum = ( (cylinder * heads + head) * sectors ) + sector - 1L; 00282 00283 return Write_AbsoluteSector(sectnum, data); 00284 } 00285 00286 00287 Bit8u imageDisk::Write_AbsoluteSector(Bit32u sectnum, const void *data) { 00288 Bit64u bytenum; 00289 00290 bytenum = (Bit64u)sectnum * sector_size; 00291 if ((bytenum + sector_size) > this->image_length) { 00292 LOG_MSG("Attempt to read invalid sector in Write_AbsoluteSector for sector %lu.\n", (unsigned long)sectnum); 00293 return 0x05; 00294 } 00295 bytenum += image_base; 00296 00297 //LOG_MSG("Writing sectors to %ld at bytenum %d", sectnum, bytenum); 00298 00299 fseeko64(diskimg,(fseek_ofs_t)bytenum,SEEK_SET); 00300 if ((Bit64u)ftello64(diskimg) != bytenum) 00301 LOG_MSG("WARNING: fseek() failed in Write_AbsoluteSector for sector %lu\n",(unsigned long)sectnum); 00302 00303 size_t ret=fwrite(data, sector_size, 1, diskimg); 00304 00305 return ((ret>0)?0x00:0x05); 00306 00307 } 00308 00309 void imageDisk::Set_Reserved_Cylinders(Bitu resCyl) { 00310 reserved_cylinders = resCyl; 00311 } 00312 00313 Bit32u imageDisk::Get_Reserved_Cylinders() { 00314 return reserved_cylinders; 00315 } 00316 00317 imageDisk::imageDisk(IMAGE_TYPE class_id) : class_id(class_id) { 00318 } 00319 00320 imageDisk::imageDisk(FILE* diskimg, const char* diskName, Bit32u cylinders, Bit32u heads, Bit32u sectors, Bit32u sector_size, bool hardDrive) { 00321 if (diskName) this->diskname = diskName; 00322 this->cylinders = cylinders; 00323 this->heads = heads; 00324 this->sectors = sectors; 00325 image_base = 0; 00326 this->image_length = (Bit64u)cylinders * heads * sectors * sector_size; 00327 refcount = 0; 00328 this->sector_size = sector_size; 00329 this->diskSizeK = this->image_length / 1024; 00330 reserved_cylinders = 0; 00331 this->diskimg = diskimg; 00332 class_id = ID_BASE; 00333 active = true; 00334 this->hardDrive = hardDrive; 00335 floppytype = 0; 00336 } 00337 00338 /* .HDI and .FDI header (NP2) */ 00339 #pragma pack(push,1) 00340 typedef struct { 00341 uint8_t dummy[4]; // +0x00 00342 uint8_t hddtype[4]; // +0x04 00343 uint8_t headersize[4]; // +0x08 00344 uint8_t hddsize[4]; // +0x0C 00345 uint8_t sectorsize[4]; // +0x10 00346 uint8_t sectors[4]; // +0x14 00347 uint8_t surfaces[4]; // +0x18 00348 uint8_t cylinders[4]; // +0x1C 00349 } HDIHDR; // =0x20 00350 00351 typedef struct { 00352 uint8_t dummy[4]; // +0x00 00353 uint8_t fddtype[4]; // +0x04 00354 uint8_t headersize[4]; // +0x08 00355 uint8_t fddsize[4]; // +0x0C 00356 uint8_t sectorsize[4]; // +0x10 00357 uint8_t sectors[4]; // +0x14 00358 uint8_t surfaces[4]; // +0x18 00359 uint8_t cylinders[4]; // +0x1C 00360 } FDIHDR; // =0x20 00361 00362 typedef struct { 00363 char sig[16]; // +0x000 00364 char comment[0x100]; // +0x010 00365 UINT8 headersize[4]; // +0x110 00366 uint8_t prot; // +0x114 00367 uint8_t nhead; // +0x115 00368 uint8_t _unknown_[10]; // +0x116 00369 } NFDHDR; // =0x120 00370 00371 typedef struct { 00372 char sig[16]; // +0x000 00373 char comment[0x100]; // +0x010 00374 UINT8 headersize[4]; // +0x110 00375 uint8_t prot; // +0x114 00376 uint8_t nhead; // +0x115 00377 uint8_t _unknown_[10]; // +0x116 00378 uint32_t trackheads[164]; // +0x120 00379 uint32_t addinfo; // +0x3b0 00380 uint8_t _unknown2_[12]; // +0x3b4 00381 } NFDHDRR1; // =0x3c0 00382 00383 typedef struct { 00384 uint8_t log_cyl; // +0x0 00385 uint8_t log_head; // +0x1 00386 uint8_t log_rec; // +0x2 00387 uint8_t sec_len_pow2; // +0x3 sz = 128 << len_pow2 00388 uint8_t flMFM; // +0x4 00389 uint8_t flDDAM; // +0x5 00390 uint8_t byStatus; // +0x6 00391 uint8_t bySTS0; // +0x7 00392 uint8_t bySTS1; // +0x8 00393 uint8_t bySTS2; // +0x9 00394 uint8_t byRetry; // +0xA 00395 uint8_t byPDA; // +0xB 00396 uint8_t _unknown_[4]; // +0xC 00397 } NFDHDR_ENTRY; // =0x10 00398 00399 typedef struct { 00400 char szFileID[15]; // 識別ID "T98HDDIMAGE.R0" 00401 char Reserve1[1]; // 予約 00402 char szComment[0x100]; // イメージコメント(ASCIIz) 00403 uint32_t dwHeadSize; // ヘッダ部のサイズ 00404 uint32_t dwCylinder; // シリンダ数 00405 uint16_t wHead; // ヘッド数 00406 uint16_t wSect; // 1トラックあたりのセクタ数 00407 uint16_t wSectLen; // セクタ長 00408 char Reserve2[2]; // 予約 00409 char Reserve3[0xe0]; // 予約 00410 }NHD_FILE_HEAD,*LP_NHD_FILE_HEAD; 00411 #pragma pack(pop) 00412 00413 imageDisk::imageDisk(FILE* imgFile, Bit8u* imgName, Bit32u imgSizeK, bool isHardDisk) : diskSizeK(imgSizeK), diskimg(imgFile), image_length((Bit64u)imgSizeK * 1024) { 00414 if (imgName != NULL) 00415 diskname = (const char*)imgName; 00416 00417 active = false; 00418 hardDrive = isHardDisk; 00419 if(!isHardDisk) { 00420 bool founddisk = false; 00421 00422 if (imgName != NULL) { 00423 const char *ext = strrchr((char*)imgName,'.'); 00424 if (ext != NULL) { 00425 if (!strcasecmp(ext,".fdi")) { 00426 if (imgSizeK >= 160) { 00427 FDIHDR fdihdr; 00428 00429 // PC-98 .FDI images appear to be 4096 bytes of a short header and many zeros. 00430 // followed by a straight sector dump of the disk. The header is NOT NECESSARILY 00431 // 4KB in size, but usually is. 00432 LOG_MSG("Image file has .FDI extension, assuming FDI image and will take on parameters in header."); 00433 00434 assert(sizeof(fdihdr) == 0x20); 00435 if (fseek(imgFile,0,SEEK_SET) == 0 && ftell(imgFile) == 0 && 00436 fread(&fdihdr,sizeof(fdihdr),1,imgFile) == 1) { 00437 uint32_t ofs = host_readd(fdihdr.headersize); 00438 uint32_t fddsize = host_readd(fdihdr.fddsize); /* includes header */ 00439 uint32_t sectorsize = host_readd(fdihdr.sectorsize); 00440 00441 if (sectorsize != 0 && ((sectorsize & (sectorsize - 1)) == 0/*is power of 2*/) && 00442 sectorsize >= 256 && sectorsize <= 1024 && 00443 ofs != 0 && (ofs % sectorsize) == 0/*offset is nonzero and multiple of sector size*/ && 00444 (ofs % 1024) == 0/*offset is a multiple of 1024 because of imgSizeK*/ && 00445 fddsize >= sectorsize && (fddsize/1024) <= (imgSizeK+4)) { 00446 00447 founddisk = true; 00448 sector_size = sectorsize; 00449 imgSizeK -= (ofs / 1024); 00450 image_base = ofs; 00451 image_length -= ofs; 00452 LOG_MSG("FDI header: sectorsize is %u bytes/sector, header is %u bytes, fdd size (plus header) is %u bytes", 00453 (unsigned int)sectorsize,(unsigned int)ofs,(unsigned int)fddsize); 00454 00455 /* take on the geometry. */ 00456 sectors = host_readd(fdihdr.sectors); 00457 heads = host_readd(fdihdr.surfaces); 00458 cylinders = host_readd(fdihdr.cylinders); 00459 LOG_MSG("FDI: Geometry is C/H/S %u/%u/%u", 00460 (unsigned int)cylinders,(unsigned int)heads,(unsigned int)sectors); 00461 } 00462 else { 00463 LOG_MSG("FDI header rejected. sectorsize=%u headersize=%u fddsize=%u", 00464 (unsigned int)sectorsize,(unsigned int)ofs,(unsigned int)fddsize); 00465 } 00466 } 00467 else { 00468 LOG_MSG("Unable to read .FDI header"); 00469 } 00470 } 00471 } 00472 } 00473 } 00474 00475 if (sectors == 0 && heads == 0 && cylinders == 0) { 00476 Bit8u i=0; 00477 while (DiskGeometryList[i].ksize!=0x0) { 00478 if ((DiskGeometryList[i].ksize==imgSizeK) || 00479 (DiskGeometryList[i].ksize+1==imgSizeK)) { 00480 if (DiskGeometryList[i].ksize!=imgSizeK) 00481 LOG_MSG("ImageLoader: image file with additional data, might not load!"); 00482 founddisk = true; 00483 active = true; 00484 floppytype = i; 00485 heads = DiskGeometryList[i].headscyl; 00486 cylinders = DiskGeometryList[i].cylcount; 00487 sectors = DiskGeometryList[i].secttrack; 00488 sector_size = DiskGeometryList[i].bytespersect; 00489 LOG_MSG("Identified '%s' as C/H/S %u/%u/%u %u bytes/sector", 00490 imgName,cylinders,heads,sectors,sector_size); 00491 break; 00492 } 00493 i++; 00494 } 00495 } 00496 if(!founddisk) { 00497 active = false; 00498 } 00499 } 00500 else { /* hard disk */ 00501 if (imgName != NULL) { 00502 char *ext = strrchr((char*)imgName,'.'); 00503 if (ext != NULL) { 00504 if (!strcasecmp(ext,".nhd")) { 00505 if (imgSizeK >= 160) { 00506 NHD_FILE_HEAD nhdhdr; 00507 00508 LOG_MSG("Image file has .NHD extension, assuming NHD image and will take on parameters in header."); 00509 00510 assert(sizeof(nhdhdr) == 0x200); 00511 if (fseek(imgFile,0,SEEK_SET) == 0 && ftell(imgFile) == 0 && 00512 fread(&nhdhdr,sizeof(nhdhdr),1,imgFile) == 1 && 00513 host_readd((ConstHostPt)(&nhdhdr.dwHeadSize)) >= 0x200 && 00514 !memcmp(nhdhdr.szFileID,"T98HDDIMAGE.R0\0",15)) { 00515 uint32_t ofs = host_readd((ConstHostPt)(&nhdhdr.dwHeadSize)); 00516 uint32_t sectorsize = host_readw((ConstHostPt)(&nhdhdr.wSectLen)); 00517 00518 if (sectorsize != 0 && ((sectorsize & (sectorsize - 1)) == 0/*is power of 2*/) && 00519 sectorsize >= 256 && sectorsize <= 1024 && 00520 ofs != 0 && (ofs % sectorsize) == 0/*offset is nonzero and multiple of sector size*/) { 00521 00522 sector_size = sectorsize; 00523 imgSizeK -= (ofs / 1024); 00524 image_base = ofs; 00525 image_length -= ofs; 00526 LOG_MSG("NHD header: sectorsize is %u bytes/sector, header is %u bytes", 00527 (unsigned int)sectorsize,(unsigned int)ofs); 00528 00529 /* take on the geometry. 00530 * PC-98 IPL1 support will need it to make sense of the partition table. */ 00531 sectors = host_readw((ConstHostPt)(&nhdhdr.wSect)); 00532 heads = host_readw((ConstHostPt)(&nhdhdr.wHead)); 00533 cylinders = host_readd((ConstHostPt)(&nhdhdr.dwCylinder)); 00534 LOG_MSG("NHD: Geometry is C/H/S %u/%u/%u", 00535 (unsigned int)cylinders,(unsigned int)heads,(unsigned int)sectors); 00536 } 00537 else { 00538 LOG_MSG("NHD header rejected. sectorsize=%u headersize=%u", 00539 (unsigned int)sectorsize,(unsigned int)ofs); 00540 } 00541 } 00542 else { 00543 LOG_MSG("Unable to read .NHD header"); 00544 } 00545 } 00546 } 00547 if (!strcasecmp(ext,".hdi")) { 00548 if (imgSizeK >= 160) { 00549 HDIHDR hdihdr; 00550 00551 // PC-98 .HDI images appear to be 4096 bytes of a short header and many zeros. 00552 // followed by a straight sector dump of the disk. The header is NOT NECESSARILY 00553 // 4KB in size, but usually is. 00554 LOG_MSG("Image file has .HDI extension, assuming HDI image and will take on parameters in header."); 00555 00556 assert(sizeof(hdihdr) == 0x20); 00557 if (fseek(imgFile,0,SEEK_SET) == 0 && ftell(imgFile) == 0 && 00558 fread(&hdihdr,sizeof(hdihdr),1,imgFile) == 1) { 00559 uint32_t ofs = host_readd(hdihdr.headersize); 00560 uint32_t hddsize = host_readd(hdihdr.hddsize); /* includes header */ 00561 uint32_t sectorsize = host_readd(hdihdr.sectorsize); 00562 00563 if (sectorsize != 0 && ((sectorsize & (sectorsize - 1)) == 0/*is power of 2*/) && 00564 sectorsize >= 256 && sectorsize <= 1024 && 00565 ofs != 0 && (ofs % sectorsize) == 0/*offset is nonzero and multiple of sector size*/ && 00566 (ofs % 1024) == 0/*offset is a multiple of 1024 because of imgSizeK*/ && 00567 hddsize >= sectorsize && (hddsize/1024) <= (imgSizeK+4)) { 00568 00569 sector_size = sectorsize; 00570 image_base = ofs; 00571 image_length -= ofs; 00572 LOG_MSG("HDI header: sectorsize is %u bytes/sector, header is %u bytes, hdd size (plus header) is %u bytes", 00573 (unsigned int)sectorsize,(unsigned int)ofs,(unsigned int)hddsize); 00574 00575 /* take on the geometry. 00576 * PC-98 IPL1 support will need it to make sense of the partition table. */ 00577 sectors = host_readd(hdihdr.sectors); 00578 heads = host_readd(hdihdr.surfaces); 00579 cylinders = host_readd(hdihdr.cylinders); 00580 LOG_MSG("HDI: Geometry is C/H/S %u/%u/%u", 00581 (unsigned int)cylinders,(unsigned int)heads,(unsigned int)sectors); 00582 } 00583 else { 00584 LOG_MSG("HDI header rejected. sectorsize=%u headersize=%u hddsize=%u", 00585 (unsigned int)sectorsize,(unsigned int)ofs,(unsigned int)hddsize); 00586 } 00587 } 00588 else { 00589 LOG_MSG("Unable to read .HDI header"); 00590 } 00591 } 00592 } 00593 } 00594 } 00595 00596 if (sectors == 0 || heads == 0 || cylinders == 0) 00597 active = false; 00598 } 00599 } 00600 00601 void imageDisk::Set_Geometry(Bit32u setHeads, Bit32u setCyl, Bit32u setSect, Bit32u setSectSize) { 00602 Bitu bigdisk_shift = 0; 00603 00604 if (IS_PC98_ARCH) { 00605 /* TODO: PC-98 has it's own 4096 cylinder limit */ 00606 } 00607 else { 00608 if(setCyl > 16384) LOG_MSG("This disk image is too big."); 00609 else if(setCyl > 8192) bigdisk_shift = 4; 00610 else if(setCyl > 4096) bigdisk_shift = 3; 00611 else if(setCyl > 2048) bigdisk_shift = 2; 00612 else if(setCyl > 1024) bigdisk_shift = 1; 00613 } 00614 00615 heads = setHeads << bigdisk_shift; 00616 cylinders = setCyl >> bigdisk_shift; 00617 sectors = setSect; 00618 sector_size = setSectSize; 00619 active = true; 00620 } 00621 00622 void imageDisk::Get_Geometry(Bit32u * getHeads, Bit32u *getCyl, Bit32u *getSect, Bit32u *getSectSize) { 00623 *getHeads = heads; 00624 *getCyl = cylinders; 00625 *getSect = sectors; 00626 *getSectSize = sector_size; 00627 } 00628 00629 Bit8u imageDisk::GetBiosType(void) { 00630 if(!hardDrive) { 00631 return (Bit8u)DiskGeometryList[floppytype].biosval; 00632 } else return 0; 00633 } 00634 00635 Bit32u imageDisk::getSectSize(void) { 00636 return sector_size; 00637 } 00638 00639 static Bit8u GetDosDriveNumber(Bit8u biosNum) { 00640 switch(biosNum) { 00641 case 0x0: 00642 return 0x0; 00643 case 0x1: 00644 return 0x1; 00645 case 0x80: 00646 return 0x2; 00647 case 0x81: 00648 return 0x3; 00649 case 0x82: 00650 return 0x4; 00651 case 0x83: 00652 return 0x5; 00653 default: 00654 return 0x7f; 00655 } 00656 } 00657 00658 static bool driveInactive(Bit8u driveNum) { 00659 if(driveNum>=(2 + MAX_HDD_IMAGES)) { 00660 LOG(LOG_BIOS,LOG_ERROR)("Disk %d non-existant", (int)driveNum); 00661 last_status = 0x01; 00662 CALLBACK_SCF(true); 00663 return true; 00664 } 00665 if(imageDiskList[driveNum] == NULL) { 00666 LOG(LOG_BIOS,LOG_ERROR)("Disk %d not active", (int)driveNum); 00667 last_status = 0x01; 00668 CALLBACK_SCF(true); 00669 return true; 00670 } 00671 if(!imageDiskList[driveNum]->active) { 00672 LOG(LOG_BIOS,LOG_ERROR)("Disk %d not active", (int)driveNum); 00673 last_status = 0x01; 00674 CALLBACK_SCF(true); 00675 return true; 00676 } 00677 return false; 00678 } 00679 00680 static struct { 00681 Bit8u sz; 00682 Bit8u res; 00683 Bit16u num; 00684 Bit16u off; 00685 Bit16u seg; 00686 Bit32u sector; 00687 } dap; 00688 00689 static void readDAP(Bit16u seg, Bit16u off) { 00690 dap.sz = real_readb(seg,off++); 00691 dap.res = real_readb(seg,off++); 00692 dap.num = real_readw(seg,off); off += 2; 00693 dap.off = real_readw(seg,off); off += 2; 00694 dap.seg = real_readw(seg,off); off += 2; 00695 00696 /* Although sector size is 64-bit, 32-bit 2TB limit should be more than enough */ 00697 dap.sector = real_readd(seg,off); off +=4; 00698 00699 if (real_readd(seg,off)) { 00700 E_Exit("INT13: 64-bit sector addressing not supported"); 00701 } 00702 } 00703 00704 void IDE_ResetDiskByBIOS(unsigned char disk); 00705 void IDE_EmuINT13DiskReadByBIOS(unsigned char disk,unsigned int cyl,unsigned int head,unsigned sect); 00706 void IDE_EmuINT13DiskReadByBIOS_LBA(unsigned char disk,uint64_t lba); 00707 00708 static Bitu INT13_DiskHandler(void) { 00709 Bit16u segat, bufptr; 00710 Bit8u sectbuf[512]; 00711 Bit8u drivenum; 00712 Bitu i,t; 00713 last_drive = reg_dl; 00714 drivenum = GetDosDriveNumber(reg_dl); 00715 bool any_images = false; 00716 for(i = 0;i < MAX_DISK_IMAGES;i++) { 00717 if(imageDiskList[i]) any_images=true; 00718 } 00719 00720 // unconditionally enable the interrupt flag 00721 CALLBACK_SIF(true); 00722 00723 /* map out functions 0x40-0x48 if not emulating INT 13h extensions */ 00724 if (!int13_extensions_enable && reg_ah >= 0x40 && reg_ah <= 0x48) { 00725 LOG_MSG("Warning: Guest is attempting to use INT 13h extensions (AH=0x%02X). Set 'int 13 extensions=1' if you want to enable them.\n",reg_ah); 00726 reg_ah=0xff; 00727 CALLBACK_SCF(true); 00728 return CBRET_NONE; 00729 } 00730 00731 //drivenum = 0; 00732 //LOG_MSG("INT13: Function %x called on drive %x (dos drive %d)", reg_ah, reg_dl, drivenum); 00733 00734 // NOTE: the 0xff error code returned in some cases is questionable; 0x01 seems more correct 00735 switch(reg_ah) { 00736 case 0x0: /* Reset disk */ 00737 { 00738 /* if there aren't any diskimages (so only localdrives and virtual drives) 00739 * always succeed on reset disk. If there are diskimages then and only then 00740 * do real checks 00741 */ 00742 if (any_images && driveInactive(drivenum)) { 00743 /* driveInactive sets carry flag if the specified drive is not available */ 00744 if ((machine==MCH_CGA) || (machine==MCH_AMSTRAD) || (machine==MCH_PCJR)) { 00745 /* those bioses call floppy drive reset for invalid drive values */ 00746 if (((imageDiskList[0]) && (imageDiskList[0]->active)) || ((imageDiskList[1]) && (imageDiskList[1]->active))) { 00747 if (machine!=MCH_PCJR && reg_dl<0x80) reg_ip++; 00748 last_status = 0x00; 00749 CALLBACK_SCF(false); 00750 } 00751 } 00752 return CBRET_NONE; 00753 } 00754 if (machine!=MCH_PCJR && reg_dl<0x80) reg_ip++; 00755 if (reg_dl >= 0x80) IDE_ResetDiskByBIOS(reg_dl); 00756 last_status = 0x00; 00757 CALLBACK_SCF(false); 00758 } 00759 break; 00760 case 0x1: /* Get status of last operation */ 00761 00762 if(last_status != 0x00) { 00763 reg_ah = last_status; 00764 CALLBACK_SCF(true); 00765 } else { 00766 reg_ah = 0x00; 00767 CALLBACK_SCF(false); 00768 } 00769 break; 00770 case 0x2: /* Read sectors */ 00771 if (reg_al==0) { 00772 reg_ah = 0x01; 00773 CALLBACK_SCF(true); 00774 return CBRET_NONE; 00775 } 00776 if (!any_images) { 00777 if (drivenum >= DOS_DRIVES || !Drives[drivenum] || Drives[drivenum]->isRemovable()) { 00778 reg_ah = 0x01; 00779 CALLBACK_SCF(true); 00780 return CBRET_NONE; 00781 } 00782 // Inherit the Earth cdrom and Amberstar use it as a disk test 00783 if (((reg_dl&0x80)==0x80) && (reg_dh==0) && ((reg_cl&0x3f)==1)) { 00784 if (reg_ch==0) { 00785 PhysPt ptr = PhysMake(SegValue(es),reg_bx); 00786 // write some MBR data into buffer for Amberstar installer 00787 mem_writeb(ptr+0x1be,0x80); // first partition is active 00788 mem_writeb(ptr+0x1c2,0x06); // first partition is FAT16B 00789 } 00790 reg_ah = 0; 00791 CALLBACK_SCF(false); 00792 return CBRET_NONE; 00793 } 00794 } 00795 if (driveInactive(drivenum)) { 00796 reg_ah = 0xff; 00797 CALLBACK_SCF(true); 00798 return CBRET_NONE; 00799 } 00800 00801 /* INT 13h is limited to 512 bytes/sector (as far as I know). 00802 * The sector buffer in this function is limited to 512 bytes/sector, 00803 * so this is also a protection against overruning the stack if you 00804 * mount a PC-98 disk image (1024 bytes/sector) and try to read it with INT 13h. */ 00805 if (imageDiskList[drivenum]->sector_size > sizeof(sectbuf)) { 00806 LOG(LOG_MISC,LOG_DEBUG)("INT 13h: Read failed because disk bytes/sector on drive %c is too large",(char)drivenum+'A'); 00807 00808 imageDiskChange[drivenum] = false; 00809 00810 reg_ah = 0x80; /* timeout */ 00811 CALLBACK_SCF(true); 00812 return CBRET_NONE; 00813 } 00814 00815 /* If the disk changed, the first INT 13h read will signal an error and set AH = 0x06 to indicate disk change */ 00816 if (drivenum < 2 && imageDiskChange[drivenum]) { 00817 LOG(LOG_MISC,LOG_DEBUG)("INT 13h: Failing first read of drive %c to indicate disk change",(char)drivenum+'A'); 00818 00819 imageDiskChange[drivenum] = false; 00820 00821 reg_ah = 0x06; /* diskette changed or removed */ 00822 CALLBACK_SCF(true); 00823 return CBRET_NONE; 00824 } 00825 00826 segat = SegValue(es); 00827 bufptr = reg_bx; 00828 for(i=0;i<reg_al;i++) { 00829 last_status = imageDiskList[drivenum]->Read_Sector((Bit32u)reg_dh, (Bit32u)(reg_ch | ((reg_cl & 0xc0)<< 2)), (Bit32u)((reg_cl & 63)+i), sectbuf); 00830 00831 /* IDE emulation: simulate change of IDE state that would occur on a real machine after INT 13h */ 00832 IDE_EmuINT13DiskReadByBIOS(reg_dl, (Bit32u)(reg_ch | ((reg_cl & 0xc0)<< 2)), (Bit32u)reg_dh, (Bit32u)((reg_cl & 63)+i)); 00833 00834 if((last_status != 0x00) || (killRead)) { 00835 LOG_MSG("Error in disk read"); 00836 killRead = false; 00837 reg_ah = 0x04; 00838 CALLBACK_SCF(true); 00839 return CBRET_NONE; 00840 } 00841 for(t=0;t<512;t++) { 00842 real_writeb(segat,bufptr,sectbuf[t]); 00843 bufptr++; 00844 } 00845 } 00846 reg_ah = 0x00; 00847 CALLBACK_SCF(false); 00848 break; 00849 case 0x3: /* Write sectors */ 00850 00851 if(driveInactive(drivenum) || !imageDiskList[drivenum]) { 00852 reg_ah = 0xff; 00853 CALLBACK_SCF(true); 00854 return CBRET_NONE; 00855 } 00856 00857 /* INT 13h is limited to 512 bytes/sector (as far as I know). 00858 * The sector buffer in this function is limited to 512 bytes/sector, 00859 * so this is also a protection against overruning the stack if you 00860 * mount a PC-98 disk image (1024 bytes/sector) and try to read it with INT 13h. */ 00861 if (imageDiskList[drivenum]->sector_size > sizeof(sectbuf)) { 00862 LOG(LOG_MISC,LOG_DEBUG)("INT 13h: Write failed because disk bytes/sector on drive %c is too large",(char)drivenum+'A'); 00863 00864 imageDiskChange[drivenum] = false; 00865 00866 reg_ah = 0x80; /* timeout */ 00867 CALLBACK_SCF(true); 00868 return CBRET_NONE; 00869 } 00870 00871 bufptr = reg_bx; 00872 for(i=0;i<reg_al;i++) { 00873 for(t=0;t<imageDiskList[drivenum]->getSectSize();t++) { 00874 sectbuf[t] = real_readb(SegValue(es),bufptr); 00875 bufptr++; 00876 } 00877 00878 last_status = imageDiskList[drivenum]->Write_Sector((Bit32u)reg_dh, (Bit32u)(reg_ch | ((reg_cl & 0xc0) << 2)), (Bit32u)((reg_cl & 63) + i), §buf[0]); 00879 if(last_status != 0x00) { 00880 CALLBACK_SCF(true); 00881 return CBRET_NONE; 00882 } 00883 } 00884 reg_ah = 0x00; 00885 CALLBACK_SCF(false); 00886 break; 00887 case 0x04: /* Verify sectors */ 00888 if (reg_al==0) { 00889 reg_ah = 0x01; 00890 CALLBACK_SCF(true); 00891 return CBRET_NONE; 00892 } 00893 if(driveInactive(drivenum)) { 00894 reg_ah = last_status; 00895 return CBRET_NONE; 00896 } 00897 00898 /* TODO: Finish coding this section */ 00899 /* 00900 segat = SegValue(es); 00901 bufptr = reg_bx; 00902 for(i=0;i<reg_al;i++) { 00903 last_status = imageDiskList[drivenum]->Read_Sector((Bit32u)reg_dh, (Bit32u)(reg_ch | ((reg_cl & 0xc0)<< 2)), (Bit32u)((reg_cl & 63)+i), sectbuf); 00904 if(last_status != 0x00) { 00905 LOG_MSG("Error in disk read"); 00906 CALLBACK_SCF(true); 00907 return CBRET_NONE; 00908 } 00909 for(t=0;t<512;t++) { 00910 real_writeb(segat,bufptr,sectbuf[t]); 00911 bufptr++; 00912 } 00913 }*/ 00914 reg_ah = 0x00; 00915 //Qbix: The following codes don't match my specs. al should be number of sector verified 00916 //reg_al = 0x10; /* CRC verify failed */ 00917 //reg_al = 0x00; /* CRC verify succeeded */ 00918 CALLBACK_SCF(false); 00919 00920 break; 00921 case 0x05: /* Format track */ 00922 /* ignore it. I just fucking want FORMAT.COM to write the FAT structure for God's sake */ 00923 LOG_MSG("WARNING: Format track ignored\n"); 00924 if (driveInactive(drivenum)) { 00925 reg_ah = 0xff; 00926 CALLBACK_SCF(true); 00927 return CBRET_NONE; 00928 } 00929 CALLBACK_SCF(false); 00930 reg_ah = 0x00; 00931 break; 00932 case 0x06: /* Format track set bad sector flags */ 00933 /* ignore it. I just fucking want FORMAT.COM to write the FAT structure for God's sake */ 00934 LOG_MSG("WARNING: Format track set bad sector flags ignored (6)\n"); 00935 if (driveInactive(drivenum)) { 00936 reg_ah = 0xff; 00937 CALLBACK_SCF(true); 00938 return CBRET_NONE; 00939 } 00940 CALLBACK_SCF(false); 00941 reg_ah = 0x00; 00942 break; 00943 case 0x07: /* Format track set bad sector flags */ 00944 /* ignore it. I just fucking want FORMAT.COM to write the FAT structure for God's sake */ 00945 LOG_MSG("WARNING: Format track set bad sector flags ignored (7)\n"); 00946 if (driveInactive(drivenum)) { 00947 reg_ah = 0xff; 00948 CALLBACK_SCF(true); 00949 return CBRET_NONE; 00950 } 00951 CALLBACK_SCF(false); 00952 reg_ah = 0x00; 00953 break; 00954 case 0x08: /* Get drive parameters */ 00955 if(driveInactive(drivenum)) { 00956 last_status = 0x07; 00957 reg_ah = last_status; 00958 CALLBACK_SCF(true); 00959 return CBRET_NONE; 00960 } 00961 reg_ax = 0x00; 00962 reg_bl = imageDiskList[drivenum]->GetBiosType(); 00963 Bit32u tmpheads, tmpcyl, tmpsect, tmpsize; 00964 imageDiskList[drivenum]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize); 00965 if (tmpcyl==0) LOG(LOG_BIOS,LOG_ERROR)("INT13 DrivParm: cylinder count zero!"); 00966 else tmpcyl--; // cylinder count -> max cylinder 00967 if (tmpheads==0) LOG(LOG_BIOS,LOG_ERROR)("INT13 DrivParm: head count zero!"); 00968 else tmpheads--; // head count -> max head 00969 00970 /* older BIOSes were known to subtract 1 or 2 additional "reserved" cylinders. 00971 * some code, such as Windows 3.1 WDCTRL, might assume that fact. emulate that here */ 00972 { 00973 Bit32u reserv = imageDiskList[drivenum]->Get_Reserved_Cylinders(); 00974 if (tmpcyl > reserv) tmpcyl -= reserv; 00975 else tmpcyl = 0; 00976 } 00977 00978 reg_ch = (Bit8u)(tmpcyl & 0xff); 00979 reg_cl = (Bit8u)(((tmpcyl >> 2) & 0xc0) | (tmpsect & 0x3f)); 00980 reg_dh = (Bit8u)tmpheads; 00981 last_status = 0x00; 00982 if (reg_dl&0x80) { // harddisks 00983 reg_dl = 0; 00984 for (int index = 2; index < MAX_DISK_IMAGES; index++) { 00985 if (imageDiskList[index] != NULL) reg_dl++; 00986 } 00987 } else { // floppy disks 00988 reg_dl = 0; 00989 if(imageDiskList[0] != NULL) reg_dl++; 00990 if(imageDiskList[1] != NULL) reg_dl++; 00991 } 00992 CALLBACK_SCF(false); 00993 break; 00994 case 0x11: /* Recalibrate drive */ 00995 reg_ah = 0x00; 00996 CALLBACK_SCF(false); 00997 break; 00998 case 0x15: /* Get disk type */ 00999 /* Korean Powerdolls uses this to detect harddrives */ 01000 LOG(LOG_BIOS,LOG_WARN)("INT13: Get disktype used!"); 01001 if (any_images) { 01002 if(driveInactive(drivenum)) { 01003 last_status = 0x07; 01004 reg_ah = last_status; 01005 CALLBACK_SCF(true); 01006 return CBRET_NONE; 01007 } 01008 imageDiskList[drivenum]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize); 01009 Bit64u largesize = tmpheads*tmpcyl*tmpsect*tmpsize; 01010 largesize/=512; 01011 Bit32u ts = static_cast<Bit32u>(largesize); 01012 reg_ah = (drivenum <2)?1:3; //With 2 for floppy MSDOS starts calling int 13 ah 16 01013 if(reg_ah == 3) { 01014 reg_cx = static_cast<Bit16u>(ts >>16); 01015 reg_dx = static_cast<Bit16u>(ts & 0xffff); 01016 } 01017 CALLBACK_SCF(false); 01018 } else { 01019 if (drivenum <DOS_DRIVES && (Drives[drivenum] != 0 || drivenum <2)) { 01020 if (drivenum <2) { 01021 //TODO use actual size (using 1.44 for now). 01022 reg_ah = 0x1; // type 01023 // reg_cx = 0; 01024 // reg_dx = 2880; //Only set size for harddrives. 01025 } else { 01026 //TODO use actual size (using 105 mb for now). 01027 reg_ah = 0x3; // type 01028 reg_cx = 3; 01029 reg_dx = 0x4800; 01030 } 01031 CALLBACK_SCF(false); 01032 } else { 01033 LOG(LOG_BIOS,LOG_WARN)("INT13: no images, but invalid drive for call 15"); 01034 reg_ah=0xff; 01035 CALLBACK_SCF(true); 01036 } 01037 } 01038 break; 01039 case 0x17: /* Set disk type for format */ 01040 /* Pirates! needs this to load */ 01041 killRead = true; 01042 reg_ah = 0x00; 01043 CALLBACK_SCF(false); 01044 break; 01045 case 0x41: /* Check Extensions Present */ 01046 if ((reg_bx == 0x55aa) && !(driveInactive(drivenum))) { 01047 LOG_MSG("INT13: Check Extensions Present for drive: 0x%x", reg_dl); 01048 reg_ah=0x1; /* 1.x extension supported */ 01049 reg_bx=0xaa55; /* Extensions installed */ 01050 reg_cx=0x1; /* Extended disk access functions (AH=42h-44h,47h,48h) supported */ 01051 CALLBACK_SCF(false); 01052 break; 01053 } 01054 LOG_MSG("INT13: AH=41h, Function not supported 0x%x for drive: 0x%x", reg_bx, reg_dl); 01055 CALLBACK_SCF(true); 01056 break; 01057 case 0x42: /* Extended Read Sectors From Drive */ 01058 /* Read Disk Address Packet */ 01059 readDAP(SegValue(ds),reg_si); 01060 01061 if (dap.num==0) { 01062 reg_ah = 0x01; 01063 CALLBACK_SCF(true); 01064 return CBRET_NONE; 01065 } 01066 if (!any_images) { 01067 // Inherit the Earth cdrom (uses it as disk test) 01068 if (((reg_dl&0x80)==0x80) && (reg_dh==0) && ((reg_cl&0x3f)==1)) { 01069 reg_ah = 0; 01070 CALLBACK_SCF(false); 01071 return CBRET_NONE; 01072 } 01073 } 01074 if (driveInactive(drivenum)) { 01075 reg_ah = 0xff; 01076 CALLBACK_SCF(true); 01077 return CBRET_NONE; 01078 } 01079 01080 segat = dap.seg; 01081 bufptr = dap.off; 01082 for(i=0;i<dap.num;i++) { 01083 last_status = imageDiskList[drivenum]->Read_AbsoluteSector(dap.sector+i, sectbuf); 01084 01085 IDE_EmuINT13DiskReadByBIOS_LBA(reg_dl,dap.sector+i); 01086 01087 if((last_status != 0x00) || (killRead)) { 01088 LOG_MSG("Error in disk read"); 01089 killRead = false; 01090 reg_ah = 0x04; 01091 CALLBACK_SCF(true); 01092 return CBRET_NONE; 01093 } 01094 for(t=0;t<512;t++) { 01095 real_writeb(segat,bufptr,sectbuf[t]); 01096 bufptr++; 01097 } 01098 } 01099 reg_ah = 0x00; 01100 CALLBACK_SCF(false); 01101 break; 01102 case 0x43: /* Extended Write Sectors to Drive */ 01103 if(driveInactive(drivenum)) { 01104 reg_ah = 0xff; 01105 CALLBACK_SCF(true); 01106 return CBRET_NONE; 01107 } 01108 01109 /* Read Disk Address Packet */ 01110 readDAP(SegValue(ds),reg_si); 01111 bufptr = dap.off; 01112 for(i=0;i<dap.num;i++) { 01113 for(t=0;t<imageDiskList[drivenum]->getSectSize();t++) { 01114 sectbuf[t] = real_readb(dap.seg,bufptr); 01115 bufptr++; 01116 } 01117 01118 last_status = imageDiskList[drivenum]->Write_AbsoluteSector(dap.sector+i, §buf[0]); 01119 if(last_status != 0x00) { 01120 CALLBACK_SCF(true); 01121 return CBRET_NONE; 01122 } 01123 } 01124 reg_ah = 0x00; 01125 CALLBACK_SCF(false); 01126 break; 01127 case 0x48: { /* get drive parameters */ 01128 uint16_t bufsz; 01129 01130 if(driveInactive(drivenum)) { 01131 reg_ah = 0xff; 01132 CALLBACK_SCF(true); 01133 return CBRET_NONE; 01134 } 01135 01136 segat = SegValue(ds); 01137 bufptr = reg_si; 01138 bufsz = real_readw(segat,bufptr+0); 01139 if (bufsz < 0x1A) { 01140 reg_ah = 0xff; 01141 CALLBACK_SCF(true); 01142 return CBRET_NONE; 01143 } 01144 if (bufsz > 0x1E) bufsz = 0x1E; 01145 else bufsz = 0x1A; 01146 01147 imageDiskList[drivenum]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize); 01148 01149 real_writew(segat,bufptr+0x00,bufsz); 01150 real_writew(segat,bufptr+0x02,0x0003); /* C/H/S valid, DMA boundary errors handled */ 01151 real_writed(segat,bufptr+0x04,tmpcyl); 01152 real_writed(segat,bufptr+0x08,tmpheads); 01153 real_writed(segat,bufptr+0x0C,tmpsect); 01154 real_writed(segat,bufptr+0x10,tmpcyl*tmpheads*tmpsect); 01155 real_writed(segat,bufptr+0x14,0); 01156 real_writew(segat,bufptr+0x18,512); 01157 if (bufsz >= 0x1E) 01158 real_writed(segat,bufptr+0x1A,0xFFFFFFFF); /* no EDD information available */ 01159 01160 reg_ah = 0x00; 01161 CALLBACK_SCF(false); 01162 } break; 01163 default: 01164 LOG(LOG_BIOS,LOG_ERROR)("INT13: Function %x called on drive %x (dos drive %d)", (int)reg_ah, (int)reg_dl, (int)drivenum); 01165 reg_ah=0xff; 01166 CALLBACK_SCF(true); 01167 } 01168 return CBRET_NONE; 01169 } 01170 01171 void CALLBACK_DeAllocate(Bitu in); 01172 01173 void BIOS_UnsetupDisks(void) { 01174 if (call_int13 != 0) { 01175 CALLBACK_DeAllocate(call_int13); 01176 RealSetVec(0x13,0); /* zero INT 13h for now */ 01177 call_int13 = 0; 01178 } 01179 if (diskparm0 != 0) { 01180 CALLBACK_DeAllocate(diskparm0); 01181 diskparm0 = 0; 01182 } 01183 if (diskparm1 != 0) { 01184 CALLBACK_DeAllocate(diskparm1); 01185 diskparm1 = 0; 01186 } 01187 } 01188 01189 void BIOS_SetupDisks(void) { 01190 unsigned int i; 01191 01192 if (IS_PC98_ARCH) { 01193 // TODO 01194 return; 01195 } 01196 01197 /* TODO Start the time correctly */ 01198 call_int13=CALLBACK_Allocate(); 01199 CALLBACK_Setup(call_int13,&INT13_DiskHandler,CB_INT13,"Int 13 Bios disk"); 01200 RealSetVec(0x13,CALLBACK_RealPointer(call_int13)); 01201 01202 //release the drives after a soft reset 01203 FreeBIOSDiskList(); 01204 01205 /* FIXME: Um... these aren't callbacks. Why are they allocated as callbacks? We have ROM general allocation now. */ 01206 diskparm0 = CALLBACK_Allocate(); 01207 CALLBACK_SetDescription(diskparm0,"BIOS Disk 0 parameter table"); 01208 diskparm1 = CALLBACK_Allocate(); 01209 CALLBACK_SetDescription(diskparm1,"BIOS Disk 1 parameter table"); 01210 swapPosition = 0; 01211 01212 RealSetVec(0x41,CALLBACK_RealPointer(diskparm0)); 01213 RealSetVec(0x46,CALLBACK_RealPointer(diskparm1)); 01214 01215 PhysPt dp0physaddr=CALLBACK_PhysPointer(diskparm0); 01216 PhysPt dp1physaddr=CALLBACK_PhysPointer(diskparm1); 01217 for(i=0;i<16;i++) { 01218 phys_writeb(dp0physaddr+i,0); 01219 phys_writeb(dp1physaddr+i,0); 01220 } 01221 01222 imgDTASeg = 0; 01223 01224 /* Setup the Bios Area */ 01225 mem_writeb(BIOS_HARDDISK_COUNT,2); 01226 01227 killRead = false; 01228 swapping_requested = false; 01229 } 01230 01231 // VFD *.FDD floppy disk format support 01232 01233 Bit8u imageDiskVFD::Read_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data,unsigned int req_sector_size) { 01234 const vfdentry *ent; 01235 01236 if (req_sector_size == 0) 01237 req_sector_size = sector_size; 01238 01239 // LOG_MSG("VFD read sector: CHS %u/%u/%u sz=%u",cylinder,head,sector,req_sector_size); 01240 01241 ent = findSector(head,cylinder,sector,req_sector_size); 01242 if (ent == NULL) return 0x05; 01243 if (ent->getSectorSize() != req_sector_size) return 0x05; 01244 01245 if (ent->hasSectorData()) { 01246 fseek(diskimg,(long)ent->data_offset,SEEK_SET); 01247 if ((uint32_t)ftell(diskimg) != ent->data_offset) return 0x05; 01248 if (fread(data,req_sector_size,1,diskimg) != 1) return 0x05; 01249 return 0; 01250 } 01251 else if (ent->hasFill()) { 01252 memset(data,ent->fillbyte,req_sector_size); 01253 return 0x00; 01254 } 01255 01256 return 0x05; 01257 } 01258 01259 Bit8u imageDiskVFD::Read_AbsoluteSector(Bit32u sectnum, void * data) { 01260 unsigned int c,h,s; 01261 01262 if (sectors == 0 || heads == 0) 01263 return 0x05; 01264 01265 s = (sectnum % sectors) + 1; 01266 h = (sectnum / sectors) % heads; 01267 c = (sectnum / sectors / heads); 01268 return Read_Sector(h,c,s,data); 01269 } 01270 01271 imageDiskVFD::vfdentry *imageDiskVFD::findSector(Bit8u head,Bit8u track,Bit8u sector/*TODO: physical head?*/,unsigned int req_sector_size) { 01272 std::vector<imageDiskVFD::vfdentry>::iterator i = dents.begin(); 01273 unsigned char szb=0xFF; 01274 01275 if (req_sector_size == 0) 01276 req_sector_size = sector_size; 01277 01278 if (req_sector_size != ~0U) { 01279 unsigned int c = req_sector_size; 01280 while (c >= 128U) { 01281 c >>= 1U; 01282 szb++; 01283 } 01284 01285 // LOG_MSG("req=%u c=%u szb=%u",req_sector_size,c,szb); 01286 01287 if (szb > 8 || c != 64U) 01288 return NULL; 01289 } 01290 01291 while (i != dents.end()) { 01292 const imageDiskVFD::vfdentry &ent = *i; 01293 01294 if (ent.head == head && 01295 ent.track == track && 01296 ent.sector == sector && 01297 (ent.sizebyte == szb || req_sector_size == ~0U)) 01298 return &(*i); 01299 01300 ++i; 01301 } 01302 01303 return NULL; 01304 } 01305 01306 Bit8u imageDiskVFD::Write_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,const void * data,unsigned int req_sector_size) { 01307 unsigned long new_offset; 01308 unsigned char tmp[12]; 01309 vfdentry *ent; 01310 01311 // LOG_MSG("VFD write sector: CHS %u/%u/%u",cylinder,head,sector); 01312 01313 if (req_sector_size == 0) 01314 req_sector_size = sector_size; 01315 01316 ent = findSector(head,cylinder,sector,req_sector_size); 01317 if (ent == NULL) return 0x05; 01318 if (ent->getSectorSize() != req_sector_size) return 0x05; 01319 01320 if (ent->hasSectorData()) { 01321 fseek(diskimg,(long)ent->data_offset,SEEK_SET); 01322 if ((uint32_t)ftell(diskimg) != ent->data_offset) return 0x05; 01323 if (fwrite(data,req_sector_size,1,diskimg) != 1) return 0x05; 01324 return 0; 01325 } 01326 else if (ent->hasFill()) { 01327 bool isfill = false; 01328 01329 /* well, is the data provided one character repeated? 01330 * note the format cannot represent a fill byte of 0xFF */ 01331 if (((unsigned char*)data)[0] != 0xFF) { 01332 unsigned int i=1; 01333 01334 do { 01335 if (((unsigned char*)data)[i] == ((unsigned char*)data)[0]) { 01336 if ((++i) == req_sector_size) { 01337 isfill = true; 01338 break; // yes! 01339 } 01340 } 01341 else { 01342 break; // nope 01343 } 01344 } while (1); 01345 } 01346 01347 if (ent->entry_offset == 0) return 0x05; 01348 01349 if (isfill) { 01350 fseek(diskimg,(long)ent->entry_offset,SEEK_SET); 01351 if ((uint32_t)ftell(diskimg) != ent->entry_offset) return 0x05; 01352 if (fread(tmp,12,1,diskimg) != 1) return 0x05; 01353 01354 tmp[0x04] = ((unsigned char*)data)[0]; // change the fill byte 01355 01356 LOG_MSG("VFD write: 'fill' sector changing fill byte to 0x%x",tmp[0x04]); 01357 01358 fseek(diskimg,(long)ent->entry_offset,SEEK_SET); 01359 if ((uint32_t)ftell(diskimg) != ent->entry_offset) return 0x05; 01360 if (fwrite(tmp,12,1,diskimg) != 1) return 0x05; 01361 } 01362 else { 01363 fseek(diskimg,0,SEEK_END); 01364 new_offset = (unsigned long)ftell(diskimg); 01365 01366 /* we have to change it from a fill sector to an actual sector */ 01367 LOG_MSG("VFD write: changing 'fill' sector to one with data (data at %lu)",(unsigned long)new_offset); 01368 01369 fseek(diskimg,(long)ent->entry_offset,SEEK_SET); 01370 if ((uint32_t)ftell(diskimg) != ent->entry_offset) return 0x05; 01371 if (fread(tmp,12,1,diskimg) != 1) return 0x05; 01372 01373 tmp[0x00] = ent->track; 01374 tmp[0x01] = ent->head; 01375 tmp[0x02] = ent->sector; 01376 tmp[0x03] = ent->sizebyte; 01377 tmp[0x04] = 0xFF; // no longer a fill byte 01378 tmp[0x05] = 0x00; // TODO ?? 01379 tmp[0x06] = 0x00; // TODO ?? 01380 tmp[0x07] = 0x00; // TODO ?? 01381 *((uint32_t*)(tmp+8)) = new_offset; 01382 ent->fillbyte = 0xFF; 01383 ent->data_offset = (uint32_t)new_offset; 01384 01385 fseek(diskimg,(long)ent->entry_offset,SEEK_SET); 01386 if ((uint32_t)ftell(diskimg) != ent->entry_offset) return 0x05; 01387 if (fwrite(tmp,12,1,diskimg) != 1) return 0x05; 01388 01389 fseek(diskimg,(long)ent->data_offset,SEEK_SET); 01390 if ((uint32_t)ftell(diskimg) != ent->data_offset) return 0x05; 01391 if (fwrite(data,req_sector_size,1,diskimg) != 1) return 0x05; 01392 } 01393 } 01394 01395 return 0x05; 01396 } 01397 01398 Bit8u imageDiskVFD::Write_AbsoluteSector(Bit32u sectnum,const void *data) { 01399 unsigned int c,h,s; 01400 01401 if (sectors == 0 || heads == 0) 01402 return 0x05; 01403 01404 s = (sectnum % sectors) + 1; 01405 h = (sectnum / sectors) % heads; 01406 c = (sectnum / sectors / heads); 01407 return Write_Sector(h,c,s,data); 01408 } 01409 01410 imageDiskVFD::imageDiskVFD(FILE *imgFile, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk) : imageDisk(ID_VFD) { 01411 (void)isHardDisk;//UNUSED 01412 unsigned char tmp[16]; 01413 01414 heads = 1; 01415 cylinders = 0; 01416 image_base = 0; 01417 sectors = 0; 01418 active = false; 01419 sector_size = 0; 01420 reserved_cylinders = 0; 01421 diskSizeK = imgSizeK; 01422 diskimg = imgFile; 01423 01424 if (imgName != NULL) 01425 diskname = (const char*)imgName; 01426 01427 // NOTES: 01428 // 01429 // +0x000: "VFD1.00" 01430 // +0x0DC: array of 12-byte entries each describing a sector 01431 // 01432 // Each entry: 01433 // +0x0: track 01434 // +0x1: head 01435 // +0x2: sector 01436 // +0x3: sector size (128 << this byte) 01437 // +0x4: fill byte, or 0xFF 01438 // +0x5: unknown 01439 // +0x6: unknown 01440 // +0x7: unknown 01441 // +0x8: absolute data offset (32-bit integer) or 0xFFFFFFFF if the entire sector is that fill byte 01442 fseek(diskimg,0,SEEK_SET); 01443 memset(tmp,0,8); 01444 size_t readResult = fread(tmp,1,8,diskimg); 01445 if (readResult != 8) { 01446 LOG(LOG_IO, LOG_ERROR) ("Reading error in imageDiskVFD constructor\n"); 01447 return; 01448 } 01449 01450 if (!memcmp(tmp,"VFD1.",5)) { 01451 uint32_t stop_at = 0xC3FC; 01452 unsigned long entof; 01453 01454 // load table. 01455 // we have to determine as we go where to stop reading. 01456 // the source of info I read assumes the whole header (and table) 01457 // is 0xC3FC bytes. I'm not inclined to assume that, so we go by 01458 // that OR the first sector offset whichever is smaller. 01459 // the table seems to trail off into a long series of 0xFF at the end. 01460 fseek(diskimg,0xDC,SEEK_SET); 01461 while ((entof=((unsigned long)ftell(diskimg)+12ul)) <= stop_at) { 01462 memset(tmp,0xFF,12); 01463 readResult = fread(tmp,12,1,diskimg); 01464 if (readResult != 1) { 01465 LOG(LOG_IO, LOG_ERROR) ("Reading error in imageDiskVFD constructor\n"); 01466 return; 01467 } 01468 01469 if (!memcmp(tmp,"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",12)) 01470 continue; 01471 if (!memcmp(tmp,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",12)) 01472 continue; 01473 01474 struct vfdentry v; 01475 01476 v.track = tmp[0]; 01477 v.head = tmp[1]; 01478 v.sector = tmp[2]; 01479 v.sizebyte = tmp[3]; 01480 v.fillbyte = tmp[4]; 01481 v.data_offset = *((uint32_t*)(tmp+8)); 01482 v.entry_offset = (uint32_t)entof; 01483 01484 // maybe the table can end sooner than 0xC3FC? 01485 // if we see sectors appear at an offset lower than our stop_at point 01486 // then adjust the stop_at point. assume the table cannot mix with 01487 // sector data. 01488 if (v.hasSectorData()) { 01489 if (stop_at > v.data_offset) 01490 stop_at = v.data_offset; 01491 } 01492 01493 dents.push_back(v); 01494 01495 LOG_MSG("VFD entry: track=%u head=%u sector=%u size=%u fill=0x%2X has_data=%u has_fill=%u entoff=%lu dataoff=%lu", 01496 v.track, 01497 v.head, 01498 v.sector, 01499 v.getSectorSize(), 01500 v.fillbyte, 01501 v.hasSectorData(), 01502 v.hasFill(), 01503 (unsigned long)v.entry_offset, 01504 (unsigned long)v.data_offset); 01505 } 01506 01507 if (!dents.empty()) { 01508 /* okay, now to figure out what the geometry of the disk is. 01509 * we cannot just work from an "absolute" disk image model 01510 * because there's no VFD header to just say what the geometry is. 01511 * Like the IBM PC BIOS, we have to look at the disk and figure out 01512 * which geometry to apply to it, even if the FDD format allows 01513 * sectors on other tracks to have wild out of range sector, track, 01514 * and head numbers or odd sized sectors. 01515 * 01516 * First, determine sector size according to the boot sector. */ 01517 const vfdentry *ent; 01518 01519 ent = findSector(/*head*/0,/*track*/0,/*sector*/1,~0U); 01520 if (ent != NULL) { 01521 if (ent->sizebyte <= 3) /* x <= 1024 */ 01522 sector_size = ent->getSectorSize(); 01523 } 01524 01525 /* oh yeah right, sure. 01526 * I suppose you're one of those FDD images where the sector size is 128 bytes/sector 01527 * in the boot sector and the rest is 256 bytes/sector elsewhere. I have no idea why 01528 * but quite a few FDD images have this arrangement. */ 01529 if (sector_size != 0 && sector_size < 512) { 01530 ent = findSector(/*head*/0,/*track*/1,/*sector*/1,~0U); 01531 if (ent != NULL) { 01532 if (ent->sizebyte <= 3) { /* x <= 1024 */ 01533 unsigned int nsz = ent->getSectorSize(); 01534 if (sector_size != nsz) 01535 LOG_MSG("VFD warning: sector size changes between track 0 and 1"); 01536 if (sector_size < nsz) 01537 sector_size = nsz; 01538 } 01539 } 01540 } 01541 01542 Bit8u i; 01543 if (sector_size != 0) { 01544 i=0; 01545 while (DiskGeometryList[i].ksize != 0) { 01546 const diskGeo &diskent = DiskGeometryList[i]; 01547 01548 if (diskent.bytespersect == sector_size) { 01549 ent = findSector(0,0,diskent.secttrack); 01550 if (ent != NULL) { 01551 LOG_MSG("VFD disk probe: %u/%u/%u exists",0,0,diskent.secttrack); 01552 if (sectors < diskent.secttrack) 01553 sectors = diskent.secttrack; 01554 } 01555 } 01556 01557 i++; 01558 } 01559 } 01560 01561 if (sector_size != 0 && sectors != 0) { 01562 i=0; 01563 while (DiskGeometryList[i].ksize != 0) { 01564 const diskGeo &diskent = DiskGeometryList[i]; 01565 01566 if (diskent.bytespersect == sector_size && diskent.secttrack >= sectors) { 01567 ent = findSector(0,diskent.cylcount-1,sectors); 01568 if (ent != NULL) { 01569 LOG_MSG("VFD disk probe: %u/%u/%u exists",0,diskent.cylcount-1,sectors); 01570 if (cylinders < diskent.cylcount) 01571 cylinders = diskent.cylcount; 01572 } 01573 } 01574 01575 i++; 01576 } 01577 } 01578 01579 if (sector_size != 0 && sectors != 0 && cylinders != 0) { 01580 ent = findSector(1,0,sectors); 01581 if (ent != NULL) { 01582 LOG_MSG("VFD disk probe: %u/%u/%u exists",1,0,sectors); 01583 heads = 2; 01584 } 01585 } 01586 01587 // TODO: drive_fat.cpp should use an extension to this API to allow changing the sectors/track 01588 // according to what it reads from the MS-DOS BIOS parameter block, just like real MS-DOS. 01589 // This would allow better representation of strange disk formats such as the "extended" 01590 // floppy format that Microsoft used to use for Word 95 and Windows 95 install floppies. 01591 01592 LOG_MSG("VFD geometry detection: C/H/S %u/%u/%u %u bytes/sector", 01593 cylinders, heads, sectors, sector_size); 01594 01595 bool founddisk = false; 01596 if (sector_size != 0 && sectors != 0 && cylinders != 0 && heads != 0) 01597 founddisk = true; 01598 01599 if(!founddisk) { 01600 active = false; 01601 } else { 01602 incrementFDD(); 01603 } 01604 } 01605 } 01606 } 01607 01608 imageDiskVFD::~imageDiskVFD() { 01609 if(diskimg != NULL) { 01610 fclose(diskimg); 01611 diskimg=NULL; 01612 } 01613 } 01614 01615 // D88 *.D88 floppy disk format support 01616 01617 enum { 01618 D88_TRACKMAX = 164, 01619 D88_HEADERSIZE = 0x20 + (D88_TRACKMAX * 4) 01620 }; 01621 01622 #pragma pack(push,1) 01623 typedef struct D88HEAD { 01624 char fd_name[17]; // +0x00 Disk Name 01625 unsigned char reserved1[9]; // +0x11 Reserved 01626 unsigned char protect; // +0x1A Write Protect bit:4 01627 unsigned char fd_type; // +0x1B Disk Format 01628 uint32_t fd_size; // +0x1C Disk Size 01629 uint32_t trackp[D88_TRACKMAX]; // +0x20 <array of DWORDs> 164 x 4 = 656 = 0x290 01630 } D88HEAD; // =0x2B0 total 01631 01632 typedef struct D88SEC { 01633 unsigned char c; // +0x00 01634 unsigned char h; // +0x01 01635 unsigned char r; // +0x02 01636 unsigned char n; // +0x03 01637 uint16_t sectors; // +0x04 Sector Count 01638 unsigned char mfm_flg; // +0x06 sides 01639 unsigned char del_flg; // +0x07 DELETED DATA 01640 unsigned char stat; // +0x08 STATUS (FDC ret) 01641 unsigned char seektime; // +0x09 Seek Time 01642 unsigned char reserved[3]; // +0x0A Reserved 01643 unsigned char rpm_flg; // +0x0D rpm 0:1.2 1:1.44 01644 uint16_t size; // +0x0E Sector Size 01645 // <sector contents follow> 01646 } D88SEC; // =0x10 total 01647 #pragma pack(pop) 01648 01649 Bit8u imageDiskD88::Read_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data,unsigned int req_sector_size) { 01650 const vfdentry *ent; 01651 01652 if (req_sector_size == 0) 01653 req_sector_size = sector_size; 01654 01655 // LOG_MSG("D88 read sector: CHS %u/%u/%u sz=%u",cylinder,head,sector,req_sector_size); 01656 01657 ent = findSector(head,cylinder,sector,req_sector_size); 01658 if (ent == NULL) return 0x05; 01659 if (ent->getSectorSize() != req_sector_size) return 0x05; 01660 01661 fseek(diskimg,(long)ent->data_offset,SEEK_SET); 01662 if ((uint32_t)ftell(diskimg) != ent->data_offset) return 0x05; 01663 if (fread(data,req_sector_size,1,diskimg) != 1) return 0x05; 01664 return 0; 01665 } 01666 01667 Bit8u imageDiskD88::Read_AbsoluteSector(Bit32u sectnum, void * data) { 01668 unsigned int c,h,s; 01669 01670 if (sectors == 0 || heads == 0) 01671 return 0x05; 01672 01673 s = (sectnum % sectors) + 1; 01674 h = (sectnum / sectors) % heads; 01675 c = (sectnum / sectors / heads); 01676 return Read_Sector(h,c,s,data); 01677 } 01678 01679 imageDiskD88::vfdentry *imageDiskD88::findSector(Bit8u head,Bit8u track,Bit8u sector/*TODO: physical head?*/,unsigned int req_sector_size) { 01680 if ((size_t)track >= dents.size()) 01681 return NULL; 01682 01683 std::vector<imageDiskD88::vfdentry>::iterator i = dents.begin(); 01684 01685 if (req_sector_size == 0) 01686 req_sector_size = sector_size; 01687 01688 while (i != dents.end()) { 01689 const imageDiskD88::vfdentry &ent = *i; 01690 01691 if (ent.head == head && 01692 ent.track == track && 01693 ent.sector == sector && 01694 (ent.sector_size == req_sector_size || req_sector_size == ~0U)) 01695 return &(*i); 01696 01697 ++i; 01698 } 01699 01700 return NULL; 01701 } 01702 01703 Bit8u imageDiskD88::Write_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,const void * data,unsigned int req_sector_size) { 01704 const vfdentry *ent; 01705 01706 if (req_sector_size == 0) 01707 req_sector_size = sector_size; 01708 01709 // LOG_MSG("D88 read sector: CHS %u/%u/%u sz=%u",cylinder,head,sector,req_sector_size); 01710 01711 ent = findSector(head,cylinder,sector,req_sector_size); 01712 if (ent == NULL) return 0x05; 01713 if (ent->getSectorSize() != req_sector_size) return 0x05; 01714 01715 fseek(diskimg,(long)ent->data_offset,SEEK_SET); 01716 if ((uint32_t)ftell(diskimg) != ent->data_offset) return 0x05; 01717 if (fwrite(data,req_sector_size,1,diskimg) != 1) return 0x05; 01718 return 0; 01719 } 01720 01721 Bit8u imageDiskD88::Write_AbsoluteSector(Bit32u sectnum,const void *data) { 01722 unsigned int c,h,s; 01723 01724 if (sectors == 0 || heads == 0) 01725 return 0x05; 01726 01727 s = (sectnum % sectors) + 1; 01728 h = (sectnum / sectors) % heads; 01729 c = (sectnum / sectors / heads); 01730 return Write_Sector(h,c,s,data); 01731 } 01732 01733 imageDiskD88::imageDiskD88(FILE *imgFile, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk) : imageDisk(ID_D88) { 01734 (void)isHardDisk;//UNUSED 01735 D88HEAD head; 01736 01737 fd_type_major = DISKTYPE_2D; 01738 fd_type_minor = 0; 01739 01740 assert(sizeof(D88HEAD) == 0x2B0); 01741 assert(sizeof(D88SEC) == 0x10); 01742 01743 heads = 0; 01744 cylinders = 0; 01745 image_base = 0; 01746 sectors = 0; 01747 active = false; 01748 sector_size = 0; 01749 reserved_cylinders = 0; 01750 diskSizeK = imgSizeK; 01751 diskimg = imgFile; 01752 01753 if (imgName != NULL) 01754 diskname = (const char*)imgName; 01755 01756 // NOTES: 01757 // 01758 // +0x000: D88 header 01759 // +0x020: Offset of D88 tracks, per track 01760 // +0x2B0: <begin data> 01761 // 01762 // Track offsets are sequential, always 01763 // 01764 // Each track is an array of: 01765 // 01766 // ENTRY: 01767 // <D88 sector head> 01768 // <sector contents> 01769 // 01770 // Array of ENTRY from offset until next track 01771 fseek(diskimg,0,SEEK_END); 01772 off_t fsz = ftell(diskimg); 01773 01774 fseek(diskimg,0,SEEK_SET); 01775 if (fread(&head,sizeof(head),1,diskimg) != 1) return; 01776 01777 // validate fd_size 01778 if ((uint32_t)host_readd((ConstHostPt)(&head.fd_size)) > (uint32_t)fsz) return; 01779 01780 fd_type_major = head.fd_type >> 4U; 01781 fd_type_minor = head.fd_type & 0xFU; 01782 01783 // validate that none of the track offsets extend past the file 01784 { 01785 for (unsigned int i=0;i < D88_TRACKMAX;i++) { 01786 uint32_t trackoff = host_readd((ConstHostPt)(&head.trackp[i])); 01787 01788 if (trackoff == 0) continue; 01789 01790 if ((trackoff + 16U) > (uint32_t)fsz) { 01791 LOG_MSG("D88: track starts past end of file"); 01792 return; 01793 } 01794 } 01795 } 01796 01797 // read each track 01798 for (unsigned int track=0;track < D88_TRACKMAX;track++) { 01799 uint32_t trackoff = host_readd((ConstHostPt)(&head.trackp[track])); 01800 01801 if (trackoff != 0) { 01802 fseek(diskimg, (long)trackoff, SEEK_SET); 01803 if ((off_t)ftell(diskimg) != (off_t)trackoff) continue; 01804 01805 D88SEC s; 01806 unsigned int count = 0; 01807 01808 do { 01809 if (fread(&s,sizeof(s),1,diskimg) != 1) break; 01810 01811 uint16_t sector_count = host_readw((ConstHostPt)(&s.sectors)); 01812 uint16_t sector_size = host_readw((ConstHostPt)(&s.size)); 01813 01814 if (sector_count == 0U || sector_size < 128U) break; 01815 if (sector_count > 128U || sector_size > 16384U) break; 01816 if (s.n > 8U) s.n = 8U; 01817 01818 vfdentry vent; 01819 vent.sector_size = 128 << s.n; 01820 vent.data_offset = (uint32_t)ftell(diskimg); 01821 vent.entry_offset = vent.data_offset - (uint32_t)16; 01822 vent.track = s.c; 01823 vent.head = s.h; 01824 vent.sector = s.r; 01825 01826 LOG_MSG("D88: trackindex=%u C/H/S/sz=%u/%u/%u/%u data-at=0x%lx", 01827 track,vent.track,vent.head,vent.sector,vent.sector_size,(unsigned long)vent.data_offset); 01828 01829 dents.push_back(vent); 01830 if ((++count) >= sector_count) break; 01831 01832 fseek(diskimg, (long)sector_size, SEEK_CUR); 01833 } while (1); 01834 } 01835 } 01836 01837 if (!dents.empty()) { 01838 /* okay, now to figure out what the geometry of the disk is. 01839 * we cannot just work from an "absolute" disk image model 01840 * because there's no D88 header to just say what the geometry is. 01841 * Like the IBM PC BIOS, we have to look at the disk and figure out 01842 * which geometry to apply to it, even if the FDD format allows 01843 * sectors on other tracks to have wild out of range sector, track, 01844 * and head numbers or odd sized sectors. 01845 * 01846 * First, determine sector size according to the boot sector. */ 01847 bool founddisk = false; 01848 const vfdentry *ent; 01849 01850 ent = findSector(/*head*/0,/*track*/0,/*sector*/1,~0U); 01851 if (ent != NULL) { 01852 if (ent->getSectorSize() <= 1024) /* x <= 1024 */ 01853 sector_size = ent->getSectorSize(); 01854 } 01855 01856 /* oh yeah right, sure. 01857 * I suppose you're one of those FDD images where the sector size is 128 bytes/sector 01858 * in the boot sector and the rest is 256 bytes/sector elsewhere. I have no idea why 01859 * but quite a few FDD images have this arrangement. */ 01860 if (sector_size != 0 && sector_size < 512) { 01861 ent = findSector(/*head*/0,/*track*/1,/*sector*/1,~0U); 01862 if (ent != NULL) { 01863 if (ent->getSectorSize() <= 1024) { /* x <= 1024 */ 01864 unsigned int nsz = ent->getSectorSize(); 01865 if (sector_size != nsz) 01866 LOG_MSG("D88 warning: sector size changes between track 0 and 1"); 01867 if (sector_size < nsz) 01868 sector_size = nsz; 01869 } 01870 } 01871 } 01872 01873 if (sector_size != 0) { 01874 unsigned int i = 0; 01875 while (DiskGeometryList[i].ksize != 0) { 01876 const diskGeo &diskent = DiskGeometryList[i]; 01877 01878 if (diskent.bytespersect == sector_size) { 01879 ent = findSector(0,0,diskent.secttrack); 01880 if (ent != NULL) { 01881 LOG_MSG("D88 disk probe: %u/%u/%u exists",0,0,diskent.secttrack); 01882 if (sectors < diskent.secttrack) 01883 sectors = diskent.secttrack; 01884 } 01885 } 01886 01887 i++; 01888 } 01889 } 01890 01891 if (sector_size != 0 && sectors != 0) { 01892 unsigned int i = 0; 01893 while (DiskGeometryList[i].ksize != 0) { 01894 const diskGeo &diskent = DiskGeometryList[i]; 01895 01896 if (diskent.bytespersect == sector_size && diskent.secttrack >= sectors) { 01897 ent = findSector(0,diskent.cylcount-1,sectors); 01898 if (ent != NULL) { 01899 LOG_MSG("D88 disk probe: %u/%u/%u exists",0,diskent.cylcount-1,sectors); 01900 if (cylinders < diskent.cylcount) 01901 cylinders = diskent.cylcount; 01902 } 01903 } 01904 01905 i++; 01906 } 01907 } 01908 01909 if (sector_size != 0 && sectors != 0 && cylinders != 0) { 01910 ent = findSector(1,0,sectors); 01911 if (ent != NULL) { 01912 LOG_MSG("D88 disk probe: %u/%u/%u exists",1,0,sectors); 01913 heads = 2; 01914 } 01915 } 01916 01917 // TODO: drive_fat.cpp should use an extension to this API to allow changing the sectors/track 01918 // according to what it reads from the MS-DOS BIOS parameter block, just like real MS-DOS. 01919 // This would allow better representation of strange disk formats such as the "extended" 01920 // floppy format that Microsoft used to use for Word 95 and Windows 95 install floppies. 01921 01922 LOG_MSG("D88 geometry detection: C/H/S %u/%u/%u %u bytes/sector", 01923 cylinders, heads, sectors, sector_size); 01924 01925 if (sector_size != 0 && sectors != 0 && cylinders != 0 && heads != 0) 01926 founddisk = true; 01927 01928 if(!founddisk) { 01929 active = false; 01930 } else { 01931 incrementFDD(); 01932 } 01933 } 01934 } 01935 01936 imageDiskD88::~imageDiskD88() { 01937 if(diskimg != NULL) { 01938 fclose(diskimg); 01939 diskimg=NULL; 01940 } 01941 } 01942 01943 /*--------------------------------*/ 01944 01945 Bit8u imageDiskNFD::Read_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data,unsigned int req_sector_size) { 01946 const vfdentry *ent; 01947 01948 if (req_sector_size == 0) 01949 req_sector_size = sector_size; 01950 01951 // LOG_MSG("NFD read sector: CHS %u/%u/%u sz=%u",cylinder,head,sector,req_sector_size); 01952 01953 ent = findSector(head,cylinder,sector,req_sector_size); 01954 if (ent == NULL) return 0x05; 01955 if (ent->getSectorSize() != req_sector_size) return 0x05; 01956 01957 fseek(diskimg,(long)ent->data_offset,SEEK_SET); 01958 if ((uint32_t)ftell(diskimg) != ent->data_offset) return 0x05; 01959 if (fread(data,req_sector_size,1,diskimg) != 1) return 0x05; 01960 return 0; 01961 } 01962 01963 Bit8u imageDiskNFD::Read_AbsoluteSector(Bit32u sectnum, void * data) { 01964 unsigned int c,h,s; 01965 01966 if (sectors == 0 || heads == 0) 01967 return 0x05; 01968 01969 s = (sectnum % sectors) + 1; 01970 h = (sectnum / sectors) % heads; 01971 c = (sectnum / sectors / heads); 01972 return Read_Sector(h,c,s,data); 01973 } 01974 01975 imageDiskNFD::vfdentry *imageDiskNFD::findSector(Bit8u head,Bit8u track,Bit8u sector/*TODO: physical head?*/,unsigned int req_sector_size) { 01976 if ((size_t)track >= dents.size()) 01977 return NULL; 01978 01979 std::vector<imageDiskNFD::vfdentry>::iterator i = dents.begin(); 01980 01981 if (req_sector_size == 0) 01982 req_sector_size = sector_size; 01983 01984 while (i != dents.end()) { 01985 const imageDiskNFD::vfdentry &ent = *i; 01986 01987 if (ent.head == head && 01988 ent.track == track && 01989 ent.sector == sector && 01990 (ent.sector_size == req_sector_size || req_sector_size == ~0U)) 01991 return &(*i); 01992 01993 ++i; 01994 } 01995 01996 return NULL; 01997 } 01998 01999 Bit8u imageDiskNFD::Write_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,const void * data,unsigned int req_sector_size) { 02000 const vfdentry *ent; 02001 02002 if (req_sector_size == 0) 02003 req_sector_size = sector_size; 02004 02005 // LOG_MSG("NFD read sector: CHS %u/%u/%u sz=%u",cylinder,head,sector,req_sector_size); 02006 02007 ent = findSector(head,cylinder,sector,req_sector_size); 02008 if (ent == NULL) return 0x05; 02009 if (ent->getSectorSize() != req_sector_size) return 0x05; 02010 02011 fseek(diskimg,(long)ent->data_offset,SEEK_SET); 02012 if ((uint32_t)ftell(diskimg) != ent->data_offset) return 0x05; 02013 if (fwrite(data,req_sector_size,1,diskimg) != 1) return 0x05; 02014 return 0; 02015 } 02016 02017 Bit8u imageDiskNFD::Write_AbsoluteSector(Bit32u sectnum,const void *data) { 02018 unsigned int c,h,s; 02019 02020 if (sectors == 0 || heads == 0) 02021 return 0x05; 02022 02023 s = (sectnum % sectors) + 1; 02024 h = (sectnum / sectors) % heads; 02025 c = (sectnum / sectors / heads); 02026 return Write_Sector(h,c,s,data); 02027 } 02028 02029 imageDiskNFD::imageDiskNFD(FILE *imgFile, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk, unsigned int revision) : imageDisk(ID_NFD) { 02030 (void)isHardDisk;//UNUSED 02031 union { 02032 NFDHDR head; 02033 NFDHDRR1 headr1; 02034 }; // these occupy the same location of memory 02035 02036 assert(sizeof(NFDHDR) == 0x120); 02037 assert(sizeof(NFDHDRR1) == 0x3C0); 02038 assert(sizeof(NFDHDR_ENTRY) == 0x10); 02039 02040 heads = 0; 02041 cylinders = 0; 02042 image_base = 0; 02043 sectors = 0; 02044 active = false; 02045 sector_size = 0; 02046 reserved_cylinders = 0; 02047 diskSizeK = imgSizeK; 02048 diskimg = imgFile; 02049 02050 if (imgName != NULL) 02051 diskname = (const char*)imgName; 02052 02053 // NOTES: 02054 // 02055 // +0x000: NFD header 02056 // +0x020: Offset of NFD tracks, per track 02057 // +0x2B0: <begin data> 02058 // 02059 // Track offsets are sequential, always 02060 // 02061 // Each track is an array of: 02062 // 02063 // ENTRY: 02064 // <NFD sector head> 02065 // <sector contents> 02066 // 02067 // Array of ENTRY from offset until next track 02068 fseek(diskimg,0,SEEK_END); 02069 off_t fsz = ftell(diskimg); 02070 02071 fseek(diskimg,0,SEEK_SET); 02072 if (revision == 0) { 02073 if (fread(&head,sizeof(head),1,diskimg) != 1) return; 02074 } 02075 else if (revision == 1) { 02076 if (fread(&headr1,sizeof(headr1),1,diskimg) != 1) return; 02077 } 02078 else { 02079 abort(); 02080 } 02081 02082 // validate fd_size 02083 if ((uint32_t)host_readd((ConstHostPt)(&head.headersize)) < sizeof(head)) return; 02084 if ((uint32_t)host_readd((ConstHostPt)(&head.headersize)) > (uint32_t)fsz) return; 02085 02086 unsigned int data_offset = host_readd((ConstHostPt)(&head.headersize)); 02087 02088 std::vector< std::pair<uint32_t,NFDHDR_ENTRY> > seclist; 02089 02090 if (revision == 0) { 02091 unsigned int secents = (host_readd((ConstHostPt)(&head.headersize)) - sizeof(head)) / sizeof(NFDHDR_ENTRY); 02092 if (secents == 0) return; 02093 secents--; 02094 if (secents == 0) return; 02095 02096 for (unsigned int i=0;i < secents;i++) { 02097 uint32_t ofs = (uint32_t)ftell(diskimg); 02098 NFDHDR_ENTRY e; 02099 02100 if (fread(&e,sizeof(e),1,diskimg) != 1) return; 02101 seclist.push_back( std::pair<uint32_t,NFDHDR_ENTRY>(ofs,e) ); 02102 02103 if (e.log_cyl == 0xFF || e.log_head == 0xFF || e.log_rec == 0xFF || e.sec_len_pow2 > 7) 02104 continue; 02105 02106 LOG_MSG("NFD %u/%u: ofs=%lu data=%lu cyl=%u head=%u sec=%u len=%u", 02107 (unsigned int)i, 02108 (unsigned int)secents, 02109 (unsigned long)ofs, 02110 (unsigned long)data_offset, 02111 e.log_cyl, 02112 e.log_head, 02113 e.log_rec, 02114 128 << e.sec_len_pow2); 02115 02116 vfdentry vent; 02117 vent.sector_size = 128 << e.sec_len_pow2; 02118 vent.data_offset = (uint32_t)data_offset; 02119 vent.entry_offset = (uint32_t)ofs; 02120 vent.track = e.log_cyl; 02121 vent.head = e.log_head; 02122 vent.sector = e.log_rec; 02123 dents.push_back(vent); 02124 02125 data_offset += 128u << e.sec_len_pow2; 02126 if (data_offset > (unsigned int)fsz) return; 02127 } 02128 } 02129 else { 02130 /* R1 has an array of offsets to where each tracks begins. 02131 * The end of the track is an entry like 0x1A 0x00 0x00 0x00 0x00 0x00 0x00 .... */ 02132 /* The R1 images I have as reference always have offsets in ascending order. */ 02133 for (unsigned int ti=0;ti < 164;ti++) { 02134 uint32_t trkoff = host_readd((ConstHostPt)(&headr1.trackheads[ti])); 02135 02136 if (trkoff == 0) break; 02137 02138 fseek(diskimg,(long)trkoff,SEEK_SET); 02139 if ((off_t)ftell(diskimg) != (off_t)trkoff) return; 02140 02141 NFDHDR_ENTRY e; 02142 02143 // track id 02144 if (fread(&e,sizeof(e),1,diskimg) != 1) return; 02145 unsigned int sectors = host_readw((ConstHostPt)(&e) + 0); 02146 unsigned int diagcount = host_readw((ConstHostPt)(&e) + 2); 02147 02148 LOG_MSG("NFD R1 track ent %u offset %lu sectors %u diag %u",ti,(unsigned long)trkoff,sectors,diagcount); 02149 02150 for (unsigned int s=0;s < sectors;s++) { 02151 uint32_t ofs = (uint32_t)ftell(diskimg); 02152 02153 if (fread(&e,sizeof(e),1,diskimg) != 1) return; 02154 02155 LOG_MSG("NFD %u/%u: ofs=%lu data=%lu cyl=%u head=%u sec=%u len=%u rep=%u", 02156 (unsigned int)s, 02157 (unsigned int)sectors, 02158 (unsigned long)ofs, 02159 (unsigned long)data_offset, 02160 e.log_cyl, 02161 e.log_head, 02162 e.log_rec, 02163 128 << e.sec_len_pow2, 02164 e.byRetry); 02165 02166 vfdentry vent; 02167 vent.sector_size = 128 << e.sec_len_pow2; 02168 vent.data_offset = (uint32_t)data_offset; 02169 vent.entry_offset = (uint32_t)ofs; 02170 vent.track = e.log_cyl; 02171 vent.head = e.log_head; 02172 vent.sector = e.log_rec; 02173 dents.push_back(vent); 02174 02175 data_offset += 128u << e.sec_len_pow2; 02176 if (data_offset > (unsigned int)fsz) return; 02177 } 02178 02179 for (unsigned int d=0;d < diagcount;d++) { 02180 if (fread(&e,sizeof(e),1,diskimg) != 1) return; 02181 02182 unsigned int retry = e.byRetry; 02183 unsigned int len = host_readd((ConstHostPt)(&e) + 10); 02184 02185 LOG_MSG("NFD diag %u/%u: retry=%u len=%u data=%lu",d,diagcount,retry,len,(unsigned long)data_offset); 02186 02187 data_offset += (1+retry) * len; 02188 } 02189 } 02190 } 02191 02192 if (!dents.empty()) { 02193 /* okay, now to figure out what the geometry of the disk is. 02194 * we cannot just work from an "absolute" disk image model 02195 * because there's no NFD header to just say what the geometry is. 02196 * Like the IBM PC BIOS, we have to look at the disk and figure out 02197 * which geometry to apply to it, even if the FDD format allows 02198 * sectors on other tracks to have wild out of range sector, track, 02199 * and head numbers or odd sized sectors. 02200 * 02201 * First, determine sector size according to the boot sector. */ 02202 bool founddisk = false; 02203 const vfdentry *ent; 02204 02205 ent = findSector(/*head*/0,/*track*/0,/*sector*/1,~0U); 02206 if (ent != NULL) { 02207 if (ent->getSectorSize() <= 1024) /* x <= 1024 */ 02208 sector_size = ent->getSectorSize(); 02209 } 02210 02211 /* oh yeah right, sure. 02212 * I suppose you're one of those FDD images where the sector size is 128 bytes/sector 02213 * in the boot sector and the rest is 256 bytes/sector elsewhere. I have no idea why 02214 * but quite a few FDD images have this arrangement. */ 02215 if (sector_size != 0 && sector_size < 512) { 02216 ent = findSector(/*head*/0,/*track*/1,/*sector*/1,~0U); 02217 if (ent != NULL) { 02218 if (ent->getSectorSize() <= 1024) { /* x <= 1024 */ 02219 unsigned int nsz = ent->getSectorSize(); 02220 if (sector_size != nsz) 02221 LOG_MSG("NFD warning: sector size changes between track 0 and 1"); 02222 if (sector_size < nsz) 02223 sector_size = nsz; 02224 } 02225 } 02226 } 02227 02228 if (sector_size != 0) { 02229 unsigned int i = 0; 02230 while (DiskGeometryList[i].ksize != 0) { 02231 const diskGeo &diskent = DiskGeometryList[i]; 02232 02233 if (diskent.bytespersect == sector_size) { 02234 ent = findSector(0,0,diskent.secttrack); 02235 if (ent != NULL) { 02236 LOG_MSG("NFD disk probe: %u/%u/%u exists",0,0,diskent.secttrack); 02237 if (sectors < diskent.secttrack) 02238 sectors = diskent.secttrack; 02239 } 02240 } 02241 02242 i++; 02243 } 02244 } 02245 02246 if (sector_size != 0 && sectors != 0) { 02247 unsigned int i = 0; 02248 while (DiskGeometryList[i].ksize != 0) { 02249 const diskGeo &diskent = DiskGeometryList[i]; 02250 02251 if (diskent.bytespersect == sector_size && diskent.secttrack >= sectors) { 02252 ent = findSector(0,diskent.cylcount-1,sectors); 02253 if (ent != NULL) { 02254 LOG_MSG("NFD disk probe: %u/%u/%u exists",0,diskent.cylcount-1,sectors); 02255 if (cylinders < diskent.cylcount) 02256 cylinders = diskent.cylcount; 02257 } 02258 } 02259 02260 i++; 02261 } 02262 } 02263 02264 if (sector_size != 0 && sectors != 0 && cylinders != 0) { 02265 ent = findSector(1,0,sectors); 02266 if (ent != NULL) { 02267 LOG_MSG("NFD disk probe: %u/%u/%u exists",1,0,sectors); 02268 heads = 2; 02269 } 02270 } 02271 02272 // TODO: drive_fat.cpp should use an extension to this API to allow changing the sectors/track 02273 // according to what it reads from the MS-DOS BIOS parameter block, just like real MS-DOS. 02274 // This would allow better representation of strange disk formats such as the "extended" 02275 // floppy format that Microsoft used to use for Word 95 and Windows 95 install floppies. 02276 02277 LOG_MSG("NFD geometry detection: C/H/S %u/%u/%u %u bytes/sector", 02278 cylinders, heads, sectors, sector_size); 02279 02280 if (sector_size != 0 && sectors != 0 && cylinders != 0 && heads != 0) 02281 founddisk = true; 02282 02283 if(!founddisk) { 02284 active = false; 02285 } else { 02286 incrementFDD(); 02287 } 02288 } 02289 } 02290 02291 imageDiskNFD::~imageDiskNFD() { 02292 if(diskimg != NULL) { 02293 fclose(diskimg); 02294 diskimg=NULL; 02295 } 02296 } 02297