summaryrefslogtreecommitdiff
path: root/elksemu
diff options
context:
space:
mode:
authorRobert de Bath <rdebath@poboxes.com>1996-03-24 17:45:55 +0100
committerLubomir Rintel <lkundrak@v3.sk>2013-10-23 23:29:43 +0200
commitfe22c37817ce338fbbc90b239320248c270957fa (patch)
treed9550410c4a20bdd382fcc58d2d3d7c5e04e5245 /elksemu
parenta7aba15e8efffb1c5d3097656f1a93955a64f01f (diff)
parent42192453ea219b80d0bf9f41e51e36d3d4d0740b (diff)
downloaddev86-fe22c37817ce338fbbc90b239320248c270957fa.tar.gz
Import Dev86-0.0.4.tar.gzv0.0.4
Diffstat (limited to 'elksemu')
-rw-r--r--elksemu/Kernel_patch19
-rw-r--r--elksemu/Makefile29
-rw-r--r--elksemu/V-files.tarbin0 -> 10240 bytes
-rw-r--r--elksemu/Version1
-rw-r--r--elksemu/elks.c258
-rw-r--r--elksemu/elks.h96
-rw-r--r--elksemu/elks_signal.c36
-rw-r--r--elksemu/elks_sys.c723
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
new file mode 100644
index 0000000..c5e6082
--- /dev/null
+++ b/elksemu/V-files.tar
Binary files differ
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;
+}