Moved Load/FreeLibrary16 definition to winbase16.h.
[wine.git] / loader / dos / dosmod.c
blobfb7da7f4dd211a7a3ee42bc36a75676024df28b9
1 /*
2 * DOS Virtual Machine
4 * Copyright 1998 Ove Kåven
5 */
7 #if defined(linux) && defined(__i386__)
9 #include "config.h"
11 /* apparently ELF images are usually loaded high anyway */
12 #ifndef __ELF__
13 /* if not, force dosmod at high addresses */
14 asm(".org 0x110000");
15 #endif /* __ELF__ */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <sys/stat.h>
25 #ifdef HAVE_SYS_MMAN_H
26 # include <sys/mman.h>
27 #endif
28 #ifdef HAVE_SYS_VM86_H
29 # include <sys/vm86.h>
30 #endif
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/ptrace.h>
34 #ifdef HAVE_SYS_WAIT_H
35 # include <sys/wait.h>
36 #endif
37 #include "dosmod.h"
39 /* FIXME: hack because libc vm86 may be the old syscall version */
41 #define SYS_vm86 166
43 static inline int vm86plus( int func, struct vm86plus_struct *ptr )
45 int res;
46 #ifdef __PIC__
47 __asm__ __volatile__( "pushl %%ebx\n\t"
48 "movl %2,%%ebx\n\t"
49 "int $0x80\n\t"
50 "popl %%ebx"
51 : "=a" (res)
52 : "0" (SYS_vm86),
53 "g" (func),
54 "c" (ptr) );
55 #else
56 __asm__ __volatile__("int $0x80"
57 : "=a" (res)
58 : "0" (SYS_vm86),
59 "b" (func),
60 "c" (ptr) );
61 #endif /* __PIC__ */
62 if (res >= 0) return res;
63 errno = -res;
64 return -1;
67 int XREAD(int fd,void*buf,int size) {
68 int res;
70 while (1) {
71 res = read(fd, buf, size);
72 if (res==size)
73 return res;
74 if (res==-1) {
75 if (errno==EINTR)
76 continue;
77 perror("dosmod read");
78 return -1;
80 if (res) /* don't print the EOF condition */
81 fprintf(stderr,"dosmod read only %d of %d bytes.\n",res,size);
82 return res;
85 int XWRITE(int fd,void*buf,int size) {
86 int res;
88 while (1) {
89 res = write(fd, buf, size);
90 if (res==size)
91 return res;
92 if (res==-1) {
93 if (errno==EINTR)
94 continue;
95 perror("dosmod write");
96 return -1;
98 fprintf(stderr,"dosmod write only %d of %d bytes.\n",res,size);
99 return res;
103 void set_timer(struct timeval*tim)
105 struct itimerval cur;
107 cur.it_interval=*tim;
108 cur.it_value=*tim;
109 setitimer(ITIMER_REAL,&cur,NULL);
112 void get_timer(struct timeval*tim)
114 struct itimerval cur;
116 getitimer(ITIMER_REAL,&cur);
117 *tim=cur.it_value;
120 volatile int sig_pend,sig_fatal=0,sig_alrm=0,sig_cb=0;
121 void*img;
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);
127 sig_pend=sig;
128 signal(sig,sig_handler);
131 void bad_handler(int sig)
133 if (sig!=SIGTERM) {
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)
143 sig_alrm++;
144 signal(sig,alarm_handler);
147 void cb_handler(int sig)
149 sig_cb++;
150 signal(sig,cb_handler);
153 int send_signal(void)
155 int ret=sig_pend; sig_pend=0;
156 if (!ret) {
157 if (sig_alrm) {
158 ret=SIGALRM; sig_alrm--;
159 } else {
160 ret=SIGUSR2; sig_cb--;
163 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
164 if (sig_fatal) return 1;
165 return 0;
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;
172 switch (ret&0xff) {
173 case DOSMOD_SIGNAL:
174 return send_signal();
176 return 0;
179 int main(int argc,char**argv)
181 int mfd=open(argv[0],O_RDWR);
182 struct timeval tim;
183 mprot_info mpr;
184 int func,ret,idle;
185 off_t fofs=0;
186 pid_t ppid=getppid();
188 /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
189 if (mfd<0) return 1;
190 /* Map in our DOS image at the start of the process address space */
191 if (argv[1]) {
192 /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine
193 address space */
194 fofs=atol(argv[1]);
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 */
198 kill(ppid,SIGSTOP);
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);
203 if (argv[1]) {
204 ptrace(PTRACE_DETACH,ppid,0,0);
205 kill(ppid,SIGCONT);
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);
210 return 1;
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);
225 #if 0
226 tim.tv_sec=0; tim.tv_usec=54925;
227 set_timer(&tim);
228 #endif
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 */
233 idle=0;
234 do {
235 if (idle) {
236 while (1) {
237 int res;
238 /* parent is idle, transmit any signals (particularly SIGALRM) */
239 if (sig_pend||sig_alrm||sig_cb) {
240 ret=DOSMOD_SIGNAL;
241 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
242 ret=send_signal();
243 if (ret) return ret;
244 break;
246 res = read(0,&func,sizeof(func));
247 if (res==sizeof(func))
248 break;
249 if (res==-1) {
250 if (errno==EINTR)
251 continue;
252 perror("dosmod read");
253 return 1;
255 if (res) /* don't print the EOF condition */
256 fprintf(stderr,"dosmod read only %d of %d bytes.\n",res,sizeof(func));
257 return 1;
259 ret=DOSMOD_LEFTIDLE;
260 if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
261 idle--;
262 } else
263 if (XREAD(0,&func,sizeof(func))!=sizeof(func)) return 1;
264 if (func<0) break;
265 switch (func) {
266 case DOSMOD_SET_TIMER: /* rev 1 */
267 if (XREAD(0,&tim,sizeof(tim))!=sizeof(tim)) return 1;
268 set_timer(&tim);
269 /* no response */
270 break;
271 case DOSMOD_GET_TIMER: /* rev 1 */
272 get_timer(&tim);
273 if (XWRITE(1,&tim,sizeof(tim))!=sizeof(tim)) return 1;
274 break;
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);
278 /* no response */
279 break;
280 case DOSMOD_ENTERIDLE: /* rev 3 */
281 idle++;
282 break;
283 case DOSMOD_LEAVEIDLE: /* rev 3 */
284 break;
285 case DOSMOD_ENTER: /* rev 0 */
286 default:
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);
292 if (ret) return ret;
294 } while (1);
295 return 0;
298 #else /* !linux-i386 */
299 int main(void) {return 1;}
300 #endif