From 7f740cbb047e465856dc4b1789401db12b72d6d9 Mon Sep 17 00:00:00 2001 From: Ove Kaaven Date: Sun, 1 Nov 1998 12:41:19 +0000 Subject: [PATCH] Indirection for INSTR_EmulateInstruction for use by DOS code. Added support for a 55Hz system timer, letting DOS apps calibrate their delay loops and such. Calls INSTR_EmulateInstruction for instruction emulation (principally I/O port access). Added macro V86_FLAG. --- if1632/signal.c | 2 + include/dosexe.h | 9 +++- loader/dos/dosvm.c | 105 ++++++++++++++++++++++++++++++++++---------- loader/dos/module.c | 11 +++-- misc/system.c | 14 +++++- miscemu/instr.c | 20 ++++++--- 6 files changed, 127 insertions(+), 34 deletions(-) diff --git a/if1632/signal.c b/if1632/signal.c index a310cf82458..29ade19212f 100644 --- a/if1632/signal.c +++ b/if1632/signal.c @@ -20,6 +20,7 @@ #include "options.h" #include "sig_context.h" #include "miscemu.h" +#include "dosexe.h" #include "thread.h" #include "debug.h" @@ -223,5 +224,6 @@ BOOL32 SIGNAL_InitEmulator(void) #ifdef SIGBUS SIGNAL_SetHandler( SIGBUS, (void (*)())SIGNAL_fault, 1); #endif + instr_emu_call = INSTR_EmulateInstruction; return TRUE; } diff --git a/include/dosexe.h b/include/dosexe.h index 202a7b2fff0..8782116475d 100644 --- a/include/dosexe.h +++ b/include/dosexe.h @@ -10,6 +10,7 @@ #include #include "windows.h" #include "winnt.h" +#include "sig_context.h" #include "wintypes.h" typedef struct _DOSTASK { @@ -20,6 +21,7 @@ typedef struct _DOSTASK { WORD xms_seg; WORD dpmi_seg,dpmi_sel,dpmi_flag; DWORD wrap_ofs,call_ofs; + WORD system_timer; HMODULE16 hModule; char mm_name[128]; int mm_fd; @@ -40,7 +42,12 @@ extern LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule ); #endif /* linux */ -extern void (*ctx_debug_call)( int sig, CONTEXT* ); +#define V86_FLAG 0x00020000 + +extern void (*ctx_debug_call)( int, CONTEXT* ); +extern BOOL32 (*instr_emu_call)( SIGCONTEXT* ); + +extern void MZ_Tick( WORD handle ); extern HINSTANCE16 MZ_CreateProcess( LPCSTR name, LPCSTR cmdline, LPCSTR env, LPSTARTUPINFO32A startup, LPPROCESS_INFORMATION info ); diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c index fc918148959..5b11561fe56 100644 --- a/loader/dos/dosvm.c +++ b/loader/dos/dosvm.c @@ -13,11 +13,13 @@ #include #include #include +#include #include #include #include "windows.h" #include "winbase.h" #include "winnt.h" +#include "sig_context.h" #include "msdos.h" #include "miscemu.h" #include "debugger.h" @@ -28,6 +30,7 @@ #include "dosexe.h" void (*ctx_debug_call)(int sig,CONTEXT*ctx)=NULL; +BOOL32 (*instr_emu_call)(SIGCONTEXT*ctx)=NULL; #ifdef MZ_SUPPORTED @@ -54,12 +57,14 @@ static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn, printf("Trapped due to pending PIC request\n"); break; case VM86_TRAP: printf("Trapped debug request\n"); break; + default: + printf("Trapped unknown VM86 type %d arg %d\n",VM86_TYPE(fn),VM86_ARG(fn)); break; } #define REGS VM86->regs - fprintf(stderr,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS.eax,REGS.ebx,REGS.ecx,REGS.edx); + fprintf(stderr,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS.eax,REGS.ecx,REGS.edx,REGS.ebx); fprintf(stderr,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS.esi,REGS.edi,REGS.esp,REGS.ebp); fprintf(stderr,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS.cs,REGS.ds,REGS.es,REGS.ss); - fprintf(stderr,"EIP=%04lX EFLAGS=%08lX\n",REGS.eip,REGS.eflags); + fprintf(stderr,"IP=%04lX EFLAGS=%08lX\n",REGS.eip,REGS.eflags); iofs=((DWORD)REGS.cs<<4)+REGS.eip; #undef REGS @@ -67,8 +72,6 @@ static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn, printf("Opcodes:"); for (x=0; x<8; x++) printf(" %02x",inst[x]); printf("\n"); - - exit(0); } static int DOSVM_Int( int vect, PCONTEXT context, LPDOSTASK lpDosTask ) @@ -86,26 +89,39 @@ static int DOSVM_Int( int vect, PCONTEXT context, LPDOSTASK lpDosTask ) return 0; } -#define CV CP(eax,Eax); CP(ecx,Ecx); CP(edx,Edx); CP(ebx,Ebx); \ - CP(esi,Esi); CP(edi,Edi); CP(esp,Esp); CP(ebp,Ebp); \ - CP(cs,SegCs); CP(ds,SegDs); CP(es,SegEs); \ - CP(ss,SegSs); CP(fs,SegFs); CP(gs,SegGs); \ - CP(eip,Eip); CP(eflags,EFlags) +#define CV CP(eax,EAX); CP(ecx,ECX); CP(edx,EDX); CP(ebx,EBX); \ + CP(esi,ESI); CP(edi,EDI); CP(esp,ESP); CP(ebp,EBP); \ + CP(cs,CS); CP(ds,DS); CP(es,ES); \ + CP(ss,SS); CP(fs,FS); CP(gs,GS); \ + CP(eip,EIP); CP(eflags,EFL) static int DOSVM_Process( LPDOSTASK lpDosTask, int fn, struct vm86plus_struct*VM86 ) { + SIGCONTEXT sigcontext; CONTEXT context; int ret=0; -#define CP(x,y) context.y = VM86->regs.x + if (VM86_TYPE(fn)==VM86_UNKNOWN) { + /* INSTR_EmulateInstruction needs a SIGCONTEXT, not a CONTEXT... */ +#define CP(x,y) y##_sig(&sigcontext) = VM86->regs.x + CV; +#undef CP + if (instr_emu_call) ret=instr_emu_call(&sigcontext); +#define CP(x,y) VM86->regs.x = y##_sig(&sigcontext) + CV; +#undef CP + if (ret) return 0; + ret=0; + } +#define CP(x,y) y##_reg(&context) = VM86->regs.x CV; #undef CP (void*)V86BASE(&context)=lpDosTask->img; switch (VM86_TYPE(fn)) { case VM86_SIGNAL: - printf("Trapped signal\n"); + DOSVM_Dump(lpDosTask,fn,VM86); ret=-1; break; case VM86_UNKNOWN: /* unhandled GPF */ DOSVM_Dump(lpDosTask,fn,VM86); @@ -123,9 +139,10 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn, break; default: DOSVM_Dump(lpDosTask,fn,VM86); + ret=-1; } -#define CP(x,y) VM86->regs.x = context.y +#define CP(x,y) VM86->regs.x = y##_reg(&context) CV; #undef CP return ret; @@ -137,7 +154,8 @@ int DOSVM_Enter( PCONTEXT context ) NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); LPDOSTASK lpDosTask; struct vm86plus_struct VM86; - int stat; + int stat,len; + fd_set readfds,exceptfds; GlobalUnlock16( GetCurrentTask() ); if (!pModule) { @@ -163,7 +181,7 @@ int DOSVM_Enter( PCONTEXT context ) } else lpDosTask=pModule->lpDosTask; if (context) { -#define CP(x,y) VM86.regs.x = context->y +#define CP(x,y) VM86.regs.x = y##_reg(context) CV; #undef CP } else { @@ -179,23 +197,47 @@ int DOSVM_Enter( PCONTEXT context ) } /* main exchange loop */ - stat = VM86_ENTER; do { + stat = VM86_ENTER; /* transmit VM86 structure to dosmod task */ - if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat)) + if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat)) { + ERR(module,"dosmod sync lost, errno=%d\n",errno); return -1; - if (write(lpDosTask->write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) + } + if (write(lpDosTask->write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) { + ERR(module,"dosmod sync lost, errno=%d\n",errno); return -1; - /* wait for response */ + } + /* wait for response, with async events enabled */ + FD_ZERO(&readfds); + FD_ZERO(&exceptfds); + SIGNAL_MaskAsyncEvents(FALSE); do { - if (read(lpDosTask->read_pipe,&stat,sizeof(stat))!=sizeof(stat)) { - if ((errno==EINTR)||(errno==EAGAIN)) continue; + FD_SET(lpDosTask->read_pipe,&readfds); + FD_SET(lpDosTask->read_pipe,&exceptfds); + select(lpDosTask->read_pipe+1,&readfds,NULL,&exceptfds,NULL); + } while (!(FD_ISSET(lpDosTask->read_pipe,&readfds)|| + FD_ISSET(lpDosTask->read_pipe,&exceptfds))); + SIGNAL_MaskAsyncEvents(TRUE); + /* read response (with async events disabled to avoid some strange problems) */ + do { + if ((len=read(lpDosTask->read_pipe,&stat,sizeof(stat)))!=sizeof(stat)) { + if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) { + WARN(module,"rereading dosmod return code due to errno=%d, result=%d\n",errno,len); + continue; + } + ERR(module,"dosmod sync lost reading return code, errno=%d, result=%d\n",errno,len); return -1; } } while (0); + TRACE(module,"dosmod return code=%d\n",stat); do { - if (read(lpDosTask->read_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) { - if ((errno==EINTR)||(errno==EAGAIN)) continue; + if ((len=read(lpDosTask->read_pipe,&VM86,sizeof(VM86)))!=sizeof(VM86)) { + if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) { + WARN(module,"rereading dosmod VM86 structure due to errno=%d, result=%d\n",errno,len); + continue; + } + ERR(module,"dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno,len); return -1; } } while (0); @@ -203,13 +245,28 @@ int DOSVM_Enter( PCONTEXT context ) } while (DOSVM_Process(lpDosTask,stat,&VM86)>=0); if (context) { -#define CP(x,y) context->y = VM86.regs.x +#define CP(x,y) y##_reg(context) = VM86.regs.x CV; #undef CP } return 0; } +void MZ_Tick( WORD handle ) +{ + /* find the DOS task that has the right system_timer handle... */ + /* should usually be the current, so let's just be lazy... */ + TDB *pTask = (TDB*)GlobalLock16( GetCurrentTask() ); + NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL; + LPDOSTASK lpDosTask = pModule ? pModule->lpDosTask : NULL; + + GlobalUnlock16( GetCurrentTask() ); + if (lpDosTask&&(lpDosTask->system_timer==handle)) { + /* BIOS timer tick */ + (*((DWORD*)(((BYTE*)(lpDosTask->img))+0x46c)))++; + } +} + #else /* !MZ_SUPPORTED */ int DOSVM_Enter( PCONTEXT context ) @@ -218,4 +275,6 @@ int DOSVM_Enter( PCONTEXT context ) return -1; } +void MZ_Tick( WORD handle ) {} + #endif diff --git a/loader/dos/module.c b/loader/dos/module.c index fa880048be4..95ea48dc9df 100644 --- a/loader/dos/module.c +++ b/loader/dos/module.c @@ -181,7 +181,7 @@ int MZ_InitMemory( LPDOSTASK lpDosTask, NE_MODULE *pModule ) DOSMEM_Init(lpDosTask->hModule); MZ_InitXMS(lpDosTask); MZ_InitDPMI(lpDosTask); - return 32; + return lpDosTask->hModule; } static int MZ_LoadImage( HFILE16 hFile, LPCSTR name, LPCSTR cmdline, @@ -263,7 +263,7 @@ static int MZ_LoadImage( HFILE16 hFile, LPCSTR name, LPCSTR cmdline, TRACE(module,"entry point: %04x:%04x\n",lpDosTask->init_cs,lpDosTask->init_ip); - return 32; + return lpDosTask->hModule; } LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule ) @@ -355,7 +355,10 @@ int MZ_InitTask( LPDOSTASK lpDosTask ) ERR(module,"Failed to spawn dosmod, error=%s\n",strerror(errno)); exit(1); } - return 32; + /* start simulated system 55Hz timer */ + lpDosTask->system_timer = CreateSystemTimer( 55, (FARPROC16)MZ_Tick ); + TRACE(module,"created 55Hz timer tick, handle=%d\n",lpDosTask->system_timer); + return lpDosTask->hModule; } HINSTANCE16 MZ_CreateProcess( LPCSTR name, LPCSTR cmdline, LPCSTR env, @@ -421,6 +424,8 @@ HINSTANCE16 MZ_CreateProcess( LPCSTR name, LPCSTR cmdline, LPCSTR env, void MZ_KillModule( LPDOSTASK lpDosTask ) { + TRACE(module,"killing DOS task\n"); + SYSTEM_KillSystemTimer(lpDosTask->system_timer); if (lpDosTask->mm_name[0]!=0) { munmap(lpDosTask->img,0x110000-START_OFFSET); close(lpDosTask->mm_fd); diff --git a/misc/system.c b/misc/system.c index 22a5dded6c0..b9588fc55ec 100644 --- a/misc/system.c +++ b/misc/system.c @@ -15,6 +15,8 @@ #include "callback.h" #include "windows.h" #include "miscemu.h" +#include "dosexe.h" +#include "vga.h" #include "selectors.h" #include "sig_context.h" #include "debug.h" @@ -56,6 +58,12 @@ static HANDLER_DEF(SYSTEM_TimerTick) if (SYS_Timers[i].callback == (FARPROC16)DOSMEM_Tick) { DOSMEM_Tick(); + } else + if (SYS_Timers[i].callback == (FARPROC16)MZ_Tick) { + MZ_Tick(i+1); + } else + if (SYS_Timers[i].callback == (FARPROC16)VGA_Poll) { + VGA_Poll(); } else Callbacks->CallSystemTimerProc( SYS_Timers[i].callback ); } @@ -143,9 +151,11 @@ WORD WINAPI CreateSystemTimer( WORD rate, FARPROC16 callback ) int i; /* FIXME: HACK: do not create system timers due to problems mentioned - * above, except DOSMEM_Tick(). + * above, except DOSMEM_Tick(), MZ_Tick(), and VGA_Poll(). */ - if (callback!=(FARPROC16)DOSMEM_Tick) { + if ((callback!=(FARPROC16)DOSMEM_Tick)&& + (callback!=(FARPROC16)MZ_Tick)&& + (callback!=(FARPROC16)VGA_Poll)) { FIXME(system,"are currently broken, returning 0.\n"); return 0; } diff --git a/miscemu/instr.c b/miscemu/instr.c index 8d57e3722e9..b9acd30ae84 100644 --- a/miscemu/instr.c +++ b/miscemu/instr.c @@ -8,20 +8,30 @@ #include "ldt.h" #include "global.h" #include "module.h" +#include "dosexe.h" #include "miscemu.h" #include "sig_context.h" #include "debug.h" +#define IS_V86(context) (EFL_sig(context)&V86_FLAG) +#define IS_SEL_32(context,seg) \ + (IS_V86(context) ? FALSE : IS_SELECTOR_32BIT(seg)) + #define STACK_sig(context) \ - (IS_SELECTOR_32BIT(SS_sig(context)) ? ESP_sig(context) : SP_sig(context)) + (IS_SEL_32(context,SS_sig(context)) ? ESP_sig(context) : SP_sig(context)) #define MAKE_PTR(seg,off) \ (IS_SELECTOR_SYSTEM(seg) ? (void *)(off) : PTR_SEG_OFF_TO_LIN(seg,off)) +#define MK_PTR(context,seg,off) \ + (IS_V86(context) ? DOSMEM_MapRealToLinear(MAKELONG(off,seg)) \ + : MAKE_PTR(seg,off)) + #define STACK_PTR(context) \ - (IS_SELECTOR_SYSTEM(SS_sig(context)) ? (void *)ESP_sig(context) : \ - (PTR_SEG_OFF_TO_LIN(SS_sig(context),STACK_sig(context)))) + (IS_V86(context) ? DOSMEM_MapRealToLinear(MAKELONG(SP_sig(context),SS_sig(context))) : \ + (IS_SELECTOR_SYSTEM(SS_sig(context)) ? (void *)ESP_sig(context) : \ + (PTR_SEG_OFF_TO_LIN(SS_sig(context),STACK_sig(context))))) /*********************************************************************** @@ -306,8 +316,8 @@ BOOL32 INSTR_EmulateInstruction( SIGCONTEXT *context ) && VIRTUAL_HandleFault( (LPVOID)CR2_sig(context) )) return TRUE; #endif - long_op = long_addr = IS_SELECTOR_32BIT(CS_sig(context)); - instr = (BYTE *)MAKE_PTR(CS_sig(context),EIP_sig(context)); + long_op = long_addr = IS_SEL_32(context,CS_sig(context)); + instr = (BYTE *)MK_PTR(context,CS_sig(context),EIP_sig(context)); if (!instr) return FALSE; /* First handle any possible prefix */