Added handling of SIGUSR2 for the new event interruption handling,
[wine/dcerpc.git] / loader / dos / dosmod.c
blob2f2c683766d8103709abc59551bd463ada27b7c2
1 /*
2 * DOS Virtual Machine
4 * Copyright 1998 Ove Kåven
5 */
7 #if defined(linux) && defined(__i386__)
9 /* apparently ELF images are usually loaded high anyway */
10 #ifndef __ELF__
11 /* if not, force dosmod at high addresses */
12 asm(".org 0x110000");
13 #endif __ELF__
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <signal.h>
22 #include <sys/stat.h>
23 #include <sys/mman.h>
24 #include <sys/vm86.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/ptrace.h>
28 #include <sys/wait.h>
29 #include "dosmod.h"
31 /* FIXME: hack because libc vm86 may be the old syscall version */
33 #define SYS_vm86 166
35 static __inline__ int vm86plus( int func, struct vm86plus_struct *ptr )
37 int res;
38 #ifdef __PIC__
39 __asm__ __volatile__( "pushl %%ebx\n\t"
40 "movl %2,%%ebx\n\t"
41 "int $0x80\n\t"
42 "popl %%ebx"
43 : "=a" (res)
44 : "0" (SYS_vm86),
45 "g" (func),
46 "c" (ptr) );
47 #else
48 __asm__ __volatile__("int $0x80"
49 : "=a" (res)
50 : "0" (SYS_vm86),
51 "b" (func),
52 "c" (ptr) );
53 #endif /* __PIC__ */
54 if (res >= 0) return res;
55 errno = -res;
56 return -1;
59 int XREAD(int fd,void*buf,int size) {
60 int res;
62 while (1) {
63 res = read(fd, buf, size);
64 if (res==size)
65 return res;
66 if (res==-1) {
67 if (errno==EINTR)
68 continue;
69 perror("dosmod read");
70 return -1;
72 if (res) /* don't print the EOF condition */
73 fprintf(stderr,"dosmod read only %d of %d bytes.\n",res,size);
74 return res;
77 int XWRITE(int fd,void*buf,int size) {
78 int res;
80 while (1) {
81 res = write(fd, buf, size);
82 if (res==size)
83 return res;
84 if (res==-1) {
85 if (errno==EINTR)
86 continue;
87 perror("dosmod write");
88 return -1;
90 fprintf(stderr,"dosmod write only %d of %d bytes.\n",res,size);
91 return res;
95 void set_timer(struct timeval*tim)
97 struct itimerval cur;
99 cur.it_interval=*tim;
100 cur.it_value=*tim;
101 setitimer(ITIMER_REAL,&cur,NULL);
104 void get_timer(struct timeval*tim)
106 struct itimerval cur;
108 getitimer(ITIMER_REAL,&cur);
109 *tim=cur.it_value;
112 volatile int sig_pend,sig_fatal=0,sig_alrm=0,sig_cb=0;
113 void*img;
114 struct vm86plus_struct VM86;
116 void sig_handler(int sig)
118 if (sig_pend) fprintf(stderr,"DOSMOD previous signal %d lost\n",sig_pend);
119 sig_pend=sig;
120 signal(sig,sig_handler);
123 void bad_handler(int sig)
125 if (sig!=SIGTERM) {
126 fprintf(stderr,"DOSMOD caught fatal signal %d\n",sig);
127 fprintf(stderr,"(Last known VM86 CS:IP was %04x:%04lx)\n",VM86.regs.cs,VM86.regs.eip);
129 sig_pend=sig; sig_fatal++;
130 signal(sig,bad_handler);
133 void alarm_handler(int sig)
135 sig_alrm++;
136 signal(sig,alarm_handler);
139 void cb_handler(int sig)
141 sig_cb++;
142 signal(sig,cb_handler);
145 int main(int argc,char**argv)
147 int mfd=open(argv[0],O_RDWR);
148 struct timeval tim;
149 int func,ret;
150 off_t fofs=0;
151 pid_t ppid=getppid();
153 /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
154 if (mfd<0) return 1;
155 /* Map in our DOS image at the start of the process address space */
156 if (argv[1]) {
157 /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine
158 address space */
159 fofs=atol(argv[1]);
160 /* linux currently only allows mapping a process memory if it's being ptraced */
161 /* Linus doesn't like it, so this probably won't work in the future */
162 /* it doesn't even work for me right now */
163 kill(ppid,SIGSTOP);
164 ptrace(PTRACE_ATTACH,ppid,0,0);
165 waitpid(ppid,NULL,0);
167 img=mmap(NULL,0x110000,PROT_EXEC|PROT_READ|PROT_WRITE,MAP_FIXED|MAP_SHARED,mfd,fofs);
168 if (argv[1]) {
169 ptrace(PTRACE_DETACH,ppid,0,0);
170 kill(ppid,SIGCONT);
172 if (img==(void*)-1) {
173 fprintf(stderr,"DOS memory map failed, error=%s\n",strerror(errno));
174 fprintf(stderr,"in attempt to map %s, offset %08lX, length 110000, to offset 0\n",argv[0],fofs);
175 return 1;
177 /* initialize signals and system timer */
178 signal(SIGHUP,sig_handler);
179 signal(SIGINT,sig_handler);
180 signal(SIGUSR1,sig_handler);
181 signal(SIGUSR2,cb_handler);
182 signal(SIGALRM,alarm_handler);
184 signal(SIGQUIT,bad_handler);
185 signal(SIGILL,bad_handler);
186 signal(SIGBUS,bad_handler);
187 signal(SIGFPE,bad_handler);
188 signal(SIGSEGV,bad_handler);
189 signal(SIGTERM,bad_handler);
190 #if 0
191 tim.tv_sec=0; tim.tv_usec=54925;
192 set_timer(&tim);
193 #endif
194 /* report back to the main program that we're ready */
195 ret=2; /* dosmod protocol revision */
196 XWRITE(1,&ret,sizeof(ret));
197 /* context exchange loop */
198 do {
199 if (XREAD(0,&func,sizeof(func))!=sizeof(func)) return 1;
200 if (func<0) break;
201 switch (func) {
202 case DOSMOD_SET_TIMER:
203 if (XREAD(0,&tim,sizeof(tim))!=sizeof(tim)) return 1;
204 set_timer(&tim);
205 /* no response */
206 break;
207 case DOSMOD_GET_TIMER:
208 get_timer(&tim);
209 if (XWRITE(1,&tim,sizeof(tim))!=sizeof(tim)) return 1;
210 break;
211 case DOSMOD_ENTER:
212 default:
213 if (XREAD(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
214 if (sig_pend||sig_alrm||sig_cb) ret=DOSMOD_SIGNAL; else
215 ret=vm86plus(func,&VM86);
216 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
217 if (XWRITE(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
218 switch (ret&0xff) {
219 case DOSMOD_SIGNAL:
220 ret=sig_pend; sig_pend=0;
221 if (!ret) {
222 if (sig_alrm) {
223 ret=SIGALRM; sig_alrm--;
224 } else {
225 ret=SIGUSR2; sig_cb--;
228 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
229 if (sig_fatal) return 1;
230 break;
233 } while (1);
234 return 0;
237 #else /* !linux-i386 */
238 int main(void) {return 1;}
239 #endif