diff options
author | Robert de Bath <rdebath@poboxes.com> | 1996-03-24 17:45:55 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2013-10-23 23:29:43 +0200 |
commit | fe22c37817ce338fbbc90b239320248c270957fa (patch) | |
tree | d9550410c4a20bdd382fcc58d2d3d7c5e04e5245 /elksemu | |
parent | a7aba15e8efffb1c5d3097656f1a93955a64f01f (diff) | |
parent | 42192453ea219b80d0bf9f41e51e36d3d4d0740b (diff) | |
download | dev86-fe22c37817ce338fbbc90b239320248c270957fa.tar.gz |
Import Dev86-0.0.4.tar.gzv0.0.4
Diffstat (limited to 'elksemu')
-rw-r--r-- | elksemu/Kernel_patch | 19 | ||||
-rw-r--r-- | elksemu/Makefile | 29 | ||||
-rw-r--r-- | elksemu/V-files.tar | bin | 0 -> 10240 bytes | |||
-rw-r--r-- | elksemu/Version | 1 | ||||
-rw-r--r-- | elksemu/elks.c | 258 | ||||
-rw-r--r-- | elksemu/elks.h | 96 | ||||
-rw-r--r-- | elksemu/elks_signal.c | 36 | ||||
-rw-r--r-- | elksemu/elks_sys.c | 723 |
8 files changed, 1162 insertions, 0 deletions
diff --git a/elksemu/Kernel_patch b/elksemu/Kernel_patch new file mode 100644 index 0000000..451455f --- /dev/null +++ b/elksemu/Kernel_patch @@ -0,0 +1,19 @@ + +This kernel patch allows you to run Linux-8086 executables transparently +on a Linux-i386 system. It requires V0.0.2 of elksemu in "/lib/elksemu". + +--- orig-13/fs/exec.c Sun Sep 24 13:22:37 1995 ++++ linux/fs/exec.c Sun Feb 11 20:11:47 1996 +@@ -615,6 +615,12 @@ + set_fs(old_fs); + if (retval < 0) + goto exec_error2; ++#ifndef NO_ELKSEMU ++ /* What a horrible hack! :-) */ ++ if ((bprm.buf[0] == 1) && (bprm.buf[1] == 3) && ++ (bprm.buf[2] == 0x20) && (bprm.buf[3] == 4)) ++ memcpy(bprm.buf, "#!/lib/elksemu\n", 16); ++#endif + if ((bprm.buf[0] == '#') && (bprm.buf[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. diff --git a/elksemu/Makefile b/elksemu/Makefile new file mode 100644 index 0000000..cee13ac --- /dev/null +++ b/elksemu/Makefile @@ -0,0 +1,29 @@ +# +# Makefile for elksemu. +# + +CFLAGS=-O2 -fno-strength-reduce -Wall +# If you need an a.out exe. NB The program _does_ now work as ELF +# CFLAGS=-O2 -fno-strength-reduce -b i486-linuxaout -N -s -static + +OBJ=elks.o elks_sys.o elks_signal.o + +elksemu: $(OBJ) + $(CC) $(CFLAGS) -o elksemu $(OBJ) + +$(OBJ): elks.h +elks_sys.o: call_tab.v + +call_tab.v: dummy + -cp -p ../libc/syscall/call_tab.v . 2>/dev/null + -cp -p ../libc/syscall/defn_tab.v . 2>/dev/null + +dummy: + +# The kernel patch _requires_ this location. +install: elksemu + install -s -m 755 elksemu /lib/elksemu + tar cvf V-files.tar call_tab.v defn_tab.v + +clean: + rm -f $(OBJ) elksemu call_tab.v defn_tab.v diff --git a/elksemu/V-files.tar b/elksemu/V-files.tar Binary files differnew file mode 100644 index 0000000..c5e6082 --- /dev/null +++ b/elksemu/V-files.tar diff --git a/elksemu/Version b/elksemu/Version new file mode 100644 index 0000000..38a680f --- /dev/null +++ b/elksemu/Version @@ -0,0 +1 @@ +Version elksemu-0.0.4 diff --git a/elksemu/elks.c b/elksemu/elks.c new file mode 100644 index 0000000..f84c994 --- /dev/null +++ b/elksemu/elks.c @@ -0,0 +1,258 @@ +/* + * ELKSEMU An emulator for Linux8086 binaries. + * + * VM86 is used to process all the 8086 mode code. + * We trap up to 386 mode for system call emulation and naughties. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/vm86.h> +#include <sys/mman.h> +#include "elks.h" + +volatile struct vm86_struct elks_cpu; +unsigned char *elks_base; /* Paragraph aligned */ + +#define dbprintf(x) db_printf x +/**/ + +static void elks_init() +{ + elks_cpu.screen_bitmap=0; + elks_cpu.cpu_type = CPU_286; + /* + * All INT xx calls are trapped. + */ + memset((void *)&elks_cpu.int_revectored,0xFF, sizeof(elks_cpu.int_revectored)); +} + +static void elks_take_interrupt(int arg) +{ + if(arg!=0x80) + { + dbprintf(("Took an int %d\n", arg)); + fflush(stderr); + kill(getpid(), SIGILL); + return; + } + + dbprintf(("syscall AX=%X BX=%X CX=%X DX=%x\n", + (unsigned short)elks_cpu.regs.eax, + (unsigned short)elks_cpu.regs.ebx, + (unsigned short)elks_cpu.regs.ecx, + (unsigned short)elks_cpu.regs.edx)); + + elks_cpu.regs.eax = elks_syscall(); + dbprintf(("elks syscall returned %d\n", elks_cpu.regs.eax)); + /* Finally return to vm86 state */ +} + + +static int load_elks(int fd) +{ + /* Load the elks binary image and set it up in a suitable VM86 segment. Load CS and DS/SS + according to image type. chmem is ignored we always use 64K segments */ + struct elks_exec_hdr mh; + unsigned char *dsp; + if(read(fd, &mh,sizeof(mh))!=sizeof(mh)) + return -ENOEXEC; + if(mh.hlen!=EXEC_HEADER_SIZE) + return -ENOEXEC; + if(mh.type!=ELKS_COMBID&&mh.type!=ELKS_SPLITID) + return -ENOEXEC; +#if 0 + fprintf(stderr,"Linux-86 binary - %lX. tseg=%ld dseg=%ld bss=%ld\n", + mh.type,mh.tseg,mh.dseg,mh.bseg); +#endif + if(read(fd,elks_base,mh.tseg)!=mh.tseg) + return -ENOEXEC; + if(mh.type==ELKS_COMBID) + dsp=elks_base+mh.tseg; + else + dsp=elks_base+65536; + if(read(fd,dsp,mh.dseg)!=mh.dseg) + return -ENOEXEC; + memset(dsp+mh.dseg,0, mh.bseg); + /* + * Load the VM86 registers + */ + +/* if(mh.type==ELKS_COMBID) + dsp=elks_base;*/ + elks_cpu.regs.ds=PARAGRAPH(dsp); + elks_cpu.regs.es=PARAGRAPH(dsp); + elks_cpu.regs.ss=PARAGRAPH(dsp); + elks_cpu.regs.esp=65536; /* Args stacked later */ + elks_cpu.regs.cs=PARAGRAPH(elks_base); + elks_cpu.regs.eip=0; /* Run from 0 */ + + /* + * Loaded, check for sanity. + */ + if( dsp != ELKS_PTR(unsigned char, 0) ) + { + printf("Error VM86 problem %lx!=%lx (Is DS > 16 bits ?)\n", + (long)dsp, (long)ELKS_PTR(char, 0)); + exit(0); + } + + return 0; +} + + +void run_elks() +{ + /* + * Execute 8086 code for a while. + */ + int err=vm86((struct vm86_struct*)&elks_cpu); + switch(VM86_TYPE(err)) + { + /* + * Signals are just re-starts of emulation (yes the + * handler might alter elks_cpu) + */ + case VM86_SIGNAL: + break; + case VM86_UNKNOWN: + fprintf(stderr, "VM86_UNKNOWN returned\n"); + exit(1); + case VM86_INTx: + elks_take_interrupt(VM86_ARG(err)); + break; + case VM86_STI: + fprintf(stderr, "VM86_STI returned\n"); + break; /* Shouldnt be seen */ + } +} + +void build_stack(char ** argv, char ** envp) +{ + char **p; + int argv_len=0, argv_count=0; + int envp_len=0, envp_count=0; + int stack_bytes; + unsigned short * pip; + unsigned short pcp; + + /* How much space for argv */ + for(p=argv; *p; p++) + { + argv_count++; argv_len += strlen(*p)+1; + } + + /* How much space for envp */ + for(p=envp; *p; p++) + { + envp_count++; envp_len += strlen(*p)+1; + } + + /* tot it all up */ + stack_bytes = 2 /* argc */ + + argv_count * 2 + 2 /* argv */ + + argv_len + + envp_count * 2 + 2 /* envp */ + + envp_len; + + /* Allocate it */ + elks_cpu.regs.esp -= stack_bytes; + +/* Sanity check + printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n", + argv_count, argv_len, envp_count, envp_len, stack_bytes); +*/ + + /* Now copy in the strings */ + pip=ELKS_PTR(unsigned short, elks_cpu.regs.esp); + pcp=elks_cpu.regs.esp+2*(1+argv_count+1+envp_count+1); + + *pip++ = argv_count; + for(p=argv; *p; p++) + { + *pip++ = pcp; + strcpy(ELKS_PTR(char, pcp), *p); + pcp += strlen(*p)+1; + } + *pip++ = 0; + + for(p=envp; *p; p++) + { + *pip++ = pcp; + strcpy(ELKS_PTR(char, pcp), *p); + pcp += strlen(*p)+1; + } + *pip++ = 0; +} + +void main(int argc, char *argv[], char *envp[]) +{ + int fd; + dbprintf(("ELKSEMU 0.01 Alpha\n")); + if(argc==1) + { + fprintf(stderr,"elksemu cmd args.....\n"); + exit(1); + } + elks_init(); + + /* The Linux vm will deal with not allocating the unused pages */ +#if __AOUT__ + /* GNU malloc will align to 4k with large chunks */ + elks_base = malloc(0x20000); +#else + /* For ELF first 128M is unmapped, it needs to be mapped manually */ + elks_base = mmap((void*)0x10000, 0x20000, + PROT_EXEC|PROT_READ|PROT_WRITE, + MAP_ANON|MAP_PRIVATE|MAP_FIXED, + 0, 0); +#endif + if( (long)elks_base < 0 || (long)elks_base >= 0xE0000 ) + { + fprintf(stderr, "Elks memory is at an illegal address\n"); + exit(255); + } + fd=open(argv[1], O_RDONLY); + if(fd==-1) + { + perror(argv[1]); + exit(1); + } + + if(load_elks(fd) < 0) + { + fprintf(stderr,"Not a elks binary.\n"); + exit(1); + } + + close(fd); + + build_stack(argv+1, envp); + + while(1) + run_elks(); +} + +void db_printf(const char * fmt, ...) +{ +static FILE * db_fd = 0; + va_list ptr; + int rv; + if( db_fd == 0 ) + { + db_fd = fopen("/tmp/ELKS_log", "a"); + if( db_fd == 0 ) db_fd = stderr; + setbuf(db_fd, 0); + } + fprintf(db_fd, "%d: ", getpid()); + va_start(ptr, fmt); + rv = vfprintf(db_fd,fmt,ptr); + va_end(ptr); +} diff --git a/elksemu/elks.h b/elksemu/elks.h new file mode 100644 index 0000000..6d52470 --- /dev/null +++ b/elksemu/elks.h @@ -0,0 +1,96 @@ +/* + * Definitions for emulating ELKS + */ + +#define ELKS_CS_OFFSET 0 +#define ELKS_DS_OFFSET 0 /* For split I/D */ + +#define HZ 100 + +#define ELKS_SIG_IGN (-1) +#define ELKS_SIG_DFL 0 + +#define WRITE_USPACE 0 +#define READ_USPACE 1 + +#if !__ELF__ +#define __AOUT__ 1 +#endif + +/* + * Minix view of stat(). We have to squash a bit here and give + * wrong values with inode >65535 etc + */ + +struct elks_stat +{ + unsigned short st_dev; + unsigned short st_inode; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + int st_size; + int st_atime; + int st_mtime; + int st_ctime; +}; + + +/* + * Minix ioctl list + */ + +#define ELKS_TIOCGETP (('t'<<8)|8) +#define ELKS_TIOCSETP (('t'<<8)|9) +#define ELKS_TIOCGETC (('t'<<8)|18) +#define ELKS_TIOCSETC (('t'<<8)|17) +#define ELKS_TIOCFLUSH (('t'<<8)|16) + +/* + * fcntl list + */ + +#define ELKS_F_DUPFD 0 +#define ELKS_F_GETFD 1 +#define ELKS_F_SETFD 2 +#define ELKS_F_GETFL 3 +#define ELKS_F_SETFL 4 +#define ELKS_F_GETLK 5 +#define ELKS_F_SETLK 6 +#define ELKS_F_SETLKW 7 + +/* + * Elks binary formats + */ + +#define EXEC_HEADER_SIZE 32 + +struct elks_exec_hdr +{ + unsigned long type; +#define ELKS_COMBID 0x04100301L +#define ELKS_SPLITID 0x04200301L + unsigned long hlen; + unsigned long tseg; + unsigned long dseg; + unsigned long bseg; + unsigned long unused; + unsigned long chmem; + unsigned long unused2; +}; + +#define PARAGRAPH(x) (((unsigned long)(x))>>4) +#define ELKS_DSEG(x) ((unsigned char *)(((x)&0xFFFF)+(elks_cpu.regs.ds<<4))) + +#define ELKS_PTR(_t,x) ((_t *) ((elks_cpu.regs.ds<<4)+((x)&0xFFFF)) ) +#define ELKS_PEEK(_t,x) (*((_t *) ((elks_cpu.regs.ds<<4)+((x)&0xFFFF)) )) +#define ELKS_POKE(_t,x,_v) \ + (*((_t *) ((elks_cpu.regs.ds<<4)+((x)&0xFFFF)) ) = (_v)) + +extern unsigned char * elks_base; +extern volatile struct vm86_struct elks_cpu; + +void db_printf(const char *, ...); +int elks_syscall(void); diff --git a/elksemu/elks_signal.c b/elksemu/elks_signal.c new file mode 100644 index 0000000..2bf1e55 --- /dev/null +++ b/elksemu/elks_signal.c @@ -0,0 +1,36 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/vm86.h> +#include "elks.h" + +static int elks_sigtrap= -1; + +void sig_trap(int signo) +{ + elks_cpu.regs.esp -= 2; + ELKS_POKE(unsigned short, elks_cpu.regs.esp, signo); + elks_cpu.regs.esp -= 2; + ELKS_POKE(unsigned short, elks_cpu.regs.esp, elks_cpu.regs.eip); + elks_cpu.regs.eip = elks_sigtrap; +} + +int elks_signal(int bx,int cx,int dx,int di,int si) +{ + int rv; + if( bx < 0 || bx >= NSIG ) { errno = EINVAL; return -1; } + if( cx == 0 ) rv = (signal(bx, SIG_DFL) == SIG_ERR); + else if( cx == 1 ) rv = (signal(bx, SIG_IGN) == SIG_ERR); + else + { + elks_sigtrap = cx; + rv = (signal(bx, sig_trap) == SIG_ERR); + } + + return -rv; +} diff --git a/elksemu/elks_sys.c b/elksemu/elks_sys.c new file mode 100644 index 0000000..7ca946c --- /dev/null +++ b/elksemu/elks_sys.c @@ -0,0 +1,723 @@ +/* + * System calls are mostly pretty easy as the emulator is tightly bound to + * the elks task. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/vm86.h> +#include <sys/times.h> +#include <utime.h> +#include <termios.h> +#include <time.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <dirent.h> +#include "elks.h" + +#define dbprintf(x) db_printf x + +#define sys_signal elks_signal +extern int elks_signal(int bx,int cx,int dx,int di,int si); + +/* Forward refs */ +static int elks_termios(int bx,int cx,int dx,int di,int si); +static int elks_enosys(int bx,int cx,int dx,int di,int si); + +#define DIRCOUNT 20 +DIR * dirtab[DIRCOUNT]; +int diropen = 0; +static int elks_opendir(char * dname); +static int elks_readdir(int bx, int cx, int dx); +static int elks_closedir(int bx); + +/* + * Compress a host stat into a elks one. Lose upper bits with wild + * abandon. For SYS5.3 this isn't a problem, but machines with 32 + * bit inodes (BSD, SYS5 with veritas, newest SCO) you lose the top + * bits which can confuse a few programs which use inode numbers + * (eg gnu tar). + */ + +static void squash_stat(struct stat *s, int bx) +{ +#if 1 /* Can't use elks_stat, shot in the foot by alignment */ + + ELKS_POKE(short, bx+0, s->st_dev); + ELKS_POKE(short, bx+2, s->st_ino ^ (s->st_ino>>16)); + ELKS_POKE(short, bx+4, s->st_mode); + ELKS_POKE(short, bx+6, s->st_nlink); + ELKS_POKE(short, bx+8, s->st_uid); + ELKS_POKE(short, bx+10, s->st_gid); + ELKS_POKE(short, bx+12, s->st_rdev); + ELKS_POKE(long, bx+14, s->st_size); + ELKS_POKE(long, bx+18, s->st_atime); + ELKS_POKE(long, bx+22, s->st_mtime); + ELKS_POKE(long, bx+26, s->st_ctime); +#else + struct elks_stat * ms = ELKS_PTR(struct elks_stat, bx); + ms->st_dev=s->st_dev; + ms->st_inode=(unsigned short)s->st_ino; /* Bits lost */ + ms->st_mode=s->st_mode; + ms->st_nlink=s->st_nlink; + ms->st_uid=s->st_uid; + ms->st_gid=s->st_gid; + ms->st_rdev=s->st_rdev; + ms->st_size=s->st_size; + ms->st_atime=s->st_atime; + ms->st_mtime=s->st_mtime; + ms->st_ctime=s->st_ctime; +#endif +} + +/* + * Implementation of ELKS syscalls. + */ + + +#define sys_exit elks_exit +static int elks_exit(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("exit(%d)\n",bx)); + exit(bx); +} + +#define sys_vfork elks_fork +#define sys_fork elks_fork +static int elks_fork(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("fork()\n")); + /* This is fun 8) - fork the emulator (its easier that way) */ + return fork(); +} + +#define sys_read elks_read +static int elks_read(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("read(%d, %d, %d)\n", + bx,cx,dx)); + if( bx >= 10000 && bx < 10000+DIRCOUNT) + return elks_readdir(bx, cx, dx); + return read(bx, ELKS_PTR(void, cx), dx); +} + +#define sys_write elks_write +static int elks_write(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("write(%d, %d, %d)\n",bx,cx,dx)); + return write(bx,ELKS_PTR(void, cx),dx); +} + +#define sys_open elks_open +static int elks_open(int bx,int cx,int dx,int di,int si) +{ + struct stat s; + + /* Assumes _all_ flags are the same */ + char *dp=ELKS_PTR(char, bx); + dbprintf(("open(%s, %d, %d)\n", + dp,cx,dx)); + + if( cx == O_RDONLY ) + { + if(stat(dp,&s)==-1) + return -1; + if( S_ISDIR(s.st_mode) ) + return elks_opendir(dp); + } + + return open(dp,cx,dx); +} + +#define sys_close elks_close +static int elks_close(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("close(%d)\n",bx)); + if( bx >= 10000 && bx < 10000+DIRCOUNT) + return elks_closedir(bx); + return close(bx); +} + +#define sys_wait4 elks_wait4 +static int elks_wait4(int bx,int cx,int dx,int di,int si) +{ + int status; + unsigned short *tp=ELKS_PTR(unsigned short, cx); + int r; + struct rusage use; + + dbprintf(("wait4(%d, %d, %d, %d)\n", bx, cx, dx, di)); + r=wait4((int)(short)bx, &status, dx, &use ); + + *tp=status; + if( di ) memcpy(ELKS_PTR(void, di), &use, sizeof(use)); + return r; +} + +#define sys_link elks_link +static int elks_link(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("link(%s,%s)\n", ELKS_PTR(char, bx), ELKS_PTR(char, cx))); + return link(ELKS_PTR(char, bx),ELKS_PTR(char, cx)); +} + +#define sys_unlink elks_unlink +static int elks_unlink(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("unlink(%s)\n",ELKS_PTR(char, bx))); + return unlink(ELKS_PTR(char, bx)); +} + +#define sys_chdir elks_chdir +static int elks_chdir(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("chdir(%s)\n",ELKS_PTR(char, bx))); + return chdir(ELKS_PTR(char, bx)); +} + +#define sys_mknod elks_mknod +static int elks_mknod(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("mknod(%s,%d,%d)\n", ELKS_PTR(char, bx),cx,dx)); + return mknod(ELKS_PTR(char, bx),cx,dx); +} + +#define sys_chmod elks_chmod +static int elks_chmod(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("chmod(%s,%d)\n", ELKS_PTR(char, bx),cx)); + return chmod(ELKS_PTR(char, bx), cx); +} + +#define sys_chown elks_chown +static int elks_chown(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("chown(%s,%d,%d)\n", ELKS_PTR(char, bx),cx,dx)); + return chown(ELKS_PTR(char, bx),cx,dx); +} + +#define sys_brk elks_brk +static int elks_brk(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("brk(%d)\n",bx)); + if(bx>=elks_cpu.regs.esp) + { + errno= 1; /* Really return -1 */ + return -1; + } + return 0; /* Can't return bx, 0xBAD1 is an error */ +} + +#define sys_stat elks_stat +static int elks_stat(int bx,int cx,int dx,int di,int si) +{ + struct stat s; + dbprintf(("stat(%s,%d)\n", ELKS_PTR(char, bx), cx)); + if(stat(ELKS_PTR(char, bx),&s)==-1) + return -1; + squash_stat(&s,cx); + return 0; +} + +#define sys_lstat elks_lstat +static int elks_lstat(int bx,int cx,int dx,int di,int si) +{ + struct stat s; + dbprintf(("lstat(%s,%d)\n", ELKS_PTR(char, bx), cx)); + if(lstat(ELKS_PTR(char, bx),&s)==-1) + return -1; + squash_stat(&s,cx); + return 0; +} + +#define sys_lseek elks_lseek +static int elks_lseek(int bx,int cx,int dx,int di,int si) +{ + long l=ELKS_PEEK(long, cx); + + dbprintf(("lseek(%d,%ld,%d)\n",bx,l,dx)); + l = lseek(bx,l,dx); + if( l < 0 ) return -1; + ELKS_POKE(long, cx, l); + return 0; +} + +#define sys_getpid elks_getpid +static int elks_getpid(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("getpid/getppid()\n")); + ELKS_POKE(unsigned short, bx, getppid()); + return getpid(); +} + +#define sys_setuid elks_setuid +static int elks_setuid(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("setuid(%d)\n",bx)); + return setuid(bx); +} + +#define sys_getuid elks_getuid +static int elks_getuid(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("get[e]uid()\n")); + ELKS_POKE(unsigned short, bx, geteuid()); + return getuid(); +} + +#define sys_alarm elks_alarm +static int elks_alarm(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("alarm(%d)\n",bx<<16|cx)); + return alarm(bx<<16|cx); +} + +#define sys_fstat elks_fstat +static int elks_fstat(int bx,int cx,int dx,int di,int si) +{ + struct stat s; + int err; + dbprintf(("fstat(%d,%d)\n",bx,cx)); + err=fstat(bx,&s); + squash_stat(&s,cx); + return err; +} + +#define sys_pause elks_pause +static int elks_pause(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("pause()\n")); + return pause(); +} + +#define sys_utime elks_utime +static int elks_utime(int bx,int cx,int dx,int di,int si) +{ + unsigned long *up=ELKS_PTR(long, cx); + struct utimbuf u; + u.actime=*up++; + u.modtime=*up; + return utime(ELKS_PTR(char, bx), &u); +} + +#define sys_access elks_access +static int elks_access(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("access(%s,%d)\n",ELKS_PTR(char, bx),cx)); + return access(ELKS_PTR(char, bx),cx); +} + +#define sys_sync elks_sync +static int elks_sync(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("sync()\n")); + sync(); + return 0; +} + +#define sys_kill elks_kill +static int elks_kill(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("kill(%d,%d)\n",bx,cx)); + return kill(bx,cx); +} + +#define sys_pipe elks_pipe +static int elks_pipe(int bx,int cx,int dx,int di,int si) +{ + unsigned short *dp=ELKS_PTR(unsigned short, bx); + int p[2]; + int err=pipe(p); + if(err==-1) + return err; + *dp++=p[0]; + *dp=p[1]; + return 0; +} + +#define sys_times elks_times +static int elks_times(int bx,int cx,int dx,int di,int si) +{ + struct tms t; + long clock_ticks=times(&t); + long *tp=ELKS_PTR(long, bx); + *tp++=t.tms_utime; + *tp++=t.tms_stime; + *tp++=t.tms_cutime; + *tp=t.tms_cstime; + return 0; /* Should be clock_ticks */ +} + +#define sys_setgid elks_setgid +static int elks_setgid(int bx,int cx,int dx,int di,int si) +{ + return setgid(bx); +} + +#define sys_getgid elks_getgid +static int elks_getgid(int bx,int cx,int dx,int di,int si) +{ + ELKS_POKE(unsigned short, bx, getegid()); + return getgid(); +} + +/* + * Exec is fun. The Minix user library builds a complete elks stack image. + * Great except that we need to unpack it all again and do a real exec. If + * its another elks image then our kernel side binary loader will load + * elksemu again and we'll take the Unix args and turn them back into a + * elks stack image. + * + * For now we run elksemu ourselves and do token attempts at binary checking. + * + * Of course with the Patch in the Linux kernel we could just run the exe. + */ +#define sys_exec elks_exec +static int elks_exec(int bx,int cx,int dx,int di,int si) +{ + int fd; + int arg_ct,env_ct; + int ct; + char **argp, **envp; + unsigned short *bp; + unsigned char *base; + unsigned short *tmp; + struct elks_exec_hdr mh; + int is_elks = 1; + + dbprintf(("exec(%s,%d,%d)\n",ELKS_PTR(char, bx), cx, dx)); + + base=ELKS_PTR(unsigned char, cx); + bp=ELKS_PTR(unsigned short, cx+2); + tmp=bp; + + fd=open(ELKS_PTR(char, bx),O_RDONLY); + if(fd==-1) + { errno = ENOENT; return -1; } + if(read(fd, &mh, sizeof(mh))!=sizeof(mh)) + { + close(fd); + errno = ENOEXEC; + return -1; + } + close(fd); + if(mh.hlen!=EXEC_HEADER_SIZE + || (mh.type!=ELKS_COMBID && mh.type!=ELKS_SPLITID)) + is_elks = 0; + + arg_ct = env_ct = 0; + while(*tmp++) + arg_ct++; + while(*tmp++) + env_ct++; + arg_ct+=2; /* elksemu-path progname arg0...argn */ + argp=malloc(sizeof(char *)*(arg_ct+1)); + envp=malloc(sizeof(char *)*(env_ct+1)); + if(!argp||!envp) { errno = ENOMEM; return -1; } + ct=0; + if( is_elks ) + { + argp[0]="/lib/elksemu"; + argp[1]=ELKS_PTR(char, bx); + ct=2; + } + while(*bp) + argp[ct++]=ELKS_PTR(char, cx+ *bp++); + argp[ct]=0; + bp++; + ct=0; + while(*bp) + envp[ct++]=ELKS_PTR(char, cx+ *bp++); + envp[ct]=0; + if( is_elks ) + execve(argp[0],argp,envp); + else + execve(ELKS_PTR(char, bx),argp,envp); + if( errno == ENOEXEC || errno == EACCES ) return -1; + perror("elksemu"); + exit(1); +} + +#define sys_umask elks_umask +static int elks_umask(int bx,int cx,int dx,int di,int si) +{ + return umask(bx); +} + +#define sys_chroot elks_chroot +static int elks_chroot(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("chroot(%s)\n", ELKS_PTR(char, bx))); + return chroot(ELKS_PTR(char, bx)); +} + + +#define sys_fcntl elks_fcntl +static int elks_fcntl(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("fcntl(%d,%d,%d)\n", bx,cx,dx)); + switch(cx) + { + case ELKS_F_GETFD: + return fcntl(bx,F_GETFD,0); + case ELKS_F_GETFL: + return fcntl(bx,F_GETFL,0); + case ELKS_F_DUPFD: + return fcntl(bx,F_DUPFD,dx); + case ELKS_F_SETFD: + return fcntl(bx,F_SETFD,dx); + case ELKS_F_SETFL: + return fcntl(bx,F_SETFL,dx); + /* + * Fixme: Unpack and process elks file locks + */ + case ELKS_F_GETLK: + case ELKS_F_SETLK: + case ELKS_F_SETLKW: + errno = EINVAL; + return -1; + } + errno = EINVAL; + return -1; +} + +#define sys_rename elks_rename +static int elks_rename(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("rename(%s,%s)\n", ELKS_PTR(char, bx), ELKS_PTR(char, cx))); + return rename(ELKS_PTR(char, bx), ELKS_PTR(char, cx)); +} + +#define sys_mkdir elks_mkdir +static int elks_mkdir(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("mkdir(%s,%d)\n", ELKS_PTR(char, bx),cx)); + return mkdir(ELKS_PTR(char, bx),cx); +} + +#define sys_rmdir elks_rmdir +static int elks_rmdir(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("rmdir(%s)\n", ELKS_PTR(char, bx))); + return rmdir(ELKS_PTR(char, bx)); +} + +#define sys_gettimeofday elks_gettimeofday +static int elks_gettimeofday(int bx,int cx,int dx,int di,int si) +{ + struct timeval tv; + struct timezone tz; + int ax; + dbprintf(("gettimeofday(%d,%d)\n",bx,cx)); + + ax = gettimeofday(&tv, &tz); + + if( ax == 0 && bx ) + { + ELKS_POKE(long, bx, tv.tv_sec); + ELKS_POKE(long, bx+4, tv.tv_usec); + } + if( ax == 0 && cx ) + { + ELKS_POKE(short, cx, tz.tz_minuteswest); + ELKS_POKE(short, cx+2, tz.tz_dsttime); + } + return ax?-1:0; +} + +#define sys_settimeofday elks_settimeofday +static int elks_settimeofday(int bx,int cx,int dx,int di,int si) +{ + struct timeval tv, *pv = 0; + struct timezone tz, *pz = 0; + int ax; + dbprintf(("settimeofday(%d,%d)\n",bx,cx)); + + if( bx ) + { + pv = &tv; + tv.tv_sec = ELKS_PEEK(long, bx); + tv.tv_usec = ELKS_PEEK(long, bx+4); + } + if( cx ) + { + pz = &tz; + tz.tz_minuteswest = ELKS_PEEK(short, cx); + tz.tz_dsttime = ELKS_PEEK(short, cx+2); + } + + ax = settimeofday(pv, pz); + return ax?-1:0; +} + +#define sys_nice elks_nice +static int elks_nice(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("nice(%d)\n",bx)); + return nice(bx); +} + +#define sys_symlink elks_symlink +static int elks_symlink(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("symlink(%s,%s)\n", ELKS_PTR(char, bx), ELKS_PTR(char, cx))); + return symlink(ELKS_PTR(char, bx), ELKS_PTR(char, cx)); +} + +#define sys_readlink elks_readlink +static int elks_readlink(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("readlink(%s,%s,%d)\n", + ELKS_PTR(char, bx), + ELKS_PTR(char, cx), + dx)); + return readlink(ELKS_PTR(char, bx), ELKS_PTR(char, cx), dx); +} + +#define sys_ioctl elks_ioctl +static int elks_ioctl(int bx,int cx,int dx,int di,int si) +{ + dbprintf(("ioctl(%d,0x%04x,0x%04x)\n", bx,cx,dx)); + switch((cx>>8)&0xFF) + { + case 'T': return elks_termios(bx,cx,dx,di,si); + default: return elks_enosys(bx,cx,dx,di,si); + } +} + +#define sys_reboot elks_reboot +static int elks_reboot(int bx,int cx,int dx,int di,int si) +{ + errno = EINVAL; + if( bx != 0xfee1 || cx != 0xdead ) return -1; + + switch(dx) + { + /* graceful shutdown, C-A-D off, kill -? 1 */ + case 0: return reboot(0xfee1dead, 672274793, 0); + /* Enable C-A-D */ + case 0xCAD: return reboot(0xfee1dead, 672274793, 0x89abcdef); + /* Time to die! */ + case 0xD1E: return reboot(0xfee1dead, 672274793, 0x1234567); + } + return -1; +} + +/****************************************************************************/ + +static int +elks_opendir(char * dname) +{ + DIR * d; + int rv; + for(rv=0; rv<DIRCOUNT; rv++) + if( dirtab[rv] == 0 ) + break; + if( rv >= DIRCOUNT ) { errno=ENOMEM; return -1; } + d = opendir(dname); + if( d == 0 ) return -1; + dirtab[rv] = d; + return 10000+rv; +} + +static int +elks_readdir(int bx, int cx, int dx) +{ + struct dirent * ent; + + /* Only read _ONE_ _WHOLE_ dirent at a time */ + if( dx != 266 ) + { + errno=EINVAL; return -1; + } + errno = 0; + ent = readdir(dirtab[bx-10000]); + if( ent == 0 ) { if( errno ) { return -1; } else return 0; } + + memcpy(ELKS_PTR(char, cx+10), ent->d_name, ent->d_reclen+1); + ELKS_POKE(long, cx, ent->d_ino); + ELKS_POKE(short, cx+8, ent->d_reclen); + return dx; +} + +static int +elks_closedir(int bx) +{ + bx-=10000; + if( dirtab[bx] ) closedir(dirtab[bx]); + dirtab[bx] = 0; + return 0; +} + +/****************************************************************************/ + +static int elks_termios(int bx,int cx,int dx,int di,int si) +{ + int rv = 0; + switch(cx&0xFF) + { + case 0x01: rv = ioctl(bx, TCGETS, ELKS_PTR(void, dx)); break; + case 0x02: rv = ioctl(bx, TCSETS, ELKS_PTR(void, dx)); break; + case 0x03: rv = ioctl(bx, TCSETSW, ELKS_PTR(void, dx)); break; + case 0x04: rv = ioctl(bx, TCSETSF, ELKS_PTR(void, dx)); break; + + case 0x09: rv = ioctl(bx, TCSBRK, dx); break; + case 0x0A: rv = ioctl(bx, TCXONC, dx); break; + case 0x0B: rv = ioctl(bx, TCFLSH, dx); break; + + default: rv = -1; errno = EINVAL; break; + } + return rv; +} + +/****************************************************************************/ +/* */ +/****************************************************************************/ +#define sys_enosys elks_enosys +static int elks_enosys(int bx,int cx,int dx,int di,int si) +{ + fprintf(stderr, "Function number %d called (%d,%d,%d)\n", + (int)(0xFFFF&elks_cpu.regs.eax), + bx, cx, dx); + errno = ENOSYS; + return -1; +} + +#include "defn_tab.v" +/* * */ + +typedef int (*funcp)(int, int, int, int, int); + +static funcp jump_tbl[] = { +#include "call_tab.v" + elks_enosys +}; + +int elks_syscall(void) +{ + int r, n; + int bx=elks_cpu.regs.ebx&0xFFFF; + int cx=elks_cpu.regs.ecx&0xFFFF; + int dx=elks_cpu.regs.edx&0xFFFF; + int di=elks_cpu.regs.edi&0xFFFF; + int si=elks_cpu.regs.esi&0xFFFF; + + errno=0; + n = (elks_cpu.regs.eax&0xFFFF); + if( n>= 0 && n< sizeof(jump_tbl)/sizeof(funcp) ) + r = (*(jump_tbl[n]))(bx, cx, dx, di, si); + else + return -ENOSYS; + + if(r>=0) + return r; + else + return -errno; +} |