4 * Copyright 1998 Ove Kåven
6 * This code hasn't been completely cleaned up yet.
17 #include <sys/types.h>
22 #include "sig_context.h"
33 void (*ctx_debug_call
)(int sig
,CONTEXT
*ctx
)=NULL
;
34 BOOL32 (*instr_emu_call
)(SIGCONTEXT
*ctx
)=NULL
;
41 static void DOSVM_Dump( LPDOSTASK lpDosTask
, int fn
, int sig
,
42 struct vm86plus_struct
*VM86
)
48 switch (VM86_TYPE(fn
)) {
50 printf("Trapped signal %d\n",sig
); break;
52 printf("Trapped unhandled GPF\n"); break;
54 printf("Trapped INT %02x\n",VM86_ARG(fn
)); break;
56 printf("Trapped STI\n"); break;
58 printf("Trapped due to pending PIC request\n"); break;
60 printf("Trapped debug request\n"); break;
62 printf("Trapped unknown VM86 type %d arg %d\n",VM86_TYPE(fn
),VM86_ARG(fn
)); break;
64 #define REGS VM86->regs
65 fprintf(stderr
,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS
.eax
,REGS
.ecx
,REGS
.edx
,REGS
.ebx
);
66 fprintf(stderr
,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS
.esi
,REGS
.edi
,REGS
.esp
,REGS
.ebp
);
67 fprintf(stderr
,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS
.cs
,REGS
.ds
,REGS
.es
,REGS
.ss
);
68 fprintf(stderr
,"IP=%04lX EFLAGS=%08lX\n",REGS
.eip
,REGS
.eflags
);
70 iofs
=((DWORD
)REGS
.cs
<<4)+REGS
.eip
;
72 inst
=(BYTE
*)lpDosTask
->img
+iofs
;
74 for (x
=0; x
<8; x
++) printf(" %02x",inst
[x
]);
78 static int DOSVM_Int( int vect
, PCONTEXT context
, LPDOSTASK lpDosTask
)
80 extern UINT16 DPMI_wrap_seg
;
83 if (CS_reg(context
)==DPMI_wrap_seg
) {
84 /* exit from real-mode wrapper */
87 /* we could probably move some other dodgy stuff here too from dpmi.c */
89 INT_RealModeInterrupt(vect
,context
);
93 static void DOSVM_SimulateInt( int vect
, PCONTEXT context
, LPDOSTASK lpDosTask
)
95 FARPROC16 handler
=INT_GetRMHandler(vect
);
96 WORD
*stack
=(WORD
*)(V86BASE(context
)+(((DWORD
)SS_reg(context
))<<4)+SP_reg(context
));
98 *(--stack
)=FL_reg(context
);
99 *(--stack
)=CS_reg(context
);
100 *(--stack
)=IP_reg(context
);
102 CS_reg(context
)=SELECTOROF(handler
);
103 IP_reg(context
)=OFFSETOF(handler
);
106 #define CV CP(eax,EAX); CP(ecx,ECX); CP(edx,EDX); CP(ebx,EBX); \
107 CP(esi,ESI); CP(edi,EDI); CP(esp,ESP); CP(ebp,EBP); \
108 CP(cs,CS); CP(ds,DS); CP(es,ES); \
109 CP(ss,SS); CP(fs,FS); CP(gs,GS); \
110 CP(eip,EIP); CP(eflags,EFL)
112 static int DOSVM_Process( LPDOSTASK lpDosTask
, int fn
, int sig
,
113 struct vm86plus_struct
*VM86
)
115 SIGCONTEXT sigcontext
;
119 if (VM86_TYPE(fn
)==VM86_UNKNOWN
) {
120 /* INSTR_EmulateInstruction needs a SIGCONTEXT, not a CONTEXT... */
121 #define CP(x,y) y##_sig(&sigcontext) = VM86->regs.x
124 if (instr_emu_call
) ret
=instr_emu_call(&sigcontext
);
125 #define CP(x,y) VM86->regs.x = y##_sig(&sigcontext)
131 #define CP(x,y) y##_reg(&context) = VM86->regs.x
134 (void*)V86BASE(&context
)=lpDosTask
->img
;
136 switch (VM86_TYPE(fn
)) {
138 TRACE(int,"DOS module caught signal %d\n",sig
);
140 DOSVM_SimulateInt(8,&context
,lpDosTask
);
143 if (ctx_debug_call
) ctx_debug_call(SIGTRAP
,&context
);
145 if ((sig
==SIGILL
)||(sig
==SIGSEGV
)) {
146 if (ctx_debug_call
) ctx_debug_call(SIGILL
,&context
);
148 DOSVM_Dump(lpDosTask
,fn
,sig
,VM86
);
152 case VM86_UNKNOWN
: /* unhandled GPF */
153 DOSVM_Dump(lpDosTask
,fn
,sig
,VM86
);
154 if (ctx_debug_call
) ctx_debug_call(SIGSEGV
,&context
); else ret
=-1;
158 DPRINTF("Call DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn
),context
.Eax
,context
.SegCs
,context
.Eip
);
159 ret
=DOSVM_Int(VM86_ARG(fn
),&context
,lpDosTask
);
161 DPRINTF("Ret DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn
),context
.Eax
,context
.SegCs
,context
.Eip
);
166 printf("Trapped due to pending PIC request\n"); break;
168 if (ctx_debug_call
) ctx_debug_call(SIGTRAP
,&context
);
171 DOSVM_Dump(lpDosTask
,fn
,sig
,VM86
);
175 #define CP(x,y) VM86->regs.x = y##_reg(&context)
181 int DOSVM_Enter( PCONTEXT context
)
183 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
184 NE_MODULE
*pModule
= NE_GetPtr( pTask
->hModule
);
186 struct vm86plus_struct VM86
;
188 fd_set readfds
,exceptfds
;
190 GlobalUnlock16( GetCurrentTask() );
192 ERR(module
,"No task is currently active!\n");
195 if (!(lpDosTask
=pModule
->lpDosTask
)) {
196 /* MZ_CreateProcess or MZ_AllocDPMITask should have been called first */
197 ERR(module
,"dosmod has not been initialized!");
202 #define CP(x,y) VM86.regs.x = y##_reg(context)
207 /* allocate standard DOS handles */
208 FILE_InitProcessDosHandles();
210 memset(&VM86
,0,sizeof(VM86
));
211 VM86
.regs
.cs
=lpDosTask
->init_cs
;
212 VM86
.regs
.eip
=lpDosTask
->init_ip
;
213 VM86
.regs
.ss
=lpDosTask
->init_ss
;
214 VM86
.regs
.esp
=lpDosTask
->init_sp
;
215 VM86
.regs
.ds
=lpDosTask
->psp_seg
;
216 VM86
.regs
.es
=lpDosTask
->psp_seg
;
217 /* hmm, what else do we need? */
220 /* main exchange loop */
224 /* transmit VM86 structure to dosmod task */
225 if (write(lpDosTask
->write_pipe
,&stat
,sizeof(stat
))!=sizeof(stat
)) {
226 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
229 if (write(lpDosTask
->write_pipe
,&VM86
,sizeof(VM86
))!=sizeof(VM86
)) {
230 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
233 /* wait for response, with async events enabled */
236 SIGNAL_MaskAsyncEvents(FALSE
);
238 FD_SET(lpDosTask
->read_pipe
,&readfds
);
239 FD_SET(lpDosTask
->read_pipe
,&exceptfds
);
240 select(lpDosTask
->read_pipe
+1,&readfds
,NULL
,&exceptfds
,NULL
);
241 } while (!(FD_ISSET(lpDosTask
->read_pipe
,&readfds
)||
242 FD_ISSET(lpDosTask
->read_pipe
,&exceptfds
)));
243 SIGNAL_MaskAsyncEvents(TRUE
);
244 /* read response (with async events disabled to avoid some strange problems) */
246 if ((len
=read(lpDosTask
->read_pipe
,&stat
,sizeof(stat
)))!=sizeof(stat
)) {
247 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
248 WARN(module
,"rereading dosmod return code due to errno=%d, result=%d\n",errno
,len
);
251 ERR(module
,"dosmod sync lost reading return code, errno=%d, result=%d\n",errno
,len
);
255 TRACE(module
,"dosmod return code=%d\n",stat
);
257 if ((len
=read(lpDosTask
->read_pipe
,&VM86
,sizeof(VM86
)))!=sizeof(VM86
)) {
258 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
259 WARN(module
,"rereading dosmod VM86 structure due to errno=%d, result=%d\n",errno
,len
);
262 ERR(module
,"dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno
,len
);
266 if ((stat
&0xff)==DOSMOD_SIGNAL
) {
268 if ((len
=read(lpDosTask
->read_pipe
,&sig
,sizeof(sig
)))!=sizeof(sig
)) {
269 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
270 WARN(module
,"rereading dosmod signal due to errno=%d, result=%d\n",errno
,len
);
273 ERR(module
,"dosmod sync lost reading signal, errno=%d, result=%d\n",errno
,len
);
279 } while (DOSVM_Process(lpDosTask
,stat
,sig
,&VM86
)>=0);
282 #define CP(x,y) y##_reg(context) = VM86.regs.x
289 void DOSVM_SetTimer( unsigned ticks
)
291 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
292 NE_MODULE
*pModule
= NE_GetPtr( pTask
->hModule
);
293 int stat
=DOSMOD_SET_TIMER
;
296 GlobalUnlock16( GetCurrentTask() );
297 if (pModule
&&pModule
->lpDosTask
) {
298 /* the PC clocks ticks at 1193180 Hz */
300 tim
.tv_usec
=((unsigned long long)ticks
*1000000)/1193180;
302 if (!tim
.tv_usec
) tim
.tv_usec
=1;
304 if (write(pModule
->lpDosTask
->write_pipe
,&stat
,sizeof(stat
))!=sizeof(stat
)) {
305 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
308 if (write(pModule
->lpDosTask
->write_pipe
,&tim
,sizeof(tim
))!=sizeof(tim
)) {
309 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
312 /* there's no return */
316 unsigned DOSVM_GetTimer( void )
318 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
319 NE_MODULE
*pModule
= NE_GetPtr( pTask
->hModule
);
320 int stat
=DOSMOD_GET_TIMER
;
323 GlobalUnlock16( GetCurrentTask() );
324 if (pModule
&&pModule
->lpDosTask
) {
325 if (write(pModule
->lpDosTask
->write_pipe
,&stat
,sizeof(stat
))!=sizeof(stat
)) {
326 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
330 if (read(pModule
->lpDosTask
->read_pipe
,&tim
,sizeof(tim
))!=sizeof(tim
)) {
331 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
334 return ((unsigned long long)tim
.tv_usec
*1193180)/1000000;
339 void MZ_Tick( WORD handle
)
341 /* find the DOS task that has the right system_timer handle... */
342 /* should usually be the current, so let's just be lazy... */
343 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
344 NE_MODULE
*pModule
= pTask
? NE_GetPtr( pTask
->hModule
) : NULL
;
345 LPDOSTASK lpDosTask
= pModule
? pModule
->lpDosTask
: NULL
;
347 GlobalUnlock16( GetCurrentTask() );
348 if (lpDosTask
&&(lpDosTask
->system_timer
==handle
)) {
349 /* BIOS timer tick */
350 (*((DWORD
*)(((BYTE
*)(lpDosTask
->img
))+0x46c)))++;
354 #else /* !MZ_SUPPORTED */
356 int DOSVM_Enter( PCONTEXT context
)
358 ERR(module
,"DOS realmode not supported on this architecture!\n");
362 void MZ_Tick( WORD handle
) {}
363 void DOSVM_SetTimer( unsigned ticks
) {}
364 unsigned DOSVM_GetTimer( void ) { return 0; }