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"
32 void (*ctx_debug_call
)(int sig
,CONTEXT
*ctx
)=NULL
;
33 BOOL32 (*instr_emu_call
)(SIGCONTEXT
*ctx
)=NULL
;
40 static void DOSVM_Dump( LPDOSTASK lpDosTask
, int fn
,
41 struct vm86plus_struct
*VM86
)
47 switch (VM86_TYPE(fn
)) {
49 printf("Trapped signal\n"); break;
51 printf("Trapped unhandled GPF\n"); break;
53 printf("Trapped INT %02x\n",VM86_ARG(fn
)); break;
55 printf("Trapped STI\n"); break;
57 printf("Trapped due to pending PIC request\n"); break;
59 printf("Trapped debug request\n"); break;
61 printf("Trapped unknown VM86 type %d arg %d\n",VM86_TYPE(fn
),VM86_ARG(fn
)); break;
63 #define REGS VM86->regs
64 fprintf(stderr
,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS
.eax
,REGS
.ecx
,REGS
.edx
,REGS
.ebx
);
65 fprintf(stderr
,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS
.esi
,REGS
.edi
,REGS
.esp
,REGS
.ebp
);
66 fprintf(stderr
,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS
.cs
,REGS
.ds
,REGS
.es
,REGS
.ss
);
67 fprintf(stderr
,"IP=%04lX EFLAGS=%08lX\n",REGS
.eip
,REGS
.eflags
);
69 iofs
=((DWORD
)REGS
.cs
<<4)+REGS
.eip
;
71 inst
=(BYTE
*)lpDosTask
->img
+iofs
;
73 for (x
=0; x
<8; x
++) printf(" %02x",inst
[x
]);
77 static int DOSVM_Int( int vect
, PCONTEXT context
, LPDOSTASK lpDosTask
)
80 if (CS_reg(context
)==lpDosTask
->dpmi_sel
) {
81 if (IP_reg(context
)>=lpDosTask
->wrap_ofs
) {
82 /* exit from real-mode wrapper */
86 /* we could probably move some other dodgy stuff here too from dpmi.c */
88 INT_RealModeInterrupt(vect
,context
);
92 #define CV CP(eax,EAX); CP(ecx,ECX); CP(edx,EDX); CP(ebx,EBX); \
93 CP(esi,ESI); CP(edi,EDI); CP(esp,ESP); CP(ebp,EBP); \
94 CP(cs,CS); CP(ds,DS); CP(es,ES); \
95 CP(ss,SS); CP(fs,FS); CP(gs,GS); \
96 CP(eip,EIP); CP(eflags,EFL)
98 static int DOSVM_Process( LPDOSTASK lpDosTask
, int fn
,
99 struct vm86plus_struct
*VM86
)
101 SIGCONTEXT sigcontext
;
105 if (VM86_TYPE(fn
)==VM86_UNKNOWN
) {
106 /* INSTR_EmulateInstruction needs a SIGCONTEXT, not a CONTEXT... */
107 #define CP(x,y) y##_sig(&sigcontext) = VM86->regs.x
110 if (instr_emu_call
) ret
=instr_emu_call(&sigcontext
);
111 #define CP(x,y) VM86->regs.x = y##_sig(&sigcontext)
117 #define CP(x,y) y##_reg(&context) = VM86->regs.x
120 (void*)V86BASE(&context
)=lpDosTask
->img
;
122 switch (VM86_TYPE(fn
)) {
124 DOSVM_Dump(lpDosTask
,fn
,VM86
);
126 case VM86_UNKNOWN
: /* unhandled GPF */
127 DOSVM_Dump(lpDosTask
,fn
,VM86
);
128 if (ctx_debug_call
) ctx_debug_call(SIGSEGV
,&context
); else ret
=-1;
131 TRACE(int,"DOS EXE calls INT %02x with AX=%04lx\n",VM86_ARG(fn
),context
.Eax
);
132 ret
=DOSVM_Int(VM86_ARG(fn
),&context
,lpDosTask
); break;
136 printf("Trapped due to pending PIC request\n"); break;
138 if (ctx_debug_call
) ctx_debug_call(SIGTRAP
,&context
);
141 DOSVM_Dump(lpDosTask
,fn
,VM86
);
145 #define CP(x,y) VM86->regs.x = y##_reg(&context)
151 int DOSVM_Enter( PCONTEXT context
)
153 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
154 NE_MODULE
*pModule
= NE_GetPtr( pTask
->hModule
);
156 struct vm86plus_struct VM86
;
158 fd_set readfds
,exceptfds
;
160 GlobalUnlock16( GetCurrentTask() );
162 ERR(module
,"No task is currently active!\n");
165 if (!pModule
->lpDosTask
) {
166 /* no VM86 (dosmod) task is currently running, start one */
167 if ((lpDosTask
= calloc(1, sizeof(DOSTASK
))) == NULL
)
169 lpDosTask
->hModule
=pModule
->self
;
170 stat
=MZ_InitMemory(lpDosTask
,pModule
);
171 if (stat
>=32) stat
=MZ_InitTask(lpDosTask
);
176 pModule
->lpDosTask
= lpDosTask
;
177 pModule
->dos_image
= lpDosTask
->img
;
178 /* Note: we're leaving it running after this, in case we need it again,
179 as this minimizes the overhead of starting it up every time...
180 it will be killed automatically when the current task terminates */
181 } else lpDosTask
=pModule
->lpDosTask
;
184 #define CP(x,y) VM86.regs.x = y##_reg(context)
189 memset(&VM86
,0,sizeof(VM86
));
190 VM86
.regs
.cs
=lpDosTask
->init_cs
;
191 VM86
.regs
.eip
=lpDosTask
->init_ip
;
192 VM86
.regs
.ss
=lpDosTask
->init_ss
;
193 VM86
.regs
.esp
=lpDosTask
->init_sp
;
194 VM86
.regs
.ds
=lpDosTask
->psp_seg
;
195 VM86
.regs
.es
=lpDosTask
->psp_seg
;
196 /* hmm, what else do we need? */
199 /* main exchange loop */
202 /* transmit VM86 structure to dosmod task */
203 if (write(lpDosTask
->write_pipe
,&stat
,sizeof(stat
))!=sizeof(stat
)) {
204 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
207 if (write(lpDosTask
->write_pipe
,&VM86
,sizeof(VM86
))!=sizeof(VM86
)) {
208 ERR(module
,"dosmod sync lost, errno=%d\n",errno
);
211 /* wait for response, with async events enabled */
214 SIGNAL_MaskAsyncEvents(FALSE
);
216 FD_SET(lpDosTask
->read_pipe
,&readfds
);
217 FD_SET(lpDosTask
->read_pipe
,&exceptfds
);
218 select(lpDosTask
->read_pipe
+1,&readfds
,NULL
,&exceptfds
,NULL
);
219 } while (!(FD_ISSET(lpDosTask
->read_pipe
,&readfds
)||
220 FD_ISSET(lpDosTask
->read_pipe
,&exceptfds
)));
221 SIGNAL_MaskAsyncEvents(TRUE
);
222 /* read response (with async events disabled to avoid some strange problems) */
224 if ((len
=read(lpDosTask
->read_pipe
,&stat
,sizeof(stat
)))!=sizeof(stat
)) {
225 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
226 WARN(module
,"rereading dosmod return code due to errno=%d, result=%d\n",errno
,len
);
229 ERR(module
,"dosmod sync lost reading return code, errno=%d, result=%d\n",errno
,len
);
233 TRACE(module
,"dosmod return code=%d\n",stat
);
235 if ((len
=read(lpDosTask
->read_pipe
,&VM86
,sizeof(VM86
)))!=sizeof(VM86
)) {
236 if (((errno
==EINTR
)||(errno
==EAGAIN
))&&(len
<=0)) {
237 WARN(module
,"rereading dosmod VM86 structure due to errno=%d, result=%d\n",errno
,len
);
240 ERR(module
,"dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno
,len
);
245 } while (DOSVM_Process(lpDosTask
,stat
,&VM86
)>=0);
248 #define CP(x,y) y##_reg(context) = VM86.regs.x
255 void MZ_Tick( WORD handle
)
257 /* find the DOS task that has the right system_timer handle... */
258 /* should usually be the current, so let's just be lazy... */
259 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
260 NE_MODULE
*pModule
= pTask
? NE_GetPtr( pTask
->hModule
) : NULL
;
261 LPDOSTASK lpDosTask
= pModule
? pModule
->lpDosTask
: NULL
;
263 GlobalUnlock16( GetCurrentTask() );
264 if (lpDosTask
&&(lpDosTask
->system_timer
==handle
)) {
265 /* BIOS timer tick */
266 (*((DWORD
*)(((BYTE
*)(lpDosTask
->img
))+0x46c)))++;
270 #else /* !MZ_SUPPORTED */
272 int DOSVM_Enter( PCONTEXT context
)
274 ERR(module
,"DOS realmode not supported on this architecture!\n");
278 void MZ_Tick( WORD handle
) {}