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],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;}