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 */
24 #ifdef HAVE_SYS_MMAN_H
25 # include <sys/mman.h>
27 #ifdef HAVE_SYS_VM86_H
28 # include <sys/vm86.h>
31 #include <sys/types.h>
32 #ifdef HAVE_SYS_PTRACE_H
33 # include <sys/ptrace.h>
35 #ifdef HAVE_SYS_WAIT_H
36 # include <sys/wait.h>
40 /* FIXME: hack because libc vm86 may be the old syscall version */
44 static inline int vm86plus( int func
, struct vm86plus_struct
*ptr
)
48 __asm__
__volatile__( "pushl %%ebx\n\t"
57 __asm__
__volatile__("int $0x80"
63 if (res
>= 0) return res
;
68 int XREAD(int fd
,void*buf
,int size
) {
72 res
= read(fd
, buf
, size
);
78 perror("dosmod read");
81 if (res
) /* don't print the EOF condition */
82 fprintf(stderr
,"dosmod read only %d of %d bytes.\n",res
,size
);
86 int XWRITE(int fd
,void*buf
,int size
) {
90 res
= write(fd
, buf
, size
);
96 perror("dosmod write");
99 fprintf(stderr
,"dosmod write only %d of %d bytes.\n",res
,size
);
104 void set_timer(struct timeval
*tim
)
106 struct itimerval cur
;
108 cur
.it_interval
=*tim
;
110 setitimer(ITIMER_REAL
,&cur
,NULL
);
113 void get_timer(struct timeval
*tim
)
115 struct itimerval cur
;
117 getitimer(ITIMER_REAL
,&cur
);
121 volatile int sig_pend
,sig_fatal
=0,sig_alrm
=0,sig_cb
=0;
123 struct vm86plus_struct VM86
;
125 void sig_handler(int sig
)
127 if (sig_pend
) fprintf(stderr
,"DOSMOD previous signal %d lost\n",sig_pend
);
129 signal(sig
,sig_handler
);
132 void bad_handler(int sig
)
135 fprintf(stderr
,"DOSMOD caught fatal signal %d\n",sig
);
136 fprintf(stderr
,"(Last known VM86 CS:IP was %04x:%04lx)\n",VM86
.regs
.cs
,VM86
.regs
.eip
);
138 sig_pend
=sig
; sig_fatal
++;
139 signal(sig
,bad_handler
);
142 void alarm_handler(int sig
)
145 signal(sig
,alarm_handler
);
148 void cb_handler(int sig
)
151 signal(sig
,cb_handler
);
154 int send_signal(void)
156 int ret
=sig_pend
; sig_pend
=0;
159 ret
=SIGALRM
; sig_alrm
--;
161 ret
=SIGUSR2
; sig_cb
--;
164 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
165 if (sig_fatal
) return 1;
169 int send_enter_reply(int ret
)
171 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
172 if (XWRITE(1,&VM86
,sizeof(VM86
))!=sizeof(VM86
)) return 1;
175 return send_signal();
180 int main(int argc
,char**argv
)
182 int mfd
=open(argv
[0],O_RDWR
);
187 pid_t ppid
=getppid();
189 /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
191 /* Map in our DOS image at the start of the process address space */
193 /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine
196 /* linux currently only allows mapping a process memory if it's being ptraced */
197 /* Linus doesn't like it, so this probably won't work in the future */
198 /* it doesn't even work for me right now */
200 ptrace(PTRACE_ATTACH
,ppid
,0,0);
201 waitpid(ppid
,NULL
,0);
203 img
=mmap(NULL
,0x110000,PROT_EXEC
|PROT_READ
|PROT_WRITE
,MAP_FIXED
|MAP_SHARED
,mfd
,fofs
);
205 ptrace(PTRACE_DETACH
,ppid
,0,0);
208 if (img
==(void*)-1) {
209 fprintf(stderr
,"DOS memory map failed, error=%s\n",strerror(errno
));
210 fprintf(stderr
,"in attempt to map %s, offset %08lX, length 110000, to offset 0\n",argv
[0],(long)fofs
);
213 /* initialize signals and system timer */
214 signal(SIGHUP
,sig_handler
);
215 signal(SIGINT
,sig_handler
);
216 signal(SIGUSR1
,sig_handler
);
217 signal(SIGUSR2
,cb_handler
);
218 signal(SIGALRM
,alarm_handler
);
220 signal(SIGQUIT
,bad_handler
);
221 signal(SIGILL
,bad_handler
);
222 signal(SIGBUS
,bad_handler
);
223 signal(SIGFPE
,bad_handler
);
224 signal(SIGSEGV
,bad_handler
);
225 signal(SIGTERM
,bad_handler
);
227 tim
.tv_sec
=0; tim
.tv_usec
=54925;
230 /* report back to the main program that we're ready */
231 ret
=3; /* dosmod protocol revision */
232 XWRITE(1,&ret
,sizeof(ret
));
233 /* context exchange loop */
239 /* parent is idle, transmit any signals (particularly SIGALRM) */
240 if (sig_pend
||sig_alrm
||sig_cb
) {
242 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
247 res
= read(0,&func
,sizeof(func
));
248 if (res
==sizeof(func
))
253 perror("dosmod read");
256 if (res
) /* don't print the EOF condition */
257 fprintf(stderr
,"dosmod read only %d of %d bytes.\n",res
,sizeof(func
));
261 if (XWRITE(1,&ret
,sizeof(ret
))!=sizeof(ret
)) return 1;
264 if (XREAD(0,&func
,sizeof(func
))!=sizeof(func
)) return 1;
267 case DOSMOD_SET_TIMER
: /* rev 1 */
268 if (XREAD(0,&tim
,sizeof(tim
))!=sizeof(tim
)) return 1;
272 case DOSMOD_GET_TIMER
: /* rev 1 */
274 if (XWRITE(1,&tim
,sizeof(tim
))!=sizeof(tim
)) return 1;
276 case DOSMOD_MPROTECT
: /* rev 3 */
277 if (XREAD(0,&mpr
,sizeof(mpr
))!=sizeof(mpr
)) return 1;
278 mprotect(mpr
.addr
,mpr
.len
,mpr
.prot
);
281 case DOSMOD_ENTERIDLE
: /* rev 3 */
284 case DOSMOD_LEAVEIDLE
: /* rev 3 */
286 case DOSMOD_ENTER
: /* rev 0 */
288 if (XREAD(0,&VM86
,sizeof(VM86
))!=sizeof(VM86
)) return 1;
289 if (sig_pend
||sig_alrm
||sig_cb
) ret
=DOSMOD_SIGNAL
; else
290 ret
=vm86plus(func
,&VM86
);
292 ret
=send_enter_reply(ret
);
299 #else /* !linux-i386 */
300 int main(void) {return 1;}