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.
This commit is contained in:
parent
1e319975d7
commit
7f740cbb04
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <sys/types.h>
|
||||
#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 );
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue