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 #ifdef HAVE_SYS_PTRACE_H
34 # include <sys/ptrace.h>
36 #ifdef HAVE_SYS_WAIT_H
37 # include <sys/wait.h>
41 /* FIXME: hack because libc vm86 may be the old syscall version */
45 static inline int vm86plus( int func
, struct vm86plus_struct
*ptr
)
49 __asm__
__volatile__( "pushl %%ebx\n\t"
58 __asm__
__volatile__("int $0x80"
64 if (res
>= 0) return res
;
69 int XREAD(int fd
,void*buf
,int size
) {
73 res
= read(fd
, buf
, size
);
79 perror("dosmod read");
82 if (res
) /* don't print the EOF condition */
83 fprintf(stderr
,"dosmod read only %d of %d bytes.\n",res
,size
);
87 int XWRITE(int fd
,void*buf
,int size
) {
91 res
= write(fd
, buf
, size
);
97 perror("dosmod write");
100 fprintf(stderr
,"dosmod write only %d of %d bytes.\n",res
,size
);
105 void set_timer(struct timeval
*tim
)
107 struct itimerval cur
;
109 cur
.it_interval
=*tim
;
111 setitimer(ITIMER_REAL
,&cur
,NULL
);
114 void get_timer(struct timeval
*tim
)
116 struct itimerval cur
;
118 getitimer(ITIMER_REAL
,&cur
);
122 volatile int sig_pend
,sig_fatal
=0,sig_alrm
=0,sig_cb
=0;
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
);
130 signal(sig
,sig_handler
);
133 void bad_handler(int sig
)
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
)
146 signal(sig
,alarm_handler
);
149 void cb_handler(int sig
)
152 signal(sig
,cb_handler
);
155 int send_signal(void)
157 int ret
=sig_pend
; sig_pend
=0;
160 ret
=SIGALRM
; sig_alrm
--;
162 ret
=SIGUSR2
; sig_cb
--;
165 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
166 if (sig_fatal
) return 1;
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;
176 return send_signal();
181 int main(int argc
,char**argv
)
183 int mfd
=open(argv
[0],O_RDWR
);
188 pid_t ppid
=getppid();
190 /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
192 /* Map in our DOS image at the start of the process address space */
194 /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine
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 */
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
);
206 ptrace(PTRACE_DETACH
,ppid
,0,0);
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
);
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
);
228 tim
.tv_sec
=0; tim
.tv_usec
=54925;
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 */
240 /* parent is idle, transmit any signals (particularly SIGALRM) */
241 if (sig_pend
||sig_alrm
||sig_cb
) {
243 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
248 res
= read(0,&func
,sizeof(func
));
249 if (res
==sizeof(func
))
254 perror("dosmod read");
257 if (res
) /* don't print the EOF condition */
258 fprintf(stderr
,"dosmod read only %d of %d bytes.\n",res
,sizeof(func
));
262 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
265 if (XREAD(0,&func
,sizeof(func
))!=sizeof(func
)) return 1;
268 case DOSMOD_SET_TIMER
: /* rev 1 */
269 if (XREAD(0,&tim
,sizeof(tim
))!=sizeof(tim
)) return 1;
273 case DOSMOD_GET_TIMER
: /* rev 1 */
275 if (XWRITE(1,&tim
,sizeof(tim
))!=sizeof(tim
)) return 1;
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
);
282 case DOSMOD_ENTERIDLE
: /* rev 3 */
285 case DOSMOD_LEAVEIDLE
: /* rev 3 */
287 case DOSMOD_ENTER
: /* rev 0 */
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
);
300 #else /* !linux-i386 */
301 int main(void) {return 1;}