DirectDraw status updated.
[wine/testsucceed.git] / loader / dos / dosvm.c
blob5b11561fe567821774fec36530fa25007ccce575
1 /*
2 * DOS Virtual Machine
4 * Copyright 1998 Ove Kåven
6 * This code hasn't been completely cleaned up yet.
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <unistd.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include "windows.h"
20 #include "winbase.h"
21 #include "winnt.h"
22 #include "sig_context.h"
23 #include "msdos.h"
24 #include "miscemu.h"
25 #include "debugger.h"
26 #include "debug.h"
27 #include "module.h"
28 #include "task.h"
29 #include "ldt.h"
30 #include "dosexe.h"
32 void (*ctx_debug_call)(int sig,CONTEXT*ctx)=NULL;
33 BOOL32 (*instr_emu_call)(SIGCONTEXT*ctx)=NULL;
35 #ifdef MZ_SUPPORTED
37 #include <sys/mman.h>
38 #include <sys/vm86.h>
40 static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn,
41 struct vm86plus_struct*VM86 )
43 unsigned iofs;
44 BYTE*inst;
45 int x;
47 switch (VM86_TYPE(fn)) {
48 case VM86_SIGNAL:
49 printf("Trapped signal\n"); break;
50 case VM86_UNKNOWN:
51 printf("Trapped unhandled GPF\n"); break;
52 case VM86_INTx:
53 printf("Trapped INT %02x\n",VM86_ARG(fn)); break;
54 case VM86_STI:
55 printf("Trapped STI\n"); break;
56 case VM86_PICRETURN:
57 printf("Trapped due to pending PIC request\n"); break;
58 case VM86_TRAP:
59 printf("Trapped debug request\n"); break;
60 default:
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;
70 #undef REGS
71 inst=(BYTE*)lpDosTask->img+iofs;
72 printf("Opcodes:");
73 for (x=0; x<8; x++) printf(" %02x",inst[x]);
74 printf("\n");
77 static int DOSVM_Int( int vect, PCONTEXT context, LPDOSTASK lpDosTask )
79 if (vect==0x31) {
80 if (CS_reg(context)==lpDosTask->dpmi_sel) {
81 if (IP_reg(context)>=lpDosTask->wrap_ofs) {
82 /* exit from real-mode wrapper */
83 return -1;
86 /* we could probably move some other dodgy stuff here too from dpmi.c */
88 INT_RealModeInterrupt(vect,context);
89 return 0;
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;
102 CONTEXT context;
103 int ret=0;
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
109 #undef CP
110 if (instr_emu_call) ret=instr_emu_call(&sigcontext);
111 #define CP(x,y) VM86->regs.x = y##_sig(&sigcontext)
113 #undef CP
114 if (ret) return 0;
115 ret=0;
117 #define CP(x,y) y##_reg(&context) = VM86->regs.x
119 #undef CP
120 (void*)V86BASE(&context)=lpDosTask->img;
122 switch (VM86_TYPE(fn)) {
123 case VM86_SIGNAL:
124 DOSVM_Dump(lpDosTask,fn,VM86);
125 ret=-1; break;
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;
129 break;
130 case VM86_INTx:
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;
133 case VM86_STI:
134 break;
135 case VM86_PICRETURN:
136 printf("Trapped due to pending PIC request\n"); break;
137 case VM86_TRAP:
138 if (ctx_debug_call) ctx_debug_call(SIGTRAP,&context);
139 break;
140 default:
141 DOSVM_Dump(lpDosTask,fn,VM86);
142 ret=-1;
145 #define CP(x,y) VM86->regs.x = y##_reg(&context)
147 #undef CP
148 return ret;
151 int DOSVM_Enter( PCONTEXT context )
153 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
154 NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
155 LPDOSTASK lpDosTask;
156 struct vm86plus_struct VM86;
157 int stat,len;
158 fd_set readfds,exceptfds;
160 GlobalUnlock16( GetCurrentTask() );
161 if (!pModule) {
162 ERR(module,"No task is currently active!\n");
163 return -1;
165 if (!pModule->lpDosTask) {
166 /* no VM86 (dosmod) task is currently running, start one */
167 if ((lpDosTask = calloc(1, sizeof(DOSTASK))) == NULL)
168 return 0;
169 lpDosTask->hModule=pModule->self;
170 stat=MZ_InitMemory(lpDosTask,pModule);
171 if (stat>=32) stat=MZ_InitTask(lpDosTask);
172 if (stat<32) {
173 free(lpDosTask);
174 return -1;
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;
183 if (context) {
184 #define CP(x,y) VM86.regs.x = y##_reg(context)
186 #undef CP
187 } else {
188 /* initial setup */
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 */
200 do {
201 stat = VM86_ENTER;
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);
205 return -1;
207 if (write(lpDosTask->write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) {
208 ERR(module,"dosmod sync lost, errno=%d\n",errno);
209 return -1;
211 /* wait for response, with async events enabled */
212 FD_ZERO(&readfds);
213 FD_ZERO(&exceptfds);
214 SIGNAL_MaskAsyncEvents(FALSE);
215 do {
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) */
223 do {
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);
227 continue;
229 ERR(module,"dosmod sync lost reading return code, errno=%d, result=%d\n",errno,len);
230 return -1;
232 } while (0);
233 TRACE(module,"dosmod return code=%d\n",stat);
234 do {
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);
238 continue;
240 ERR(module,"dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno,len);
241 return -1;
243 } while (0);
244 /* got response */
245 } while (DOSVM_Process(lpDosTask,stat,&VM86)>=0);
247 if (context) {
248 #define CP(x,y) y##_reg(context) = VM86.regs.x
250 #undef CP
252 return 0;
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");
275 return -1;
278 void MZ_Tick( WORD handle ) {}
280 #endif