/* * DOS Virtual Machine * * Copyright 1998 Ove Kåven */ #ifdef linux /* apparently ELF images are usually loaded high anyway */ #ifndef __ELF__ /* if not, force dosmod at high addresses */ asm(".org 0x110000"); #endif __ELF__ #include #include #include #include #include #include #include #include #include #include #include #include #include /* FIXME: hack because libc vm86 may be the old syscall version */ #define SYS_vm86 166 static __inline__ int vm86plus( int func, struct vm86plus_struct *ptr ) { int res; #ifdef __PIC__ __asm__ __volatile__( "pushl %%ebx\n\t" "movl %2,%%ebx\n\t" "int $0x80\n\t" "popl %%ebx" : "=a" (res) : "0" (SYS_vm86), "g" (func), "c" (ptr) ); #else __asm__ __volatile__("int $0x80" : "=a" (res) : "0" (SYS_vm86), "b" (func), "c" (ptr) ); #endif /* __PIC__ */ if (res >= 0) return res; errno = -res; return -1; } int main(int argc,char**argv) { int mfd=open(argv[0],O_RDWR); void*img; struct vm86plus_struct VM86; int func,ret; off_t fofs=0; pid_t ppid=getppid(); /* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */ if (mfd<0) return 1; /* Map in our DOS image at the start of the process address space */ if (argv[1]) { /* Ulrich Weigand suggested mapping in the DOS image directly from the Wine address space */ fofs=atol(argv[1]); /* linux currently only allows mapping a process memory if it's being ptraced */ /* Linus doesn't like it, so this probably won't work in the future */ /* it doesn't even work for me right now */ ptrace(PTRACE_ATTACH,ppid,0,0); kill(ppid,SIGSTOP); waitpid(ppid,NULL,0); } img=mmap(NULL,0x110000,PROT_EXEC|PROT_READ|PROT_WRITE,MAP_FIXED|MAP_SHARED,mfd,fofs); if (argv[1]) { ptrace(PTRACE_DETACH,ppid,0,0); kill(ppid,SIGCONT); } if (img==(void*)-1) { fprintf(stderr,"DOS memory map failed, error=%s\n",strerror(errno)); fprintf(stderr,"in attempt to map %s, offset %08lX, length 110000, to offset 0\n",argv[0],fofs); return 1; } /* fprintf(stderr,"Successfully mapped DOS memory, entering vm86 loop\n"); */ signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN); /* report back to the main program that we're ready */ ret=0; write(1,&ret,sizeof(ret)); /* context exchange loop */ do { if (read(0,&func,sizeof(func))!=sizeof(func)) return 1; if (read(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1; if (func<0) break; ret=vm86plus(func,&VM86); if (write(1,&ret,sizeof(ret))!=sizeof(ret)) return 1; if (write(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1; } while (1); return 0; } #else /* !linux */ int main(void) {return 1;} #endif