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 "dosbox.h" 00021 #include "callback.h" 00022 #include "mem.h" 00023 #include "regs.h" 00024 #include "dos_inc.h" 00025 #include "control.h" 00026 #include <list> 00027 00028 Bit32u DOS_HMA_LIMIT(); 00029 Bit32u DOS_HMA_FREE_START(); 00030 Bit32u DOS_HMA_GET_FREE_SPACE(); 00031 void DOS_HMA_CLAIMED(Bit16u bytes); 00032 bool ANSI_SYS_installed(); 00033 00034 extern bool enable_share_exe_fake; 00035 00036 extern Bitu XMS_EnableA20(bool enable); 00037 00038 bool enable_a20_on_windows_init = false; 00039 00040 static Bitu call_int2f,call_int2a; 00041 00042 static std::list<MultiplexHandler*> Multiplex; 00043 typedef std::list<MultiplexHandler*>::iterator Multiplex_it; 00044 00045 const char *Win_NameThatVXD(Bit16u devid) { 00046 switch (devid) { 00047 case 0x0006: return "V86MMGR"; 00048 case 0x000C: return "VMD"; 00049 case 0x000D: return "VKD"; 00050 case 0x0010: return "BLOCKDEV"; 00051 case 0x0014: return "VNETBIOS"; 00052 case 0x0015: return "DOSMGR"; 00053 case 0x0018: return "VMPOLL"; 00054 case 0x0021: return "PAGEFILE"; 00055 case 0x002D: return "W32S"; 00056 case 0x0040: return "IFSMGR"; 00057 case 0x0446: return "VADLIBD"; 00058 case 0x0484: return "IFSMGR"; 00059 case 0x0487: return "NWSUP"; 00060 case 0x28A1: return "PHARLAP"; 00061 case 0x7A5F: return "SIWVID"; 00062 } 00063 00064 return NULL; 00065 } 00066 00067 void DOS_AddMultiplexHandler(MultiplexHandler * handler) { 00068 Multiplex.push_front(handler); 00069 } 00070 00071 void DOS_DelMultiplexHandler(MultiplexHandler * handler) { 00072 for(Multiplex_it it =Multiplex.begin();it != Multiplex.end();++it) { 00073 if(*it == handler) { 00074 Multiplex.erase(it); 00075 return; 00076 } 00077 } 00078 } 00079 00080 static Bitu INT2F_Handler(void) { 00081 for(Multiplex_it it = Multiplex.begin();it != Multiplex.end();++it) 00082 if( (*it)() ) return CBRET_NONE; 00083 00084 LOG(LOG_DOSMISC,LOG_ERROR)("DOS:INT 2F Unhandled call AX=%4X",reg_ax); 00085 return CBRET_NONE; 00086 } 00087 00088 00089 static Bitu INT2A_Handler(void) { 00090 return CBRET_NONE; 00091 } 00092 00093 extern RealPt DOS_DriveDataListHead; // INT 2Fh AX=0803h DRIVER.SYS drive data table list 00094 00095 // INT 2F 00096 char regpath[CROSS_LEN+1]="C:\\WINDOWS\\SYSTEM.DAT"; 00097 static bool DOS_MultiplexFunctions(void) { 00098 char name[256]; 00099 switch (reg_ax) { 00100 case 0x0800: /* DRIVER.SYS function */ 00101 case 0x0801: /* DRIVER.SYS function */ 00102 case 0x0802: /* DRIVER.SYS function */ 00103 LOG(LOG_MISC,LOG_DEBUG)("Unhandled DRIVER.SYS call AX=%04x BX=%04x CX=%04x DX=%04x BP=%04x",reg_ax,reg_bx,reg_cx,reg_dx,reg_bp); 00104 break; 00105 case 0x0803: /* DRIVER.SYS function */ 00106 LOG(LOG_MISC,LOG_DEBUG)("Unhandled DRIVER.SYS call AX=%04x BX=%04x CX=%04x DX=%04x BP=%04x",reg_ax,reg_bx,reg_cx,reg_dx,reg_bp); 00107 // FIXME: Windows 95 SCANDISK.EXE relies on the drive data table list pointer provided by this call. 00108 // Returning DS:DI unmodified or set to 0:0 will only send it off into the weeds chasing random data 00109 // as a linked list. However looking at the code DI=0xFFFF is sufficient to prevent that until 00110 // DOSBox-X emulates DRIVER.SYS functions and provides the information it expects according to RBIL. 00111 // BUT, Windows 95 setup checks if the pointer is NULL, and considers 0:FFFF valid >_<. 00112 // It's just easier to return a pointer to a dummy table. 00113 // [http://www.ctyme.com/intr/rb-4283.htm] 00114 SegSet16(ds,DOS_DriveDataListHead >> 16); 00115 reg_di = DOS_DriveDataListHead; 00116 break; 00117 /* ert, 20100711: Locking extensions */ 00118 case 0x1000: /* SHARE.EXE installation check */ 00119 if (enable_share_exe_fake) { 00120 reg_al = 0xff; /* Pretend that share.exe is installed.. Of course it's a bloody LIE! */ 00121 } 00122 return true; 00123 case 0x1216: /* GET ADDRESS OF SYSTEM FILE TABLE ENTRY */ 00124 // reg_bx is a system file table entry, should coincide with 00125 // the file handle so just use that 00126 LOG(LOG_DOSMISC,LOG_ERROR)("Some BAD filetable call used bx=%X",reg_bx); 00127 if(reg_bx <= DOS_FILES) CALLBACK_SCF(false); 00128 else CALLBACK_SCF(true); 00129 if (reg_bx<16) { 00130 RealPt sftrealpt=mem_readd(Real2Phys(dos_infoblock.GetPointer())+4); 00131 PhysPt sftptr=Real2Phys(sftrealpt); 00132 Bit32u sftofs=0x06u+reg_bx*0x3bu; 00133 00134 if (Files[reg_bx]) mem_writeb(sftptr+sftofs, (Bit8u)(Files[reg_bx]->refCtr)); 00135 else mem_writeb(sftptr+sftofs,0); 00136 00137 if (!Files[reg_bx]) return true; 00138 00139 Bit32u handle=RealHandle(reg_bx); 00140 if (handle>=DOS_FILES) { 00141 mem_writew(sftptr+sftofs+0x02,0x02); // file open mode 00142 mem_writeb(sftptr+sftofs+0x04,0x00); // file attribute 00143 mem_writew(sftptr+sftofs+0x05,Files[reg_bx]->GetInformation()); // device info word 00144 mem_writed(sftptr+sftofs+0x07,0); // device driver header 00145 mem_writew(sftptr+sftofs+0x0d,0); // packed time 00146 mem_writew(sftptr+sftofs+0x0f,0); // packed date 00147 mem_writew(sftptr+sftofs+0x11,0); // size 00148 mem_writew(sftptr+sftofs+0x15,0); // current position 00149 } else { 00150 Bit8u drive=Files[reg_bx]->GetDrive(); 00151 00152 mem_writew(sftptr+sftofs+0x02,(Bit16u)(Files[reg_bx]->flags&3)); // file open mode 00153 mem_writeb(sftptr+sftofs+0x04,(Bit8u)(Files[reg_bx]->attr)); // file attribute 00154 mem_writew(sftptr+sftofs+0x05,0x40|drive); // device info word 00155 mem_writed(sftptr+sftofs+0x07,RealMake(dos.tables.dpb,drive*dos.tables.dpb_size)); // dpb of the drive 00156 mem_writew(sftptr+sftofs+0x0d,Files[reg_bx]->time); // packed file time 00157 mem_writew(sftptr+sftofs+0x0f,Files[reg_bx]->date); // packed file date 00158 Bit32u curpos=0; 00159 Files[reg_bx]->Seek(&curpos,DOS_SEEK_CUR); 00160 Bit32u endpos=0; 00161 Files[reg_bx]->Seek(&endpos,DOS_SEEK_END); 00162 mem_writed(sftptr+sftofs+0x11,endpos); // size 00163 mem_writed(sftptr+sftofs+0x15,curpos); // current position 00164 Files[reg_bx]->Seek(&curpos,DOS_SEEK_SET); 00165 } 00166 00167 // fill in filename in fcb style 00168 // (space-padded name (8 chars)+space-padded extension (3 chars)) 00169 const char* filename=(const char*)Files[reg_bx]->GetName(); 00170 if (strrchr(filename,'\\')) filename=strrchr(filename,'\\')+1; 00171 if (strrchr(filename,'/')) filename=strrchr(filename,'/')+1; 00172 if (!filename) return true; 00173 const char* dotpos=strrchr(filename,'.'); 00174 if (dotpos) { 00175 dotpos++; 00176 size_t nlen=strlen(filename); 00177 size_t extlen=strlen(dotpos); 00178 Bits nmelen=(Bits)nlen-(Bits)extlen; 00179 if (nmelen<1) return true; 00180 nlen-=(extlen+1); 00181 00182 if (nlen>8) nlen=8; 00183 size_t i; 00184 00185 for (i=0; i<nlen; i++) 00186 mem_writeb((PhysPt)(sftptr+sftofs+0x20u+i),(unsigned char)filename[i]); 00187 for (i=nlen; i<8; i++) 00188 mem_writeb((PhysPt)(sftptr+sftofs+0x20u+i),(unsigned char)' '); 00189 00190 if (extlen>3) extlen=3; 00191 for (i=0; i<extlen; i++) 00192 mem_writeb((PhysPt)(sftptr+sftofs+0x28u+i),(unsigned char)dotpos[i]); 00193 for (i=extlen; i<3; i++) 00194 mem_writeb((PhysPt)(sftptr+sftofs+0x28u+i),(unsigned char)' '); 00195 } else { 00196 size_t i; 00197 size_t nlen=strlen(filename); 00198 if (nlen>8) nlen=8; 00199 for (i=0; i<nlen; i++) 00200 mem_writeb((PhysPt)(sftptr+sftofs+0x20u+i),(unsigned char)filename[i]); 00201 for (i=nlen; i<11; i++) 00202 mem_writeb((PhysPt)(sftptr+sftofs+0x20u+i),(unsigned char)' '); 00203 } 00204 00205 SegSet16(es,RealSeg(sftrealpt)); 00206 reg_di=RealOff(sftrealpt+sftofs); 00207 reg_ax=0xc000; 00208 00209 } 00210 return true; 00211 case 0x1300: 00212 case 0x1302: 00213 reg_ax=0; 00214 return true; 00215 case 0x1611: /* Get shell parameters */ 00216 { 00217 if (dos.version.major < 7) return false; 00218 char psp_name[9]; 00219 DOS_MCB psp_mcb(dos.psp()-1); 00220 psp_mcb.GetFileName(psp_name); 00221 if (strcmp(psp_name, "DOSSETUP") == 0) { 00222 /* Hack for Windows 98 SETUP.EXE (Wengier) */ 00223 return false; 00224 } 00225 strcpy(name,"COMMAND.COM"); 00226 MEM_BlockWrite(SegPhys(ds)+reg_dx,name,(Bitu)(strlen(name)+1)); 00227 strcpy(name+1,"/P /D /K AUTOEXEC"); 00228 name[0]=(char)strlen(name+1); 00229 MEM_BlockWrite(SegPhys(ds)+reg_si,name,(Bitu)(strlen(name+1)+2)); 00230 reg_ax=0; 00231 reg_bx=0; 00232 return true; 00233 } 00234 case 0x1612: 00235 if (dos.version.major < 7) return false; 00236 reg_ax=0; 00237 name[0]=1; 00238 name[1]=0; 00239 MEM_BlockWrite(SegPhys(es)+reg_bx,name,0x20); 00240 return true; 00241 case 0x1613: /* Get SYSTEM.DAT path */ 00242 if (dos.version.major < 7) return false; 00243 strcpy(name,regpath); 00244 MEM_BlockWrite(SegPhys(es)+reg_di,name,(Bitu)(strlen(name)+1)); 00245 reg_ax=0; 00246 reg_cx=(Bit16u)strlen(name); 00247 return true; 00248 case 0x1614: /* Set SYSTEM.DAT path */ 00249 if (dos.version.major < 7) return false; 00250 MEM_StrCopy(SegPhys(es)+reg_di,regpath,CROSS_LEN+1); 00251 reg_ax=0; 00252 return true; 00253 case 0x1600: /* Windows enhanced mode installation check */ 00254 // Leave AX as 0x1600, indicating that neither Windows 3.x enhanced mode, Windows/386 2.x 00255 // nor Windows 95 are running, nor is XMS version 1 driver installed 00256 #ifdef WIN32 00257 if (!control->SecureMode() && (reg_sp == 0xFFF6 && mem_readw(SegPhys(ss)+reg_sp) == 0x142A || reg_sp >= 0xFF7A && reg_sp <= 0xFF8F && mem_readw(SegPhys(ss)+reg_sp) == reg_sp + 21)) 00258 reg_ax = 0x301; 00259 #endif 00260 return true; 00261 case 0x1605: /* Windows init broadcast */ 00262 if (enable_a20_on_windows_init) { 00263 /* This hack exists because Windows 3.1 doesn't seem to enable A20 first during an 00264 * initial critical period where it assumes it's on, prior to checking and enabling/disabling it. 00265 * 00266 * Note that Windows 3.1 also makes this mistake in Standard/286 mode, but it doesn't even 00267 * make this callout, so this hack is useless unless you are using Enhanced/386 mode. 00268 * If you want to run Windows 3.1 Standard mode with a20=mask you will have to run builtin 00269 * command "a20gate on" to turn on the A20 gate prior to starting Windows. */ 00270 LOG_MSG("Enabling A20 gate for Windows in response to INIT broadcast"); 00271 XMS_EnableA20(true); 00272 } 00273 00274 /* TODO: Maybe future parts of DOSBox-X will do something with this */ 00275 /* TODO: Don't show this by default. Show if the user wants it by a) setting something to "true" in dosbox.conf or b) running a builtin command in Z:\ */ 00276 LOG_MSG("DEBUG: INT 2Fh Windows 286/386 DOSX init broadcast issued (ES:BX=%04x:%04x DS:SI=%04x:%04x CX=%04x DX=%04x DI=%04x(aka version %u.%u))", 00277 SegValue(es),reg_bx, 00278 SegValue(ds),reg_si, 00279 reg_cx,reg_dx,reg_di, 00280 reg_di>>8,reg_di&0xFF); 00281 if (reg_dx & 0x0001) 00282 LOG_MSG(" [286 DOS extender]"); 00283 else 00284 LOG_MSG(" [Enhanced mode]"); 00285 LOG_MSG("\n"); 00286 00287 /* NTS: The way this protocol works, is that when you (the program hooking this call) receive it, 00288 * you first pass the call down to the previous INT 2Fh handler with registers unmodified, 00289 * and then when the call unwinds back up the chain, THEN you modify the results to notify 00290 * yourself to Windows. So logically, since we're the DOS kernel at the end of the chain, 00291 * we should still see ES:BX=0000:0000 and DS:SI=0000:0000 and CX=0000 unmodified from the 00292 * way the Windows kernel issued the call. If that's not the case, then we need to issue 00293 * a warning because some bastard on the call chain is ruining it for all of us. */ 00294 if (SegValue(es) != 0 || reg_bx != 0 || SegValue(ds) != 0 || reg_si != 0 || reg_cx != 0) { 00295 LOG_MSG("WARNING: Some registers at this point (the top of the call chain) are nonzero.\n"); 00296 LOG_MSG(" That means a TSR or other entity has modified registers on the way down\n"); 00297 LOG_MSG(" the call chain. The Windows init broadcast is supposed to be handled\n"); 00298 LOG_MSG(" going down the chain by calling the previous INT 2Fh handler with registers\n"); 00299 LOG_MSG(" unmodified, and only modify registers on the way back up the chain!\n"); 00300 } 00301 00302 return false; /* pass it on to other INT 2F handlers */ 00303 case 0x1606: /* Windows exit broadcast */ 00304 /* TODO: Maybe future parts of DOSBox-X will do something with this */ 00305 /* TODO: Don't show this by default. Show if the user wants it by a) setting something to "true" in dosbox.conf or b) running a builtin command in Z:\ */ 00306 LOG_MSG("DEBUG: INT 2Fh Windows 286/386 DOSX exit broadcast issued (DX=0x%04x)",reg_dx); 00307 if (reg_dx & 0x0001) 00308 LOG_MSG(" [286 DOS extender]"); 00309 else 00310 LOG_MSG(" [Enhanced mode]"); 00311 LOG_MSG("\n"); 00312 return false; /* pass it on to other INT 2F handlers */ 00313 case 0x1607: 00314 /* TODO: Don't show this by default. Show if the user wants it by a) setting something to "true" in dosbox.conf or b) running a builtin command in Z:\ 00315 * Additionally, if the user WANTS to see every invocation of the IDLE call, then allow them to enable that too */ 00316 if (reg_bx != 0x18) { /* don't show the idle call. it's used too often */ 00317 const char *str = Win_NameThatVXD(reg_bx); 00318 00319 if (str == NULL) str = "??"; 00320 LOG_MSG("DEBUG: INT 2Fh Windows virtual device '%s' callout (BX(deviceID)=0x%04x CX(function)=0x%04x)\n", 00321 str,reg_bx,reg_cx); 00322 } 00323 00324 if (reg_bx == 0x15) { /* DOSMGR */ 00325 switch (reg_cx) { 00326 case 0x0000: // query instance 00327 reg_cx = 0x0001; 00328 reg_dx = 0x50; // dos driver segment 00329 SegSet16(es,0x50); // patch table seg 00330 reg_bx = 0x60; // patch table ofs 00331 return true; 00332 case 0x0001: // set patches 00333 reg_ax = 0xb97c; 00334 reg_bx = (reg_dx & 0x16); 00335 reg_dx = 0xa2ab; 00336 return true; 00337 case 0x0003: // get size of data struc 00338 if (reg_dx==0x0001) { 00339 // CDS size requested 00340 reg_ax = 0xb97c; 00341 reg_dx = 0xa2ab; 00342 reg_cx = 0x000e; // size 00343 } 00344 return true; 00345 case 0x0004: // instanced data 00346 reg_dx = 0; // none 00347 return true; 00348 case 0x0005: // get device driver size 00349 reg_ax = 0; 00350 reg_dx = 0; 00351 return true; 00352 default: 00353 return false; 00354 } 00355 } 00356 else if (reg_bx == 0x18) { /* VMPoll (idle) */ 00357 return true; 00358 } 00359 else return false; 00360 case 0x160A: 00361 { 00362 char psp_name[9]; 00363 DOS_MCB psp_mcb(dos.psp()-1); 00364 psp_mcb.GetFileName(psp_name); 00365 // Report Windows version 4.0 (95) to NESTICLE x.xx so that it uses LFN when available 00366 if (uselfn && (!strcmp(psp_name, "NESTICLE") || reg_sp == 0x220A && mem_readw(SegPhys(ss)+reg_sp)/0x100 == 0x1F)) { 00367 reg_ax = 0; 00368 reg_bx = 0x400; 00369 reg_cx = 2; 00370 return true; 00371 } 00372 return false; 00373 } 00374 case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ 00375 //TODO Maybe do some idling but could screw up other systems :) 00376 return true; //So no warning in the debugger anymore 00377 case 0x1689: /* Kernel IDLE CALL */ 00378 case 0x168f: /* Close awareness crap */ 00379 /* Removing warning */ 00380 return true; 00381 #ifdef WIN32 00382 case 0x1700: 00383 if(control->SecureMode()) return false; 00384 reg_al = 1; 00385 reg_ah = 1; 00386 return true; 00387 case 0x1701: 00388 if(control->SecureMode()) return false; 00389 reg_ax=0; 00390 if (OpenClipboard(NULL)) { 00391 reg_ax=1; 00392 CloseClipboard(); 00393 } 00394 return true; 00395 case 0x1702: 00396 if(control->SecureMode()) return false; 00397 reg_ax=0; 00398 if (OpenClipboard(NULL)) 00399 { 00400 reg_ax=EmptyClipboard()?1:0; 00401 CloseClipboard(); 00402 } 00403 return true; 00404 case 0x1703: 00405 if(control->SecureMode()) return false; 00406 reg_ax=0; 00407 if ((reg_dx==1||reg_dx==7)&&OpenClipboard(NULL)) 00408 { 00409 char *text, *buffer; 00410 text = new char[reg_cx]; 00411 MEM_StrCopy(SegPhys(es)+reg_bx,text,reg_cx); 00412 *(text+reg_cx-1)=0; 00413 HGLOBAL clipbuffer; 00414 EmptyClipboard(); 00415 clipbuffer = GlobalAlloc(GMEM_DDESHARE, strlen(text)+1); 00416 buffer = (char*)GlobalLock(clipbuffer); 00417 strcpy(buffer, text); 00418 delete[] text; 00419 GlobalUnlock(clipbuffer); 00420 SetClipboardData(reg_dx==1?CF_TEXT:CF_OEMTEXT,clipbuffer); 00421 reg_ax++; 00422 CloseClipboard(); 00423 } 00424 return true; 00425 case 0x1704: 00426 if(control->SecureMode()) return false; 00427 reg_ax=0; 00428 if ((reg_dx==1||reg_dx==7)&&OpenClipboard(NULL)) 00429 { 00430 if (HANDLE text = GetClipboardData(reg_dx==1?CF_TEXT:CF_OEMTEXT)) 00431 { 00432 reg_ax=(Bit16u)strlen((char *)text)+1; 00433 reg_dx=(Bit16u)((strlen((char *)text)+1)/65536); 00434 } 00435 else 00436 reg_dx=0; 00437 CloseClipboard(); 00438 } 00439 return true; 00440 case 0x1705: 00441 if(control->SecureMode()) return false; 00442 reg_ax=0; 00443 if ((reg_dx==1||reg_dx==7)&&OpenClipboard(NULL)) 00444 { 00445 if (HANDLE text = GetClipboardData(reg_dx==1?CF_TEXT:CF_OEMTEXT)) 00446 { 00447 MEM_BlockWrite(SegPhys(es)+reg_bx,text,(Bitu)(strlen((char *)text)+1)); 00448 reg_ax++; 00449 } 00450 CloseClipboard(); 00451 } 00452 return true; 00453 case 0x1708: 00454 if(control->SecureMode()) return false; 00455 reg_ax=1; 00456 CloseClipboard(); 00457 return true; 00458 #endif 00459 case 0x1a00: /* ANSI.SYS installation check (MS-DOS 4.0 or higher) */ 00460 if (IS_PC98_ARCH) { 00461 /* NTS: PC-98 MS-DOS has ANSI handling directly within the kernel HOWEVER it does NOT 00462 * respond to this INT 2Fh call. */ 00463 return true; 00464 } 00465 else if (ANSI_SYS_installed()) { 00466 /* See also: [http://www.delorie.com/djgpp/doc/rbinter/id/71/46.html] */ 00467 /* Reported behavior was confirmed with ANSI.SYS loaded on a Windows 95 MS-DOS boot disk, result AX=1AFF */ 00468 reg_al = 0xFF; /* DOSBox/DOSBox-X console device emulates ANSI.SYS, so respond like it's installed */ 00469 return true; 00470 } 00471 else { 00472 /* MS-DOS without ANSI.SYS loaded doesn't modify any registers in response to this call. */ 00473 return true; 00474 } 00475 case 0x4680: /* Windows v3.0 check */ 00476 // Leave AX as 0x4680, indicating that Windows 3.0 is not running in real (/R) or standard (/S) mode, 00477 // nor is DOS 5 DOSSHELL active 00478 return true; 00479 case 0x4a01: { /* Query free hma space */ 00480 Bit32u limit = DOS_HMA_LIMIT(); 00481 00482 if (limit == 0) { 00483 /* TODO: What does MS-DOS prior to v5.0? */ 00484 reg_bx = 0; 00485 reg_di = 0xFFFF; 00486 SegSet16(es,0xFFFF); 00487 LOG(LOG_MISC,LOG_DEBUG)("HMA query: rejected"); 00488 return true; 00489 } 00490 00491 Bit32u start = DOS_HMA_FREE_START(); 00492 reg_bx = limit - start; /* free space in bytes */ 00493 SegSet16(es,0xffff); 00494 reg_di = (start + 0x10) & 0xFFFF; 00495 LOG(LOG_MISC,LOG_DEBUG)("HMA query: start=0x%06x limit=0x%06x free=0x%06x -> bx=%u %04x:%04x", 00496 start,limit,DOS_HMA_GET_FREE_SPACE(),(int)reg_bx,(int)SegValue(es),(int)reg_di); 00497 } return true; 00498 case 0x4a02: { /* ALLOCATE HMA SPACE */ 00499 Bit32u limit = DOS_HMA_LIMIT(); 00500 00501 if (limit == 0) { 00502 /* TODO: What does MS-DOS prior to v5.0? */ 00503 reg_bx = 0; 00504 reg_di = 0xFFFF; 00505 SegSet16(es,0xFFFF); 00506 LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: rejected"); 00507 return true; 00508 } 00509 00510 /* NTS: According to RBIL, Windows 95 adds a deallocate function and changes HMA allocation up to follow a 00511 * MCB chain structure. Which is something we're probably not going to add for awhile. */ 00512 /* FIXME: So, according to Ralph Brown Interrupt List, MS-DOS 5 and 6 liked to round up to the next paragraph? */ 00513 if (dos.version.major < 7 && (reg_bx & 0xF) != 0) 00514 reg_bx = (reg_bx + 0xF) & (~0xF); 00515 00516 Bit32u start = DOS_HMA_FREE_START(); 00517 if ((start+reg_bx) > limit) { 00518 LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: rejected (not enough room) for %u bytes (0x%x + 0x%x > 0x%x)",reg_bx, 00519 (unsigned int)start,(unsigned int)reg_bx,(unsigned int)limit); 00520 reg_bx = 0; 00521 reg_di = 0xFFFF; 00522 SegSet16(es,0xFFFF); 00523 return true; 00524 } 00525 00526 /* convert the start to segment:offset, normalized to FFFF:offset */ 00527 reg_di = (start + 0x10) & 0xFFFF; 00528 SegSet16(es,0xFFFF); 00529 00530 /* let HMA emulation know what was claimed */ 00531 LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: %u bytes at FFFF:%04x",reg_bx,reg_di); 00532 DOS_HMA_CLAIMED(reg_bx); 00533 } return true; 00534 case 0x4a10: { /* Microsoft SmartDrive (SMARTDRV) API */ 00535 LOG(LOG_MISC,LOG_DEBUG)("Unhandled SMARTDRV call AX=%04x BX=%04x CX=%04x DX=%04x BP=%04x",reg_ax,reg_bx,reg_cx,reg_dx,reg_bp); 00536 } return true; 00537 case 0x4a11: { /* Microsoft DoubleSpace (DBLSPACE.BIN) API */ 00538 LOG(LOG_MISC,LOG_DEBUG)("Unhandled DBLSPACE call AX=%04x BX=%04x CX=%04x DX=%04x BP=%04x",reg_ax,reg_bx,reg_cx,reg_dx,reg_bp); 00539 } return true; 00540 case 0x4a16: /* Open bootlog */ 00541 return true; 00542 case 0x4a17: /* Write bootlog */ 00543 MEM_StrCopy(SegPhys(ds)+reg_dx,name,255); 00544 LOG_MSG("BOOTLOG: %s\n",name); 00545 return true; 00546 case 0x4a18: /* Close bootlog */ 00547 return true; 00548 case 0x4a33: /* Check MS-DOS Version 7 */ 00549 if (dos.version.major > 6) { 00550 reg_ax=0; 00551 return true; 00552 } 00553 } 00554 00555 return false; 00556 } 00557 00558 void DOS_SetupMisc(void) { 00559 /* Setup the dos multiplex interrupt */ 00560 call_int2f=CALLBACK_Allocate(); 00561 CALLBACK_Setup(call_int2f,&INT2F_Handler,CB_IRET,"DOS Int 2f"); 00562 RealSetVec(0x2f,CALLBACK_RealPointer(call_int2f)); 00563 DOS_AddMultiplexHandler(DOS_MultiplexFunctions); 00564 /* Setup the dos network interrupt */ 00565 call_int2a=CALLBACK_Allocate(); 00566 CALLBACK_Setup(call_int2a,&INT2A_Handler,CB_IRET,"DOS Int 2a"); 00567 RealSetVec(0x2A,CALLBACK_RealPointer(call_int2a)); 00568 } 00569 00570 void CALLBACK_DeAllocate(Bitu in); 00571 00572 void DOS_UninstallMisc(void) { 00573 /* these vectors shouldn't exist when booting a guest OS */ 00574 if (call_int2a) { 00575 RealSetVec(0x2a,0); 00576 CALLBACK_DeAllocate(call_int2a); 00577 call_int2a=0; 00578 } 00579 if (call_int2f) { 00580 RealSetVec(0x2f,0); 00581 CALLBACK_DeAllocate(call_int2f); 00582 call_int2f=0; 00583 } 00584 } 00585