4 * Copyright 1998 Ove Kåven
7 #if defined(linux) && defined(__i386__)
11 /* apparently ELF images are usually loaded high anyway */
13 /* if not, force dosmod at high addresses */
25 #ifdef HAVE_SYS_MMAN_H
26 # include <sys/mman.h>
28 #ifdef HAVE_SYS_VM86_H
29 # include <sys/vm86.h>
32 #include <sys/types.h>
33 #include <sys/ptrace.h>
34 #ifdef HAVE_SYS_WAIT_H
35 # include <sys/wait.h>
39 /* FIXME: hack because libc vm86 may be the old syscall version */
43 static inline int vm86plus( int func
, struct vm86plus_struct
*ptr
)
47 __asm__
__volatile__( "pushl %%ebx\n\t"
56 __asm__
__volatile__("int $0x80"
62 if (res
>= 0) return res
;
67 int XREAD(int fd
,void*buf
,int size
) {
71 res
= read(fd
, buf
, size
);
77 perror("dosmod read");
80 if (res
) /* don't print the EOF condition */
81 fprintf(stderr
,"dosmod read only %d of %d bytes.\n",res
,size
);
85 int XWRITE(int fd
,void*buf
,int size
) {
89 res
= write(fd
, buf
, size
);
95 perror("dosmod write");
98 fprintf(stderr
,"dosmod write only %d of %d bytes.\n",res
,size
);
103 void set_timer(struct timeval
*tim
)
105 struct itimerval cur
;
107 cur
.it_interval
=*tim
;
109 setitimer(ITIMER_REAL
,&cur
,NULL
);
112 void get_timer(struct timeval
*tim
)
114 struct itimerval cur
;
116 getitimer(ITIMER_REAL
,&cur
);
120 volatile int sig_pend
,sig_fatal
=0,sig_alrm
=0,sig_cb
=0;
122 struct vm86plus_struct VM86
;
124 void sig_handler(int sig
)
126 if (sig_pend
) fprintf(stderr
,"DOSMOD previous signal %d lost\n",sig_pend
);
128 signal(sig
,sig_handler
);
131 void bad_handler(int sig
)
134 fprintf(stderr
,"DOSMOD caught fatal signal %d\n",sig
);
135 fprintf(stderr
,"(Last known VM86 CS:IP was %04x:%04lx)\n",VM86
.regs
.cs
,VM86
.regs
.eip
);
137 sig_pend
=sig
; sig_fatal
++;
138 signal(sig
,bad_handler
);
141 void alarm_handler(int sig
)
144 signal(sig
,alarm_handler
);
147 void cb_handler(int sig
)
150 signal(sig
,cb_handler
);
153 int send_signal(void)
155 int ret
=sig_pend
; sig_pend
=0;
158 ret
=SIGALRM
; sig_alrm
--;
160 ret
=SIGUSR2
; sig_cb
--;
163 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
164 if (sig_fatal
) return 1;
168 int send_enter_reply(int ret
)
170 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
171 if (XWRITE(1,&VM86
,sizeof(VM86
))!=sizeof(VM86
)) return 1;
174 return send_signal();
179 int main(int argc
,char**argv
)
181 int mfd
=open(argv
[0],O_RDWR
);
186 pid_t ppid
=getppid();
188 /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
190 /* Map in our DOS image at the start of the process address space */
192 /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine
195 /* linux currently only allows mapping a process memory if it's being ptraced */
196 /* Linus doesn't like it, so this probably won't work in the future */
197 /* it doesn't even work for me right now */
199 ptrace(PTRACE_ATTACH
,ppid
,0,0);
200 waitpid(ppid
,NULL
,0);
202 img
=mmap(NULL
,0x110000,PROT_EXEC
|PROT_READ
|PROT_WRITE
,MAP_FIXED
|MAP_SHARED
,mfd
,fofs
);
204 ptrace(PTRACE_DETACH
,ppid
,0,0);
207 if (img
==(void*)-1) {
208 fprintf(stderr
,"DOS memory map failed, error=%s\n",strerror(errno
));
209 fprintf(stderr
,"in attempt to map %s, offset %08lX, length 110000, to offset 0\n",argv
[0],fofs
);
212 /* initialize signals and system timer */
213 signal(SIGHUP
,sig_handler
);
214 signal(SIGINT
,sig_handler
);
215 signal(SIGUSR1
,sig_handler
);
216 signal(SIGUSR2
,cb_handler
);
217 signal(SIGALRM
,alarm_handler
);
219 signal(SIGQUIT
,bad_handler
);
220 signal(SIGILL
,bad_handler
);
221 signal(SIGBUS
,bad_handler
);
222 signal(SIGFPE
,bad_handler
);
223 signal(SIGSEGV
,bad_handler
);
224 signal(SIGTERM
,bad_handler
);
226 tim
.tv_sec
=0; tim
.tv_usec
=54925;
229 /* report back to the main program that we're ready */
230 ret
=3; /* dosmod protocol revision */
231 XWRITE(1,&ret
,sizeof(ret
));
232 /* context exchange loop */
238 /* parent is idle, transmit any signals (particularly SIGALRM) */
239 if (sig_pend
||sig_alrm
||sig_cb
) {
241 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
246 res
= read(0,&func
,sizeof(func
));
247 if (res
==sizeof(func
))
252 perror("dosmod read");
255 if (res
) /* don't print the EOF condition */
256 fprintf(stderr
,"dosmod read only %d of %d bytes.\n",res
,sizeof(func
));
260 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
263 if (XREAD(0,&func
,sizeof(func
))!=sizeof(func
)) return 1;
266 case DOSMOD_SET_TIMER
: /* rev 1 */
267 if (XREAD(0,&tim
,sizeof(tim
))!=sizeof(tim
)) return 1;
271 case DOSMOD_GET_TIMER
: /* rev 1 */
273 if (XWRITE(1,&tim
,sizeof(tim
))!=sizeof(tim
)) return 1;
275 case DOSMOD_MPROTECT
: /* rev 3 */
276 if (XREAD(0,&mpr
,sizeof(mpr
))!=sizeof(mpr
)) return 1;
277 mprotect(mpr
.addr
,mpr
.len
,mpr
.prot
);
280 case DOSMOD_ENTERIDLE
: /* rev 3 */
283 case DOSMOD_LEAVEIDLE
: /* rev 3 */
285 case DOSMOD_ENTER
: /* rev 0 */
287 if (XREAD(0,&VM86
,sizeof(VM86
))!=sizeof(VM86
)) return 1;
288 if (sig_pend
||sig_alrm
||sig_cb
) ret
=DOSMOD_SIGNAL
; else
289 ret
=vm86plus(func
,&VM86
);
291 ret
=send_enter_reply(ret
);
298 #else /* !linux-i386 */
299 int main(void) {return 1;}