Sweden-Number/loader/dos/dosmod.c

111 lines
3.0 KiB
C

/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/vm86.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
/* 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