static Bitu INT74_Handler(void) { if (mouse.events>0) { mouse.events--; /* Check for an active Interrupt Handler that will get called */ if (mouse.sub_mask & mouse.event_queue[mouse.events].type) { reg_ax=mouse.event_queue[mouse.events].type; reg_bx=mouse.event_queue[mouse.events].buttons; reg_cx=POS_X; reg_dx=POS_Y; reg_si=(Bit16s)(mouse.mickey_x*mouse.mickeysPerPixel_x); reg_di=(Bit16s)(mouse.mickey_y*mouse.mickeysPerPixel_y); CPU_Push16(RealSeg(CALLBACK_RealPointer(int74_ret_callback))); CPU_Push16(RealOff(CALLBACK_RealPointer(int74_ret_callback))); SegSet16(cs, mouse.sub_seg); reg_ip = mouse.sub_ofs; if(mouse.in_UIR) LOG(LOG_MOUSE,LOG_ERROR)("Already in UIR!"); mouse.in_UIR = true; } else if (useps2callback) { CPU_Push16(RealSeg(CALLBACK_RealPointer(int74_ret_callback))); CPU_Push16(RealOff(CALLBACK_RealPointer(int74_ret_callback))); DoPS2Callback(mouse.event_queue[mouse.events].buttons, POS_X, POS_Y); } else { SegSet16(cs, RealSeg(CALLBACK_RealPointer(int74_ret_callback))); reg_ip = RealOff(CALLBACK_RealPointer(int74_ret_callback)); } } else { SegSet16(cs, RealSeg(CALLBACK_RealPointer(int74_ret_callback))); reg_ip = RealOff(CALLBACK_RealPointer(int74_ret_callback)); } return CBRET_NONE; }
void INT10_SetupVESA(void) { /* Put the mode list somewhere in memory */ Bitu i; i=0; int10.rom.vesa_modes=RealMake(0xc000,int10.rom.used); //TODO Maybe add normal vga modes too, but only seems to complicate things while (ModeList_VGA[i].mode!=0xffff) { bool canuse_mode=false; if (!svga.accepts_mode) canuse_mode=true; else { if (svga.accepts_mode(ModeList_VGA[i].mode)) canuse_mode=true; } if (ModeList_VGA[i].mode>=0x100 && canuse_mode) { if ((!int10.vesa_oldvbe) || (ModeList_VGA[i].mode<0x120)) { phys_writew(PhysMake(0xc000,int10.rom.used),ModeList_VGA[i].mode); int10.rom.used+=2; } } i++; } phys_writew(PhysMake(0xc000,int10.rom.used),0xffff); int10.rom.used+=2; int10.rom.oemstring=RealMake(0xc000,int10.rom.used); Bitu len=(Bitu)(strlen(string_oem)+1); for (i=0;i<len;i++) { phys_writeb(0xc0000+int10.rom.used++,string_oem[i]); } switch (svgaCard) { case SVGA_S3Trio: break; } callback.setwindow=CALLBACK_Allocate(); callback.pmPalette=CALLBACK_Allocate(); callback.pmStart=CALLBACK_Allocate(); CALLBACK_Setup(callback.setwindow,VESA_SetWindow,CB_RETF, "VESA Real Set Window"); /* Prepare the pmode interface */ int10.rom.pmode_interface=RealMake(0xc000,int10.rom.used); int10.rom.used += 8; //Skip the byte later used for offsets /* PM Set Window call */ int10.rom.pmode_interface_window = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 0, int10.rom.pmode_interface_window ); callback.pmWindow=CALLBACK_Allocate(); int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmWindow, VESA_PMSetWindow, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Window"); /* PM Set start call */ int10.rom.pmode_interface_start = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 2, int10.rom.pmode_interface_start); callback.pmStart=CALLBACK_Allocate(); int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmStart, VESA_PMSetStart, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Start"); /* PM Set Palette call */ int10.rom.pmode_interface_palette = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 4, int10.rom.pmode_interface_palette); callback.pmPalette=CALLBACK_Allocate(); int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmPalette, VESA_PMSetPalette, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Palette"); /* Finalize the size and clear the required ports pointer */ phys_writew( Real2Phys(int10.rom.pmode_interface) + 6, 0); int10.rom.pmode_interface_size=int10.rom.used - RealOff( int10.rom.pmode_interface ); }
bool DOS_FCBDeleteFile(Bit16u seg, Bit16u offset) { /* FCB DELETE honours wildcards. it will return true if one or more * files get deleted. * To get this: the dta is set to temporary dta in which found files are * stored. This can not be the tempdta as that one is used by fcbfindfirst */ RealPt old_dta = dos.dta(); dos.dta(dos.tables.tempdta_fcbdelete); DOS_FCB fcb(RealSeg(dos.dta()), RealOff(dos.dta())); DOS_FCB fcb1(seg, offset); bool return_value = false; bool nextfile = DOS_FCBFindFirst(seg, offset); while (nextfile) { char shortname[DOS_FCBNAME] = { 0 }; fcb1.GetName(shortname); // Fix to get the correct FCB FCBNameToStr(shortname); bool res = DOS_UnlinkFile(shortname); if (!return_value && res) return_value = true; // At least one file deleted nextfile = DOS_FCBFindNext(seg, offset); } dos.dta(old_dta); // Restore dta return return_value; }
void IO_WriteW(Bitu port,Bitu val) { if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,2)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); CPU_Decoder * old_cpudecoder; old_cpudecoder=cpudecoder; cpudecoder=&IOFaultCore; IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; entry->cs=SegValue(cs); entry->eip=reg_eip; CPU_Push16(SegValue(cs)); CPU_Push16(reg_ip); Bit16u old_ax = reg_ax; Bit16u old_dx = reg_dx; reg_al = val; reg_dx = port; RealPt icb = CALLBACK_RealPointer(call_priv_io); SegSet16(cs,RealSeg(icb)); reg_eip = RealOff(icb)+0x0a; CPU_Exception(cpu.exception.which,cpu.exception.error); DOSBOX_RunMachine(); iof_queue.used--; reg_ax = old_ax; reg_dx = old_dx; memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); cpudecoder=old_cpudecoder; } else { IO_USEC_write_delay(); io_writehandlers[1][port](port,val,2); } }
void DoPS2Callback(Bit16u data, Bit16s mouseX, Bit16s mouseY) { if (useps2callback) { Bit16u mdat = (data & 0x03) | 0x08; Bit16s xdiff = mouseX-oldmouseX; Bit16s ydiff = oldmouseY-mouseY; oldmouseX = mouseX; oldmouseY = mouseY; if ((xdiff>0xff) || (xdiff<-0xff)) mdat |= 0x40; // x overflow if ((ydiff>0xff) || (ydiff<-0xff)) mdat |= 0x80; // y overflow xdiff %= 256; ydiff %= 256; if (xdiff<0) { xdiff = (0x100+xdiff); mdat |= 0x10; } if (ydiff<0) { ydiff = (0x100+ydiff); mdat |= 0x20; } CPU_Push16((Bit16u)mdat); CPU_Push16((Bit16u)(xdiff % 256)); CPU_Push16((Bit16u)(ydiff % 256)); CPU_Push16((Bit16u)0); CPU_Push16(RealSeg(ps2_callback)); CPU_Push16(RealOff(ps2_callback)); SegSet16(cs, ps2cbseg); reg_ip = ps2cbofs; } }
Bitu IO_ReadD(Bitu port) { if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,4)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); CPU_Decoder * old_cpudecoder; old_cpudecoder=cpudecoder; cpudecoder=&IOFaultCore; IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; entry->cs=SegValue(cs); entry->eip=reg_eip; CPU_Push16(SegValue(cs)); CPU_Push16(reg_ip); Bit16u old_dx = reg_dx; reg_dx = port; RealPt icb = CALLBACK_RealPointer(call_priv_io); SegSet16(cs,RealSeg(icb)); reg_eip = RealOff(icb)+0x04; CPU_Exception(cpu.exception.which,cpu.exception.error); DOSBOX_RunMachine(); iof_queue.used--; Bitu retval = reg_eax; reg_dx = old_dx; memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); cpudecoder=old_cpudecoder; return retval; } else return io_readhandlers[2][port](port,4); }
bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters) { if (!drive) drive = DOS_GetDefaultDrive(); else drive--; if (drive >= DOS_DRIVES || !Drives[drive]) return false; Bit16u _free_clusters; Drives[drive]->AllocationInfo(_bytes_sector,_sectors_cluster,_total_clusters,&_free_clusters); SegSet16(ds,RealSeg(dos.tables.mediaid)); reg_bx=RealOff(dos.tables.mediaid+drive*2); return true; }
void CALLBACK_RunRealFar(Bit16u seg,Bit16u off) { reg_sp-=4; mem_writew(SegPhys(ss)+reg_sp,RealOff(CALLBACK_RealPointer(call_stop))); mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(CALLBACK_RealPointer(call_stop))); Bit32u oldeip=reg_eip; Bit16u oldcs=SegValue(cs); reg_eip=off; SegSet16(cs,seg); DOSBOX_RunMachine(); reg_eip=oldeip; SegSet16(cs,oldcs); }
static bool multiplex_xms(void) { switch (reg_ax) { case 0x4300: /* XMS installed check */ reg_al=0x80; return true; case 0x4310: /* XMS handler seg:offset */ SegSet16(es,RealSeg(xms_callback)); reg_bx=RealOff(xms_callback); return true; } return false; }
static void SaveFindResult(DOS_FCB & find_fcb) { DOS_DTA find_dta(dos.tables.tempdta); char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u date;Bit16u time;Bit8u attr;Bit8u drive; char file_name[9];char ext[4]; find_dta.GetResult(name,size,date,time,attr); drive=find_fcb.GetDrive()+1; /* Create a correct file and extention */ DTAExtendName(name,file_name,ext); DOS_FCB fcb(RealSeg(dos.dta()),RealOff(dos.dta()));//TODO fcb.Create(find_fcb.Extended()); fcb.SetName(drive,file_name,ext); fcb.SetAttr(attr); /* Only adds attribute if fcb is extended */ fcb.SetSizeDateTime(size,date,time); }
bool DOS_Terminate(bool tsr) { dos.return_code=reg_al; dos.return_mode=RETURN_EXIT; Bit16u mempsp = dos.psp(); DOS_PSP curpsp(mempsp); if (mempsp==curpsp.GetParent()) return true; /* Free Files owned by process */ if (!tsr) curpsp.CloseFiles(); /* Get the termination address */ RealPt old22 = curpsp.GetInt22(); /* Restore vector 22,23,24 */ curpsp.RestoreVectors(); /* Set the parent PSP */ dos.psp(curpsp.GetParent()); DOS_PSP parentpsp(curpsp.GetParent()); /* Restore the SS:SP to the previous one */ SegSet16(ss,RealSeg(parentpsp.GetStack())); reg_sp = RealOff(parentpsp.GetStack()); /* Restore the old CS:IP from int 22h */ RestoreRegisters(); /* Set the CS:IP stored in int 0x22 back on the stack */ mem_writew(SegPhys(ss)+reg_sp+0,RealOff(old22)); mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(old22)); /* set IOPL=3 (Strike Commander), nested task set, interrupts enabled, test flags cleared */ mem_writew(SegPhys(ss)+reg_sp+4,0x7202); // Free memory owned by process if (!tsr) DOS_FreeProcessMemory(mempsp); DOS_UpdatePSPName(); return true; }
void SHELL_Init() { /* Add messages */ MSG_Add("SHELL_ILLEGAL_PATH","Illegal Path.\n"); MSG_Add("SHELL_CMD_HELP","If you want a list of all supported commands type \033[33;1mhelp /all\033[0m .\nA short list of the most often used commands:\n"); MSG_Add("SHELL_CMD_ECHO_ON","ECHO is on.\n"); MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off.\n"); MSG_Add("SHELL_ILLEGAL_SWITCH","Illegal switch: %s.\n"); MSG_Add("SHELL_MISSING_PARAMETER","Required parameter missing.\n"); MSG_Add("SHELL_CMD_CHDIR_ERROR","Unable to change to: %s.\n"); MSG_Add("SHELL_CMD_CHDIR_HINT","To change to different drive type \033[31m%c:\033[0m\n"); MSG_Add("SHELL_CMD_CHDIR_HINT_2","directoryname is longer than 8 characters and/or contains spaces.\nTry \033[31mcd %s\033[0m\n"); MSG_Add("SHELL_CMD_CHDIR_HINT_3","You are still on drive Z:, change to a mounted drive with \033[31mC:\033[0m.\n"); MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %s.\n"); MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %s.\n"); MSG_Add("SHELL_CMD_DEL_ERROR","Unable to delete: %s.\n"); MSG_Add("SHELL_SYNTAXERROR","The syntax of the command is incorrect.\n"); MSG_Add("SHELL_CMD_SET_NOT_SET","Environment variable %s not defined.\n"); MSG_Add("SHELL_CMD_SET_OUT_OF_SPACE","Not enough environment space left.\n"); MSG_Add("SHELL_CMD_IF_EXIST_MISSING_FILENAME","IF EXIST: Missing filename.\n"); MSG_Add("SHELL_CMD_IF_ERRORLEVEL_MISSING_NUMBER","IF ERRORLEVEL: Missing number.\n"); MSG_Add("SHELL_CMD_IF_ERRORLEVEL_INVALID_NUMBER","IF ERRORLEVEL: Invalid number.\n"); MSG_Add("SHELL_CMD_GOTO_MISSING_LABEL","No label supplied to GOTO command.\n"); MSG_Add("SHELL_CMD_GOTO_LABEL_NOT_FOUND","GOTO: Label %s not found.\n"); MSG_Add("SHELL_CMD_FILE_NOT_FOUND","File %s not found.\n"); MSG_Add("SHELL_CMD_FILE_EXISTS","File %s already exists.\n"); MSG_Add("SHELL_CMD_DIR_INTRO","Directory of %s.\n"); MSG_Add("SHELL_CMD_DIR_BYTES_USED","%5d File(s) %17s Bytes.\n"); MSG_Add("SHELL_CMD_DIR_BYTES_FREE","%5d Dir(s) %17s Bytes free.\n"); MSG_Add("SHELL_EXECUTE_DRIVE_NOT_FOUND","Drive %c does not exist!\nYou must \033[31mmount\033[0m it first. Type \033[1;33mintro\033[0m or \033[1;33mintro mount\033[0m for more information.\n"); MSG_Add("SHELL_EXECUTE_ILLEGAL_COMMAND","Illegal command: %s.\n"); MSG_Add("SHELL_CMD_PAUSE","Press any key to continue.\n"); MSG_Add("SHELL_CMD_PAUSE_HELP","Waits for 1 keystroke to continue.\n"); MSG_Add("SHELL_CMD_COPY_FAILURE","Copy failure : %s.\n"); MSG_Add("SHELL_CMD_COPY_SUCCESS"," %d File(s) copied.\n"); MSG_Add("SHELL_CMD_SUBST_NO_REMOVE","Removing drive not supported. Doing nothing.\n"); MSG_Add("SHELL_CMD_SUBST_FAILURE","SUBST failed. You either made an error in your commandline or the target drive is already used.\nIt's only possible to use SUBST on Local drives"); MSG_Add("SHELL_STARTUP_BEGIN", "\033[44;1m\xC9\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBB\n" "\xBA \033[32mWelcome to DOSBox v%-8s\033[37m \xBA\n" "\xBA \xBA\n" // "\xBA DOSBox runs real and protected mode games. \xBA\n" "\xBA For a short introduction for new users type: \033[33mINTRO\033[37m \xBA\n" "\xBA For supported shell commands type: \033[33mHELP\033[37m \xBA\n" "\xBA \xBA\n" "\xBA To adjust the emulated CPU speed, use \033[31mctrl-F11\033[37m and \033[31mctrl-F12\033[37m. \xBA\n" "\xBA To activate the keymapper \033[31mctrl-F1\033[37m. \xBA\n" "\xBA For more information read the \033[36mREADME\033[37m file in the DOSBox directory. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_CGA","\xBA DOSBox supports Composite CGA mode. \xBA\n" "\xBA Use \033[31m(alt-)F11\033[37m to change the colours when in this mode. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_HERC","\xBA Use \033[31mF11\033[37m to cycle through white, amber, and green monochrome color. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_DEBUG", "\xBA Press \033[31malt-Pause\033[37m to enter the debugger or start the exe with \033[33mDEBUG\033[37m. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_END", "\xBA \033[32mHAVE FUN!\033[37m \xBA\n" "\xBA \033[32mThe DOSBox Team \033[33mhttp://www.dosbox.com\033[37m \xBA\n" "\xC8\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBC\033[0m\n" //"\n" //Breaks the startup message if you type a mount and a drive change. ); MSG_Add("SHELL_CMD_CHDIR_HELP","Displays/changes the current directory.\n"); MSG_Add("SHELL_CMD_CHDIR_HELP_LONG","CHDIR [drive:][path]\n" "CHDIR [..]\n" "CD [drive:][path]\n" "CD [..]\n\n" " .. Specifies that you want to change to the parent directory.\n\n" "Type CD drive: to display the current directory in the specified drive.\n" "Type CD without parameters to display the current drive and directory.\n"); MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n"); MSG_Add("SHELL_CMD_DIR_HELP","Directory View.\n"); MSG_Add("SHELL_CMD_ECHO_HELP","Display messages and enable/disable command echoing.\n"); MSG_Add("SHELL_CMD_EXIT_HELP","Exit from the shell.\n"); MSG_Add("SHELL_CMD_HELP_HELP","Show help.\n"); MSG_Add("SHELL_CMD_MKDIR_HELP","Make Directory.\n"); MSG_Add("SHELL_CMD_MKDIR_HELP_LONG","MKDIR [drive:][path]\n" "MD [drive:][path]\n"); MSG_Add("SHELL_CMD_RMDIR_HELP","Remove Directory.\n"); MSG_Add("SHELL_CMD_RMDIR_HELP_LONG","RMDIR [drive:][path]\n" "RD [drive:][path]\n"); MSG_Add("SHELL_CMD_SET_HELP","Change environment variables.\n"); MSG_Add("SHELL_CMD_IF_HELP","Performs conditional processing in batch programs.\n"); MSG_Add("SHELL_CMD_GOTO_HELP","Jump to a labeled line in a batch script.\n"); MSG_Add("SHELL_CMD_SHIFT_HELP","Leftshift commandline parameters in a batch script.\n"); MSG_Add("SHELL_CMD_TYPE_HELP","Display the contents of a text-file.\n"); MSG_Add("SHELL_CMD_TYPE_HELP_LONG","TYPE [drive:][path][filename]\n"); MSG_Add("SHELL_CMD_REM_HELP","Add comments in a batch file.\n"); MSG_Add("SHELL_CMD_REM_HELP_LONG","REM [comment]\n"); MSG_Add("SHELL_CMD_NO_WILD","This is a simple version of the command, no wildcards allowed!\n"); MSG_Add("SHELL_CMD_RENAME_HELP","Renames one or more files.\n"); MSG_Add("SHELL_CMD_RENAME_HELP_LONG","RENAME [drive:][path]filename1 filename2.\n" "REN [drive:][path]filename1 filename2.\n\n" "Note that you can not specify a new drive or path for your destination file.\n"); MSG_Add("SHELL_CMD_DELETE_HELP","Removes one or more files.\n"); MSG_Add("SHELL_CMD_COPY_HELP","Copy files.\n"); MSG_Add("SHELL_CMD_CALL_HELP","Start a batch file from within another batch file.\n"); MSG_Add("SHELL_CMD_SUBST_HELP","Assign an internal directory to a drive.\n"); MSG_Add("SHELL_CMD_LOADHIGH_HELP","Loads a program into upper memory (requires xms=true,umb=true).\n"); MSG_Add("SHELL_CMD_CHOICE_HELP","Waits for a keypress and sets ERRORLEVEL.\n"); MSG_Add("SHELL_CMD_CHOICE_HELP_LONG","CHOICE [/C:choices] [/N] [/S] text\n" " /C[:]choices - Specifies allowable keys. Default is: yn.\n" " /N - Do not display the choices at end of prompt.\n" " /S - Enables case-sensitive choices to be selected.\n" " text - The text to display as a prompt.\n"); MSG_Add("SHELL_CMD_ATTRIB_HELP","Does nothing. Provided for compatibility.\n"); MSG_Add("SHELL_CMD_PATH_HELP","Provided for compatibility.\n"); MSG_Add("SHELL_CMD_VER_HELP","View and set the reported DOS version.\n"); MSG_Add("SHELL_CMD_VER_VER","DOSBox version %s. Reported DOS version %d.%02d.\n"); #ifdef IPHONEOS MSG_Add("SHELL_CMD_UNZIP_HELP","Extract zip file to current directory.\n"); #endif /* Regular startup */ call_shellstop=CALLBACK_Allocate(); /* Setup the startup CS:IP to kill the last running machine when exitted */ RealPt newcsip=CALLBACK_RealPointer(call_shellstop); SegSet16(cs,RealSeg(newcsip)); reg_ip=RealOff(newcsip); CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET,"shell stop"); PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart); /* Now call up the shell for the first time */ Bit16u psp_seg=DOS_FIRST_SHELL; Bit16u env_seg=DOS_FIRST_SHELL+19; //DOS_GetMemory(1+(4096/16))+1; Bit16u stack_seg=DOS_GetMemory(2048/16); SegSet16(ss,stack_seg); reg_sp=2046; /* Set up int 24 and psp (Telarium games) */ real_writeb(psp_seg+16+1,0,0xea); /* far jmp */ real_writed(psp_seg+16+1,1,real_readd(0,0x24*4)); real_writed(0,0x24*4,((Bit32u)psp_seg<<16) | ((16+1)<<4)); /* Set up int 23 to "int 20" in the psp. Fixes what.exe */ real_writed(0,0x23*4,((Bit32u)psp_seg<<16)); /* Setup MCBs */ DOS_MCB pspmcb((Bit16u)(psp_seg-1)); pspmcb.SetPSPSeg(psp_seg); // MCB of the command shell psp pspmcb.SetSize(0x10+2); pspmcb.SetType(0x4d); DOS_MCB envmcb((Bit16u)(env_seg-1)); envmcb.SetPSPSeg(psp_seg); // MCB of the command shell environment envmcb.SetSize(DOS_MEM_START-env_seg); envmcb.SetType(0x4d); /* Setup environment */ PhysPt env_write=PhysMake(env_seg,0); MEM_BlockWrite(env_write,path_string,(Bitu)(strlen(path_string)+1)); env_write += (PhysPt)(strlen(path_string)+1); MEM_BlockWrite(env_write,comspec_string,(Bitu)(strlen(comspec_string)+1)); env_write += (PhysPt)(strlen(comspec_string)+1); mem_writeb(env_write++,0); mem_writew(env_write,1); env_write+=2; MEM_BlockWrite(env_write,full_name,(Bitu)(strlen(full_name)+1)); DOS_PSP psp(psp_seg); psp.MakeNew(0); dos.psp(psp_seg); /* The start of the filetable in the psp must look like this: * 01 01 01 00 02 * In order to achieve this: First open 2 files. Close the first and * duplicate the second (so the entries get 01) */ Bit16u dummy=0; DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDIN */ DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDOUT */ DOS_CloseFile(0); /* Close STDIN */ DOS_ForceDuplicateEntry(1,0); /* "new" STDIN */ DOS_ForceDuplicateEntry(1,2); /* STDERR */ DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDAUX */ DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDPRN */ psp.SetParent(psp_seg); /* Set the environment */ psp.SetEnvironment(env_seg); /* Set the command line for the shell start up */ CommandTail tail; tail.count=(Bit8u)strlen(init_line); strcpy(tail.buffer,init_line); MEM_BlockWrite(PhysMake(psp_seg,128),&tail,128); /* Setup internal DOS Variables */ dos.dta(RealMake(psp_seg,0x80)); dos.psp(psp_seg); SHELL_ProgramStart(&first_shell); first_shell->Run(); delete first_shell; first_shell = 0;//Make clear that it shouldn't be used anymore }
static Bitu DOS_21Handler(void) { if (((reg_ah != 0x50) && (reg_ah != 0x51) && (reg_ah != 0x62) && (reg_ah != 0x64)) && (reg_ah<0x6c)) { DOS_PSP psp(dos.psp()); psp.SetStack(RealMake(SegValue(ss),reg_sp-18)); } char name1[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII]; char name2[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII]; static Bitu time_start = 0; //For emulating temporary time changes. switch (reg_ah) { case 0x00: /* Terminate Program */ DOS_Terminate(mem_readw(SegPhys(ss)+reg_sp+2),false,0); break; case 0x01: /* Read character from STDIN, with echo */ { Bit8u c;Bit16u n=1; dos.echo=true; DOS_ReadFile(STDIN,&c,&n); reg_al=c; dos.echo=false; } break; case 0x02: /* Write character to STDOUT */ { Bit8u c=reg_dl;Bit16u n=1; DOS_WriteFile(STDOUT,&c,&n); //Not in the official specs, but happens nonetheless. (last written character) reg_al = c;// reg_al=(c==9)?0x20:c; //Officially: tab to spaces } break; case 0x03: /* Read character from STDAUX */ { Bit16u port = real_readw(0x40,0); if(port!=0 && serialports[0]) { Bit8u status; // RTS/DTR on IO_WriteB(port+4,0x3); serialports[0]->Getchar(®_al, &status, true, 0xFFFFFFFF); } } break; case 0x04: /* Write Character to STDAUX */ { Bit16u port = real_readw(0x40,0); if(port!=0 && serialports[0]) { // RTS/DTR on IO_WriteB(port+4,0x3); serialports[0]->Putchar(reg_dl,true,true, 0xFFFFFFFF); // RTS off IO_WriteB(port+4,0x1); } } break; case 0x05: /* Write Character to PRINTER */ E_Exit("DOS:Unhandled call %02X",reg_ah); break; case 0x06: /* Direct Console Output / Input */ switch (reg_dl) { case 0xFF: /* Input */ { //Simulate DOS overhead for timing sensitive games //MM1 overhead(); //TODO Make this better according to standards if (!DOS_GetSTDINStatus()) { reg_al=0; CALLBACK_SZF(true); break; } Bit8u c;Bit16u n=1; DOS_ReadFile(STDIN,&c,&n); reg_al=c; CALLBACK_SZF(false); break; } default: { Bit8u c = reg_dl;Bit16u n = 1; DOS_WriteFile(STDOUT,&c,&n); reg_al = reg_dl; } break; }; break; case 0x07: /* Character Input, without echo */ { Bit8u c;Bit16u n=1; DOS_ReadFile (STDIN,&c,&n); reg_al=c; break; }; case 0x08: /* Direct Character Input, without echo (checks for breaks officially :)*/ { Bit8u c;Bit16u n=1; DOS_ReadFile (STDIN,&c,&n); reg_al=c; break; }; case 0x09: /* Write string to STDOUT */ { Bit8u c;Bit16u n=1; PhysPt buf=SegPhys(ds)+reg_dx; while ((c=mem_readb(buf++))!='$') { DOS_WriteFile(STDOUT,&c,&n); } } break; case 0x0a: /* Buffered Input */ { //TODO ADD Break checkin in STDIN but can't care that much for it PhysPt data=SegPhys(ds)+reg_dx; Bit8u free=mem_readb(data); Bit8u read=0;Bit8u c;Bit16u n=1; if (!free) break; free--; for(;;) { DOS_ReadFile(STDIN,&c,&n); if (c == 8) { // Backspace if (read) { //Something to backspace. // STDOUT treats backspace as non-destructive. DOS_WriteFile(STDOUT,&c,&n); c = ' '; DOS_WriteFile(STDOUT,&c,&n); c = 8; DOS_WriteFile(STDOUT,&c,&n); --read; } continue; } if (read == free && c != 13) { // Keyboard buffer full Bit8u bell = 7; DOS_WriteFile(STDOUT, &bell, &n); continue; } DOS_WriteFile(STDOUT,&c,&n); mem_writeb(data+read+2,c); if (c==13) break; read++; }; mem_writeb(data+1,read); break; }; case 0x0b: /* Get STDIN Status */ if (!DOS_GetSTDINStatus()) {reg_al=0x00;} else {reg_al=0xFF;} //Simulate some overhead for timing issues //Tankwar menu (needs maybe even more) overhead(); break; case 0x0c: /* Flush Buffer and read STDIN call */ { /* flush buffer if STDIN is CON */ Bit8u handle=RealHandle(STDIN); if (handle!=0xFF && Files[handle] && Files[handle]->IsName("CON")) { Bit8u c;Bit16u n; while (DOS_GetSTDINStatus()) { n=1; DOS_ReadFile(STDIN,&c,&n); } } switch (reg_al) { case 0x1: case 0x6: case 0x7: case 0x8: case 0xa: { Bit8u oldah=reg_ah; reg_ah=reg_al; DOS_21Handler(); reg_ah=oldah; } break; default: // LOG_ERROR("DOS:0C:Illegal Flush STDIN Buffer call %d",reg_al); reg_al=0; break; } } break; //TODO Find out the values for when reg_al!=0 //TODO Hope this doesn't do anything special case 0x0d: /* Disk Reset */ //Sure let's reset a virtual disk break; case 0x0e: /* Select Default Drive */ DOS_SetDefaultDrive(reg_dl); reg_al=DOS_DRIVES; break; case 0x0f: /* Open File using FCB */ if(DOS_FCBOpen(SegValue(ds),reg_dx)){ reg_al=0; }else{ reg_al=0xff; } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x0f FCB-fileopen used, result:al=%d",reg_al); break; case 0x10: /* Close File using FCB */ if(DOS_FCBClose(SegValue(ds),reg_dx)){ reg_al=0; }else{ reg_al=0xff; } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x10 FCB-fileclose used, result:al=%d",reg_al); break; case 0x11: /* Find First Matching File using FCB */ if(DOS_FCBFindFirst(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x11 FCB-FindFirst used, result:al=%d",reg_al); break; case 0x12: /* Find Next Matching File using FCB */ if(DOS_FCBFindNext(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x12 FCB-FindNext used, result:al=%d",reg_al); break; case 0x13: /* Delete File using FCB */ if (DOS_FCBDeleteFile(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x16 FCB-Delete used, result:al=%d",reg_al); break; case 0x14: /* Sequential read from FCB */ reg_al = DOS_FCBRead(SegValue(ds),reg_dx,0); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x14 FCB-Read used, result:al=%d",reg_al); break; case 0x15: /* Sequential write to FCB */ reg_al=DOS_FCBWrite(SegValue(ds),reg_dx,0); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x15 FCB-Write used, result:al=%d",reg_al); break; case 0x16: /* Create or truncate file using FCB */ if (DOS_FCBCreate(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x16 FCB-Create used, result:al=%d",reg_al); break; case 0x17: /* Rename file using FCB */ if (DOS_FCBRenameFile(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; break; case 0x1b: /* Get allocation info for default drive */ if (!DOS_GetAllocationInfo(0,®_cx,®_al,®_dx)) reg_al=0xff; break; case 0x1c: /* Get allocation info for specific drive */ if (!DOS_GetAllocationInfo(reg_dl,®_cx,®_al,®_dx)) reg_al=0xff; break; case 0x21: /* Read random record from FCB */ { Bit16u toread=1; reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,&toread,true); } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x21 FCB-Random read used, result:al=%d",reg_al); break; case 0x22: /* Write random record to FCB */ { Bit16u towrite=1; reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,&towrite,true); } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x22 FCB-Random write used, result:al=%d",reg_al); break; case 0x23: /* Get file size for FCB */ if (DOS_FCBGetFileSize(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; break; case 0x24: /* Set Random Record number for FCB */ DOS_FCBSetRandomRecord(SegValue(ds),reg_dx); break; case 0x27: /* Random block read from FCB */ reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,®_cx,false); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x27 FCB-Random(block) read used, result:al=%d",reg_al); break; case 0x28: /* Random Block write to FCB */ reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,®_cx,false); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x28 FCB-Random(block) write used, result:al=%d",reg_al); break; case 0x29: /* Parse filename into FCB */ { Bit8u difference; char string[1024]; MEM_StrCopy(SegPhys(ds)+reg_si,string,1023); // 1024 toasts the stack reg_al=FCB_Parsename(SegValue(es),reg_di,reg_al ,string, &difference); reg_si+=difference; } LOG(LOG_FCB,LOG_NORMAL)("DOS:29:FCB Parse Filename, result:al=%d",reg_al); break; case 0x19: /* Get current default drive */ reg_al=DOS_GetDefaultDrive(); break; case 0x1a: /* Set Disk Transfer Area Address */ dos.dta(RealMakeSeg(ds,reg_dx)); break; case 0x25: /* Set Interrupt Vector */ RealSetVec(reg_al,RealMakeSeg(ds,reg_dx)); break; case 0x26: /* Create new PSP */ DOS_NewPSP(reg_dx,DOS_PSP(dos.psp()).GetSize()); reg_al=0xf0; /* al destroyed */ break; case 0x2a: /* Get System Date */ { reg_ax=0; // get time CALLBACK_RunRealInt(0x1a); if(reg_al) DOS_AddDays(reg_al); int a = (14 - dos.date.month)/12; int y = dos.date.year - a; int m = dos.date.month + 12*a - 2; reg_al=(dos.date.day+y+(y/4)-(y/100)+(y/400)+(31*m)/12) % 7; reg_cx=dos.date.year; reg_dh=dos.date.month; reg_dl=dos.date.day; } break; case 0x2b: /* Set System Date */ if (reg_cx<1980) { reg_al=0xff;break;} if ((reg_dh>12) || (reg_dh==0)) { reg_al=0xff;break;} if (reg_dl==0) { reg_al=0xff;break;} if (reg_dl>DOS_DATE_months[reg_dh]) { if(!((reg_dh==2)&&(reg_cx%4 == 0)&&(reg_dl==29))) // february pass { reg_al=0xff;break; } } dos.date.year=reg_cx; dos.date.month=reg_dh; dos.date.day=reg_dl; reg_al=0; break; case 0x2c: { /* Get System Time */ reg_ax=0; // get time CALLBACK_RunRealInt(0x1a); if(reg_al) DOS_AddDays(reg_al); reg_ah=0x2c; Bitu ticks=((Bitu)reg_cx<<16)|reg_dx; if(time_start<=ticks) ticks-=time_start; Bitu time=(Bitu)((100.0/((double)PIT_TICK_RATE/65536.0)) * (double)ticks); reg_dl=(Bit8u)((Bitu)time % 100); // 1/100 seconds time/=100; reg_dh=(Bit8u)((Bitu)time % 60); // seconds time/=60; reg_cl=(Bit8u)((Bitu)time % 60); // minutes time/=60; reg_ch=(Bit8u)((Bitu)time % 24); // hours //Simulate DOS overhead for timing-sensitive games //Robomaze 2 overhead(); break; } case 0x2d: /* Set System Time */ LOG(LOG_DOSMISC,LOG_ERROR)("DOS:Set System Time not supported"); //Check input parameters nonetheless if( reg_ch > 23 || reg_cl > 59 || reg_dh > 59 || reg_dl > 99 ) reg_al = 0xff; else { //Allow time to be set to zero. Restore the orginal time for all other parameters. (QuickBasic) if (reg_cx == 0 && reg_dx == 0) {time_start = mem_readd(BIOS_TIMER);LOG_MSG("Warning: game messes with DOS time!");} else time_start = 0; reg_al = 0; } break; case 0x2e: /* Set Verify flag */ dos.verify=(reg_al==1); break; case 0x2f: /* Get Disk Transfer Area */ SegSet16(es,RealSeg(dos.dta())); reg_bx=RealOff(dos.dta()); break; case 0x30: /* Get DOS Version */ if (reg_al==0) reg_bh=0xFF; /* Fake Microsoft DOS */ if (reg_al==1) reg_bh=0x10; /* DOS is in HMA */ reg_al=dos.version.major; reg_ah=dos.version.minor; /* Serialnumber */ reg_bl=0x00; reg_cx=0x0000; break; case 0x31: /* Terminate and stay resident */ // Important: This service does not set the carry flag! DOS_ResizeMemory(dos.psp(),®_dx); DOS_Terminate(dos.psp(),true,reg_al); break; case 0x1f: /* Get drive parameter block for default drive */ case 0x32: /* Get drive parameter block for specific drive */ { /* Officially a dpb should be returned as well. The disk detection part is implemented */ Bit8u drive=reg_dl; if (!drive || reg_ah==0x1f) drive = DOS_GetDefaultDrive(); else drive--; if (Drives[drive]) { reg_al = 0x00; SegSet16(ds,dos.tables.dpb); reg_bx = drive;//Faking only the first entry (that is the driveletter) LOG(LOG_DOSMISC,LOG_ERROR)("Get drive parameter block."); } else { reg_al=0xff; } } break; case 0x33: /* Extended Break Checking */ switch (reg_al) { case 0:reg_dl=dos.breakcheck;break; /* Get the breakcheck flag */ case 1:dos.breakcheck=(reg_dl>0);break; /* Set the breakcheck flag */ case 2:{bool old=dos.breakcheck;dos.breakcheck=(reg_dl>0);reg_dl=old;}break; case 3: /* Get cpsw */ /* Fallthrough */ case 4: /* Set cpsw */ LOG(LOG_DOSMISC,LOG_ERROR)("Someone playing with cpsw %x",reg_ax); break; case 5:reg_dl=3;break;//TODO should be z /* Always boot from c: :) */ case 6: /* Get true version number */ reg_bl=dos.version.major; reg_bh=dos.version.minor; reg_dl=dos.version.revision; reg_dh=0x10; /* Dos in HMA */ break; default: LOG(LOG_DOSMISC,LOG_ERROR)("Weird 0x33 call %2X",reg_al); reg_al =0xff; break; } break; case 0x34: /* Get INDos Flag */ SegSet16(es,DOS_SDA_SEG); reg_bx=DOS_SDA_OFS + 0x01; break; case 0x35: /* Get interrupt vector */ reg_bx=real_readw(0,((Bit16u)reg_al)*4); SegSet16(es,real_readw(0,((Bit16u)reg_al)*4+2)); break; case 0x36: /* Get Free Disk Space */ { Bit16u bytes,clusters,free; Bit8u sectors; if (DOS_GetFreeDiskSpace(reg_dl,&bytes,§ors,&clusters,&free)) { reg_ax=sectors; reg_bx=free; reg_cx=bytes; reg_dx=clusters; } else { Bit8u drive=reg_dl; if (drive==0) drive=DOS_GetDefaultDrive(); else drive--; if (drive<2) { // floppy drive, non-present drivesdisks issue floppy check through int24 // (critical error handler); needed for Mixed up Mother Goose (hook) // CALLBACK_RunRealInt(0x24); } reg_ax=0xffff; // invalid drive specified } } break; case 0x37: /* Get/Set Switch char Get/Set Availdev thing */ //TODO Give errors for these functions to see if anyone actually uses this shit- switch (reg_al) { case 0: reg_al=0;reg_dl=0x2f;break; /* always return '/' like dos 5.0+ */ case 1: reg_al=0;break; case 2: reg_al=0;reg_dl=0x2f;break; case 3: reg_al=0;break; }; LOG(LOG_MISC,LOG_ERROR)("DOS:0x37:Call for not supported switchchar"); break; case 0x38: /* Set Country Code */ if (reg_al==0) { /* Get country specidic information */ PhysPt dest = SegPhys(ds)+reg_dx; MEM_BlockWrite(dest,dos.tables.country,0x18); reg_ax = reg_bx = 0x01; CALLBACK_SCF(false); break; } else { /* Set country code */ LOG(LOG_MISC,LOG_ERROR)("DOS:Setting country code not supported"); } CALLBACK_SCF(true); break; case 0x39: /* MKDIR Create directory */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_MakeDir(name1)) { reg_ax=0x05; /* ax destroyed */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3a: /* RMDIR Remove directory */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_RemoveDir(name1)) { reg_ax=0x05; /* ax destroyed */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); LOG(LOG_MISC,LOG_NORMAL)("Remove dir failed on %s with error %X",name1,dos.errorcode); } break; case 0x3b: /* CHDIR Set current directory */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_ChangeDir(name1)) { reg_ax=0x00; /* ax destroyed */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3c: /* CREATE Create of truncate file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_CreateFile(name1,reg_cx,®_ax)) { CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3d: /* OPEN Open existing file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_OpenFile(name1,reg_al,®_ax)) { CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3e: /* CLOSE Close file */ if (DOS_CloseFile(reg_bx)) { // reg_al=0x01; /* al destroyed. Refcount */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3f: /* READ Read from file or device */ { Bit16u toread=reg_cx; dos.echo=true; if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) { MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread); reg_ax=toread; CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } modify_cycles(reg_ax); dos.echo=false; break; } case 0x40: /* WRITE Write to file or device */ { Bit16u towrite=reg_cx; MEM_BlockRead(SegPhys(ds)+reg_dx,dos_copybuf,towrite); if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) { reg_ax=towrite; CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } modify_cycles(reg_ax); break; }; case 0x41: /* UNLINK Delete file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_UnlinkFile(name1)) { CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x42: /* LSEEK Set current file position */ { Bit32u pos=(reg_cx<<16) + reg_dx; if (DOS_SeekFile(reg_bx,&pos,reg_al)) { reg_dx=(Bit16u)(pos >> 16); reg_ax=(Bit16u)(pos & 0xFFFF); CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; }
void MOUSE_Init(Section* /*sec*/) { // Callback for mouse interrupt 0x33 call_int33=CALLBACK_Allocate(); // RealPt i33loc=RealMake(CB_SEG+1,(call_int33*CB_SIZE)-0x10); RealPt i33loc=RealMake(DOS_GetMemory(0x1)-1,0x10); CALLBACK_Setup(call_int33,&INT33_Handler,CB_MOUSE,Real2Phys(i33loc),"Mouse"); // Wasteland needs low(seg(int33))!=0 and low(ofs(int33))!=0 real_writed(0,0x33<<2,i33loc); call_mouse_bd=CALLBACK_Allocate(); CALLBACK_Setup(call_mouse_bd,&MOUSE_BD_Handler,CB_RETF8, PhysMake(RealSeg(i33loc),RealOff(i33loc)+2),"MouseBD"); // pseudocode for CB_MOUSE (including the special backdoor entry point): // jump near i33hd // callback MOUSE_BD_Handler // retf 8 // label i33hd: // callback INT33_Handler // iret // Callback for ps2 irq call_int74=CALLBACK_Allocate(); CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRQ12,"int 74"); // pseudocode for CB_IRQ12: // push ds // push es // pushad // sti // callback INT74_Handler // doesn't return here, but rather to CB_IRQ12_RET // (ps2 callback/user callback inbetween if requested) int74_ret_callback=CALLBACK_Allocate(); CALLBACK_Setup(int74_ret_callback,&MOUSE_UserInt_CB_Handler,CB_IRQ12_RET,"int 74 ret"); // pseudocode for CB_IRQ12_RET: // callback MOUSE_UserInt_CB_Handler // cli // mov al, 0x20 // out 0xa0, al // out 0x20, al // popad // pop es // pop ds // iret Bit8u hwvec=(MOUSE_IRQ>7)?(0x70+MOUSE_IRQ-8):(0x8+MOUSE_IRQ); RealSetVec(hwvec,CALLBACK_RealPointer(call_int74)); // Callback for ps2 user callback handling useps2callback = false; ps2callbackinit = false; call_ps2=CALLBACK_Allocate(); CALLBACK_Setup(call_ps2,&PS2_Handler,CB_RETF,"ps2 bios callback"); ps2_callback=CALLBACK_RealPointer(call_ps2); memset(&mouse,0,sizeof(mouse)); mouse.hidden = 1; //Hide mouse on startup mouse.timer_in_progress = false; mouse.mode = 0xFF; //Non existing mode mouse.sub_mask=0; mouse.sub_seg=0x6362; // magic value mouse.sub_ofs=0; Mouse_ResetHardware(); Mouse_Reset(); Mouse_SetSensitivity(50,50,50); }
static bool DOS_MultiplexFunctions(void) { switch (reg_ax) { /* ert, 20100711: Locking extensions */ case 0x1000: /* SHARE.EXE installation check */ if (enable_share_exe_fake) { reg_ax=0xffff; /* Pretend that share.exe is installed.. Of course it's a bloody LIE! */ } else { return false; /* pass it on */ } break; case 0x1216: /* GET ADDRESS OF SYSTEM FILE TABLE ENTRY */ // reg_bx is a system file table entry, should coincide with // the file handle so just use that LOG(LOG_DOSMISC,LOG_ERROR)("Some BAD filetable call used bx=%X",reg_bx); if(reg_bx <= DOS_FILES) CALLBACK_SCF(false); else CALLBACK_SCF(true); if (reg_bx<16) { RealPt sftrealpt=mem_readd(Real2Phys(dos_infoblock.GetPointer())+4); PhysPt sftptr=Real2Phys(sftrealpt); Bitu sftofs=0x06+reg_bx*0x3b; if (Files[reg_bx]) mem_writeb(sftptr+sftofs,Files[reg_bx]->refCtr); else mem_writeb(sftptr+sftofs,0); if (!Files[reg_bx]) return true; Bit32u handle=RealHandle(reg_bx); if (handle>=DOS_FILES) { mem_writew(sftptr+sftofs+0x02,0x02); // file open mode mem_writeb(sftptr+sftofs+0x04,0x00); // file attribute mem_writew(sftptr+sftofs+0x05,Files[reg_bx]->GetInformation()); // device info word mem_writed(sftptr+sftofs+0x07,0); // device driver header mem_writew(sftptr+sftofs+0x0d,0); // packed time mem_writew(sftptr+sftofs+0x0f,0); // packed date mem_writew(sftptr+sftofs+0x11,0); // size mem_writew(sftptr+sftofs+0x15,0); // current position } else { Bit8u drive=Files[reg_bx]->GetDrive(); mem_writew(sftptr+sftofs+0x02,(Bit16u)(Files[reg_bx]->flags&3)); // file open mode mem_writeb(sftptr+sftofs+0x04,(Bit8u)(Files[reg_bx]->attr)); // file attribute mem_writew(sftptr+sftofs+0x05,0x40|drive); // device info word mem_writed(sftptr+sftofs+0x07,RealMake(dos.tables.dpb,drive)); // dpb of the drive mem_writew(sftptr+sftofs+0x0d,Files[reg_bx]->time); // packed file time mem_writew(sftptr+sftofs+0x0f,Files[reg_bx]->date); // packed file date Bit32u curpos=0; Files[reg_bx]->Seek(&curpos,DOS_SEEK_CUR); Bit32u endpos=0; Files[reg_bx]->Seek(&endpos,DOS_SEEK_END); mem_writed(sftptr+sftofs+0x11,endpos); // size mem_writed(sftptr+sftofs+0x15,curpos); // current position Files[reg_bx]->Seek(&curpos,DOS_SEEK_SET); } // fill in filename in fcb style // (space-padded name (8 chars)+space-padded extension (3 chars)) const char* filename=(const char*)Files[reg_bx]->GetName(); if (strrchr(filename,'\\')) filename=strrchr(filename,'\\')+1; if (strrchr(filename,'/')) filename=strrchr(filename,'/')+1; if (!filename) return true; const char* dotpos=strrchr(filename,'.'); if (dotpos) { dotpos++; size_t nlen=strlen(filename); size_t extlen=strlen(dotpos); Bits nmelen=(Bits)nlen-(Bits)extlen; if (nmelen<1) return true; nlen-=(extlen+1); if (nlen>8) nlen=8; size_t i; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<8; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); if (extlen>3) extlen=3; for (i=0; i<extlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),dotpos[i]); for (i=extlen; i<3; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),' '); } else { size_t i; size_t nlen=strlen(filename); if (nlen>8) nlen=8; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<11; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); } SegSet16(es,RealSeg(sftrealpt)); reg_di=RealOff(sftrealpt+sftofs); reg_ax=0xc000; } return true; case 0x1605: /* Windows init broadcast */ if (enable_a20_on_windows_init) { /* This hack exists because Windows 3.1 doesn't seem to enable A20 first during an * initial critical period where it assumes it's on, prior to checking and enabling/disabling it. * * Note that Windows 3.1 also makes this mistake in Standard/286 mode, but it doesn't even * make this callout, so this hack is useless unless you are using Enhanced/386 mode. * If you want to run Windows 3.1 Standard mode with a20=mask you will have to run builtin * command "a20gate on" to turn on the A20 gate prior to starting Windows. */ LOG_MSG("Enabling A20 gate for Windows in response to INIT broadcast"); XMS_EnableA20(true); } /* TODO: Maybe future parts of DOSBox-X will do something with this */ /* 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:\ */ 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))", SegValue(es),reg_bx, SegValue(ds),reg_si, reg_cx,reg_dx,reg_di, reg_di>>8,reg_di&0xFF); if (reg_dx & 0x0001) LOG_MSG(" [286 DOS extender]"); else LOG_MSG(" [Enhanced mode]"); LOG_MSG("\n"); /* NTS: The way this protocol works, is that when you (the program hooking this call) receive it, * you first pass the call down to the previous INT 2Fh handler with registers unmodified, * and then when the call unwinds back up the chain, THEN you modify the results to notify * yourself to Windows. So logically, since we're the DOS kernel at the end of the chain, * we should still see ES:BX=0000:0000 and DS:SI=0000:0000 and CX=0000 unmodified from the * way the Windows kernel issued the call. If that's not the case, then we need to issue * a warning because some bastard on the call chain is ruining it for all of us. */ if (SegValue(es) != 0 || reg_bx != 0 || SegValue(ds) != 0 || reg_si != 0 || reg_cx != 0) { LOG_MSG("WARNING: Some registers at this point (the top of the call chain) are nonzero.\n"); LOG_MSG(" That means a TSR or other entity has modified registers on the way down\n"); LOG_MSG(" the call chain. The Windows init broadcast is supposed to be handled\n"); LOG_MSG(" going down the chain by calling the previous INT 2Fh handler with registers\n"); LOG_MSG(" unmodified, and only modify registers on the way back up the chain!\n"); } return false; /* pass it on to other INT 2F handlers */ case 0x1606: /* Windows exit broadcast */ /* TODO: Maybe future parts of DOSBox-X will do something with this */ /* 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:\ */ LOG_MSG("DEBUG: INT 2Fh Windows 286/386 DOSX exit broadcast issued (DX=0x%04x)",reg_dx); if (reg_dx & 0x0001) LOG_MSG(" [286 DOS extender]"); else LOG_MSG(" [Enhanced mode]"); LOG_MSG("\n"); return false; /* pass it on to other INT 2F handlers */ case 0x1607: /* 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:\ * Additionally, if the user WANTS to see every invocation of the IDLE call, then allow them to enable that too */ if (reg_bx != 0x18) { /* don't show the idle call. it's used too often */ const char *str = Win_NameThatVXD(reg_bx); if (str == NULL) str = "??"; LOG_MSG("DEBUG: INT 2Fh Windows virtual device '%s' callout (BX(deviceID)=0x%04x CX(function)=0x%04x)\n", str,reg_bx,reg_cx); } if (reg_bx == 0x15) { /* DOSMGR */ switch (reg_cx) { case 0x0000: // query instance reg_cx = 0x0001; reg_dx = 0x50; // dos driver segment SegSet16(es,0x50); // patch table seg reg_bx = 0x60; // patch table ofs return true; case 0x0001: // set patches reg_ax = 0xb97c; reg_bx = (reg_dx & 0x16); reg_dx = 0xa2ab; return true; case 0x0003: // get size of data struc if (reg_dx==0x0001) { // CDS size requested reg_ax = 0xb97c; reg_dx = 0xa2ab; reg_cx = 0x000e; // size } return true; case 0x0004: // instanced data reg_dx = 0; // none return true; case 0x0005: // get device driver size reg_ax = 0; reg_dx = 0; return true; default: return false; } } else if (reg_bx == 0x18) { /* VMPoll (idle) */ return true; } else return false; case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ //TODO Maybe do some idling but could screw up other systems :) return true; //So no warning in the debugger anymore case 0x1689: /* Kernel IDLE CALL */ case 0x168f: /* Close awareness crap */ /* Removing warning */ return true; case 0x4a01: { /* Query free hma space */ Bit32u limit = DOS_HMA_LIMIT(); if (limit == 0) { /* TODO: What does MS-DOS prior to v5.0? */ reg_bx = 0; reg_di = 0xFFFF; SegSet16(es,0xFFFF); LOG(LOG_MISC,LOG_DEBUG)("HMA query: rejected"); return true; } Bit32u start = DOS_HMA_FREE_START(); reg_bx = limit - start; /* free space in bytes */ SegSet16(es,0xffff); reg_di = (start + 0x10) & 0xFFFF; LOG(LOG_MISC,LOG_DEBUG)("HMA query: start=0x%06x limit=0x%06x free=0x%06x -> bx=%u %04x:%04x", start,limit,DOS_HMA_GET_FREE_SPACE(),(int)reg_bx,(int)SegValue(es),(int)reg_di); } return true; case 0x4a02: { /* ALLOCATE HMA SPACE */ Bit32u limit = DOS_HMA_LIMIT(); if (limit == 0) { /* TODO: What does MS-DOS prior to v5.0? */ reg_bx = 0; reg_di = 0xFFFF; SegSet16(es,0xFFFF); LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: rejected"); return true; } /* NTS: According to RBIL, Windows 95 adds a deallocate function and changes HMA allocation up to follow a * MCB chain structure. Which is something we're probably not going to add for awhile. */ /* FIXME: So, according to Ralph Brown Interrupt List, MS-DOS 5 and 6 liked to round up to the next paragraph? */ if (dos.version.major < 7 && (reg_bx & 0xF) != 0) reg_bx = (reg_bx + 0xF) & (~0xF); Bit32u start = DOS_HMA_FREE_START(); if ((start+reg_bx) > limit) { LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: rejected (not enough room) for %u bytes",reg_bx); reg_bx = 0; reg_di = 0xFFFF; SegSet16(es,0xFFFF); return true; } /* convert the start to segment:offset, normalized to FFFF:offset */ reg_di = (start - 0x10) & 0xFFFF; SegSet16(es,0xFFFF); /* let HMA emulation know what was claimed */ LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: %u bytes at FFFF:%04x",reg_bx,reg_di); DOS_HMA_CLAIMED(reg_bx); } return true; } return false; }
bool INT10_VideoState_Save(Bitu state,RealPt buffer) { Bitu ct; if ((state&7)==0) return false; Bitu base_seg=RealSeg(buffer); Bitu base_dest=RealOff(buffer)+0x20; if (state&1) { real_writew(base_seg,RealOff(buffer),base_dest); Bit16u crt_reg=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); real_writew(base_seg,base_dest+0x40,crt_reg); real_writeb(base_seg,base_dest+0x00,IO_ReadB(0x3c4)); real_writeb(base_seg,base_dest+0x01,IO_ReadB(0x3d4)); real_writeb(base_seg,base_dest+0x02,IO_ReadB(0x3ce)); IO_ReadB(crt_reg+6); real_writeb(base_seg,base_dest+0x03,IO_ReadB(0x3c0)); real_writeb(base_seg,base_dest+0x04,IO_ReadB(0x3ca)); // sequencer for (ct=1; ct<5; ct++) { IO_WriteB(0x3c4,ct); real_writeb(base_seg,base_dest+0x04+ct,IO_ReadB(0x3c5)); } real_writeb(base_seg,base_dest+0x09,IO_ReadB(0x3cc)); // crt controller for (ct=0; ct<0x19; ct++) { IO_WriteB(crt_reg,ct); real_writeb(base_seg,base_dest+0x0a+ct,IO_ReadB(crt_reg+1)); } // attr registers for (ct=0; ct<4; ct++) { IO_ReadB(crt_reg+6); IO_WriteB(0x3c0,0x10+ct); real_writeb(base_seg,base_dest+0x33+ct,IO_ReadB(0x3c1)); } // graphics registers for (ct=0; ct<9; ct++) { IO_WriteB(0x3ce,ct); real_writeb(base_seg,base_dest+0x37+ct,IO_ReadB(0x3cf)); } // save some registers IO_WriteB(0x3c4,2); Bit8u crtc_2=IO_ReadB(0x3c5); IO_WriteB(0x3c4,4); Bit8u crtc_4=IO_ReadB(0x3c5); IO_WriteB(0x3ce,6); Bit8u gfx_6=IO_ReadB(0x3cf); IO_WriteB(0x3ce,5); Bit8u gfx_5=IO_ReadB(0x3cf); IO_WriteB(0x3ce,4); Bit8u gfx_4=IO_ReadB(0x3cf); // reprogram for full access to plane latches IO_WriteW(0x3c4,0x0f02); IO_WriteW(0x3c4,0x0704); IO_WriteW(0x3ce,0x0406); IO_WriteW(0x3ce,0x0105); mem_writeb(0xaffff,0); for (ct=0; ct<4; ct++) { IO_WriteW(0x3ce,0x0004+ct*0x100); real_writeb(base_seg,base_dest+0x42+ct,mem_readb(0xaffff)); } // restore registers IO_WriteW(0x3ce,0x0004|(gfx_4<<8)); IO_WriteW(0x3ce,0x0005|(gfx_5<<8)); IO_WriteW(0x3ce,0x0006|(gfx_6<<8)); IO_WriteW(0x3c4,0x0004|(crtc_4<<8)); IO_WriteW(0x3c4,0x0002|(crtc_2<<8)); for (ct=0; ct<0x10; ct++) { IO_ReadB(crt_reg+6); IO_WriteB(0x3c0,ct); real_writeb(base_seg,base_dest+0x23+ct,IO_ReadB(0x3c1)); } IO_WriteB(0x3c0,0x20); base_dest+=0x46; } if (state&2) { real_writew(base_seg,RealOff(buffer)+2,base_dest); real_writeb(base_seg,base_dest+0x00,mem_readb(0x410)&0x30); for (ct=0; ct<0x1e; ct++) { real_writeb(base_seg,base_dest+0x01+ct,mem_readb(0x449+ct)); } for (ct=0; ct<0x07; ct++) { real_writeb(base_seg,base_dest+0x1f+ct,mem_readb(0x484+ct)); } real_writed(base_seg,base_dest+0x26,mem_readd(0x48a)); real_writed(base_seg,base_dest+0x2a,mem_readd(0x14)); // int 5 real_writed(base_seg,base_dest+0x2e,mem_readd(0x74)); // int 1d real_writed(base_seg,base_dest+0x32,mem_readd(0x7c)); // int 1f real_writed(base_seg,base_dest+0x36,mem_readd(0x10c)); // int 43 base_dest+=0x3a; } if (state&4) { real_writew(base_seg,RealOff(buffer)+4,base_dest); Bit16u crt_reg=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); IO_ReadB(crt_reg+6); IO_WriteB(0x3c0,0x14); real_writeb(base_seg,base_dest+0x303,IO_ReadB(0x3c1)); Bitu dac_state=IO_ReadB(0x3c7)&1; Bitu dac_windex=IO_ReadB(0x3c8); if (dac_state!=0) dac_windex--; real_writeb(base_seg,base_dest+0x000,dac_state); real_writeb(base_seg,base_dest+0x001,dac_windex); real_writeb(base_seg,base_dest+0x002,IO_ReadB(0x3c6)); for (ct=0; ct<0x100; ct++) { IO_WriteB(0x3c7,ct); real_writeb(base_seg,base_dest+0x003+ct*3+0,IO_ReadB(0x3c9)); real_writeb(base_seg,base_dest+0x003+ct*3+1,IO_ReadB(0x3c9)); real_writeb(base_seg,base_dest+0x003+ct*3+2,IO_ReadB(0x3c9)); } IO_ReadB(crt_reg+6); IO_WriteB(0x3c0,0x20); base_dest+=0x303; } if ((svgaCard==SVGA_S3Trio) && (state&8)) { real_writew(base_seg,RealOff(buffer)+6,base_dest); Bit16u crt_reg=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); IO_WriteB(0x3c4,0x08); // Bitu seq_8=IO_ReadB(0x3c5); IO_ReadB(0x3c5); // real_writeb(base_seg,base_dest+0x00,IO_ReadB(0x3c5)); IO_WriteB(0x3c5,0x06); // unlock s3-specific registers // sequencer for (ct=0; ct<0x13; ct++) { IO_WriteB(0x3c4,0x09+ct); real_writeb(base_seg,base_dest+0x00+ct,IO_ReadB(0x3c5)); } // unlock s3-specific registers IO_WriteW(crt_reg,0x4838); IO_WriteW(crt_reg,0xa539); // crt controller Bitu ct_dest=0x13; for (ct=0; ct<0x40; ct++) { if ((ct==0x4a-0x30) || (ct==0x4b-0x30)) { IO_WriteB(crt_reg,0x45); IO_ReadB(crt_reg+1); IO_WriteB(crt_reg,0x30+ct); real_writeb(base_seg,base_dest+(ct_dest++),IO_ReadB(crt_reg+1)); real_writeb(base_seg,base_dest+(ct_dest++),IO_ReadB(crt_reg+1)); real_writeb(base_seg,base_dest+(ct_dest++),IO_ReadB(crt_reg+1)); } else { IO_WriteB(crt_reg,0x30+ct); real_writeb(base_seg,base_dest+(ct_dest++),IO_ReadB(crt_reg+1)); } } } return true; }
bool INT10_VideoState_Restore(Bitu state,RealPt buffer) { Bitu ct; if ((state&7)==0) return false; Bit16u base_seg=RealSeg(buffer); Bit16u base_dest; if (state&1) { base_dest=real_readw(base_seg,RealOff(buffer)); Bit16u crt_reg=real_readw(base_seg,base_dest+0x40); // reprogram for full access to plane latches IO_WriteW(0x3c4,0x0704); IO_WriteW(0x3ce,0x0406); IO_WriteW(0x3ce,0x0005); IO_WriteW(0x3c4,0x0002); mem_writeb(0xaffff,real_readb(base_seg,base_dest+0x42)); IO_WriteW(0x3c4,0x0102); mem_writeb(0xaffff,real_readb(base_seg,base_dest+0x43)); IO_WriteW(0x3c4,0x0202); mem_writeb(0xaffff,real_readb(base_seg,base_dest+0x44)); IO_WriteW(0x3c4,0x0402); mem_writeb(0xaffff,real_readb(base_seg,base_dest+0x45)); IO_WriteW(0x3c4,0x0f02); mem_readb(0xaffff); IO_WriteW(0x3c4,0x0100); // sequencer for (ct=1; ct<5; ct++) { IO_WriteW(0x3c4,ct+(real_readb(base_seg,base_dest+0x04+ct)<<8)); } IO_WriteB(0x3c2,real_readb(base_seg,base_dest+0x09)); IO_WriteW(0x3c4,0x0300); IO_WriteW(crt_reg,0x0011); // crt controller for (ct=0; ct<0x19; ct++) { IO_WriteW(crt_reg,ct+(real_readb(base_seg,base_dest+0x0a+ct)<<8)); } IO_ReadB(crt_reg+6); // attr registers for (ct=0; ct<4; ct++) { IO_WriteB(0x3c0,0x10+ct); IO_WriteB(0x3c0,real_readb(base_seg,base_dest+0x33+ct)); } // graphics registers for (ct=0; ct<9; ct++) { IO_WriteW(0x3ce,ct+(real_readb(base_seg,base_dest+0x37+ct)<<8)); } IO_WriteB(crt_reg+6,real_readb(base_seg,base_dest+0x04)); IO_ReadB(crt_reg+6); // attr registers for (ct=0; ct<0x10; ct++) { IO_WriteB(0x3c0,ct); IO_WriteB(0x3c0,real_readb(base_seg,base_dest+0x23+ct)); } IO_WriteB(0x3c4,real_readb(base_seg,base_dest+0x00)); IO_WriteB(0x3d4,real_readb(base_seg,base_dest+0x01)); IO_WriteB(0x3ce,real_readb(base_seg,base_dest+0x02)); IO_ReadB(crt_reg+6); IO_WriteB(0x3c0,real_readb(base_seg,base_dest+0x03)); } if (state&2) { base_dest=real_readw(base_seg,RealOff(buffer)+2); mem_writeb(0x410,(mem_readb(0x410)&0xcf) | real_readb(base_seg,base_dest+0x00)); for (ct=0; ct<0x1e; ct++) { mem_writeb(0x449+ct,real_readb(base_seg,base_dest+0x01+ct)); } for (ct=0; ct<0x07; ct++) { mem_writeb(0x484+ct,real_readb(base_seg,base_dest+0x1f+ct)); } mem_writed(0x48a,real_readd(base_seg,base_dest+0x26)); mem_writed(0x14,real_readd(base_seg,base_dest+0x2a)); // int 5 mem_writed(0x74,real_readd(base_seg,base_dest+0x2e)); // int 1d mem_writed(0x7c,real_readd(base_seg,base_dest+0x32)); // int 1f mem_writed(0x10c,real_readd(base_seg,base_dest+0x36)); // int 43 } if (state&4) { base_dest=real_readw(base_seg,RealOff(buffer)+4); Bit16u crt_reg=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); IO_WriteB(0x3c6,real_readb(base_seg,base_dest+0x002)); for (ct=0; ct<0x100; ct++) { IO_WriteB(0x3c8,ct); IO_WriteB(0x3c9,real_readb(base_seg,base_dest+0x003+ct*3+0)); IO_WriteB(0x3c9,real_readb(base_seg,base_dest+0x003+ct*3+1)); IO_WriteB(0x3c9,real_readb(base_seg,base_dest+0x003+ct*3+2)); } IO_ReadB(crt_reg+6); IO_WriteB(0x3c0,0x14); IO_WriteB(0x3c0,real_readb(base_seg,base_dest+0x303)); Bitu dac_state=real_readb(base_seg,base_dest+0x000); if (dac_state==0) { IO_WriteB(0x3c8,real_readb(base_seg,base_dest+0x001)); } else { IO_WriteB(0x3c7,real_readb(base_seg,base_dest+0x001)); } } if ((svgaCard==SVGA_S3Trio) && (state&8)) { base_dest=real_readw(base_seg,RealOff(buffer)+6); Bit16u crt_reg=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); Bitu seq_idx=IO_ReadB(0x3c4); IO_WriteB(0x3c4,0x08); // Bitu seq_8=IO_ReadB(0x3c5); IO_ReadB(0x3c5); // real_writeb(base_seg,base_dest+0x00,IO_ReadB(0x3c5)); IO_WriteB(0x3c5,0x06); // unlock s3-specific registers // sequencer for (ct=0; ct<0x13; ct++) { IO_WriteW(0x3c4,(0x09+ct)+(real_readb(base_seg,base_dest+0x00+ct)<<8)); } IO_WriteB(0x3c4,seq_idx); // Bitu crtc_idx=IO_ReadB(0x3d4); // unlock s3-specific registers IO_WriteW(crt_reg,0x4838); IO_WriteW(crt_reg,0xa539); // crt controller Bitu ct_dest=0x13; for (ct=0; ct<0x40; ct++) { if ((ct==0x4a-0x30) || (ct==0x4b-0x30)) { IO_WriteB(crt_reg,0x45); IO_ReadB(crt_reg+1); IO_WriteB(crt_reg,0x30+ct); IO_WriteB(crt_reg,real_readb(base_seg,base_dest+(ct_dest++))); } else { IO_WriteW(crt_reg,(0x30+ct)+(real_readb(base_seg,base_dest+(ct_dest++))<<8)); } } // mmio /* IO_WriteB(crt_reg,0x40); Bitu sysval1=IO_ReadB(crt_reg+1); IO_WriteB(crt_reg+1,sysval|1); IO_WriteB(crt_reg,0x53); Bitu sysva2=IO_ReadB(crt_reg+1); IO_WriteB(crt_reg+1,sysval2|0x10); real_writew(0xa000,0x8128,0xffff); IO_WriteB(crt_reg,0x40); IO_WriteB(crt_reg,sysval1); IO_WriteB(crt_reg,0x53); IO_WriteB(crt_reg,sysval2); IO_WriteB(crt_reg,crtc_idx); */ } return true; }
static bool DOS_MultiplexFunctions(void) { char name[256]; switch (reg_ax) { case 0x1216: /* GET ADDRESS OF SYSTEM FILE TABLE ENTRY */ // reg_bx is a system file table entry, should coincide with // the file handle so just use that LOG(LOG_DOSMISC,LOG_ERROR)("Some BAD filetable call used bx=%X",reg_bx); if(reg_bx <= DOS_FILES) CALLBACK_SCF(false); else CALLBACK_SCF(true); if (reg_bx<16) { RealPt sftrealpt=mem_readd(Real2Phys(dos_infoblock.GetPointer())+4); PhysPt sftptr=Real2Phys(sftrealpt); Bitu sftofs=0x06+reg_bx*0x3b; if (Files[reg_bx]) mem_writeb(sftptr+sftofs,Files[reg_bx]->refCtr); else mem_writeb(sftptr+sftofs,0); if (!Files[reg_bx]) return true; Bit32u handle=RealHandle(reg_bx); if (handle>=DOS_FILES) { mem_writew(sftptr+sftofs+0x02,0x02); // file open mode mem_writeb(sftptr+sftofs+0x04,0x00); // file attribute mem_writew(sftptr+sftofs+0x05,Files[reg_bx]->GetInformation()); // device info word mem_writed(sftptr+sftofs+0x07,0); // device driver header mem_writew(sftptr+sftofs+0x0d,0); // packed time mem_writew(sftptr+sftofs+0x0f,0); // packed date mem_writew(sftptr+sftofs+0x11,0); // size mem_writew(sftptr+sftofs+0x15,0); // current position } else { Bit8u drive=Files[reg_bx]->GetDrive(); mem_writew(sftptr+sftofs+0x02,(Bit16u)(Files[reg_bx]->flags&3)); // file open mode mem_writeb(sftptr+sftofs+0x04,(Bit8u)(Files[reg_bx]->attr)); // file attribute mem_writew(sftptr+sftofs+0x05,0x40|drive); // device info word mem_writed(sftptr+sftofs+0x07,RealMake(dos.tables.dpb,drive)); // dpb of the drive mem_writew(sftptr+sftofs+0x0d,Files[reg_bx]->time); // packed file time mem_writew(sftptr+sftofs+0x0f,Files[reg_bx]->date); // packed file date Bit32u curpos=0; Files[reg_bx]->Seek(&curpos,DOS_SEEK_CUR); Bit32u endpos=0; Files[reg_bx]->Seek(&endpos,DOS_SEEK_END); mem_writed(sftptr+sftofs+0x11,endpos); // size mem_writed(sftptr+sftofs+0x15,curpos); // current position Files[reg_bx]->Seek(&curpos,DOS_SEEK_SET); } // fill in filename in fcb style // (space-padded name (8 chars)+space-padded extension (3 chars)) const char* filename=(const char*)Files[reg_bx]->GetName(); if (strrchr(filename,'\\')) filename=strrchr(filename,'\\')+1; if (strrchr(filename,'/')) filename=strrchr(filename,'/')+1; if (!filename) return true; const char* dotpos=strrchr(filename,'.'); if (dotpos) { dotpos++; size_t nlen=strlen(filename); size_t extlen=strlen(dotpos); Bits nmelen=(Bits)nlen-(Bits)extlen; if (nmelen<1) return true; nlen-=(extlen+1); if (nlen>8) nlen=8; size_t i; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<8; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); if (extlen>3) extlen=3; for (i=0; i<extlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),dotpos[i]); for (i=extlen; i<3; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),' '); } else { size_t i; size_t nlen=strlen(filename); if (nlen>8) nlen=8; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<11; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); } SegSet16(es,RealSeg(sftrealpt)); reg_di=RealOff(sftrealpt+sftofs); reg_ax=0xc000; } return true; case 0x1607: if (reg_bx == 0x15) { switch (reg_cx) { case 0x0000: // query instance reg_cx = 0x0001; reg_dx = 0x50; // dos driver segment SegSet16(es,0x50); // patch table seg reg_bx = 0x60; // patch table ofs return true; case 0x0001: // set patches reg_ax = 0xb97c; reg_bx = (reg_dx & 0x16); reg_dx = 0xa2ab; return true; case 0x0003: // get size of data struc if (reg_dx==0x0001) { // CDS size requested reg_ax = 0xb97c; reg_dx = 0xa2ab; reg_cx = 0x000e; // size } return true; case 0x0004: // instanced data reg_dx = 0; // none return true; case 0x0005: // get device driver size reg_ax = 0; reg_dx = 0; return true; default: return false; } } else if (reg_bx == 0x18) return true; // idle callout else return false; case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ //TODO Maybe do some idling but could screw up other systems :) return true; //So no warning in the debugger anymore case 0x1689: /* Kernel IDLE CALL */ case 0x168f: /* Close awareness crap */ /* Removing warning */ return true; case 0x4a01: /* Query free hma space */ case 0x4a02: /* ALLOCATE HMA SPACE */ LOG(LOG_DOSMISC,LOG_WARN)("INT 2f:4a HMA. DOSBox reports none available."); reg_bx=0; //number of bytes available in HMA or amount successfully allocated //ESDI=ffff:ffff Location of HMA/Allocated memory SegSet16(es,0xffff); reg_di=0xffff; return true; case 0x1300: case 0x1302: reg_ax=0; return true; case 0x1605: return true; case 0x1612: reg_ax=0; name[0]=1; name[1]=0; MEM_BlockWrite(SegPhys(es)+reg_bx,name,0x20); return true; case 0x1613: /* Get SYSTEM.DAT path */ strcpy(name,"C:\\WINDOWS\\SYSTEM.DAT"); MEM_BlockWrite(SegPhys(es)+reg_di,name,(Bitu)(strlen(name)+1)); reg_ax=0; reg_cx=strlen(name); return true; case 0x4a16: /* Open bootlog */ return true; case 0x4a17: /* Write bootlog */ MEM_StrCopy(SegPhys(ds)+reg_dx,name,255); LOG(LOG_DOSMISC,LOG_NORMAL)("BOOTLOG: %s\n",name); return true; case 0x4a33: /* Check MS-DOS Version 7 */ reg_ax=0; return true; } return false; }
bool DOS_Shell::Execute(char * name,char * args) { /* return true => don't check for hardware changes in do_command * return false => check for hardware changes in do_command */ char fullname[DOS_PATHLENGTH+4]; //stores results from Which char* p_fullname; char line[CMD_MAXLINE]; if(strlen(args)!= 0){ if(*args != ' '){ //put a space in front line[0]=' ';line[1]=0; strncat(line,args,CMD_MAXLINE-2); line[CMD_MAXLINE-1]=0; } else { safe_strncpy(line,args,CMD_MAXLINE); } }else{ line[0]=0; }; /* check for a drive change */ if (((strcmp(name + 1, ":") == 0) || (strcmp(name + 1, ":\\") == 0)) && isalpha(*name)) { if (!DOS_SetDrive(toupper(name[0])-'A')) { WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0])); } return true; } /* Check for a full name */ p_fullname = Which(name); if (!p_fullname) return false; strcpy(fullname,p_fullname); const char* extension = strrchr(fullname,'.'); __android_log_print(ANDROID_LOG_INFO, "dosbox", "command fullname:%s", fullname); /*always disallow files without extension from being executed. */ /*only internal commands can be run this way and they never get in this handler */ if(extension == 0) { //Check if the result will fit in the parameters. Else abort if(strlen(fullname) >( DOS_PATHLENGTH - 1) ) return false; char temp_name[DOS_PATHLENGTH+4],* temp_fullname; //try to add .com, .exe and .bat extensions to filename strcpy(temp_name,fullname); strcat(temp_name,".COM"); temp_fullname=Which(temp_name); if (temp_fullname) { extension=".com";strcpy(fullname,temp_fullname); } else { strcpy(temp_name,fullname); strcat(temp_name,".EXE"); temp_fullname=Which(temp_name); if (temp_fullname) { extension=".exe";strcpy(fullname,temp_fullname);} else { strcpy(temp_name,fullname); strcat(temp_name,".BAT"); temp_fullname=Which(temp_name); if (temp_fullname) { extension=".bat";strcpy(fullname,temp_fullname);} else { return false; } } } } if (strcasecmp(extension, ".bat") == 0) { /* Run the .bat file */ /* delete old batch file if call is not active*/ bool temp_echo=echo; /*keep the current echostate (as delete bf might change it )*/ if(bf && !call) delete bf; bf=new BatchFile(this,fullname,name,line); echo=temp_echo; //restore it. } else { /* only .bat .exe .com extensions maybe be executed by the shell */ if(strcasecmp(extension, ".com") !=0) { if(strcasecmp(extension, ".exe") !=0) return false; } /* Run the .exe or .com file from the shell */ /* Allocate some stack space for tables in physical memory */ reg_sp-=0x200; //Add Parameter block DOS_ParamBlock block(SegPhys(ss)+reg_sp); block.Clear(); //Add a filename RealPt file_name=RealMakeSeg(ss,reg_sp+0x20); MEM_BlockWrite(Real2Phys(file_name),fullname,(Bitu)(strlen(fullname)+1)); /* HACK: Store full commandline for mount and imgmount */ full_arguments.assign(line); /* Fill the command line */ CommandTail cmdtail; cmdtail.count = 0; memset(&cmdtail.buffer,0,126); //Else some part of the string is unitialized (valgrind) if (strlen(line)>126) line[126]=0; cmdtail.count=(Bit8u)strlen(line); memcpy(cmdtail.buffer,line,strlen(line)); cmdtail.buffer[strlen(line)]=0xd; /* Copy command line in stack block too */ MEM_BlockWrite(SegPhys(ss)+reg_sp+0x100,&cmdtail,128); /* Parse FCB (first two parameters) and put them into the current DOS_PSP */ Bit8u add; FCB_Parsename(dos.psp(),0x5C,0x00,cmdtail.buffer,&add); FCB_Parsename(dos.psp(),0x6C,0x00,&cmdtail.buffer[add],&add); block.exec.fcb1=RealMake(dos.psp(),0x5C); block.exec.fcb2=RealMake(dos.psp(),0x6C); /* Set the command line in the block and save it */ block.exec.cmdtail=RealMakeSeg(ss,reg_sp+0x100); block.SaveData(); #if 0 /* Save CS:IP to some point where i can return them from */ Bit32u oldeip=reg_eip; Bit16u oldcs=SegValue(cs); RealPt newcsip=CALLBACK_RealPointer(call_shellstop); SegSet16(cs,RealSeg(newcsip)); reg_ip=RealOff(newcsip); #endif /* Start up a dos execute interrupt */ reg_ax=0x4b00; //Filename pointer SegSet16(ds,SegValue(ss)); reg_dx=RealOff(file_name); //Paramblock SegSet16(es,SegValue(ss)); reg_bx=reg_sp; SETFLAGBIT(IF,false); CALLBACK_RunRealInt(0x21); /* Restore CS:IP and the stack */ reg_sp+=0x200; #if 0 reg_eip=oldeip; SegSet16(cs,oldcs); #endif } return true; //Executable started }
bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { EXE_Header head;Bitu i; Bit16u fhandle;Bit16u len;Bit32u pos; Bit16u pspseg,envseg,loadseg,memsize,readsize; PhysPt loadaddress;RealPt relocpt; Bitu headersize,imagesize; DOS_ParamBlock block(block_pt); block.LoadData(); if (flags!=LOADNGO && flags!=OVERLAY && flags!=LOAD) { E_Exit("DOS:Not supported execute mode %d for file %s",flags,name); } /* Check for EXE or COM File */ bool iscom=false; if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false; len=sizeof(EXE_Header); if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&len)) { DOS_CloseFile(fhandle); return false; } if (len<sizeof(EXE_Header)) { if (len==0) { /* Prevent executing zero byte files */ DOS_SetError(DOSERR_ACCESS_DENIED); DOS_CloseFile(fhandle); return false; } /* Otherwise must be a .com file */ iscom=true; } else { /* Convert the header to correct endian, i hope this works */ HostPt endian=(HostPt)&head; for (i=0;i<sizeof(EXE_Header)/2;i++) { *((Bit16u *)endian)=host_readw(endian); endian+=2; } if ((head.signature!=MAGIC1) && (head.signature!=MAGIC2)) iscom=true; else { if(head.pages & ~0x07ff) /* 1 MB dos maximum address limit. Fixes TC3 IDE (kippesoep) */ LOG(LOG_EXEC,LOG_NORMAL)("Weird header: head.pages > 1 MB"); head.pages&=0x07ff; headersize = head.headersize*16; imagesize = head.pages*512-headersize; if (imagesize+headersize<512) imagesize = 512-headersize; } } Bit8u * loadbuf=(Bit8u *)new Bit8u[0x10000]; if (flags!=OVERLAY) { /* Create an environment block */ envseg=block.exec.envseg; if (!MakeEnv(name,&envseg)) { DOS_CloseFile(fhandle); return false; } /* Get Memory */ Bit16u minsize,maxsize;Bit16u maxfree=0xffff;DOS_AllocateMemory(&pspseg,&maxfree); if (iscom) { minsize=0x1000;maxsize=0xffff; if (machine==MCH_PCJR) { /* try to load file into memory below 96k */ pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); Bit16u dataread=0x1800; DOS_ReadFile(fhandle,loadbuf,&dataread); if (dataread<0x1800) maxsize=dataread; if (minsize>maxsize) minsize=maxsize; } } else { /* Exe size calculated from header */ minsize=long2para(imagesize+(head.minmemory<<4)+256); if (head.maxmemory!=0) maxsize=long2para(imagesize+(head.maxmemory<<4)+256); else maxsize=0xffff; } if (maxfree<minsize) { DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); DOS_FreeMemory(envseg); return false; } if (maxfree<maxsize) memsize=maxfree; else memsize=maxsize; if (!DOS_AllocateMemory(&pspseg,&memsize)) E_Exit("DOS:Exec error in memory"); if (iscom && (machine==MCH_PCJR) && (pspseg<0x2000)) { maxsize=0xffff; /* resize to full extent of memory block */ DOS_ResizeMemory(pspseg,&maxsize); /* now try to lock out memory above segment 0x2000 */ if ((real_readb(0x2000,0)==0x5a) && (real_readw(0x2000,1)==0) && (real_readw(0x2000,3)==0x7ffe)) { /* MCB after PCJr graphics memory region is still free */ if (pspseg+maxsize==0x17ff) { DOS_MCB cmcb((Bit16u)(pspseg-1)); cmcb.SetType(0x5a); // last block } } } loadseg=pspseg+16; if (!iscom) { /* Check if requested to load program into upper part of allocated memory */ if ((head.minmemory == 0) && (head.maxmemory == 0)) loadseg = ((pspseg+memsize)*0x10-imagesize)/0x10; } } else loadseg=block.overlay.loadseg; /* Load the executable */ loadaddress=PhysMake(loadseg,0); if (iscom) { /* COM Load 64k - 256 bytes max */ pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); readsize=0xffff-256; DOS_ReadFile(fhandle,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,readsize); } else { /* EXE Load in 32kb blocks and then relocate */ pos=headersize;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); while (imagesize>0x7FFF) { readsize=0x8000;DOS_ReadFile(fhandle,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,readsize); // if (readsize!=0x8000) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header"); loadaddress+=0x8000;imagesize-=0x8000; } if (imagesize>0) { readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,readsize); // if (readsize!=imagesize) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header"); } /* Relocate the exe image */ Bit16u relocate; if (flags==OVERLAY) relocate=block.overlay.relocation; else relocate=loadseg; pos=head.reloctable;DOS_SeekFile(fhandle,&pos,0); for (i=0;i<head.relocations;i++) { readsize=4;DOS_ReadFile(fhandle,(Bit8u *)&relocpt,&readsize); relocpt=host_readd((HostPt)&relocpt); //Endianize PhysPt address=PhysMake(RealSeg(relocpt)+loadseg,RealOff(relocpt)); mem_writew(address,mem_readw(address)+relocate); } } delete[] loadbuf; DOS_CloseFile(fhandle); /* Setup a psp */ if (flags!=OVERLAY) { // Create psp after closing exe, to avoid dead file handle of exe in copied psp SetupPSP(pspseg,memsize,envseg); SetupCMDLine(pspseg,block); }; CALLBACK_SCF(false); /* Carry flag cleared for caller if successfull */ if (flags==OVERLAY) return true; /* Everything done for overlays */ RealPt csip,sssp; if (iscom) { csip=RealMake(pspseg,0x100); sssp=RealMake(pspseg,0xfffe); mem_writew(PhysMake(pspseg,0xfffe),0); } else { csip=RealMake(loadseg+head.initCS,head.initIP); sssp=RealMake(loadseg+head.initSS,head.initSP); } if (flags==LOAD) { DOS_PSP callpsp(dos.psp()); /* Save the SS:SP on the PSP of calling program */ callpsp.SetStack(RealMakeSeg(ss,reg_sp)); /* Switch the psp's */ dos.psp(pspseg); DOS_PSP newpsp(dos.psp()); dos.dta(RealMake(newpsp.GetSegment(),0x80)); block.exec.initsssp = sssp; block.exec.initcsip = csip; block.SaveData(); return true; } if (flags==LOADNGO) { /* Get Caller's program CS:IP of the stack and set termination address to that */ RealSetVec(0x22,RealMake(mem_readw(SegPhys(ss)+reg_sp+2),mem_readw(SegPhys(ss)+reg_sp))); SaveRegisters(); DOS_PSP callpsp(dos.psp()); /* Save the SS:SP on the PSP of calling program */ callpsp.SetStack(RealMakeSeg(ss,reg_sp)); /* Switch the psp's and set new DTA */ dos.psp(pspseg); DOS_PSP newpsp(dos.psp()); dos.dta(RealMake(newpsp.GetSegment(),0x80)); /* save vectors */ newpsp.SaveVectors(); /* copy fcbs */ newpsp.SetFCB1(block.exec.fcb1); newpsp.SetFCB2(block.exec.fcb2); /* Set the stack for new program */ SegSet16(ss,RealSeg(sssp));reg_sp=RealOff(sssp); /* Add some flags and CS:IP on the stack for the IRET */ reg_sp-=6; mem_writew(SegPhys(ss)+reg_sp+0,RealOff(csip)); mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(csip)); /* DOS starts programs with a RETF, so our IRET should not modify critical flags (IOPL in v86 mode); interrupt flag is set explicitly, test flags cleared */ mem_writew(SegPhys(ss)+reg_sp+4,(reg_flags&(~FMASK_TEST))|FLAG_IF); /* Setup the rest of the registers */ reg_ax=reg_bx=0;reg_cx=0xff; reg_dx=pspseg; reg_si=RealOff(csip); reg_di=RealOff(sssp); reg_bp=0x91c; /* DOS internal stack begin relict */ SegSet16(ds,pspseg);SegSet16(es,pspseg); #if C_DEBUG /* Started from debug.com, then set breakpoint at start */ DEBUG_CheckExecuteBreakpoint(RealSeg(csip),RealOff(csip)); #endif /* Add the filename to PSP and environment MCB's */ char stripname[8];Bitu index=0; while (char chr=*name++) { switch (chr) { case ':':case '\\':case '/':index=0;break; default:if (index<8) stripname[index++]=toupper(chr); } } index=0; while (index<8) { if (stripname[index]=='.') break; if (!stripname[index]) break; index++; } memset(&stripname[index],0,8-index); DOS_MCB pspmcb(dos.psp()-1); pspmcb.SetFileName(stripname); DOS_UpdatePSPName(); return true; } return false; }
static Bitu DOS_21Handler(void) { if (((reg_ah != 0x50) && (reg_ah != 0x51) && (reg_ah != 0x62) && (reg_ah != 0x64)) && (reg_ah < 0x6c)) if (dos.psp() != 0) // No program loaded yet? { DOS_PSP psp(dos.psp()); psp.SetStack(SegOff2dWord(SegValue(ss), reg_sp-18)); psp.FindFreeFileEntry(); } char name1[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII]; char name2[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII]; switch (reg_ah) { case 0x00: // Terminate Program DOS_Terminate(Mem_Lodsw(SegPhys(ss)+reg_sp+2), false, 0); break; case 0x01: // Read character from STDIN, with echo { Bit8u c; Bit16u n = 1; dos.echo = true; DOS_ReadFile(STDIN, &c, &n); reg_al = c; dos.echo = false; } break; case 0x02: // Write character to STDOUT { Bit8u c = reg_dl; Bit16u n = 1; DOS_WriteFile(STDOUT, &c, &n); // Not in the official specs, but happens nonetheless. (last written character) reg_al = c; // reg_al=(c==9)?0x20:c; //Officially: tab to spaces } break; case 0x03: // Read character from STDAUX { Bit16u port = Mem_Lodsw(0x40, 0); if (port != 0 && serialPorts[0]) serialPorts[0]->Getchar(®_al); } break; case 0x04: // Write Character to STDAUX { Bit16u port = Mem_Lodsw(0x40, 0); if (port != 0 && serialPorts[0]) serialPorts[0]->Putchar(reg_dl); } break; case 0x05: // Write Character to PRINTER parallelPorts[0]->Putchar(reg_dl); break; case 0x06: // Direct Console Output/Input if (reg_dl == 0xff) // Input { // TODO Make this better according to standards if (!DOS_GetSTDINStatus()) { reg_al = 0; CALLBACK_SZF(true); break; } Bit8u c; Bit16u n = 1; DOS_ReadFile(STDIN, &c, &n); reg_al = c; CALLBACK_SZF(false); } else // Ouput { Bit8u c = reg_dl; Bit16u n = 1; DOS_WriteFile(STDOUT, &c, &n); reg_al = reg_dl; } break; case 0x07: // Character Input, without echo case 0x08: // Direct Character Input, without echo (checks for breaks officially :) { Bit8u c; Bit16u n = 1; DOS_ReadFile (STDIN, &c, &n); reg_al = c; } break; case 0x09: // Write string to STDOUT { Bit8u c; Bit16u n = 1; PhysPt buf = SegPhys(ds)+reg_dx; while ((c = Mem_Lodsb(buf++)) != '$') DOS_WriteFile(STDOUT, &c, &n); } break; case 0x0a: // Buffered Input { // TODO ADD Break checkin in STDIN but can't care that much for it PhysPt data = SegPhys(ds)+reg_dx; Bit8u free = Mem_Lodsb(data); if (!free) break; Bit8u read = 0; Bit8u c; Bit16u n = 1; for(;;) { DOS_ReadFile(STDIN, &c ,&n); if (c == 8) { // Backspace if (read) { // Something to backspace. DOS_WriteFile(STDOUT, &c, &n); // STDOUT treats backspace as non-destructive. c = ' '; DOS_WriteFile(STDOUT, &c, &n); c = 8; DOS_WriteFile(STDOUT, &c, &n); --read; } continue; } if (read >= free) // Keyboard buffer full { Beep(1750, 300); continue; } DOS_WriteFile(STDOUT, &c, &n); Mem_Stosb(data+read+2, c); if (c == 13) break; read++; } Mem_Stosb(data+1, read); } break; case 0x0b: // Get STDIN Status reg_al = DOS_GetSTDINStatus() ? 0xff : 0x00; break; case 0x0c: // Flush Buffer and read STDIN call { Bit8u handle = RealHandle(STDIN); if (handle != 0xFF && Files[handle] && Files[handle]->IsName("CON")) // flush buffer if STDIN is CON { Bit8u c; Bit16u n; while (DOS_GetSTDINStatus()) { n = 1; DOS_ReadFile(STDIN, &c, &n); } } if (reg_al == 0x1 || reg_al == 0x6 || reg_al == 0x7 || reg_al == 0x8 || reg_al == 0xa) { Bit8u oldah = reg_ah; reg_ah = reg_al; DOS_21Handler(); reg_ah = oldah; } else reg_al = 0; } break; case 0x0d: // Disk Reset break; case 0x0e: // Select Default Drive DOS_SetDefaultDrive(reg_dl); reg_al = DOS_DRIVES; break; case 0x0f: // Open File using FCB reg_al = DOS_FCBOpen(SegValue(ds), reg_dx) ? 0 : 0xFF; break; case 0x10: // Close File using FCB reg_al = DOS_FCBClose(SegValue(ds), reg_dx) ? 0 : 0xFF; break; case 0x11: // Find First Matching File using FCB reg_al = DOS_FCBFindFirst(SegValue(ds), reg_dx) ? 0 : 0xFF; // No test for C:\COMMAND.COM! break; case 0x12: // Find Next Matching File using FCB reg_al = DOS_FCBFindNext(SegValue(ds), reg_dx) ? 0 : 0xFF; break; case 0x13: // Delete File using FCB reg_al = DOS_FCBDeleteFile(SegValue(ds), reg_dx) ? 0 : 0xFF; break; case 0x14: // Sequential read from FCB reg_al = DOS_FCBRead(SegValue(ds), reg_dx, 0); break; case 0x15: // Sequential write to FCB reg_al = DOS_FCBWrite(SegValue(ds), reg_dx, 0); break; case 0x16: // Create or truncate file using FCB reg_al = DOS_FCBCreate(SegValue(ds), reg_dx) ? 0 : 0xFF; break; case 0x17: // Rename file using FCB reg_al = DOS_FCBRenameFile(SegValue(ds), reg_dx) ? 0 : 0xFF; break; case 0x1b: // Get allocation info for default drive if (!DOS_GetAllocationInfo(0, ®_cx, ®_al, ®_dx)) reg_al = 0xFF; break; case 0x1c: // Get allocation info for specific drive if (!DOS_GetAllocationInfo(reg_dl, ®_cx, ®_al, ®_dx)) reg_al = 0xFF; break; case 0x21: // Read random record from FCB reg_al = DOS_FCBRandomRead(SegValue(ds), reg_dx, 1, true); break; case 0x22: // Write random record to FCB reg_al = DOS_FCBRandomWrite(SegValue(ds), reg_dx, 1, true); break; case 0x23: // Get file size for FCB reg_al = DOS_FCBGetFileSize(SegValue(ds), reg_dx) ? 0 : 0xFF; break; case 0x24: // Set Random Record number for FCB DOS_FCBSetRandomRecord(SegValue(ds), reg_dx); break; case 0x27: // Random block read from FCB reg_al = DOS_FCBRandomRead(SegValue(ds), reg_dx, reg_cx, false); break; case 0x28: // Random Block write to FCB reg_al = DOS_FCBRandomWrite(SegValue(ds), reg_dx, reg_cx, false); break; case 0x29: // Parse filename into FCB { Bit8u difference; char string[1024]; Mem_StrnCopyFrom(string, SegPhys(ds)+reg_si, 1023); // 1024 toasts the stack reg_al = FCB_Parsename(SegValue(es), reg_di, reg_al, string, &difference); reg_si += difference; } break; case 0x19: // Get current default drive reg_al = DOS_GetDefaultDrive(); break; case 0x1a: // Set Disk Transfer Area Address dos.dta(RealMakeSeg(ds, reg_dx)); break; case 0x25: // Set Interrupt Vector RealSetVec(reg_al, RealMakeSeg(ds, reg_dx)); break; case 0x26: // Create new PSP DOS_NewPSP(reg_dx, DOS_PSP(dos.psp()).GetSize()); break; case 0x2a: // Get System Date { _SYSTEMTIME systime; // Return the Windows localdate GetLocalTime(&systime); reg_al = (Bit8u)systime.wDayOfWeek; // NB Sunday = 0, despite of MSDN documentation reg_cx = systime.wYear; reg_dx = (systime.wMonth<<8)+systime.wDay; } break; case 0x2b: // Set System Date (we don't!) reg_al = 0xff; daysInMonth[2] = reg_cx&3 ? 28 : 29; // Year is from 1980 to 2099, it is this simple if (reg_cx >= 1980 && reg_cx <= 2099) if (reg_dh > 0 && reg_dh <= 12) if (reg_dl > 0 && reg_dl <= daysInMonth[reg_dh]) reg_al = 0; // Date is valid, fake set break; case 0x2c: // Get System Time { _SYSTEMTIME systime; // Return the Windows localtime GetLocalTime(&systime); reg_cx = (systime.wHour<<8) + systime.wMinute; reg_dx = (systime.wSecond<<8) + systime.wMilliseconds/10; } break; case 0x2d: // Set System Time (we don't!) if (reg_ch < 24 && reg_cl < 60 && reg_dh < 60 && reg_dl < 100) reg_al = 0; // Time is valid, fake set else reg_al = 0xff; break; case 0x2e: // Set Verify flag dos.verify = (reg_al == 1); break; case 0x2f: // Get Disk Transfer Area SegSet16(es, RealSeg(dos.dta())); reg_bx = RealOff(dos.dta()); break; case 0x30: // Get DOS Version if (reg_al == 0) reg_bh = 0xFF; // Fake Microsoft DOS else if (reg_al == 1) reg_bh = 0; // DOS is NOT in HMA reg_al = dos.version.major; reg_ah = dos.version.minor; reg_bl = 0; // Serialnumber reg_cx = 0; break; case 0x31: // Terminate and stay resident // Important: This service does not set the carry flag! DOS_ResizeMemory(dos.psp(), ®_dx); DOS_Terminate(dos.psp(), true, reg_al); break; case 0x1f: // Get drive parameter block for default drive case 0x32: // Get drive parameter block for specific drive { // Officially a dpb should be returned as well. The disk detection part is implemented Bit8u drive = reg_dl; if (!drive || reg_ah == 0x1f) drive = DOS_GetDefaultDrive(); else drive--; if (Drives[drive]) { reg_al = 0; SegSet16(ds, dos.tables.dpb); reg_bx = drive; // Faking only the first entry (that is the driveletter) } else reg_al = 0xff; } break; case 0x33: // Extended Break Checking switch (reg_al) { case 0: // Get the breakcheck flag reg_dl = dos.breakcheck; break; case 1: // Set the breakcheck flag dos.breakcheck = (reg_dl > 0); break; case 2: { bool old = dos.breakcheck; dos.breakcheck = (reg_dl > 0); reg_dl = old; } break; case 3: // Get cpsw case 4: // Set cpsw, both not used really break; case 5: reg_dl = 3; // Boot drive = C: break; case 6: // Get true version number reg_bx = (dos.version.minor<<8) + dos.version.major; reg_dx = 0x1000; // Dos in ROM break; default: reg_al = 0xff; } break; case 0x34: // Get address of INDos Flag SegSet16(es, DOS_SDA_SEG); reg_bx = DOS_SDA_OFS + 0x01; break; case 0x35: // Get interrupt vector reg_bx = Mem_Lodsw(0, ((Bit16u)reg_al)*4); SegSet16(es, Mem_Lodsw(0, ((Bit16u)reg_al)*4+2)); break; case 0x36: // Get Free Disk Space { Bit16u bytes, clusters, free; Bit8u sectors; if (DOS_GetFreeDiskSpace(reg_dl, &bytes, §ors, &clusters, &free)) { reg_ax = sectors; reg_bx = free; reg_cx = bytes; reg_dx = clusters; } else reg_ax = 0xffff; // invalid drive specified } break; case 0x37: // Get/Set Switch char Get/Set Availdev thing switch (reg_al) { case 0: reg_dl = 0x2f; // Always return '/' like dos 5.0+ break; case 1: reg_al = 0; break; case 2: reg_al = 0; reg_dl = 0x2f; break; case 3: reg_al = 0; break; } break; case 0x38: // Get/set Country Code if (reg_al == 0) // Get country specidic information { PhysPt dest = SegPhys(ds)+reg_dx; Mem_CopyTo(dest, dos.tables.country, 0x18); reg_ax = reg_bx = 1; CALLBACK_SCF(false); } else // Set country code CALLBACK_SCF(true); break; case 0x39: // MKDIR Create directory Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF); rSpTrim(name1); if (DOS_MakeDir(name1)) { reg_ax = 0xffff; // AX destroyed CALLBACK_SCF(false); } else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } break; case 0x3a: // RMDIR Remove directory Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF); rSpTrim(name1); if (DOS_RemoveDir(name1)) { reg_ax = 0xffff; // AX destroyed CALLBACK_SCF(false); } else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } break; case 0x3b: // CHDIR Set current directory Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF); rSpTrim(name1); if (DOS_ChangeDir(name1)) { reg_ax = 0xff00; // AX destroyed CALLBACK_SCF(false); } else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } break; case 0x3c: // CREATE Create or truncate file Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF); rSpTrim(name1); if (DOS_CreateFile(name1, reg_cx, ®_ax)) CALLBACK_SCF(false); else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } break; case 0x3d: // OPEN Open existing file { Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF); rSpTrim(name1); if (DOS_OpenFile(name1, reg_al, ®_ax)) CALLBACK_SCF(false); else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } break; } case 0x3e: // CLOSE Close file if (DOS_CloseFile(reg_bx)) CALLBACK_SCF(false); else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } break; case 0x3f: // READ Read from file or device { Bit16u toread = reg_cx; dos.echo = true; if (DOS_ReadFile(reg_bx, dos_copybuf, &toread)) { Mem_CopyTo(SegPhys(ds)+reg_dx, dos_copybuf, toread); reg_ax = toread; CALLBACK_SCF(false); } else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } dos.echo = false; } break; case 0x40: // WRITE Write to file or device { Bit16u towrite = reg_cx; Mem_CopyFrom(SegPhys(ds)+reg_dx, dos_copybuf, towrite); if (DOS_WriteFile(reg_bx, dos_copybuf, &towrite)) { reg_ax = towrite; CALLBACK_SCF(false); } else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } } break; case 0x41: // UNLINK Delete file Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF); rSpTrim(name1); if (DOS_UnlinkFile(name1)) CALLBACK_SCF(false); else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } break; case 0x42: // LSEEK Set current file position { Bit32u pos = (reg_cx<<16) + reg_dx; if (DOS_SeekFile(reg_bx, &pos, reg_al)) { reg_dx = (Bit16u)(pos >> 16); reg_ax = (Bit16u)(pos & 0xFFFF); CALLBACK_SCF(false); } else { reg_ax = dos.errorcode; CALLBACK_SCF(true); } }