Added first version of the Perl regression testing framework.
[wine/multimedia.git] / loader / dos / dosmod.c
blob8aea170bb41c242314dc59732034d1096993a6db
1 /*
2 * DOS Virtual Machine
4 * Copyright 1998 Ove Kåven
5 */
7 #if defined(linux) && defined(__i386__)
9 #include "config.h"
11 /* apparently ELF images are usually loaded high anyway */
12 #ifndef __ELF__
13 /* if not, force dosmod at high addresses */
14 asm(".org 0x110000");
15 #endif /* __ELF__ */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <sys/stat.h>
25 #ifdef HAVE_SYS_MMAN_H
26 # include <sys/mman.h>
27 #endif
28 #ifdef HAVE_SYS_VM86_H
29 # include <sys/vm86.h>
30 #endif
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #ifdef HAVE_SYS_PTRACE_H
34 # include <sys/ptrace.h>
35 #endif
36 #ifdef HAVE_SYS_WAIT_H
37 # include <sys/wait.h>
38 #endif
39 #include "dosmod.h"
41 /* FIXME: hack because libc vm86 may be the old syscall version */
43 #define SYS_vm86 166
45 static inline int vm86plus( int func, struct vm86plus_struct *ptr )
47 int res;
48 #ifdef __PIC__
49 __asm__ __volatile__( "pushl %%ebx\n\t"
50 "movl %2,%%ebx\n\t"
51 "int $0x80\n\t"
52 "popl %%ebx"
53 : "=a" (res)
54 : "0" (SYS_vm86),
55 "g" (func),
56 "c" (ptr) );
57 #else
58 __asm__ __volatile__("int $0x80"
59 : "=a" (res)
60 : "0" (SYS_vm86),
61 "b" (func),
62 "c" (ptr) );
63 #endif /* __PIC__ */
64 if (res >= 0) return res;
65 errno = -res;
66 return -1;
69 int XREAD(int fd,void*buf,int size) {
70 int res;
72 while (1) {
73 res = read(fd, buf, size);
74 if (res==size)
75 return res;
76 if (res==-1) {
77 if (errno==EINTR)
78 continue;
79 perror("dosmod read");
80 return -1;
82 if (res) /* don't print the EOF condition */
83 fprintf(stderr,"dosmod read only %d of %d bytes.\n",res,size);
84 return res;
87 int XWRITE(int fd,void*buf,int size) {
88 int res;
90 while (1) {
91 res = write(fd, buf, size);
92 if (res==size)
93 return res;
94 if (res==-1) {
95 if (errno==EINTR)
96 continue;
97 perror("dosmod write");
98 return -1;
100 fprintf(stderr,"dosmod write only %d of %d bytes.\n",res,size);
101 return res;
105 void set_timer(struct timeval*tim)
107 struct itimerval cur;
109 cur.it_interval=*tim;
110 cur.it_value=*tim;
111 setitimer(ITIMER_REAL,&cur,NULL);
114 void get_timer(struct timeval*tim)
116 struct itimerval cur;
118 getitimer(ITIMER_REAL,&cur);
119 *tim=cur.it_value;
122 volatile int sig_pend,sig_fatal=0,sig_alrm=0,sig_cb=0;
123 void*img;
124 struct vm86plus_struct VM86;
126 void sig_handler(int sig)
128 if (sig_pend) fprintf(stderr,"DOSMOD previous signal %d lost\n",sig_pend);
129 sig_pend=sig;
130 signal(sig,sig_handler);
133 void bad_handler(int sig)
135 if (sig!=SIGTERM) {
136 fprintf(stderr,"DOSMOD caught fatal signal %d\n",sig);
137 fprintf(stderr,"(Last known VM86 CS:IP was %04x:%04lx)\n",VM86.regs.cs,VM86.regs.eip);
139 sig_pend=sig; sig_fatal++;
140 signal(sig,bad_handler);
143 void alarm_handler(int sig)
145 sig_alrm++;
146 signal(sig,alarm_handler);
149 void cb_handler(int sig)
151 sig_cb++;
152 signal(sig,cb_handler);
155 int send_signal(void)
157 int ret=sig_pend; sig_pend=0;
158 if (!ret) {
159 if (sig_alrm) {
160 ret=SIGALRM; sig_alrm--;
161 } else {
162 ret=SIGUSR2; sig_cb--;
165 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
166 if (sig_fatal) return 1;
167 return 0;
170 int send_enter_reply(int ret)
172 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
173 if (XWRITE(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
174 switch (ret&0xff) {
175 case DOSMOD_SIGNAL:
176 return send_signal();
178 return 0;
181 int main(int argc,char**argv)
183 int mfd=open(argv[0],O_RDWR);
184 struct timeval tim;
185 mprot_info mpr;
186 int func,ret,idle;
187 off_t fofs=0;
188 pid_t ppid=getppid();
190 /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
191 if (mfd<0) return 1;
192 /* Map in our DOS image at the start of the process address space */
193 if (argv[1]) {
194 /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine
195 address space */
196 fofs=atol(argv[1]);
197 /* linux currently only allows mapping a process memory if it's being ptraced */
198 /* Linus doesn't like it, so this probably won't work in the future */
199 /* it doesn't even work for me right now */
200 kill(ppid,SIGSTOP);
201 ptrace(PTRACE_ATTACH,ppid,0,0);
202 waitpid(ppid,NULL,0);
204 img=mmap(NULL,0x110000,PROT_EXEC|PROT_READ|PROT_WRITE,MAP_FIXED|MAP_SHARED,mfd,fofs);
205 if (argv[1]) {
206 ptrace(PTRACE_DETACH,ppid,0,0);
207 kill(ppid,SIGCONT);
209 if (img==(void*)-1) {
210 fprintf(stderr,"DOS memory map failed, error=%s\n",strerror(errno));
211 fprintf(stderr,"in attempt to map %s, offset %08lX, length 110000, to offset 0\n",argv[0],fofs);
212 return 1;
214 /* initialize signals and system timer */
215 signal(SIGHUP,sig_handler);
216 signal(SIGINT,sig_handler);
217 signal(SIGUSR1,sig_handler);
218 signal(SIGUSR2,cb_handler);
219 signal(SIGALRM,alarm_handler);
221 signal(SIGQUIT,bad_handler);
222 signal(SIGILL,bad_handler);
223 signal(SIGBUS,bad_handler);
224 signal(SIGFPE,bad_handler);
225 signal(SIGSEGV,bad_handler);
226 signal(SIGTERM,bad_handler);
227 #if 0
228 tim.tv_sec=0; tim.tv_usec=54925;
229 set_timer(&tim);
230 #endif
231 /* report back to the main program that we're ready */
232 ret=3; /* dosmod protocol revision */
233 XWRITE(1,&ret,sizeof(ret));
234 /* context exchange loop */
235 idle=0;
236 do {
237 if (idle) {
238 while (1) {
239 int res;
240 /* parent is idle, transmit any signals (particularly SIGALRM) */
241 if (sig_pend||sig_alrm||sig_cb) {
242 ret=DOSMOD_SIGNAL;
243 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
244 ret=send_signal();
245 if (ret) return ret;
246 break;
248 res = read(0,&func,sizeof(func));
249 if (res==sizeof(func))
250 break;
251 if (res==-1) {
252 if (errno==EINTR)
253 continue;
254 perror("dosmod read");
255 return 1;
257 if (res) /* don't print the EOF condition */
258 fprintf(stderr,"dosmod read only %d of %d bytes.\n",res,sizeof(func));
259 return 1;
261 ret=DOSMOD_LEFTIDLE;
262 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
263 idle--;
264 } else
265 if (XREAD(0,&func,sizeof(func))!=sizeof(func)) return 1;
266 if (func<0) break;
267 switch (func) {
268 case DOSMOD_SET_TIMER: /* rev 1 */
269 if (XREAD(0,&tim,sizeof(tim))!=sizeof(tim)) return 1;
270 set_timer(&tim);
271 /* no response */
272 break;
273 case DOSMOD_GET_TIMER: /* rev 1 */
274 get_timer(&tim);
275 if (XWRITE(1,&tim,sizeof(tim))!=sizeof(tim)) return 1;
276 break;
277 case DOSMOD_MPROTECT: /* rev 3 */
278 if (XREAD(0,&mpr,sizeof(mpr))!=sizeof(mpr)) return 1;
279 mprotect(mpr.addr,mpr.len,mpr.prot);
280 /* no response */
281 break;
282 case DOSMOD_ENTERIDLE: /* rev 3 */
283 idle++;
284 break;
285 case DOSMOD_LEAVEIDLE: /* rev 3 */
286 break;
287 case DOSMOD_ENTER: /* rev 0 */
288 default:
289 if (XREAD(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
290 if (sig_pend||sig_alrm||sig_cb) ret=DOSMOD_SIGNAL; else
291 ret=vm86plus(func,&VM86);
293 ret=send_enter_reply(ret);
294 if (ret) return ret;
296 } while (1);
297 return 0;
300 #else /* !linux-i386 */
301 int main(void) {return 1;}
302 #endif