Added #ifdef HAVE_WCTYPE_H.
[wine] / loader / dos / dosmod.c
1 /*
2  * DOS Virtual Machine
3  *
4  * Copyright 1998 Ove Kåven
5  */
6
7 #if defined(linux) && defined(__i386__)
8
9 /* apparently ELF images are usually loaded high anyway */
10 #ifndef __ELF__
11 /* if not, force dosmod at high addresses */
12 asm(".org 0x110000");
13 #endif __ELF__
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <signal.h>
22 #include <sys/stat.h>
23 #include <sys/mman.h>
24 #include <sys/vm86.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/ptrace.h>
28 #include <sys/wait.h>
29 #include "dosmod.h"
30
31  /* FIXME: hack because libc vm86 may be the old syscall version */
32
33 #define SYS_vm86   166
34
35 static __inline__ int vm86plus( int func, struct vm86plus_struct *ptr )
36 {
37     int res;
38 #ifdef __PIC__
39     __asm__ __volatile__( "pushl %%ebx\n\t"
40                           "movl %2,%%ebx\n\t"
41                           "int $0x80\n\t"
42                           "popl %%ebx"
43                           : "=a" (res)
44                           : "0" (SYS_vm86),
45                             "g" (func),
46                             "c" (ptr) );
47 #else
48     __asm__ __volatile__("int $0x80"
49                          : "=a" (res)
50                          : "0" (SYS_vm86),
51                            "b" (func),
52                            "c" (ptr) );
53 #endif  /* __PIC__ */
54     if (res >= 0) return res;
55     errno = -res;
56     return -1;
57 }
58
59 int XREAD(int fd,void*buf,int size) {
60  int res;
61
62  while (1) {
63   res = read(fd, buf, size);
64   if (res==size)
65    return res;
66   if (res==-1) {
67    if (errno==EINTR)
68     continue;
69    perror("dosmod read");
70    return -1;
71   }
72   fprintf(stderr,"dosmod read only %d of %d bytes.\n",res,size);
73   return res;
74  }
75 }
76 int XWRITE(int fd,void*buf,int size) {
77  int res;
78
79  while (1) {
80   res = write(fd, buf, size);
81   if (res==size)
82    return res;
83   if (res==-1) {
84    if (errno==EINTR)
85     continue;
86    perror("dosmod write");
87    return -1;
88   }
89   fprintf(stderr,"dosmod write only %d of %d bytes.\n",res,size);
90   return res;
91  }
92 }
93
94 void set_timer(struct timeval*tim)
95 {
96  struct itimerval cur;
97
98  cur.it_interval=*tim;
99  cur.it_value=*tim;
100  setitimer(ITIMER_REAL,&cur,NULL);
101 }
102
103 void get_timer(struct timeval*tim)
104 {
105  struct itimerval cur;
106
107  getitimer(ITIMER_REAL,&cur);
108  *tim=cur.it_value;
109 }
110
111 volatile int sig_pend,sig_fatal=0,sig_alrm=0;
112 void*img;
113 struct vm86plus_struct VM86;
114
115 void sig_handler(int sig)
116 {
117  if (sig_pend) fprintf(stderr,"DOSMOD previous signal %d lost\n",sig_pend);
118  sig_pend=sig;
119  signal(sig,sig_handler);
120 }
121
122 void bad_handler(int sig)
123 {
124  fprintf(stderr,"DOSMOD caught fatal signal %d\n",sig);
125  fprintf(stderr,"(Last known VM86 CS:IP was %04x:%04lx)\n",VM86.regs.cs,VM86.regs.eip);
126  sig_pend=sig; sig_fatal++;
127  signal(sig,bad_handler);
128 }
129
130 void alarm_handler(int sig)
131 {
132  sig_alrm++;
133  signal(sig,alarm_handler);
134 }
135
136 int main(int argc,char**argv)
137 {
138  int mfd=open(argv[0],O_RDWR);
139  struct timeval tim;
140  int func,ret;
141  off_t fofs=0;
142  pid_t ppid=getppid();
143  
144 /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
145  if (mfd<0) return 1;
146 /* Map in our DOS image at the start of the process address space */
147  if (argv[1]) {
148   /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine
149      address space */
150   fofs=atol(argv[1]);
151   /* linux currently only allows mapping a process memory if it's being ptraced */
152   /* Linus doesn't like it, so this probably won't work in the future */
153   /* it doesn't even work for me right now */
154   kill(ppid,SIGSTOP);
155   ptrace(PTRACE_ATTACH,ppid,0,0);
156   waitpid(ppid,NULL,0);
157  }
158  img=mmap(NULL,0x110000,PROT_EXEC|PROT_READ|PROT_WRITE,MAP_FIXED|MAP_SHARED,mfd,fofs);
159  if (argv[1]) {
160   ptrace(PTRACE_DETACH,ppid,0,0);
161   kill(ppid,SIGCONT);
162  }
163  if (img==(void*)-1) {
164   fprintf(stderr,"DOS memory map failed, error=%s\n",strerror(errno));
165   fprintf(stderr,"in attempt to map %s, offset %08lX, length 110000, to offset 0\n",argv[0],fofs);
166   return 1;
167  }
168 /* initialize signals and system timer */
169  signal(SIGHUP,sig_handler);
170  signal(SIGINT,sig_handler);
171  signal(SIGUSR1,sig_handler);
172  signal(SIGUSR2,sig_handler);
173  signal(SIGALRM,alarm_handler);
174
175  signal(SIGQUIT,bad_handler);
176  signal(SIGILL,bad_handler);
177  signal(SIGBUS,bad_handler);
178  signal(SIGFPE,bad_handler);
179  signal(SIGSEGV,bad_handler);
180  signal(SIGTERM,bad_handler);
181 #if 0
182  tim.tv_sec=0; tim.tv_usec=54925;
183  set_timer(&tim);
184 #endif
185 /* report back to the main program that we're ready */
186  ret=1; /* dosmod protocol revision 1 */
187  XWRITE(1,&ret,sizeof(ret));
188 /* context exchange loop */
189  do {
190   if (XREAD(0,&func,sizeof(func))!=sizeof(func)) return 1;
191   if (func<0) break;
192   switch (func) {
193    case DOSMOD_SET_TIMER:
194     if (XREAD(0,&tim,sizeof(tim))!=sizeof(tim)) return 1;
195     set_timer(&tim);
196     /* no response */
197     break;
198    case DOSMOD_GET_TIMER:
199     get_timer(&tim);
200     if (XWRITE(1,&tim,sizeof(tim))!=sizeof(tim)) return 1;
201     break;
202    case DOSMOD_ENTER:
203    default:
204     if (XREAD(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
205     if (sig_pend||sig_alrm) ret=DOSMOD_SIGNAL; else
206      ret=vm86plus(func,&VM86);
207     if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
208     if (XWRITE(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
209     switch (ret&0xff) {
210      case DOSMOD_SIGNAL:
211       ret=sig_pend; sig_pend=0;
212       if (!ret) { ret=SIGALRM; sig_alrm--; }
213       if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
214       if (sig_fatal) return 1;
215       break;
216     }
217   }
218  } while (1);
219  return 0;
220 }
221
222 #else /* !linux-i386 */
223 int main(void) {return 1;}
224 #endif