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 (!pModule
->lpDosTask
) {
196 /* no VM86 (dosmod) task is currently running, start one */
197 if ((lpDosTask
= calloc(1, sizeof(DOSTASK
))) == NULL
)
199 lpDosTask
->hModule
=pModule
->self
;
200 stat
=MZ_InitMemory(lpDosTask
,pModule
);
201 if (stat
>=32) stat
=MZ_InitTask(lpDosTask
);
206 pModule
->lpDosTask
= lpDosTask
;
207 pModule
->dos_image
= lpDosTask
->img
;
208 /* Note: we're leaving it running after this, in case we need it again,
209 as this minimizes the overhead of starting it up every time...
210 it will be killed automatically when the current task terminates */
211 } else lpDosTask
=pModule
->lpDosTask
;
214 #define CP(x,y) VM86.regs.x = y##_reg(context)
219 memset(&VM86
,0,sizeof(VM86
));
220 VM86
.regs
.cs
=lpDosTask
->init_cs
;
221 VM86
.regs
.eip
=lpDosTask
->init_ip
;
222 VM86
.regs
.ss
=lpDosTask
->init_ss
;
223 VM86
.regs
.esp
=lpDosTask
->init_sp
;
224 VM86
.regs
.ds
=lpDosTask
->psp_seg
;
225 VM86
.regs
.es
=lpDosTask
->psp_seg
;
226 /* hmm, what else do we need? */
229 /* main exchange loop */
233 /* transmit VM86 structure to dosmod task */
234 if (write(lpDosTask
->write_pipe
,&stat
,sizeof(stat
))!=sizeof(stat
)) {
235 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
238 if (write(lpDosTask
->write_pipe
,&VM86
,sizeof(VM86
))!=sizeof(VM86
)) {
239 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
242 /* wait for response, with async events enabled */
245 SIGNAL_MaskAsyncEvents(FALSE
);
247 FD_SET(lpDosTask
->read_pipe
,&readfds
);
248 FD_SET(lpDosTask
->read_pipe
,&exceptfds
);
249 select(lpDosTask
->read_pipe
+1,&readfds
,NULL
,&exceptfds
,NULL
);
250 } while (!(FD_ISSET(lpDosTask
->read_pipe
,&readfds
)||
251 FD_ISSET(lpDosTask
->read_pipe
,&exceptfds
)));
252 SIGNAL_MaskAsyncEvents(TRUE
);
253 /* read response (with async events disabled to avoid some strange problems) */
255 if ((len
=read(lpDosTask
->read_pipe
,&stat
,sizeof(stat
)))!=sizeof(stat
)) {
256 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
257 WARN(module
,"rereading dosmod return code due to errno=%d, result=%d\n",errno
,len
);
260 ERR(module
,"dosmod sync lost reading return code, errno=%d, result=%d\n",errno
,len
);
264 TRACE(module
,"dosmod return code=%d\n",stat
);
266 if ((len
=read(lpDosTask
->read_pipe
,&VM86
,sizeof(VM86
)))!=sizeof(VM86
)) {
267 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
268 WARN(module
,"rereading dosmod VM86 structure due to errno=%d, result=%d\n",errno
,len
);
271 ERR(module
,"dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno
,len
);
275 if ((stat
&0xff)==DOSMOD_SIGNAL
) {
277 if ((len
=read(lpDosTask
->read_pipe
,&sig
,sizeof(sig
)))!=sizeof(sig
)) {
278 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
279 WARN(module
,"rereading dosmod signal due to errno=%d, result=%d\n",errno
,len
);
282 ERR(module
,"dosmod sync lost reading signal, errno=%d, result=%d\n",errno
,len
);
288 } while (DOSVM_Process(lpDosTask
,stat
,sig
,&VM86
)>=0);
291 #define CP(x,y) y##_reg(context) = VM86.regs.x
298 void MZ_Tick( WORD handle
)
300 /* find the DOS task that has the right system_timer handle... */
301 /* should usually be the current, so let's just be lazy... */
302 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
303 NE_MODULE
*pModule
= pTask
? NE_GetPtr( pTask
->hModule
) : NULL
;
304 LPDOSTASK lpDosTask
= pModule
? pModule
->lpDosTask
: NULL
;
306 GlobalUnlock16( GetCurrentTask() );
307 if (lpDosTask
&&(lpDosTask
->system_timer
==handle
)) {
308 /* BIOS timer tick */
309 (*((DWORD
*)(((BYTE
*)(lpDosTask
->img
))+0x46c)))++;
313 #else /* !MZ_SUPPORTED */
315 int DOSVM_Enter( PCONTEXT context
)
317 ERR(module
,"DOS realmode not supported on this architecture!\n");
321 void MZ_Tick( WORD handle
) {}