ref: b9b3baa39ef278fcaf53302031c251432d430acd
parent: a62654ed1b81fb99271d6a7e8ebe7a870ea1099c
author: joe9 <joe9mail@gmail.com>
date: Thu Mar 25 16:44:12 EDT 2021
working 9front amd64 build
--- /dev/null
+++ b/9front/amd64/include/emu.h
@@ -1,0 +1,23 @@
+/*
+ * system- and machine-specific declarations for emu:
+ * floating-point save and restore, signal handling primitive, and
+ * implementation of the current-process variable `up'.
+ */
+
+extern Proc** Xup;
+#define up (*Xup)
+
+typedef struct FPU FPU;
+
+/*
+ * This structure must agree with FPsave and FPrestore asm routines
+ */
+struct FPU
+{
+ /* TODO check this 28 bytes. 28 -> 56? */
+ uchar env[28];
+};
+
+typedef jmp_buf osjmpbuf;
+#define ossetjmp(buf) setjmp(buf)
+
--- /dev/null
+++ b/9front/amd64/include/lib9.h
@@ -1,0 +1,1 @@
+#include "../../include/lib9.h"
--- /dev/null
+++ b/9front/amd64/include/u.h
@@ -1,0 +1,1 @@
+#include "/amd64/include/u.h"
--- /dev/null
+++ b/9front/include/lib9.h
@@ -1,0 +1,14 @@
+#include <u.h>
+typedef usize size_t;
+
+#define Rendez xRendez
+#include <libc.h>
+#undef Rendez
+
+
+/*
+ * Extensions for Inferno to basic libc.h
+ */
+
+#define setbinmode()
+#define USE_FPdbleword
--- /dev/null
+++ b/9front/include/lib9x.h
@@ -1,0 +1,20 @@
+#include <u.h>
+typedef usize size_t;
+
+#define Runeerror xRuneerror
+#define Rendez xRendez
+#include <libc.h>
+#undef Runeerror
+#undef Rendez
+
+
+enum
+{
+ Runeerror = 0x80, /* decoding error in UTF */
+};
+/*
+ * Extensions for Inferno to basic libc.h
+ */
+
+#define setbinmode()
+#define USE_FPdbleword
--- /dev/null
+++ b/emu/9front/asm-386.s
@@ -1,0 +1,33 @@
+
+TEXT tramp(SB),$0
+ MOVL nsp+0(FP), BX /* new stack */
+ MOVL fn+4(FP), CX /* func to exec */
+ MOVL arg+8(FP),DX
+
+ LEAL -8(BX), SP /* new stack */
+ PUSHL DX
+ CALL *CX
+ POPL AX
+
+ PUSHL $0
+ CALL _exits(SB)
+ POPL AX
+ RET
+
+TEXT vstack(SB),$0
+ MOVL arg+0(FP), AX
+ MOVL ustack(SB), SP
+ PUSHL AX
+ CALL exectramp(SB)
+ POPL AX /* dammit ken! */
+ RET
+
+TEXT FPsave(SB), 1, $0
+ MOVL fpu+0(FP), AX
+ FSTENV 0(AX)
+ RET
+
+TEXT FPrestore(SB), 1, $0
+ MOVL fpu+0(FP), AX
+ FLDENV 0(AX)
+ RET
--- /dev/null
+++ b/emu/9front/asm-amd64.s
@@ -1,0 +1,35 @@
+
+TEXT tramp(SB),$0
+ /* RARG has the first argument - new stack */
+ /* even though the first argument is in RARG, the 0(FP) is still filled with some value */
+ /* FP is 64 bytes from SP(?) as there is a SUBQ $0x40, SP on function entry */
+ MOVQ fn+8(FP), CX /* func to exec - second argument */
+ MOVQ arg+16(FP),DX /* argument to the function */
+
+ LEAQ -16(RARG), SP /* new stack */
+ MOVQ DX, RARG
+ PUSHQ RARG /* not sure why I need this, but, using it to balance the POPQ below */
+ CALL *CX
+ POPQ AX
+
+ MOVQ $0, RARG
+ PUSHQ RARG /* not sure why I need this PUSHQ and CALL. Why not just a JMP to _exits() */
+ CALL _exits(SB)
+ POPQ AX
+ RET
+
+TEXT vstack(SB),$0
+ /* MOVL arg+0(FP), AX not needed as the first argument is in RARG */
+ MOVQ ustack(SB), SP
+ PUSHQ RARG /* cannot figure out why I need this. But, the compiler will not compile without this */
+ CALL exectramp(SB)
+ POPQ AX /* dammit ken! */
+ RET
+
+TEXT FPsave(SB), 1, $0
+ FSTENV 0(RARG) /* in amd64, the first argument is passed in RARG */
+ RET
+
+TEXT FPrestore(SB), 1, $0
+ FLDENV 0(RARG)
+ RET
--- /dev/null
+++ b/emu/9front/asm-arm.s
@@ -1,0 +1,32 @@
+/* for VFP */
+#define VMRS(fp, cpu) WORD $(0xeef00a10 | (fp)<<16 | (cpu)<<12) /* FP → arm */
+#define VMSR(cpu, fp) WORD $(0xeee00a10 | (fp)<<16 | (cpu)<<12) /* arm → FP */
+
+#define Fpscr 1
+
+ TEXT tramp(SB), 1, $0
+ MOVW fn+4(FP), R1 /* func to exec */
+ MOVW arg+8(FP), R2 /* argument */
+ SUB $8, R0 /* new stack */
+ MOVW R0, SP
+ MOVW R2, R0
+ BL (R1)
+
+ MOVW $0, R0
+ BL _exits(SB)
+ RET
+
+ TEXT vstack(SB), 1, $0
+ MOVW ustack(SB), SP
+ BL exectramp(SB)
+ RET
+
+ TEXT FPsave(SB), 1, $0
+ VMRS(Fpscr, 1)
+ MOVW R1, 0(R0)
+ RET
+
+ TEXT FPrestore(SB), 1, $0
+ MOVW (R0), R0
+ VMSR(0, Fpscr)
+ RET
--- /dev/null
+++ b/emu/9front/asm-mips.s
@@ -1,0 +1,24 @@
+
+ TEXT tramp(SB), 1, $0
+ ADDU $-8, R1, R3 /* new stack */
+ MOVW 4(FP), R2 /* func to exec */
+ MOVW 8(FP), R1 /* arg to reg */
+ MOVW R3, R29 /* new stack */
+ JAL (R2)
+ MOVW R0, R1
+ JMP _exits(SB)
+
+ TEXT vstack(SB), 1, $0 /* Passes &targ through R1 */
+ MOVW ustack(SB), R29
+ JMP exectramp(SB)
+ RET
+
+ TEXT FPsave(SB), 1, $0
+ MOVW FCR31, R2
+ MOVW R2, 0(R1)
+ RET
+
+ TEXT FPrestore(SB), 1, $0
+ MOVW 0(R1), R2
+ MOVW R2, FCR31
+ RET
--- /dev/null
+++ b/emu/9front/asm-power.s
@@ -1,0 +1,28 @@
+ TEXT tramp(SB), 1, $0
+ ADD $-8, R3, R4 /* new stack */
+ MOVW 4(FP), R5 /* func to exec */
+ MOVW R5, LR
+ MOVW 8(FP), R3 /* arg to reg */
+ MOVW R4, R1 /* new stack */
+ BL (LR)
+ MOVW R0, R3
+ MOVW $_exits(SB), R4
+ MOVW R4, LR
+ BR (LR)
+
+ TEXT vstack(SB), 1, $0 /* Passes &targ through R3 */
+ MOVW ustack(SB), R1
+ MOVW $exectramp(SB), R4
+ MOVW R4, CTR
+ BR (CTR)
+ RETURN
+
+ TEXT FPsave(SB), 1, $0
+ MOVFL FPSCR, F0
+ FMOVD F0, 0(R3)
+ RETURN
+
+ TEXT FPrestore(SB), 1, $0
+ FMOVD 0(R3), F0
+ MOVFL F0, FPSCR
+ RETURN
--- /dev/null
+++ b/emu/9front/asm-sparc.s
@@ -1,0 +1,22 @@
+ TEXT tramp(SB), 1, $0
+ ADD $-8, R7, R3 /* new stack */
+ MOVW 4(FP), R4 /* func to exec */
+ MOVW 8(FP), R7 /* arg to reg */
+ MOVW R3, R1 /* new stack */
+ JMPL (R4)
+ MOVW R0, R7
+ JMPL _exits(SB) /* Leaks the stack in R29 */
+
+ TEXT vstack(SB), 1, $0 /* Passes &targ through R7 */
+ MOVW ustack(SB), R1
+ MOVW $exectramp(SB), R3
+ JMP (R3)
+ RETURN
+
+ TEXT FPsave(SB), 1, $0
+ MOVW FSR, 0(R7)
+ RETURN
+
+ TEXT FPrestore(SB), 1, $0
+ MOVW 0(R7), FSR
+ RETURN
--- /dev/null
+++ b/emu/9front/cmd.c
@@ -1,0 +1,189 @@
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+extern void vstack(void*);
+
+/*
+ * all this is for the benefit of devcmd.
+ * i hope it's grateful.
+ */
+
+typedef struct Targ Targ;
+struct Targ
+{
+ int fd[3]; /* standard input, output and error */
+ int wfd;
+ int* spin;
+ char** args;
+ char* dir;
+ int pid;
+ int nice;
+};
+
+/*
+ * called by vstack once it has moved to
+ * the unshared stack in the new process.
+ */
+void
+exectramp(Targ *t)
+{
+ int *fd, i, nfd;
+ char filename[128], err[ERRMAX], status[2*ERRMAX];
+
+ t->pid = getpid();
+ *t->spin = 0; /* allow parent to proceed: can't just rendezvous: see below */
+ fd = t->fd;
+
+ snprint(filename, sizeof(filename), "#d/%d", t->wfd);
+ t->wfd = open(filename, OWRITE|OCEXEC);
+ /* if it failed, we'll manage */
+
+ nfd = MAXNFD; /* TO DO: should read from /fd */
+ for(i = 0; i < nfd; i++)
+ if(i != fd[0] && i != fd[1] && i != fd[2] && i != t->wfd)
+ close(i);
+
+ if(fd[0] != 0){
+ dup(fd[0], 0);
+ close(fd[0]);
+ }
+ if(fd[1] != 1){
+ dup(fd[1], 1);
+ close(fd[1]);
+ }
+ if(fd[2] != 2){
+ dup(fd[2], 2);
+ close(fd[2]);
+ }
+
+ if(t->dir != nil && chdir(t->dir) < 0){
+ if(t->wfd > 0)
+ fprint(t->wfd, "chdir: %s: %r", t->dir);
+ _exits("bad dir");
+ }
+ if(t->nice)
+ oslopri();
+
+ exec(t->args[0], t->args);
+ err[0] = 0;
+ errstr(err, sizeof(err));
+ if(t->args[0][0] != '/' && t->args[0][0] != '#' &&
+ strncmp(t->args[0], "../", 3) != 0 && strncmp(t->args[0], "./", 2) != 0 &&
+ strlen(t->args[0])+5 < sizeof(filename)){
+ snprint(filename, sizeof(filename), "/bin/%s", t->args[0]);
+ exec(filename, t->args);
+ errstr(err, sizeof(err));
+ }
+ snprint(status, sizeof(status), "%s: can't exec: %s", t->args[0], err);
+ if(t->wfd > 0)
+ write(t->wfd, status, strlen(status));
+ _exits(status);
+}
+
+void*
+oscmd(char **args, int nice, char *dir, int *fd)
+{
+ Targ *t;
+ int spin, *spinptr, fd0[2], fd1[2], fd2[2], wfd[2], n;
+ Dir *d;
+
+ up->genbuf[0] = 0;
+ t = mallocz(sizeof(*t), 1);
+ if(t == nil)
+ return nil;
+ t->args = args;
+ t->dir = dir;
+ t->nice = nice;
+ fd0[0] = fd0[1] = -1;
+ fd1[0] = fd1[1] = -1;
+ fd2[0] = fd2[1] = -1;
+ wfd[0] = wfd[1] = -1;
+ if(dir != nil){
+ d = dirstat(dir);
+ if(d == nil)
+ goto Error;
+ free(d);
+ }
+ if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0)
+ goto Error;
+
+ spinptr = &spin;
+ spin = 1;
+
+ t->fd[0] = fd0[0];
+ t->fd[1] = fd1[1];
+ t->fd[2] = fd2[1];
+ t->wfd = wfd[1];
+ t->spin = spinptr;
+ switch(rfork(RFPROC|RFMEM|RFREND|RFNOTEG|RFFDG|RFNAMEG|RFENVG)) {
+ case -1:
+ goto Error;
+ case 0:
+ /* if child returns first from rfork, its call to vstack replaces ... */
+ vstack(t);
+ /* ... parent's return address from rfork and parent returns here */
+ default:
+ /* if parent returns first from rfork, it comes here */
+ /* can't call anything: on shared stack until child releases spin in exectramp */
+ while(*spinptr)
+ ;
+ break;
+ }
+
+ close(fd0[0]);
+ close(fd1[1]);
+ close(fd2[1]);
+ close(wfd[1]);
+
+ n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1);
+ close(wfd[0]);
+ if(n > 0){
+ close(fd0[1]);
+ close(fd1[0]);
+ close(fd2[0]);
+ up->genbuf[n] = 0;
+ errstr(up->genbuf, sizeof(up->genbuf));
+ free(t);
+ return nil;
+ }
+
+ fd[0] = fd0[1];
+ fd[1] = fd1[0];
+ fd[2] = fd2[0];
+ return t;
+
+Error:
+ errstr(up->genbuf, sizeof(up->genbuf)); /* save the message before close */
+ close(fd0[0]);
+ close(fd0[1]);
+ close(fd1[0]);
+ close(fd1[1]);
+ close(fd2[0]);
+ close(fd2[1]);
+ close(wfd[0]);
+ close(wfd[1]);
+ free(t);
+ errstr(up->genbuf, sizeof(up->genbuf));
+ return nil;
+}
+
+int
+oscmdkill(void *a)
+{
+ Targ *t = a;
+
+ return postnote(PNGROUP, t->pid, "kill");
+}
+
+int
+oscmdwait(void*, char *buf, int n)
+{
+ return await(buf, n);
+}
+
+void
+oscmdfree(void *a)
+{
+ free(a);
+}
--- /dev/null
+++ b/emu/9front/devfs.c
@@ -1,0 +1,365 @@
+/*
+ * Plan 9 file system interface
+ */
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+typedef struct Fsinfo Fsinfo;
+struct Fsinfo
+{
+ int fd;
+ QLock; /* serialise access to offset */
+ ulong offset; /* offset used only for directory reads */
+ Cname* name; /* Plan 9's name for file */
+ Qid rootqid; /* Plan 9's qid for Inferno's root */
+ char* root; /* prefix to strip from all names in diagnostics */
+};
+#define FS(c) ((Fsinfo*)((c)->aux))
+
+char rootdir[MAXROOT] = ROOT;
+
+static void
+fserr(Fsinfo *f)
+{
+ int n;
+ char *p;
+
+ oserrstr(up->env->errstr, ERRMAX);
+ if(f != nil && *up->env->errstr == '\'' && (n = strlen(f->root)) > 1){
+ /* don't reveal full names */
+ if(strncmp(up->env->errstr+1, f->root, n-1) == 0){
+ p = up->env->errstr+1+n;
+ memmove(up->env->errstr+1, p, strlen(p)+1);
+ }
+ }
+ error(up->env->errstr);
+}
+
+static void
+fsfree(Chan *c)
+{
+ cnameclose(FS(c)->name);
+ free(c->aux);
+}
+
+Chan*
+fsattach(char *spec)
+{
+ Chan *c;
+ Dir *d;
+ char *root;
+ Qid rootqid;
+ static int devno;
+ static Lock l;
+
+ if(!emptystr(spec)){
+ if(strcmp(spec, "*") != 0)
+ error(Ebadspec);
+ root = "/";
+ }else
+ root = rootdir;
+
+ d = dirstat(root);
+ if(d == nil)
+ fserr(nil);
+ rootqid = d->qid;
+ free(d);
+
+ c = devattach('U', spec);
+ lock(&l);
+ c->dev = devno++;
+ c->qid = rootqid;
+ unlock(&l);
+ c->aux = smalloc(sizeof(Fsinfo));
+ FS(c)->name = newcname(root);
+ FS(c)->rootqid = rootqid;
+ FS(c)->fd = -1;
+ FS(c)->root = root;
+
+ return c;
+}
+
+Walkqid*
+fswalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ int j, alloc;
+ Walkqid *wq;
+ Dir *dir;
+ char *n;
+ Cname *current, *next;
+ Qid rootqid;
+
+ if(nname > 0)
+ isdir(c); /* do we need this? */
+
+ alloc = 0;
+ current = nil;
+ wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
+ if(waserror()){
+ if(alloc && wq->clone!=nil)
+ cclose(wq->clone);
+ cnameclose(current);
+ free(wq);
+ return nil;
+ }
+ if(nc == nil){
+ nc = devclone(c);
+ nc->type = 0;
+ alloc = 1;
+ }
+ wq->clone = nc;
+
+ rootqid = FS(c)->rootqid;
+ current = FS(c)->name;
+ if(current != nil)
+ incref(¤t->r);
+ for(j=0; j<nname; j++){
+ if(!(nc->qid.type&QTDIR)){
+ if(j==0)
+ error(Enotdir);
+ break;
+ }
+ n = name[j];
+ if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){ /* TO DO: underlying qids aliased */
+ //print("** ufs walk '%s' -> %s\n", current->s, n);
+ next = current;
+ incref(&next->r);
+ next = addelem(current, n);
+ dir = dirstat(next->s);
+ if(dir == nil){
+ cnameclose(next);
+ if(j == 0)
+ error(Enonexist);
+ strcpy(up->env->errstr, Enonexist);
+ break;
+ }
+ nc->qid = dir->qid;
+ free(dir);
+ cnameclose(current);
+ current = next;
+ }
+ wq->qid[wq->nqid++] = nc->qid;
+ }
+// print("** ufs walk '%s'\n", current->s);
+
+ poperror();
+ if(wq->nqid < nname){
+ cnameclose(current);
+ if(alloc)
+ cclose(wq->clone);
+ wq->clone = nil;
+ }else if(wq->clone){
+ /* now attach to our device */
+ nc->aux = smalloc(sizeof(Fsinfo));
+ nc->type = c->type;
+ FS(nc)->rootqid = FS(c)->rootqid;
+ FS(nc)->name = current;
+ FS(nc)->fd = -1;
+ FS(nc)->root = FS(c)->root;
+ }else
+ panic("fswalk: can't happen");
+ return wq;
+}
+
+int
+fsstat(Chan *c, uchar *dp, int n)
+{
+ if(FS(c)->fd >= 0)
+ n = fstat(FS(c)->fd, dp, n);
+ else
+ n = stat(FS(c)->name->s, dp, n);
+ if(n < 0)
+ fserr(FS(c));
+ /* TO DO: change name to / if rootqid */
+ return n;
+}
+
+Chan*
+fsopen(Chan *c, int mode)
+{
+ osenter();
+ FS(c)->fd = open(FS(c)->name->s, mode);
+ osleave();
+ if(FS(c)->fd < 0)
+ fserr(FS(c));
+ c->mode = openmode(mode);
+ c->offset = 0;
+ FS(c)->offset = 0;
+ c->flag |= COPEN;
+ return c;
+}
+
+void
+fscreate(Chan *c, char *name, int mode, ulong perm)
+{
+ Dir *d;
+ Cname *n;
+
+ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+ error(Efilename);
+ n = addelem(newcname(FS(c)->name->s), name);
+ osenter();
+ FS(c)->fd = create(n->s, mode, perm);
+ osleave();
+ if(FS(c)->fd < 0) {
+ cnameclose(n);
+ fserr(FS(c));
+ }
+ d = dirfstat(FS(c)->fd);
+ if(d == nil) {
+ cnameclose(n);
+ close(FS(c)->fd);
+ FS(c)->fd = -1;
+ fserr(FS(c));
+ }
+ c->qid = d->qid;
+ free(d);
+
+ cnameclose(FS(c)->name);
+ FS(c)->name = n;
+
+ c->mode = openmode(mode);
+ c->offset = 0;
+ FS(c)->offset = 0;
+ c->flag |= COPEN;
+}
+
+void
+fsclose(Chan *c)
+{
+ if(c->flag & COPEN){
+ osenter();
+ close(FS(c)->fd);
+ osleave();
+ }
+ /* don't need to check for CRCLOSE, because Plan 9 itself implements ORCLOSE */
+ fsfree(c);
+}
+
+static long
+fsdirread(Chan *c, void *va, long count, vlong offset)
+{
+ long n, r;
+ static char slop[16384];
+
+ if(FS(c)->offset != offset){
+ seek(FS(c)->fd, 0, 0);
+ for(n=0; n<offset;) {
+ r = offset - n;
+ if(r > sizeof(slop))
+ r = sizeof(slop);
+ osenter();
+ r = read(FS(c)->fd, slop, r);
+ osleave();
+ if(r <= 0){
+ FS(c)->offset = n;
+ return 0;
+ }
+ n += r;
+ }
+ FS(c)->offset = offset;
+ }
+ osenter();
+ r = read(FS(c)->fd, va, count);
+ osleave();
+ if(r < 0)
+ return r;
+ FS(c)->offset = offset+r;
+ return r;
+}
+
+long
+fsread(Chan *c, void *va, long n, vlong offset)
+{
+ int r;
+
+ if(c->qid.type & QTDIR){ /* need to maintain offset only for directories */
+ qlock(FS(c));
+ if(waserror()){
+ qunlock(FS(c));
+ nexterror();
+ }
+ r = fsdirread(c, va, n, offset);
+ poperror();
+ qunlock(FS(c));
+ }else{
+ osenter();
+ r = pread(FS(c)->fd, va, n, offset);
+ osleave();
+ }
+ if(r < 0)
+ fserr(FS(c));
+ return r;
+}
+
+long
+fswrite(Chan *c, void *va, long n, vlong offset)
+{
+ int r;
+
+ osenter();
+ r = pwrite(FS(c)->fd, va, n, offset);
+ osleave();
+ if(r < 0)
+ fserr(FS(c));
+ return r;
+}
+
+void
+fsremove(Chan *c)
+{
+ int r;
+
+ if(waserror()){
+ fsfree(c);
+ nexterror();
+ }
+ osenter();
+ r = remove(FS(c)->name->s);
+ osleave();
+ if(r < 0)
+ fserr(FS(c));
+ poperror();
+ fsfree(c);
+}
+
+int
+fswstat(Chan *c, uchar *dp, int n)
+{
+ osenter();
+ if(FS(c)->fd >= 0)
+ n = fwstat(FS(c)->fd, dp, n);
+ else
+ n = wstat(FS(c)->name->s, dp, n);
+ osleave();
+ if(n < 0)
+ fserr(FS(c));
+ return n;
+}
+
+void
+setid(char *name, int owner)
+{
+ if(!owner || iseve())
+ kstrdup(&up->env->user, name);
+}
+
+Dev fsdevtab = {
+ 'U',
+ "fs",
+
+ devinit,
+ fsattach,
+ fswalk,
+ fsstat,
+ fsopen,
+ fscreate,
+ fsclose,
+ fsread,
+ devbread,
+ fswrite,
+ devbwrite,
+ fsremove,
+ fswstat
+};
--- /dev/null
+++ b/emu/9front/devsrv9.c
@@ -1,0 +1,395 @@
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+typedef struct Srv Srv;
+struct Srv
+{
+ Ref;
+ int fd; /* fd for opened /srv or /srv/X, or -1 */
+ int sfd; /* fd for created /srv entry or -1 */
+ uvlong path;
+ Srv *next;
+};
+
+static QLock srv9lk;
+static Srv *srv9;
+static Srv *srvroot;
+
+static char*
+srvname(Chan *c)
+{
+ char *p;
+
+ p = strrchr(c->name->s, '/');
+ if(p == nil)
+ return "";
+ return p+1;
+}
+
+static Srv*
+srvget(uvlong path)
+{
+ Srv *sv;
+
+ qlock(&srv9lk);
+ for(sv = srv9; sv != nil; sv = sv->next)
+ if(sv->path == path){
+ incref(sv);
+ qunlock(&srv9lk);
+ return sv;
+ }
+ sv = smalloc(sizeof(*sv));
+ sv->path = path;
+ sv->fd = -1;
+ sv->sfd = -1;
+ sv->ref = 1;
+ sv->next = srv9;
+ srv9 = sv;
+ qunlock(&srv9lk);
+ return sv;
+}
+
+static void
+srvput(Srv *sv)
+{
+ Srv **l;
+ int fd, sfd;
+
+ if(sv != nil && decref(sv) == 0){
+ qlock(&srv9lk);
+ for(l = &srv9; *l != nil; l = &(*l)->next)
+ if(*l == sv){
+ *l = sv->next;
+ break;
+ }
+ qunlock(&srv9lk);
+ fd = sv->fd;
+ sfd = sv->sfd;
+ free(sv);
+ if(sfd >= 0){
+ osenter();
+ close(sfd);
+ osleave();
+ }
+ if(fd >= 0){
+ osenter();
+ close(fd);
+ osleave();
+ }
+ }
+}
+
+static void
+srv9init(void)
+{
+ Srv *sv;
+
+ sv = mallocz(sizeof(*srvroot), 1);
+ sv->path = 0;
+ sv->fd = -1;
+ sv->ref = 1; /* subsequently never reaches zero */
+ srvroot = srv9 = sv;
+}
+
+static Chan*
+srv9attach(char *spec)
+{
+ Chan *c;
+
+ if(*spec)
+ error(Ebadspec);
+ c = devattach(L'₪', spec);
+ if(c != nil){
+ incref(srvroot);
+ c->aux = srvroot;
+ }
+ return c;
+}
+
+static Walkqid*
+srv9walk(Chan *c, Chan *nc, char **name, int nname)
+{
+ int j, alloc;
+ Walkqid *wq;
+ char *n;
+ Dir *d;
+
+ if(nname > 0)
+ isdir(c);
+
+ alloc = 0;
+ wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
+ if(waserror()){
+ if(alloc)
+ cclose(wq->clone);
+ free(wq);
+ return nil;
+ }
+ if(nc == nil){
+ nc = devclone(c);
+ nc->type = 0; /* device doesn't know about this channel yet */
+ alloc = 1;
+ }
+ wq->clone = nc;
+
+ for(j=0; j<nname; j++){
+ if(!(nc->qid.type&QTDIR)){
+ if(j==0)
+ error(Enotdir);
+ break;
+ }
+ n = name[j];
+ if(strcmp(n, ".") != 0 && strcmp(n, "..") != 0){
+ snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", n);
+ d = dirstat(up->genbuf);
+ if(d == nil){
+ if(j == 0)
+ error(Enonexist);
+ kstrcpy(up->env->errstr, Enonexist, ERRMAX);
+ break;
+ }
+ nc->qid = d->qid;
+ free(d);
+ }
+ wq->qid[wq->nqid++] = nc->qid;
+ }
+ poperror();
+ if(wq->nqid < nname){
+ if(alloc)
+ cclose(wq->clone);
+ wq->clone = nil;
+ }else{
+ /* attach cloned channel to device */
+ wq->clone->type = c->type;
+ if(wq->clone != c)
+ nc->aux = srvget(nc->qid.path);
+ }
+ return wq;
+}
+
+static int
+srv9stat(Chan *c, uchar *db, int n)
+{
+ Srv *sv;
+ Dir d;
+
+ if(c->qid.type & QTDIR){
+ devdir(c, c->qid, "#₪", 0, eve, 0775, &d);
+ n = convD2M(&d, db, n);
+ if(n == 0)
+ error(Eshortstat);
+ return n;
+ }
+ sv = c->aux;
+ if(sv->fd >= 0){
+ osenter();
+ n = fstat(sv->fd, db, n);
+ osleave();
+ }else{
+ osenter();
+ n = stat(srvname(c), db, n);
+ osleave();
+ }
+ return n;
+}
+
+static Chan*
+srv9open(Chan *c, int omode)
+{
+ Srv *sv;
+ char *args[10];
+ int fd[2], i, ifd, is9p;
+ Dir *d;
+
+ sv = c->aux;
+ if(c->qid.type == QTDIR){
+ osenter();
+ sv->fd = open("/srv", omode);
+ osleave();
+ if(sv->fd < 0)
+ oserror();
+ c->mode = omode;
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+ }
+
+ if(omode&OTRUNC || openmode(omode) != ORDWR)
+ error(Eperm);
+ if(sv->fd < 0){
+ snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", srvname(c));
+
+ /* check permission */
+ osenter();
+ ifd = open(up->genbuf, omode);
+ osleave();
+ if(ifd < 0)
+ oserror();
+ osenter();
+ d = dirfstat(ifd);
+ is9p = d != nil && d->qid.type & QTMOUNT;
+ free(d);
+ osleave();
+
+ if(is9p){
+ close(ifd);
+
+ /* spawn exportfs */
+ args[0] = "exportfs";
+ args[1] = "-S";
+ args[2] = up->genbuf;
+ args[3] = nil;
+ if(pipe(fd) < 0)
+ oserror();
+ /* TO DO: without RFMEM there's a copy made of each page touched by any kproc until the exec */
+ switch(rfork(RFPROC|RFNOWAIT|RFREND|RFFDG|RFNAMEG|RFENVG)){ /* no sharing except NOTEG */
+ case -1:
+ oserrstr(up->genbuf, sizeof(up->genbuf));
+ close(fd[0]);
+ close(fd[1]);
+ error(up->genbuf);
+ case 0:
+ for(i=3; i<MAXNFD; i++)
+ if(i != fd[1])
+ close(i);
+ dup(fd[1], 0);
+ if(fd[0] != 0)
+ close(fd[0]);
+ dup(0, 1);
+ exec("/bin/exportfs", args);
+ exits("exportfs failed");
+ default:
+ sv->fd = fd[0];
+ close(fd[1]);
+ break;
+ }
+ }else
+ sv->fd = ifd;
+ }
+
+ c->mode = ORDWR;
+ c->offset = 0;
+ c->flag |= COPEN;
+ return c;
+}
+
+static void
+srv9close(Chan *c)
+{
+ srvput(c->aux);
+}
+
+static long
+srv9read(Chan *c, void *va, long n, vlong off)
+{
+ Srv *sv;
+
+ sv = c->aux;
+ osenter();
+ n = pread(sv->fd, va, n, off);
+ osleave();
+ if(n < 0)
+ oserror();
+ return n;
+}
+
+static long
+srv9write(Chan *c, void *va, long n, vlong off)
+{
+ Srv *sv;
+
+ sv = c->aux;
+ osenter();
+ n = pwrite(sv->fd, va, n, off);
+ osleave();
+ if(n == 0)
+ error(Ehungup);
+ if(n < 0)
+ oserror();
+ return n;
+}
+
+static void
+srv9create(Chan *c, char *name, int omode, ulong perm)
+{
+ Srv *sv;
+ int sfd, fd[2];
+ vlong path;
+ Dir *d;
+
+ if(openmode(omode) != ORDWR)
+ error(Eperm);
+
+ if(pipe(fd) < 0)
+ oserror();
+ if(waserror()){
+ close(fd[0]);
+ close(fd[1]);
+ nexterror();
+ }
+
+ snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", name);
+ osenter();
+ sfd = create(up->genbuf, OWRITE|ORCLOSE, perm);
+ osleave();
+ if(sfd < 0)
+ oserror();
+ if(waserror()){
+ close(sfd);
+ nexterror();
+ }
+ osenter();
+ if(fprint(sfd, "%d", fd[1]) < 0){
+ osleave();
+ oserror();
+ }
+ d = dirfstat(sfd);
+ osleave();
+ if(d != nil){
+ path = d->qid.path;
+ free(d);
+ }else
+ oserror();
+
+ poperror();
+ poperror();
+ close(fd[1]);
+
+ if(waserror()){
+ close(sfd);
+ close(fd[0]);
+ nexterror();
+ }
+ sv = srvget(path);
+ sv->fd = fd[0];
+ sv->sfd = sfd;
+ poperror();
+
+ srvput((Srv*)c->aux);
+ c->qid.type = QTFILE;
+ c->qid.path = path;
+ c->aux = sv;
+ c->flag |= COPEN;
+ c->mode = ORDWR;
+ c->offset = 0;
+}
+
+Dev srv9devtab = {
+ L'₪',
+ "srv9",
+
+ srv9init,
+ srv9attach,
+ srv9walk,
+ srv9stat,
+ srv9open,
+ srv9create, /* TO DO */
+ srv9close,
+ srv9read,
+ devbread,
+ srv9write,
+ devbwrite,
+ devremove, /* TO DO */
+ devwstat, /* TO DO */
+};
--- /dev/null
+++ b/emu/9front/emu
@@ -1,0 +1,114 @@
+dev
+ root
+ cons
+ env
+ mnt
+ pipe
+ prog
+ prof
+ srv
+ dup
+ ssl
+ cap
+ fs
+ cmd cmd
+ indir
+# sign
+
+ draw win
+ pointer
+
+ dynld
+ mem
+ srv9
+
+# ip and eia are simply bound in from Plan 9
+
+lib
+ interp
+ tk
+ freetype
+ math
+ draw
+
+ memlayer
+ memdraw
+ keyring
+ sec
+ mp
+ dynld
+ 9
+
+link
+
+mod
+ sys
+ draw
+
+ tk
+ math
+# srv not used on Plan 9
+ keyring
+ crypt
+ ipints
+ loader
+ freetype
+
+port
+ alloc
+ cache
+ chan
+ dev
+ devtab
+
+ dial
+ dis
+ discall
+ env
+ error
+ errstr
+ exception
+ exportfs
+ exptab
+ inferno
+ latin1
+ main
+ parse
+ pgrp
+ proc
+ qio
+ random
+ sysfile
+ uqid
+
+code
+
+init
+ emuinit
+
+root
+ /chan /
+ /dev /
+ /fd /
+ /prog /
+ /prof /
+ /net /
+ /net.alt /
+ /nvfs /
+ /env /
+ /root /
+ /srv /
+# /tmp /
+# /dis
+# /env
+# /n
+# /net
+# /nvfs /
+# /prog
+# /icons
+# /osinit.dis
+# /dis/emuinit.dis
+# /dis/lib/auth.dis
+# /dis/lib/ssl.dis
+# /n/local /
--- /dev/null
+++ b/emu/9front/mkfile
@@ -1,0 +1,45 @@
+SYSTARG=9front
+OBJTYPE=$objtype
+<../../mkconfig
+
+#Configurable parameters
+
+CONF=emu #default configuration
+CONFLIST=emu
+CLEANCONFLIST=
+
+INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed
+
+#end configurable parameters
+
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system
+
+<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS
+
+OBJ=\
+ asm-$OBJTYPE.$O\
+ os.$O\
+ $CONF.root.$O\
+ $DEVS\
+ $PORT\
+
+
+HFILES=\
+
+CFLAGS='-DROOT="'$ROOT'"' -DEMU -I. -I../port -I$ROOT/$SYSTARG/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp $CTHREADFLAGS $CFLAGS $EMUOPTIONS
+KERNDATE=`{$NDATE}
+
+default:V: $O.$CONF
+
+<../port/portmkfile
+
+$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBFILES
+ $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c
+ $LD -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS
+
+safeinstall:V: $O.$CONF
+ mv $INSTALLDIR/$CONF $INSTALLDIR/$CONF.`{date -n}
+ cp $O.$CONF $INSTALLDIR/$CONF
+
+install:V: $O.$CONF
+ cp $O.$CONF $INSTALLDIR/$CONF
--- /dev/null
+++ b/emu/9front/os.c
@@ -1,0 +1,428 @@
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+enum
+{
+ KSTACK = 16*1024,
+ DELETE = 0x7F,
+};
+
+Proc **Xup;
+
+extern void killrefresh(void);
+extern void tramp(char*, void (*)(void*), void*);
+
+extern int usenewwin;
+
+int *ustack; /* address on unshared stack: see vstack in asm*.s */
+extern int dflag;
+char *hosttype = "Plan9";
+char *cputype;
+
+void
+osblock(void)
+{
+ rendezvous(up, nil);
+}
+
+void
+osready(Proc *p)
+{
+ rendezvous(p, nil);
+}
+
+void
+pexit(char *msg, int)
+{
+ Osenv *e;
+
+ USED(msg);
+
+ lock(&procs.l);
+ if(up->prev)
+ up->prev->next = up->next;
+ else
+ procs.head = up->next;
+
+ if(up->next)
+ up->next->prev = up->prev;
+ else
+ procs.tail = up->prev;
+ unlock(&procs.l);
+
+/* print("pexit: %s: %s\n", up->text, msg); /**/
+ e = up->env;
+ if(e != nil) {
+ closefgrp(e->fgrp);
+ closepgrp(e->pgrp);
+ closeegrp(e->egrp);
+ closesigs(e->sigs);
+ }
+ free(e->user);
+ free(up->prog);
+ up->prog = nil;
+ up->type = Moribund;
+ longjmp(up->privstack, 1);
+}
+
+int
+kproc1(char *name, void (*func)(void*), void *arg, int flags)
+{
+ int pid;
+ Proc *p;
+ Pgrp *pg;
+ Fgrp *fg;
+ Egrp *eg;
+
+ p = newproc();
+ if(p == nil)
+ panic("kproc: no memory");
+ p->kstack = mallocz(KSTACK, 0);
+ if(p->kstack == nil)
+ panic("kproc: no memory");
+
+ if(flags & KPDUPPG) {
+ pg = up->env->pgrp;
+ incref(&pg->r);
+ p->env->pgrp = pg;
+ }
+ if(flags & KPDUPFDG) {
+ fg = up->env->fgrp;
+ incref(&fg->r);
+ p->env->fgrp = fg;
+ }
+ if(flags & KPDUPENVG) {
+ eg = up->env->egrp;
+ incref(&eg->r);
+ p->env->egrp = eg;
+ }
+
+ p->env->uid = up->env->uid;
+ p->env->gid = up->env->gid;
+ kstrdup(&p->env->user, up->env->user);
+
+ strcpy(p->text, name);
+
+ p->func = func;
+ p->arg = arg;
+
+ lock(&procs.l);
+ if(procs.tail != nil) {
+ p->prev = procs.tail;
+ procs.tail->next = p;
+ }
+ else {
+ procs.head = p;
+ p->prev = nil;
+ }
+ procs.tail = p;
+ unlock(&procs.l);
+
+ /*
+ * switch back to the unshared stack to do the fork
+ * only the parent returns from kproc
+ */
+ up->kid = p;
+ up->kidsp = p->kstack;
+ pid = setjmp(up->sharestack);
+ if(pid == 0)
+ longjmp(up->privstack, 1);
+ return pid;
+}
+
+void
+kproc(char *name, void (*func)(void*), void *arg, int flags)
+{
+ kproc1(name, func, arg, flags);
+}
+
+void
+traphandler(void *reg, char *msg)
+{
+ int intwait;
+
+ intwait = up->intwait;
+ up->intwait = 0;
+ /* Ignore pipe writes from devcmd */
+ if(strstr(msg, "write on closed pipe") != nil)
+ noted(NCONT);
+
+ if(sflag) {
+ if(intwait && strcmp(msg, Eintr) == 0)
+ noted(NCONT);
+ else
+ noted(NDFLT);
+ }
+ if(intwait == 0)
+ disfault(reg, msg);
+ noted(NCONT);
+}
+
+int
+readfile(char *path, char *buf, int n)
+{
+ int fd;
+
+ fd = open(path, OREAD);
+ if(fd >= 0) {
+ n = read(fd, buf, n-1);
+ if(n > 0) /* both calls to readfile() have a ``default'' */
+ buf[n] = '\0';
+ close(fd);
+ return n;
+ }
+ return 0;
+}
+
+static void
+dobinds(void)
+{
+ char dir[MAXROOT+9];
+
+ snprint(dir, sizeof(dir), "%s/net", rootdir);
+ bind("/net", dir, MREPL);
+
+ snprint(dir, sizeof(dir), "%s/net.alt", rootdir);
+ bind("/net.alt", dir, MREPL);
+
+ snprint(dir, sizeof(dir), "%s/dev", rootdir);
+ bind("#t", dir, MAFTER);
+ bind("#A", dir, MAFTER);
+}
+
+void
+libinit(char *imod)
+{
+ char *sp;
+ Proc *xup, *p;
+ int fd, n, pid;
+ char nbuf[64];
+
+ xup = nil;
+ Xup = &xup;
+
+ /*
+ * setup personality
+ */
+ if(readfile("/dev/user", nbuf, sizeof nbuf))
+ kstrdup(&eve, nbuf);
+ if(readfile("/dev/sysname", nbuf, sizeof nbuf))
+ kstrdup(&ossysname, nbuf);
+ if(readfile("/env/cputype", nbuf, sizeof nbuf))
+ kstrdup(&cputype, nbuf);
+
+ /*
+ * guess at a safe stack for vstack
+ */
+ ustack = &fd;
+
+ rfork(RFNAMEG|RFREND);
+
+ if(!dflag){
+ fd = open("/dev/consctl", OWRITE);
+ if(fd < 0)
+ fprint(2, "libinit: open /dev/consctl: %r\n");
+ n = write(fd, "rawon", 5);
+ if(n != 5)
+ fprint(2, "keyboard rawon (n=%d, %r)\n", n);
+ }
+
+ osmillisec(); /* set the epoch */
+ dobinds();
+
+ notify(traphandler);
+
+ /*
+ * dummy up a up and stack so the first proc
+ * calls emuinit after setting up his private jmp_buf
+ */
+ p = newproc();
+ p->kstack = mallocz(KSTACK, 0);
+ if(p == nil || p->kstack == nil)
+ panic("libinit: no memory");
+ sp = p->kstack;
+ p->func = emuinit;
+ p->arg = imod;
+
+ /*
+ * set up a stack for forking kids on separate stacks.
+ * longjmp back here from kproc.
+ */
+ while(setjmp(p->privstack)){
+ if(up->type == Moribund){
+ free(up->kstack);
+ free(up);
+ _exits("");
+ }
+ p = up->kid;
+ sp = up->kidsp;
+ up->kid = nil;
+ switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
+ case 0:
+ /*
+ * send the kid around the loop to set up his private jmp_buf
+ */
+ break;
+ default:
+ /*
+ * parent just returns to his shared stack in kproc
+ */
+ longjmp(up->sharestack, pid);
+ panic("longjmp failed");
+ }
+ }
+
+ /*
+ * you get here only once per Proc
+ * go to the shared memory stack
+ */
+ up = p;
+ up->pid = up->sigid = getpid();
+ tramp(sp+KSTACK, up->func, up->arg);
+ panic("tramp returned");
+}
+
+void
+oshostintr(Proc *p)
+{
+ postnote(PNPROC, p->sigid, Eintr);
+}
+
+void
+oslongjmp(void *regs, osjmpbuf env, int val)
+{
+ if(regs != nil)
+ notejmp(regs, env, val);
+ else
+ longjmp(env, val);
+}
+
+void
+osreboot(char*, char**)
+{
+}
+
+void
+cleanexit(int x)
+{
+ USED(x);
+ killrefresh();
+ postnote(PNGROUP, getpid(), "interrupt");
+ exits("interrupt");
+}
+
+int
+readkbd(void)
+{
+ int n;
+ char buf[1];
+
+ n = read(0, buf, sizeof(buf));
+ if(n < 0)
+ fprint(2, "emu: keyboard read error: %r\n");
+ if(n <= 0)
+ pexit("keyboard", 0);
+ switch(buf[0]) {
+ case DELETE:
+ cleanexit(0);
+ case '\r':
+ buf[0] = '\n';
+ }
+ return buf[0];
+}
+
+static vlong
+b2v(uchar *p)
+{
+ int i;
+ vlong v;
+
+ v = 0;
+ for(i=0; i<sizeof(uvlong); i++)
+ v = (v<<8)|p[i];
+ return v;
+}
+
+vlong
+nsec(void)
+{
+ int n;
+ static int nsecfd = -1;
+ uchar buf[sizeof(uvlong)];
+
+ if(nsecfd < 0){
+ nsecfd = open("/dev/bintime", OREAD|OCEXEC); /* never closed */
+ if(nsecfd<0){
+ fprint(2,"can't open /dev/bintime: %r\n");
+ return 0;
+ }
+ }
+ n = read(nsecfd, buf, sizeof(buf));
+ if(n!=sizeof(buf)) {
+ fprint(2,"read err on /dev/bintime: %r\n");
+ return 0;
+ }
+ return b2v(buf);
+}
+
+long
+osmillisec(void)
+{
+ static vlong nsec0 = 0;
+
+ if(nsec0 == 0){
+ nsec0 = nsec();
+ return 0;
+ }
+ return (nsec()-nsec0)/1000000;
+}
+
+/*
+ * Return the time since the epoch in microseconds
+ * The epoch is defined at 1 Jan 1970
+ */
+vlong
+osusectime(void)
+{
+ return nsec()/1000;
+}
+
+int
+osmillisleep(ulong milsec)
+{
+ sleep(milsec);
+ return 0;
+}
+
+int
+limbosleep(ulong milsec)
+{
+ return osmillisleep(milsec);
+}
+
+void
+osyield(void)
+{
+ sleep(0);
+}
+
+void
+ospause(void)
+{
+ for(;;)
+ sleep(1000000);
+}
+
+void
+oslopri(void)
+{
+ int fd;
+ char buf[32];
+
+ snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
+ if((fd = open(buf, OWRITE)) >= 0){
+ fprint(fd, "pri 8");
+ close(fd);
+ }
+}
--- /dev/null
+++ b/emu/9front/win.c
@@ -1,0 +1,566 @@
+#include "dat.h"
+#include "fns.h"
+#include "kernel.h"
+#include "error.h"
+
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "keyboard.h"
+
+enum
+{
+ Margin = 4,
+ Lsize = 100,
+};
+
+extern Memimage *screenimage;
+
+extern int kproc1(char*, void (*)(void*), void*, int);
+
+static ulong* attachwindow(Rectangle*, ulong*, int*, int*);
+
+static void plan9readmouse(void*);
+static void plan9readkeybd(void*);
+static int mapspecials(char *s1, char *s2, int *n);
+
+int usenewwin = 1;
+int kbdiscons;
+static int truedepth;
+
+static int datafd;
+static int ctlfd;
+static int mousefd = -1;
+static int keybdfd;
+static int mousepid = -1;
+static int keybdpid = -1;
+static int cursfd;
+static char winname[64];
+
+/* Following updated by attachwindow() asynchronously */
+static QLock ql;
+static Rectangle tiler;
+static ulong* data;
+static uchar* loadbuf;
+static int cursfd;
+static int imageid;
+static Rectangle imager;
+static uchar *chunk;
+static int chunksize;
+static int dispbufsize;
+
+#define NINFO 12*12
+#define HDR 21
+
+
+void
+killrefresh(void)
+{
+ if(mousepid < 0)
+ return;
+ close(mousefd);
+ close(ctlfd);
+ close(datafd);
+ postnote(PNPROC, mousepid, Eintr);
+ postnote(PNPROC, keybdpid, Eintr);
+}
+
+uchar*
+attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
+{
+ int fd;
+ char *p, buf[128], info[NINFO+1];
+
+ if(usenewwin){
+ p = getenv("wsys");
+ if(p == nil)
+ return nil;
+
+ fd = open(p, ORDWR);
+ if(fd < 0) {
+ fprint(2, "attachscreen: can't open window manager: %r\n");
+ return nil;
+ }
+ sprint(buf, "new -dx %d -dy %d", Xsize+2*Margin, Ysize+2*Margin);
+ if(mount(fd, -1, "/mnt/wsys", MREPL, buf) < 0) {
+ fprint(2, "attachscreen: can't mount window manager: %r\n");
+ return nil;
+ }
+ if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){
+ fprint(2, "attachscreen: can't bind /mnt/wsys before /dev: %r\n");
+ return nil;
+ }
+ }
+
+ cursfd = open("/dev/cursor", OWRITE);
+ if(cursfd < 0) {
+ fprint(2, "attachscreen: open cursor: %r\n");
+ return nil;
+ }
+
+ /* Set up graphics window console (chars->gkbdq) */
+ keybdfd = open("/dev/cons", OREAD);
+ if(keybdfd < 0) {
+ fprint(2, "attachscreen: open keyboard: %r\n");
+ return nil;
+ }
+ mousefd = open("/dev/mouse", ORDWR);
+ if(mousefd < 0){
+ fprint(2, "attachscreen: can't open mouse: %r\n");
+ return nil;
+ }
+ if(usenewwin || 1){
+ fd = open("/dev/consctl", OWRITE);
+ if(fd < 0)
+ fprint(2, "attachscreen: open /dev/consctl: %r\n");
+ if(write(fd, "rawon", 5) != 5)
+ fprint(2, "attachscreen: write /dev/consctl: %r\n");
+ }
+
+ /* Set up graphics files */
+ ctlfd = open("/dev/draw/new", ORDWR);
+ if(ctlfd < 0){
+ fprint(2, "attachscreen: can't open graphics control file: %r\n");
+ return nil;
+ }
+ if(read(ctlfd, info, sizeof info) < NINFO){
+ close(ctlfd);
+ fprint(2, "attachscreen: can't read graphics control file: %r\n");
+ return nil;
+ }
+ sprint(buf, "/dev/draw/%d/data", atoi(info+0*12));
+ datafd = open(buf, ORDWR|OCEXEC);
+ if(datafd < 0){
+ close(ctlfd);
+ fprint(2, "attachscreen: can't read graphics data file: %r\n");
+ return nil;
+ }
+ dispbufsize = iounit(datafd);
+ if(dispbufsize <= 0)
+ dispbufsize = 8000;
+ if(dispbufsize < 512){
+ close(ctlfd);
+ close(datafd);
+ fprint(2, "attachscreen: iounit %d too small\n", dispbufsize);
+ return nil;
+ }
+ chunksize = dispbufsize - 64;
+
+ if(attachwindow(r, chan, d, width) == nil){
+ close(ctlfd);
+ close(datafd);
+ return nil;
+ }
+
+ mousepid = kproc1("readmouse", plan9readmouse, nil, 0);
+ keybdpid = kproc1("readkbd", plan9readkeybd, nil, 0);
+
+ fd = open("/dev/label", OWRITE);
+ if(fd >= 0){
+ snprint(buf, sizeof(buf), "inferno %d", getpid());
+ write(fd, buf, strlen(buf));
+ close(fd);
+ }
+
+ *softscreen = 1;
+ return (uchar*)data;
+}
+
+static ulong*
+attachwindow(Rectangle *r, ulong *chan, int *d, int *width)
+{
+ int n, fd, nb;
+ char buf[256];
+ uchar ubuf[128];
+ ulong imagechan;
+
+ /*
+ * Discover name of window
+ */
+ fd = open("/mnt/wsys/winname", OREAD);
+ if(fd<0 || (n=read(fd, winname, sizeof winname))<=0){
+ fprint(2, "attachwindow: can only run inferno under rio, not stand-alone\n");
+ return nil;
+ }
+ close(fd);
+ /*
+ * If had previous window, release it
+ */
+ if(imageid > 0){
+ ubuf[0] = 'f';
+ BPLONG(ubuf+1, imageid);
+ if(write(datafd, ubuf, 1+4) != 1+4)
+ fprint(2, "attachwindow: cannot free old window: %r\n");
+ }
+ /*
+ * Allocate image pointing to window, and discover its ID
+ */
+ ubuf[0] = 'n';
+ ++imageid;
+ BPLONG(ubuf+1, imageid);
+ ubuf[5] = n;
+ memmove(ubuf+6, winname, n);
+ if(write(datafd, ubuf, 6+n) != 6+n){
+ fprint(2, "attachwindow: cannot bind %d to window id '%s': %r\n", imageid, winname);
+ return nil;
+ }
+ if(read(ctlfd, buf, sizeof buf) < 12*12){
+ fprint(2, "attachwindow: cannot read window id: %r\n");
+ return nil;
+ }
+ imagechan = strtochan(buf+2*12);
+ truedepth = chantodepth(imagechan);
+ if(truedepth == 0){
+ fprint(2, "attachwindow: cannot handle window depth specifier %.12s\n", buf+2*12);
+ return nil;
+ }
+
+ /*
+ * Report back
+ */
+ if(chan != nil)
+ *chan = imagechan;
+ if(d != nil)
+ *d = chantodepth(imagechan);
+ nb = 0;
+ if(r != nil){
+ Xsize = atoi(buf+6*12)-atoi(buf+4*12)-2*Margin;
+ Ysize = atoi(buf+7*12)-atoi(buf+5*12)-2*Margin;
+ r->min.x = 0;
+ r->min.y = 0;
+ r->max.x = Xsize;
+ r->max.y = Ysize;
+ nb = bytesperline(*r, truedepth);
+ data = malloc(nb*Ysize);
+ loadbuf = malloc(nb*Lsize+1);
+ chunk = malloc(HDR+chunksize+5); /* +5 for flush (1 old, 5 new) */
+ }
+ imager.min.x = atoi(buf+4*12);
+ imager.min.y = atoi(buf+5*12);
+ imager.max.x = atoi(buf+6*12);
+ imager.max.y = atoi(buf+7*12);
+
+ if(width != nil)
+ *width = nb/4;
+
+ tiler.min.x = atoi(buf+4*12)+Margin;
+ tiler.min.y = atoi(buf+5*12)+Margin;
+ tiler.max.x = atoi(buf+6*12)-Margin;
+ tiler.max.y = atoi(buf+7*12)-Margin;
+
+ return data;
+}
+
+static int
+plan9loadimage(Rectangle r, uchar *data, int ndata)
+{
+ long dy;
+ int n, bpl;
+
+ if(!rectinrect(r, imager)){
+ werrstr("loadimage: bad rectangle");
+ return -1;
+ }
+ bpl = bytesperline(r, truedepth);
+ n = bpl*Dy(r);
+ if(n > ndata){
+ werrstr("loadimage: insufficient data");
+ return -1;
+ }
+ ndata = 0;
+ while(r.max.y > r.min.y){
+ dy = r.max.y - r.min.y;
+ if(dy*bpl> chunksize)
+ dy = chunksize/bpl;
+ n = dy*bpl;
+ chunk[0] = 'y';
+ BPLONG(chunk+1, imageid);
+ BPLONG(chunk+5, r.min.x);
+ BPLONG(chunk+9, r.min.y);
+ BPLONG(chunk+13, r.max.x);
+ BPLONG(chunk+17, r.min.y+dy);
+ memmove(chunk+21, data, n);
+ ndata += n;
+ data += n;
+ r.min.y += dy;
+ n += 21;
+ if(r.min.y >= r.max.y) /* flush to screen */
+ chunk[n++] = 'v';
+ if(write(datafd, chunk, n) != n)
+ return -1;
+ }
+ return ndata;
+}
+
+static void
+_flushmemscreen(Rectangle r)
+{
+ int n, dy, l;
+ Rectangle rr;
+
+ if(data == nil || loadbuf == nil || chunk==nil)
+ return;
+ if(!rectclip(&r, Rect(0, 0, Xsize, Ysize)))
+ return;
+ if(!rectclip(&r, Rect(0, 0, Dx(tiler), Dy(tiler))))
+ return;
+ if(Dx(r)<=0 || Dy(r)<=0)
+ return;
+ l = bytesperline(r, truedepth);
+ while(r.min.y < r.max.y){
+ dy = Dy(r);
+ if(dy > Lsize)
+ dy = Lsize;
+ rr = r;
+ rr.max.y = rr.min.y+dy;
+ n = unloadmemimage(screenimage, rr, loadbuf, l*dy);
+ /* offset from (0,0) to window */
+ rr.min.x += tiler.min.x;
+ rr.min.y += tiler.min.y;
+ rr.max.x += tiler.min.x;
+ rr.max.y += tiler.min.y;
+ if(plan9loadimage(rr, loadbuf, n) != n)
+ fprint(2, "flushmemscreen: %d bytes: %r\n", n);
+ r.min.y += dy;
+ }
+}
+
+void
+flushmemscreen(Rectangle r)
+{
+ qlock(&ql);
+ _flushmemscreen(r);
+ qunlock(&ql);
+}
+
+void
+drawcursor(Drawcursor *c)
+{
+ int j, i, h, w, bpl;
+ uchar *bc, *bs, *cclr, *cset, curs[2*4+2*2*16];
+
+ /* Set the default system cursor */
+ if(c->data == nil) {
+ write(cursfd, curs, 0);
+ return;
+ }
+
+ BPLONG(curs+0*4, c->hotx);
+ BPLONG(curs+1*4, c->hoty);
+
+ w = (c->maxx-c->minx);
+ h = (c->maxy-c->miny)/2;
+
+ cclr = curs+2*4;
+ cset = curs+2*4+2*16;
+ bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1);
+ bc = c->data;
+ bs = c->data + h*bpl;
+
+ if(h > 16)
+ h = 16;
+ if(w > 16)
+ w = 16;
+ w /= 8;
+ for(i = 0; i < h; i++) {
+ for(j = 0; j < w; j++) {
+ cclr[j] = bc[j];
+ cset[j] = bs[j];
+ }
+ bc += bpl;
+ bs += bpl;
+ cclr += 2;
+ cset += 2;
+ }
+ write(cursfd, curs, sizeof curs);
+}
+
+static int
+checkmouse(char *buf, int n)
+{
+ int x, y, tick, b;
+ static int lastb, lastt, lastx, lasty, lastclick;
+
+ switch(n){
+ default:
+ kwerrstr("atomouse: bad count");
+ return -1;
+
+ case 1+4*12:
+ if(buf[0] == 'r'){
+ qlock(&ql);
+ if(attachwindow(nil, nil, nil, nil) == nil) {
+ qunlock(&ql);
+ return -1;
+ }
+ _flushmemscreen(Rect(0, 0, Xsize, Ysize));
+ qunlock(&ql);
+ }
+ x = atoi(buf+1+0*12) - tiler.min.x;
+ y = atoi(buf+1+1*12) - tiler.min.y;
+ b = atoi(buf+1+2*12);
+ tick = atoi(buf+1+3*12);
+ if(b && lastb == 0){ /* button newly pressed */
+ if(b==lastclick && tick-lastt<400
+ && abs(x-lastx)<10 && abs(y-lasty)<10)
+ b |= (1<<8);
+ lastt = tick;
+ lastclick = b&0xff;
+ lastx = x;
+ lasty = y;
+ }
+ lastb = b&0xff;
+ //mouse.msec = tick;
+ mousetrack(b, x, y, 0);
+ return n;
+ }
+}
+
+static void
+plan9readmouse(void *v)
+{
+ int n;
+ char buf[128];
+
+ USED(v);
+ for(;;){
+ n = read(mousefd, buf, sizeof(buf));
+ if(n < 0) /* probably interrupted */
+ _exits(0);
+ checkmouse(buf, n);
+ }
+}
+
+static void
+plan9readkeybd(void*)
+{
+ int n, partial;
+ char buf[32];
+ char dbuf[32 * 3]; /* overestimate but safe */
+
+ partial = 0;
+ for(;;){
+ n = read(keybdfd, buf + partial, sizeof(buf) - partial);
+ if(n < 0) /* probably interrupted */
+ _exits(0);
+ partial += n;
+ n = mapspecials(dbuf, buf, &partial);
+ qproduce(gkbdq, dbuf, n);
+ }
+}
+
+void
+setpointer(int x, int y)
+{
+ char buf[50];
+ int n;
+
+ if(mousefd < 0)
+ return;
+ x += tiler.min.x;
+ y += tiler.min.y;
+ n = snprint(buf, sizeof buf, "m%11d %11d ", x, y);
+ write(mousefd, buf, n);
+}
+
+/*
+ * plan9 keyboard codes; from /sys/include/keyboard.h; can't include directly
+ * because constant names clash.
+ */
+enum {
+ P9KF= 0xF000, /* Rune: beginning of private Unicode space */
+ P9Spec= 0xF800,
+ /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */
+ Khome= P9KF|0x0D,
+ Kup= P9KF|0x0E,
+ Kpgup= P9KF|0x0F,
+ Kprint= P9KF|0x10,
+ Kleft= P9KF|0x11,
+ Kright= P9KF|0x12,
+ Kdown= P9Spec|0x00,
+ Kview= P9Spec|0x00,
+ Kpgdown= P9KF|0x13,
+ Kins= P9KF|0x14,
+ Kend= KF|0x18,
+
+ Kalt= P9KF|0x15,
+ Kshift= P9KF|0x16,
+ Kctl= P9KF|0x17,
+};
+
+/*
+ * translate plan 9 special characters from s2 (of length *n) into s1;
+ * return number of chars placed into s1.
+ * any trailing incomplete chars are moved to the beginning of s2,
+ * and *n set to the number moved there.
+ */
+static int
+mapspecials(char *s1, char *s2, int *n)
+{
+ char *s, *d, *es2;
+ Rune r;
+ d = s1;
+ s = s2;
+ es2 = s2 + *n;
+ while (fullrune(s, es2 - s)) {
+ s += chartorune(&r, s);
+ switch (r) {
+ case Kshift:
+ r = LShift;
+ break;
+ case Kctl:
+ r = LCtrl;
+ break;
+ case Kalt:
+ r = LAlt;
+ break;
+ case Khome:
+ r = Home;
+ break;
+ case Kend:
+ r = End;
+ break;
+ case Kup:
+ r = Up;
+ break;
+ case Kdown:
+ r = Down;
+ break;
+ case Kleft:
+ r = Left;
+ break;
+ case Kright:
+ r = Right;
+ break;
+ case Kpgup:
+ r = Pgup;
+ break;
+ case Kpgdown:
+ r = Pgdown;
+ break;
+ case Kins:
+ r = Ins;
+ break;
+ /*
+ * function keys
+ */
+ case P9KF|1:
+ case P9KF|2:
+ case P9KF|3:
+ case P9KF|4:
+ case P9KF|5:
+ case P9KF|6:
+ case P9KF|7:
+ case P9KF|8:
+ case P9KF|9:
+ case P9KF|10:
+ case P9KF|11:
+ case P9KF|12:
+ r = (r - P9KF) + KF;
+ }
+ d += runetochar(d, &r);
+ }
+ *n = es2 - s;
+ memmove(s2, s, *n);
+ return d - s1;
+}
--- a/emu/mkfile
+++ b/emu/mkfile
@@ -17,3 +17,7 @@
&-Plan9:QV:
echo '@{builtin cd' $SYSTARG '; mk $MKFLAGS $stem}'
@{builtin cd $SYSTARG; mk $MKFLAGS $stem }
+
+&-9front:QV:
+ echo '@{builtin cd' $SYSTARG '; mk $MKFLAGS $stem}'
+ @{builtin cd $SYSTARG; mk $MKFLAGS $stem }
--- a/emu/port/alloc.c
+++ b/emu/port/alloc.c
@@ -40,6 +40,12 @@
void* initbrk(ulong);
+/* keep the quanta above the size of 5 pointers and 2 longs else the next block
+ will be getting overwritten by the header -- starts a corruption hunt
+ when pointer size = 8 bytes, then 63 = 2^q -1
+ for 4 bytes, 31
+ TODO make this a macro?
+ */
struct
{
int n;
@@ -48,9 +54,9 @@
} table = {
3,
{
- { "main", 0, 32*1024*1024, 31, 512*1024, 0, 31*1024*1024 },
- { "heap", 1, 32*1024*1024, 31, 512*1024, 0, 31*1024*1024 },
- { "image", 2, 64*1024*1024+256, 31, 4*1024*1024, 1, 63*1024*1024 },
+ { "main", 0, 32*1024*1024, 63, 512*1024, 0, 31*1024*1024 },
+ { "heap", 1, 32*1024*1024, 63, 512*1024, 0, 31*1024*1024 },
+ { "image", 2, 64*1024*1024+256, 63, 4*1024*1024, 1, 63*1024*1024 },
}
};
@@ -84,12 +90,12 @@
Monitor = 1
};
-void (*memmonitor)(int, ulong, ulong, ulong) = nil;
+void (*memmonitor)(int, uintptr, void *, ulong) = nil;
#define MM(v,pc,base,size) if(!Monitor || memmonitor==nil){} else memmonitor((v),(pc),(base),(size))
#define CKLEAK 0
int ckleak;
-#define ML(v, sz, pc) if(CKLEAK && ckleak && v){ if(sz) fprint(2, "%lux %lux %lux\n", (ulong)v, (ulong)sz, (ulong)pc); else fprint(2, "%lux\n", (ulong)v); }
+#define ML(v, sz, pc) if(CKLEAK && ckleak && v){ if(sz) fprint(2, "%zx %lux %zx\n", (uintptr)v, (ulong)sz, (uintptr)pc); else fprint(2, "%zx\n", (uintptr)v); }
int
memusehigh(void)
@@ -279,7 +285,7 @@
}
static void*
-dopoolalloc(Pool *p, ulong asize, ulong pc)
+dopoolalloc(Pool *p, ulong asize, uintptr pc)
{
Bhdr *q, *t;
int alloc, ldr, ns, frag;
@@ -306,7 +312,7 @@
p->hw = p->cursize;
unlock(&p->l);
if(p->monitor)
- MM(p->pnum, pc, (ulong)B2D(t), size);
+ MM(p->pnum, pc, B2D(t), size);
return B2D(t);
}
if(size < t->size) {
@@ -326,7 +332,7 @@
p->hw = p->cursize;
unlock(&p->l);
if(p->monitor)
- MM(p->pnum, pc, (ulong)B2D(q), size);
+ MM(p->pnum, pc, B2D(q), size);
return B2D(q);
}
/* Split */
@@ -342,7 +348,7 @@
p->hw = p->cursize;
unlock(&p->l);
if(p->monitor)
- MM(p->pnum, pc, (ulong)B2D(q), size);
+ MM(p->pnum, pc, B2D(q), size);
return B2D(q);
}
@@ -393,7 +399,7 @@
}
#else
/* Double alignment */
- t = (Bhdr *)(((ulong)t + 7) & ~7);
+ t = (Bhdr *)(((uintptr)t + 7) & ~7);
#endif
if(p->chain != nil && (char*)t-(char*)B2LIMIT(p->chain)-ldr == 0){
/* can merge chains */
@@ -438,7 +444,7 @@
p->hw = p->cursize;
unlock(&p->l);
if(p->monitor)
- MM(p->pnum, pc, (ulong)B2D(t), size);
+ MM(p->pnum, pc, B2D(t), size);
return B2D(t);
}
@@ -460,7 +466,7 @@
D2B(b, v);
if(p->monitor)
- MM(p->pnum|(1<<8), getcallerpc(&p), (ulong)v, b->size);
+ MM(p->pnum|(1<<8), getcallerpc(&p), v, b->size);
lock(&p->l);
p->nfree++;
@@ -611,7 +617,7 @@
if(v != nil)
break;
if(0)
- print("smalloc waiting from %lux\n", getcallerpc(&size));
+ print("smalloc waiting from %zx\n", getcallerpc(&size));
osenter();
osmillisleep(100);
osleave();
@@ -626,16 +632,16 @@
{
void *v;
- v = dopoolalloc(mainmem, size+Npadlong*sizeof(ulong), getcallerpc(&size));
+ v = dopoolalloc(mainmem, size+Npadlong*sizeof(uintptr), getcallerpc(&size));
if(v != nil){
ML(v, size, getcallerpc(&size));
if(Npadlong){
- v = (ulong*)v+Npadlong;
+ v = (uintptr*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
setrealloctag(v, 0);
}
memset(v, 0, size);
- MM(0, getcallerpc(&size), (ulong)v, size);
+ MM(0, getcallerpc(&size), v, size);
}
return v;
}
@@ -647,18 +653,18 @@
{
void *v;
- v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
+ v = poolalloc(mainmem, size+Npadlong*sizeof(uintptr));
if(v != nil){
ML(v, size, getcallerpc(&size));
if(Npadlong){
- v = (ulong*)v+Npadlong;
+ v = (uintptr*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
setrealloctag(v, 0);
}
memset(v, 0, size);
- MM(0, getcallerpc(&size), (ulong)v, size);
+ MM(0, getcallerpc(&size), v, size);
} else
- print("malloc failed from %lux\n", getcallerpc(&size));
+ print("malloc failed from %zx\n", getcallerpc(&size));
return v;
}
@@ -667,19 +673,19 @@
{
void *v;
- v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
+ v = poolalloc(mainmem, size+Npadlong*sizeof(uintptr));
if(v != nil){
ML(v, size, getcallerpc(&size));
if(Npadlong){
- v = (ulong*)v+Npadlong;
+ v = (uintptr*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
setrealloctag(v, 0);
}
if(clr)
memset(v, 0, size);
- MM(0, getcallerpc(&size), (ulong)v, size);
+ MM(0, getcallerpc(&size), v, size);
} else
- print("mallocz failed from %lux\n", getcallerpc(&size));
+ print("mallocz failed from %zx\n", getcallerpc(&size));
return v;
}
@@ -690,10 +696,10 @@
if(v != nil) {
if(Npadlong)
- v = (ulong*)v-Npadlong;
+ v = (uintptr*)v-Npadlong;
D2B(b, v);
ML(v, 0, 0);
- MM(1<<8|0, getcallerpc(&v), (ulong)((ulong*)v+Npadlong), b->size);
+ MM(1<<8|0, getcallerpc(&v), ((uintptr*)v+Npadlong), b->size);
poolfree(mainmem, v);
}
}
@@ -706,26 +712,26 @@
if(size == 0)
return malloc(size); /* temporary change until realloc calls can be checked */
if(v != nil)
- v = (ulong*)v-Npadlong;
+ v = (uintptr*)v-Npadlong;
if(Npadlong!=0 && size!=0)
- size += Npadlong*sizeof(ulong);
+ size += Npadlong*sizeof(uintptr);
nv = poolrealloc(mainmem, v, size);
ML(v, 0, 0);
ML(nv, size, getcallerpc(&v));
if(nv != nil) {
- nv = (ulong*)nv+Npadlong;
+ nv = (uintptr*)nv+Npadlong;
setrealloctag(nv, getcallerpc(&v));
if(v == nil)
setmalloctag(v, getcallerpc(&v));
} else
- print("realloc failed from %lux\n", getcallerpc(&v));
+ print("realloc failed from %zx\n", getcallerpc(&v));
return nv;
}
void
-setmalloctag(void *v, ulong pc)
+setmalloctag(void *v, uintptr pc)
{
- ulong *u;
+ uintptr *u;
USED(v);
USED(pc);
@@ -735,19 +741,19 @@
u[-Npadlong+MallocOffset] = pc;
}
-ulong
+uintptr
getmalloctag(void *v)
{
USED(v);
if(Npadlong <= MallocOffset)
return ~0;
- return ((ulong*)v)[-Npadlong+MallocOffset];
+ return ((uintptr*)v)[-Npadlong+MallocOffset];
}
void
-setrealloctag(void *v, ulong pc)
+setrealloctag(void *v, uintptr pc)
{
- ulong *u;
+ uintptr *u;
USED(v);
USED(pc);
@@ -757,12 +763,12 @@
u[-Npadlong+ReallocOffset] = pc;
}
-ulong
+uintptr
getrealloctag(void *v)
{
USED(v);
if(Npadlong <= ReallocOffset)
- return ((ulong*)v)[-Npadlong+ReallocOffset];
+ return ((uintptr*)v)[-Npadlong+ReallocOffset];
return ~0;
}
@@ -771,7 +777,7 @@
{
if(v == nil)
return 0;
- return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
+ return poolmsize(mainmem, (uintptr*)v-Npadlong)-Npadlong*sizeof(uintptr);
}
void*
@@ -881,7 +887,7 @@
}
static void
-dumpvl(char *msg, ulong *v, int n)
+dumpvl(char *msg, uintptr *v, int n)
{
int i, l;
@@ -891,7 +897,7 @@
print("\n");
l = print(" %p: ", v);
}
- l += print(" %lux", *v++);
+ l += print(" %zx", *v++);
}
print("\n");
}
@@ -901,7 +907,7 @@
{
print("%s(%p): pool %s CORRUPT: %s at %p'%lud(magic=%lux)\n",
str, v, p->name, msg, b, b->size, b->magic);
- dumpvl("bad Bhdr", (ulong *)((ulong)b & ~3)-4, 10);
+ dumpvl("bad Bhdr", (uintptr *)((uintptr)b & ~3)-4, 10);
}
static void
@@ -981,7 +987,7 @@
print(" is %s '%lux\n", fmsg, fsz);
else
print(" in %s at %p'%lux\n", fmsg, fb, fsz);
- dumpvl("area", (ulong *)((ulong)v & ~3)-4, 20);
+ dumpvl("area", (uintptr *)((uintptr)v & ~3)-4, 20);
}
}
--- a/emu/port/fns.h
+++ b/emu/port/fns.h
@@ -78,7 +78,7 @@
void freeb(Block*);
void freeblist(Block*);
void freeskey(Signerkey*);
-ulong getcallerpc(void*);
+uintptr getcallerpc(void*);
ulong getFPcontrol(void);
ulong getFPstatus(void);
void gkbdputc(Queue*, int);
--- /dev/null
+++ b/lib9/errstr-9front.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+void
+oserrstr(char *buf, uint nerr)
+{
+ *buf = 0;
+ errstr(buf, nerr);
+}
--- /dev/null
+++ b/lib9/mkfile-9front
@@ -1,0 +1,2 @@
+TARGFILES=errstr-9front.$O\
+
--- /dev/null
+++ b/libdynld/dynld-amd64.c
@@ -1,0 +1,42 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | I_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ int i;
+ ulong v, *pp;
+
+ p += (ulong)b;
+ pp = (ulong*)p;
+ v = *pp;
+ switch(m){
+ case 0:
+ v += (ulong)b;
+ break;
+ case 1:
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ break;
+ case 2:
+ i = v>>22;
+ CHK(i, ntab);
+ v = tab[i]->addr -p-4;
+ break;
+ default:
+ return "bad relocation mode";
+ }
+ *pp = v;
+ return nil;
+}
--- /dev/null
+++ b/libinterp/comp-amd64.c
@@ -1,0 +1,1991 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define DOT ((ulong)code)
+
+#define RESCHED 1 /* check for interpreter reschedule */
+
+enum
+{
+ RAX = 0,
+ RAH = 4,
+ RCX = 1,
+ RDX = 2,
+ RBX = 3,
+ RSP = 4,
+ RBP = 5,
+ RSI = 6,
+ RDI = 7,
+
+ RFP = RSI,
+ RMP = RDI,
+ RTA = RDX,
+ RTMP = RBX,
+
+ Omovzxb = 0xb6,
+ Omovzxw = 0xb7,
+ Osal = 0xd1,
+ Oaddf = 0xdc,
+ Ocall = 0xe8,
+ Ocallrm = 0xff,
+ Ocdq = 0x99,
+ Ocld = 0xfc,
+ Ocmpb = 0x38,
+ Ocmpw = 0x39,
+ Ocmpi = 0x83,
+ Odecrm = 0xff,
+ Oincr = 0x40,
+ Oincrm = 0xff,
+ Ojccl = 0x83,
+ Ojcsl = 0x82,
+ Ojeqb = 0x74,
+ Ojeql = 0x84,
+ Ojgel = 0x8d,
+ Ojgtl = 0x8f,
+ Ojhil = 0x87,
+ Ojlel = 0x8e,
+ Ojlsl = 0x86,
+ Ojltl = 0x8c,
+ Ojol = 0x80,
+ Ojnol = 0x81,
+ Ojbl = 0x82,
+ Ojael = 0x83,
+ Ojal = 0x87,
+ Ojnel = 0x85,
+ Ojbel = 0x86,
+ Ojneb = 0x75,
+ Ojgtb = 0x7f,
+ Ojgeb = 0x7d,
+ Ojleb = 0x7e,
+ Ojltb = 0x7c,
+ Ojmp = 0xe9,
+ Ojmpb = 0xeb,
+ Ojmprm = 0xff,
+ Oldb = 0x8a,
+ Olds = 0x89,
+ Oldw = 0x8b,
+ Olea = 0x8d,
+ Otestib = 0xf6,
+ Oshld = 0xa5,
+ Oshrd = 0xad,
+ Osar = 0xd3,
+ Osarimm = 0xc1,
+ Omov = 0xc7,
+ Omovf = 0xdd,
+ Omovimm = 0xb8,
+ Omovsb = 0xa4,
+ Orep = 0xf3,
+ Oret = 0xc3,
+ Oshl = 0xd3,
+ Oshr = 0xd1,
+ Ostb = 0x88,
+ Ostw = 0x89,
+ Osubf = 0xdc,
+ Oxchg = 0x87,
+ OxchgAX = 0x90,
+ Oxor = 0x31,
+ Opopl = 0x58,
+ Opushl = 0x50,
+ Opushrm = 0xff,
+ Oneg = 0xf7,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET = 1,
+ MacCASE = 2,
+ MacCOLR = 3,
+ MacMCAL = 4,
+ MacFRAM = 5,
+ MacMFRA = 6,
+ MacRELQ = 7,
+ NMACRO
+};
+
+static uchar* code;
+static uchar* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static void macrelq(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(uchar*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+} mactab[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacFRAM, macfram, /* frame instruction */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacRELQ, macrelq, /* reschedule */
+};
+
+static void
+bounds(void)
+{
+ error(exBounds);
+}
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static int
+bc(int o)
+{
+ if(o < 127 && o > -128)
+ return 1;
+ return 0;
+}
+
+static void
+urk(void)
+{
+ error(exCompile);
+}
+
+static void
+genb(uchar o)
+{
+ *code++ = o;
+}
+
+static void
+gen2(uchar o1, uchar o2)
+{
+ code[0] = o1;
+ code[1] = o2;
+ code += 2;
+}
+
+static void
+genw(ulong o)
+{
+ *(ulong*)code = o;
+ code += 4;
+}
+
+static void
+modrm(int inst, ulong disp, int rm, int r)
+{
+ *code++ = inst;
+ if(disp == 0) {
+ *code++ = (0<<6)|(r<<3)|rm;
+ return;
+ }
+ if(bc(disp)) {
+ code[0] = (1<<6)|(r<<3)|rm;
+ code[1] = disp;
+ code += 2;
+ return;
+ }
+ *code++ = (2<<6)|(r<<3)|rm;
+ *(ulong*)code = disp;
+ code += 4;
+}
+
+static void
+con(ulong o, int r)
+{
+ if(o == 0) {
+ gen2(Oxor, (3<<6)|(r<<3)|r);
+ return;
+ }
+ genb(Omovimm+r);
+ genw(o);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ modrm(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ modrm(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ con(i->s.imm, r);
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ modrm(Oldw, i->s.i.f, ir, rta);
+ modrm(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ con(i->d.imm, r);
+ return;
+ case DST(AFP):
+ modrm(mi, i->d.ind, RFP, r);
+ return;
+ case DST(AMP):
+ modrm(mi, i->d.ind, RMP, r);
+ return;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ modrm(Oldw, i->d.i.f, ir, rta);
+ modrm(mi, i->d.i.s, rta, r);
+}
+
+static void
+bra(ulong dst, int op)
+{
+ dst -= (DOT+5);
+ genb(op);
+ genw(dst);
+}
+
+static void
+rbra(ulong dst, int op)
+{
+ dst += (ulong)base;
+ dst -= DOT+5;
+ genb(op);
+ genw(dst);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ genb(Omovimm+RAX);
+ genw((ulong)litpool);
+ modrm(Ostw, roff, RTMP, RAX);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ con((ulong)&R, RTMP);
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, RAX);
+ modrm(Ostw, O(REG, s), RTMP, RAX);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Olea, 0);
+ modrm(Ostw, O(REG, d), RTMP, RAX);
+ }
+ if(m & WRTPC) {
+ modrm(Omov, O(REG, PC), RTMP, 0);
+ pc = patch[i-mod->prog+1];
+ genw((ulong)base + pc);
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal((ulong)base+pc, O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ modrm(Oldw, O(REG, d), RTMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ modrm(Olea, i->reg, RFP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ case AXINM:
+ modrm(Olea, i->reg, RMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ }
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+
+ bra((ulong)fn, Ocall);
+
+ con((ulong)&R, RTMP);
+ if(m & TCHECK) {
+ modrm(Ocmpi, O(REG, t), RTMP, 7);// CMPL $0, R.t
+ genb(0x00);
+ gen2(Ojeqb, 0x06); // JEQ .+6
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ }
+
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+
+ if(m & NEWPC) {
+ modrm(Oldw, O(REG, PC), RTMP, RAX);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+ }
+}
+
+static void
+mid(Inst *i, uchar mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ modrm(mi, i->reg, ir, r);
+}
+
+static void
+arith(Inst *i, int op2, int rm)
+{
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostw, 0);
+ return;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, op2, 0);
+ return;
+ }
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ if(bc(i->s.imm)) {
+ gen2(0x83, (3<<6)|(rm<<3)|RAX);
+ genb(i->s.imm);
+ }
+ else {
+ gen2(0x81, (3<<6)|(rm<<3)|RAX);
+ genw(i->s.imm);
+ }
+ opwst(i, Ostw, RAX);
+ return;
+ }
+ if(bc(i->s.imm)) {
+ opwst(i, 0x83, rm);
+ genb(i->s.imm);
+ return;
+ }
+ opwst(i, 0x81, rm);
+ genw(i->s.imm);
+}
+
+static void
+arithb(Inst *i, int op2)
+{
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ if(i->add&ARM) {
+ mid(i, Oldb, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostb, 0);
+ return;
+ }
+ opwld(i, Oldb, RAX);
+ opwst(i, op2, RAX);
+}
+
+static void
+shift(Inst *i, int ld, int st, int op, int r)
+{
+ mid(i, ld, RAX);
+ opwld(i, Oldw, RCX);
+ gen2(op, (3<<6)|(r<<3)|RAX);
+ opwst(i, st, RAX);
+}
+
+static void
+arithf(Inst *i, int op)
+{
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, op);
+ opwst(i, Omovf, 3);
+}
+
+static void
+cmpl(int r, ulong v)
+{
+ if(bc(v)) {
+ gen2(0x83, (3<<6)|(7<<3)|r);
+ genb(v);
+ return;
+ }
+ gen2(0x81, (3<<6)|(7<<3)|r);
+ genw(v);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Ojgel:
+ return Ojlel;
+ case Ojlel:
+ return Ojgel;
+ case Ojgtl:
+ return Ojltl;
+ case Ojltl:
+ return Ojgtl;
+ }
+ return b;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ if(RESCHED && i->d.ins <= i){
+ con((ulong)&R, RTMP);
+ /* sub $1, R.IC */
+ modrm(0x83, O(REG, IC), RTMP, 5);
+ genb(1);
+ gen2(Ojgtb, 5);
+ rbra(macro[MacRELQ], Ocall);
+ }
+}
+
+static void
+cbra(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldw, RAX);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ cmpl(RAX, i->s.imm);
+ jmp = swapbraop(jmp);
+ }
+ else
+ opwld(i, Ocmpw, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst;
+ uchar *label;
+
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ocmpw, 4, RTMP, RAX);
+ label = 0;
+ dst = patch[i->d.ins-mod->prog];
+ switch(mode) {
+ case ANDAND:
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ case OROR:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ break;
+ case EQAND:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ }
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ocmpw, 0, RTMP, RAX);
+ genb(0x0f);
+ rbra(dst, jlsw);
+ if(label != nil)
+ *label = code-label-1;
+}
+
+static void
+cbrab(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldb, RAX);
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ opwld(i, Ocmpb, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbraf(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, 3); // FCOMP
+ genb(0x9b); // FWAIT
+ gen2(0xdf, 0xe0); // FSTSW AX
+ genb(0x9e); // SAHF
+
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Oldw, RAX); // v
+ genb(Opushl+RSI);
+ opwst(i, Olea, RSI); // table
+ rbra(macro[MacCASE], Ojmp);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)base + patch[t[2]];
+ t += 3;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ int o;
+ uchar *punt, *mlnil;
+
+ opwld(i, Oldw, RAX);
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM) {
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA);
+ } else {
+ gen2(Oldw, (3<<6)|(RTMP<<3)|RAX); // MOVL AX, RTMP
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (AX)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RAX); // assumes sizeof(Modl) == 8 hence 3
+ o = OA(Modlink, links)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA); // frame
+ genb(OxchgAX+RTMP); // get old AX back
+ }
+ modrm(0x83, O(Type, initialize), RTA, 7);
+ genb(0);
+ gen2(Ojneb, 0);
+ punt = code - 1;
+ genb(OxchgAX+RTA);
+ opwst(i, Olea, RTA);
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMFRA], Ocall);
+ rbra(patch[i-mod->prog+1], Ojmp);
+
+ *punt = code-punt-1;
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+}
+
+static void
+commcall(Inst *i)
+{
+ uchar *mlnil;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ opwld(i, Oldw, RCX);
+ modrm(Omov, O(Frame, lr), RCX, 0); // MOVL $.+1, lr(CX) f->lr = R.PC
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RCX, RFP); // MOVL RFP, fp(CX) f->fp = R.FP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Ostw, O(Frame, mr), RCX, RTA); // MOVL RTA, mr(CX) f->mr = R.M
+ opwst(i, Oldw, RTA); // MOVL ml, RTA
+ cmpl(RTA, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM)
+ modrm(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RTA, RAX);
+ else {
+ genb(Opushl+RCX);
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (RTA)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RTA); // assumes sizeof(Modl) == 8 hence 3
+ modrm(Oldw, OA(Modlink, links)+O(Modl, u.pc), RAX, RAX);
+ genb(Opopl+RCX);
+ }
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMCAL], Ocall);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 0, RTA, RAX); // MOVL 0(RTA), AX
+ modrm(op, 0, RTMP, RAX); // ADDL 0(RTMP), AX
+ modrm(Oldw, 4, RTA, RCX); // MOVL 4(RTA), CX
+ modrm(opc, 4, RTMP, RCX); // ADCL 4(RTMP), CX
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RCX);
+}
+
+static void
+shll(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshld, (3<<6)|(RAX<<3)|RBX);
+ gen2(Oshl, (3<<6)|(4<<3)|RAX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 0, RTA, RBX);
+ con(0, RAX);
+ gen2(Oshl, (3<<6)|(4<<3)|RBX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+static void
+shrl(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshrd, (3<<6)|(RBX<<3)|RAX);
+ gen2(Osar, (3<<6)|(7<<3)|RBX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 4, RTA, RBX);
+ gen2(Oldw, (3<<6)|(RAX<<3)|RBX);
+ gen2(Osarimm, (3<<6)|(7<<3)|RBX);
+ genb(0x1f);
+ gen2(Osar, (3<<6)|(7<<3)|RAX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+ int r;
+ WORD *t, *e;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADL:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Oldb, RAX);
+ genb(0x0f);
+ gen2(0xb6, (3<<6)|(RAX<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWB:
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ICVTFW:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdb, 3);
+ break;
+ case ICVTWF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdb, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTLF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdf, 5);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTFL:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdf, 7);
+ break;
+ case IHEADM:
+ opwld(i, Oldw, RAX);
+ modrm(Olea, OA(List, data), RAX, RAX);
+ goto movm;
+ case IMOVM:
+ opwld(i, Olea, RAX);
+ movm:
+ opwst(i, Olea, RBX);
+ mid(i, Oldw, RCX);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ genb(Ocld);
+ gen2(Orep, Omovsb);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ break;
+ case IRET:
+ rbra(macro[MacRET], Ojmp);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RTA);
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+ break;
+ case ILEA:
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ gen2(Ojmpb, 4);
+ genw(i->s.imm);
+ con((ulong)(code-4), RAX);
+ }
+ else
+ opwld(i, Olea, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADW:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, OA(List, data), RAX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADF:
+ opwld(i, Oldw, RAX);
+ modrm(Omovf, OA(List, data), RAX, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case IHEADB:
+ opwld(i, Oldw, RAX);
+ modrm(Oldb, OA(List, data), RAX, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ITAIL:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, O(List, tail), RAX, RBX);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, Oldw, RBX);
+ if(i->op == IHEADP)
+ modrm(Oldw, OA(List, data), RBX, RBX);
+ movp:
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ rbra(macro[MacCOLR], Ocall);
+ opwst(i, Oldw, RAX);
+ opwst(i, Ostw, RBX);
+ rbra(macro[MacFRP], Ocall);
+ break;
+ case ILENA:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x02);
+ modrm(Oldw, O(Array, len), RBX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENC:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x09);
+ modrm(Oldw, O(String, len), RBX, RAX);
+ cmpl(RAX, 0);
+ gen2(Ojgeb, 0x02);
+ gen2(Oneg, (3<<6)|(3<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENL:
+ con(0, RAX);
+ opwld(i, Oldw, RBX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ modrm(Oldw, O(List, tail), RBX, RBX);
+ genb(Oincr+RAX);
+ gen2(Ojmpb, 0xf6);
+ opwst(i, Ostw, RAX);
+ break;
+ case IBEQF:
+ cbraf(i, Ojeql);
+ break;
+ case IBNEF:
+ cbraf(i, Ojnel);
+ break;
+ case IBLEF:
+ cbraf(i, Ojlsl);
+ break;
+ case IBLTF:
+ cbraf(i, Ojcsl);
+ break;
+ case IBGEF:
+ cbraf(i, Ojccl);
+ break;
+ case IBGTF:
+ cbraf(i, Ojhil);
+ break;
+ case IBEQW:
+ cbra(i, Ojeql);
+ break;
+ case IBLEW:
+ cbra(i, Ojlel);
+ break;
+ case IBNEW:
+ cbra(i, Ojnel);
+ break;
+ case IBGTW:
+ cbra(i, Ojgtl);
+ break;
+ case IBLTW:
+ cbra(i, Ojltl);
+ break;
+ case IBGEW:
+ cbra(i, Ojgel);
+ break;
+ case IBEQB:
+ cbrab(i, Ojeql);
+ break;
+ case IBLEB:
+ cbrab(i, Ojlsl);
+ break;
+ case IBNEB:
+ cbrab(i, Ojnel);
+ break;
+ case IBGTB:
+ cbrab(i, Ojhil);
+ break;
+ case IBLTB:
+ cbrab(i, Ojbl);
+ break;
+ case IBGEB:
+ cbrab(i, Ojael);
+ break;
+ case ISUBW:
+ arith(i, 0x29, 5);
+ break;
+ case ISUBB:
+ arithb(i, 0x28);
+ break;
+ case ISUBF:
+ arithf(i, 5);
+ break;
+ case IADDW:
+ arith(i, 0x01, 0);
+ break;
+ case IADDB:
+ arithb(i, 0x00);
+ break;
+ case IADDF:
+ arithf(i, 0);
+ break;
+ case IORW:
+ arith(i, 0x09, 1);
+ break;
+ case IORB:
+ arithb(i, 0x08);
+ break;
+ case IANDW:
+ arith(i, 0x21, 4);
+ break;
+ case IANDB:
+ arithb(i, 0x20);
+ break;
+ case IXORW:
+ arith(i, Oxor, 6);
+ break;
+ case IXORB:
+ arithb(i, 0x30);
+ break;
+ case ISHLW:
+ shift(i, Oldw, Ostw, 0xd3, 4);
+ break;
+ case ISHLB:
+ shift(i, Oldb, Ostb, 0xd2, 4);
+ break;
+ case ISHRW:
+ shift(i, Oldw, Ostw, 0xd3, 7);
+ break;
+ case ISHRB:
+ shift(i, Oldb, Ostb, 0xd2, 5);
+ break;
+ case IMOVF:
+ opwld(i, Omovf, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case INEGF:
+ opwld(i, Omovf, 0);
+ genb(0xd9);
+ genb(0xe0);
+ opwst(i, Omovf, 3);
+ break;
+ case IMOVB:
+ opwld(i, Oldb, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case IMOVW:
+ case ICVTLW: // Little endian
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ opwst(i, Omov, RAX);
+ genw(i->s.imm);
+ break;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWL:
+ opwst(i, Olea, RTMP);
+ opwld(i, Oldw, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ genb(0x99);
+ modrm(Ostw, 4, RTMP, RDX);
+ break;
+ case ICALL:
+ if(UXDST(i->add) != DST(AIMM))
+ opwst(i, Oldw, RTA);
+ opwld(i, Oldw, RAX);
+ modrm(Omov, O(Frame, lr), RAX, 0); // MOVL $.+1, lr(AX)
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RAX, RFP); // MOVL RFP, fp(AX)
+ gen2(Oldw, (3<<6)|(RFP<<3)|RAX); // MOVL AX,RFP
+ if(UXDST(i->add) != DST(AIMM)){
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA);
+ break;
+ }
+ /* no break */
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ rbra(patch[i->d.ins-mod->prog], Ojmp);
+ break;
+ case IMOVPC:
+ opwst(i, Omov, RAX);
+ genw(patch[i->s.imm]+(ulong)base);
+ break;
+ case IGOTO:
+ opwst(i, Olea, RBX);
+ opwld(i, Oldw, RAX);
+ gen2(Ojmprm, (0<<6)|(4<<3)|4);
+ genb((2<<6)|(RAX<<3)|RBX);
+
+ if(pass == 0)
+ break;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)base + patch[t[0]];
+ t++;
+ }
+ break;
+ case IMULF:
+ arithf(i, 1);
+ break;
+ case IDIVF:
+ arithf(i, 7);
+ break;
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ mid(i, Oldw, RAX);
+ opwld(i, Oldw, RTMP);
+ if(i->op == IMULW)
+ gen2(0xf7, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf7, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODW)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ mid(i, Oldb, RAX);
+ opwld(i, Oldb, RTMP);
+ if(i->op == IMULB)
+ gen2(0xf6, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf6, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODB)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostb, RAX);
+ break;
+ case IINDX:
+ opwld(i, Oldw, RTMP); // MOVW xx(s), BX
+
+ if(bflag){
+ opwst(i, Oldw, RAX);
+ modrm(0x3b, O(Array, len), RTMP, RAX); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ modrm(Oldw, O(Array, t), RTMP, RTA);
+ modrm(0xf7, O(Type, size), RTA, 5); /* IMULL AX, xx(t) */
+ }
+ else{
+ modrm(Oldw, O(Array, t), RTMP, RAX); // MOVW t(BX), AX
+ modrm(Oldw, O(Type, size), RAX, RAX); // MOVW size(AX), AX
+ if(UXDST(i->add) == DST(AIMM)) {
+ gen2(0x69, (3<<6)|(RAX<<3)|0);
+ genw(i->d.imm);
+ }
+ else
+ opwst(i, 0xf7, 5); // IMULL AX,xx(d)
+ }
+
+ modrm(0x03, O(Array, data), RBX, RAX); // ADDL data(BX), AX
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDB:
+ r = 0;
+ goto idx;
+ case IINDF:
+ case IINDL:
+ r = 3;
+ goto idx;
+ case IINDW:
+ r = 2;
+ idx:
+ opwld(i, Oldw, RAX);
+ opwst(i, Oldw, RTMP);
+ if(bflag){
+ modrm(0x3b, O(Array, len), RAX, RTMP); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ }
+ modrm(Oldw, O(Array, data), RAX, RAX);
+ gen2(Olea, (0<<6)|(0<<3)|4); /* lea (AX)(RTMP*r) */
+ genb((r<<6)|(RTMP<<3)|RAX);
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDC:
+ opwld(i, Oldw, RAX); // string
+ mid(i, Oldw, RBX); // index
+ if(bflag){
+ modrm(Oldw, O(String, len), RAX, RTA);
+ cmpl(RTA, 0);
+ gen2(Ojltb, 16);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4);
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ gen2(Ojmpb, sizeof(Rune)==4? 10: 11);
+ gen2(Oneg, (3<<6)|(3<<3)|RTA);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x73, 0xee); /* JNB */
+ if(sizeof(Rune) == 4){
+ gen2(Oldw, (1<<6)|(0<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+ }else{
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4);
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ }
+ modrm(Ocmpi, O(String, len), RAX, 7);
+ genb(0);
+ gen2(Ojltb, 7);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4); /* movzbx 12(AX)(RBX*1), RAX */
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ if(sizeof(Rune) == 4){
+ gen2(Ojmpb, 4);
+ gen2(Oldw, (1<<6)|(0<<3)|4); /* movl 12(AX)(RBX*4), RAX */
+ gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+ }else{
+ gen2(Ojmpb, 5);
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4); /* movzwx 12(AX)(RBX*2), RAX */
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IMOVL:
+ opwld(i, Olea, RTA);
+ opwst(i, Olea, RTMP);
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ostw, 4, RTMP, RAX);
+ break;
+ case IADDL:
+ larith(i, 0x03, 0x13);
+ break;
+ case ISUBL:
+ larith(i, 0x2b, 0x1b);
+ break;
+ case IORL:
+ larith(i, 0x0b, 0x0b);
+ break;
+ case IANDL:
+ larith(i, 0x23, 0x23);
+ break;
+ case IXORL:
+ larith(i, 0x33, 0x33);
+ break;
+ case IBEQL:
+ cbral(i, Ojnel, Ojeql, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Ojnel, Ojnel, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Ojltl, Ojbel, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Ojgtl, Ojal, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Ojltl, Ojbl, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Ojgtl, Ojael, EQAND);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ if(comvec)
+ return;
+
+ comvec = malloc(32);
+ if(comvec == nil)
+ error(exNomem);
+ code = (uchar*)comvec;
+
+ genb(Opushl+RBX);
+ genb(Opushl+RCX);
+ genb(Opushl+RDX);
+ genb(Opushl+RSI);
+ genb(Opushl+RDI);
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ modrm(Ojmprm, O(REG, PC), RTMP, 4);
+
+ segflush(comvec, 32);
+}
+
+static void
+maccase(void)
+{
+ uchar *loop, *def, *lab1;
+
+ modrm(Oldw, 0, RSI, RDX); // n = t[0]
+ modrm(Olea, 4, RSI, RSI); // t = &t[1]
+ gen2(Oldw, (3<<6)|(RBX<<3)|RDX); // MOVL DX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RDX<<3)|RBX); // ADDL DX, BX BX = n*3
+ gen2(Opushrm, (0<<6)|(6<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // PUSHL 0(SI)(BX*4)
+ loop = code;
+ cmpl(RDX, 0);
+ gen2(Ojleb, 0);
+ def = code-1;
+ gen2(Oldw, (3<<6)|(RCX<<3)|RDX); // MOVL DX, CX n2 = n
+ gen2(Oshr, (3<<6)|(5<<3)|RCX); // SHR CX,1 n2 = n2>>1
+ gen2(Oldw, (3<<6)|(RBX<<3)|RCX); // MOVL CX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RCX<<3)|RBX); // ADDL CX, BX BX = n2*3
+ gen2(0x3b, (0<<6)|(RAX<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // CMPL AX, 0(SI)(BX*4)
+ gen2(Ojgeb, 0); // JGE lab1
+ lab1 = code-1;
+ gen2(Oldw, (3<<6)|(RDX<<3)|RCX);
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(0x3b, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 4); // CMPL AX, 4(SI)(BX*4)
+ gen2(Ojltb, 0);
+ lab1 = code-1;
+ gen2(Olea, (1<<6)|(RSI<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 12); // LEA 12(SI)(RBX*4), RSI
+ gen2(0x2b, (3<<6)|(RDX<<3)|RCX); // SUBL CX, DX n -= n2
+ gen2(Odecrm, (3<<6)|(1<<3)|RDX); // DECL DX n -= 1
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(Oldw, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 8); // MOVL 8(SI)(BX*4), AX
+ genb(Opopl+RSI); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *def = code-def-1; // def:
+ genb(Opopl+RAX); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+}
+
+static void
+macfrp(void)
+{
+ cmpl(RAX, (ulong)H); // CMPL AX, $H
+ gen2(Ojneb, 0x01); // JNE .+1
+ genb(Oret); // RET
+ modrm(0x83, O(Heap, ref)-sizeof(Heap), RAX, 7);
+ genb(0x01); // CMP AX.ref, $1
+ gen2(Ojeqb, 0x04); // JNE .+4
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RAX, 1);
+ genb(Oret); // DEC AX.ref
+ // RET
+ con((ulong)&R, RTMP); // MOV $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ modrm(Ostw, O(REG, s), RTMP, RAX); // MOVL RAX, R.s
+ bra((ulong)rdestroy, Ocall); // CALL rdestroy
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ genb(Oret);
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ uchar *s;
+ static ulong lpunt, lnomr, lfrmr, linterp;
+
+ s = code;
+
+ lpunt -= 2;
+ lnomr -= 2;
+ lfrmr -= 2;
+ linterp -= 2;
+
+ con(0, RBX); // MOVL $0, RBX
+ modrm(Oldw, O(Frame, t), RFP, RAX); // MOVL t(FP), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Oldw, O(Type, destroy), RAX, RAX);// MOVL destroy(RAX), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, fp), RFP, RBX); // CMPL fp(FP), RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, mr), RFP, RBX); // CMPL mr(FP), RBX
+ gen2(Ojeqb, lnomr-(code-s)); // JEQ lnomr
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RTA, 1);
+ gen2(Ojneb, lfrmr-(code-s)); // JNE lfrmr
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ gen2(Ojmpb, lpunt-(code-s)); // JMP lpunt
+ lfrmr = code - s;
+ modrm(Oldw, O(Frame, mr), RFP, RTA); // MOVL mr(FP), RTA
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL MP(RTA), RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ gen2(Ojeqb, linterp-(code-s)); // JEQ linterp
+ lnomr = code - s;
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+
+ linterp = code - s; // return to uncompiled code
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL RAX, R.PC
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ genb(Opopl+RDI); // return to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ // label:
+ lpunt = code - s;
+
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RBX, 0);
+ gen2(Oldw, (0<<6)|(RAX<<3)|5); // INCL ref(BX)
+ genw((ulong)&mutator); // MOVL mutator, RAX
+ modrm(Ocmpw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ojneb, 0x01); // CMPL color(BX), RAX
+ genb(Oret); // MOVL $propagator,RTMP
+ con(propagator, RAX); // MOVL RTMP, color(BX)
+ modrm(Ostw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ostw, (0<<6)|(RAX<<3)|5); // can be any !0 value
+ genw((ulong)&nprop); // MOVL RBX, nprop
+ genb(Oret);
+}
+
+static void
+macmcal(void)
+{
+ uchar *label, *mlnil, *interp;
+
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ modrm(0x83, O(Modlink, prog), RTA, 7); // CMPL $0, ml->prog
+ genb(0x00);
+ gen2(Ojneb, 0); // JNE patch
+ label = code-1;
+ *mlnil = code-mlnil-1;
+ modrm(Ostw, O(REG, FP), RTMP, RCX);
+ modrm(Ostw, O(REG, dt), RTMP, RAX);
+ bra((ulong)rmcall, Ocall); // CALL rmcall
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+ *label = code-label-1; // patch:
+ gen2(Oldw, (3<<6)|(RFP<<3)|RCX); // MOVL CX, RFP R.FP = f
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL R.M->mp, RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP R.MP = ml->MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ genb(Opopl+RTA); // balance call
+ gen2(Ojeqb, 0); // JEQ interp
+ interp = code-1;
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *interp = code-interp-1; // interp:
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI); // call to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+static void
+macfram(void)
+{
+ uchar *label;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, SP), RTMP, RAX); // MOVL R.SP, AX
+ modrm(0x03, O(Type, size), RTA, RAX); // ADDL size(RCX), RAX
+ modrm(0x3b, O(REG, TS), RTMP, RAX); // CMPL AX, R.TS
+ gen2(0x7c, 0x00); // JL .+(patch)
+ label = code-1;
+
+ modrm(Ostw, O(REG, s), RTMP, RTA);
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ bra((ulong)extend, Ocall); // CALL extend
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ modrm(Oldw, O(REG, s), RTMP, RCX); // MOVL R.s, *R.d
+ genb(Oret); // RET
+ *label = code-label-1;
+ modrm(Oldw, O(REG, SP), RTMP, RCX); // MOVL R.SP, CX
+ modrm(Ostw, O(REG, SP), RTMP, RAX); // MOVL AX, R.SP
+
+ modrm(Ostw, O(Frame, t), RCX, RTA); // MOVL RTA, t(CX) f->t = t
+ modrm(Omov, REGMOD*4, RCX, 0); // MOVL $0, mr(CX) f->mr
+ genw(0);
+ modrm(Oldw, O(Type, initialize), RTA, RTA);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA); // JMP*L RTA
+ genb(Oret); // RET
+}
+
+static void
+macmfra(void)
+{
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+ modrm(Ostw, O(REG, s), RTMP, RAX); // Save type
+ modrm(Ostw, O(REG, d), RTMP, RTA); // Save destination
+ bra((ulong)rmfram, Ocall); // CALL rmfram
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+}
+
+static void
+macrelq(void)
+{
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ genb(Opopl+RAX);
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ modrm(Oldw, j, RFP, RAX);
+ rbra(macro[MacFRP], Ocall);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RAX);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ modrm(Ostw, j, RCX, RAX);
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ uchar *tmp;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(uchar), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ if(cflag > 3)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ (ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+
+ segflush(t->initialize, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ ulong v;
+ Modl *e;
+ Link *l;
+ int i, n;
+ uchar *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = mallocz(4096*sizeof(uchar),0);
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+
+ n = (n+3)&~3;
+
+ nlit *= sizeof(ulong);
+ base = mallocz(n + nlit, 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d 386=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = (ulong*)(base+n);
+ code = base;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(cflag > 4) {
+ print("%D\n", &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++)
+ mactab[i].gen();
+
+ v = (ulong)base;
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(v+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(v+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(base);
+ return 0;
+}
+
--- /dev/null
+++ b/libinterp/das-amd64.c
@@ -1,0 +1,1630 @@
+#include <lib9.h>
+#include <kernel.h>
+
+int i386inst(ulong, char, char*, int);
+int i386das(ulong, char*, int);
+int i386instlen(ulong);
+
+static uchar *dasdata;
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+/*
+ * an instruction
+ */
+typedef struct Instr Instr;
+struct Instr
+{
+ uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
+ ulong addr; /* address of start of instruction */
+ int n; /* number of bytes in instruction */
+ char *prefix; /* instr prefix */
+ char *segment; /* segment override */
+ uchar jumptype; /* set to the operand type for jump/ret/call */
+ char osize; /* 'W' or 'L' */
+ char asize; /* address size 'W' or 'L' */
+ uchar mod; /* bits 6-7 of mod r/m field */
+ uchar reg; /* bits 3-5 of mod r/m field */
+ char ss; /* bits 6-7 of SIB */
+ char index; /* bits 3-5 of SIB */
+ char base; /* bits 0-2 of SIB */
+ short seg; /* segment of far address */
+ ulong disp; /* displacement */
+ ulong imm; /* immediate */
+ ulong imm2; /* second immediate operand */
+ char *curr; /* fill level in output buffer */
+ char *end; /* end of output buffer */
+ char *err; /* error message */
+};
+
+ /* 386 register (ha!) set */
+enum{
+ AX=0,
+ CX,
+ DX,
+ BX,
+ SP,
+ BP,
+ SI,
+ DI,
+};
+ /* Operand Format codes */
+/*
+%A - address size register modifier (!asize -> 'E')
+%C - Control register CR0/CR1/CR2
+%D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I - second immediate operand
+%O - Operand size register modifier (!osize -> 'E')
+%T - Test register TR6/TR7
+%S - size code ('W' or 'L')
+%X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d - displacement 16-32 bits
+%e - effective address - Mod R/M value
+%f - floating point register F0-F7 - from Mod R/M register
+%g - segment register
+%i - immediate operand 8-32 bits
+%p - PC-relative - signed displacement in immediate field
+%r - Reg from Mod R/M
+%x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+ char operand[2];
+ void *proto; /* actually either (char*) or (Optable*) */
+};
+ /* Operand decoding codes */
+enum {
+ Ib = 1, /* 8-bit immediate - (no sign extension)*/
+ Ibs, /* 8-bit immediate (sign extended) */
+ Jbs, /* 8-bit sign-extended immediate in jump or call */
+ Iw, /* 16-bit immediate -> imm */
+ Iw2, /* 16-bit immediate -> imm2 */
+ Iwd, /* Operand-sized immediate (no sign extension)*/
+ Awd, /* Address offset */
+ Iwds, /* Operand-sized immediate (sign extended) */
+ RM, /* Word or long R/M field with register (/r) */
+ RMB, /* Byte R/M field with register (/r) */
+ RMOP, /* Word or long R/M field with op code (/digit) */
+ RMOPB, /* Byte R/M field with op code (/digit) */
+ RMR, /* R/M register only (mod = 11) */
+ RMM, /* R/M memory only (mod = 0/1/2) */
+ R0, /* Base reg of Mod R/M is literal 0x00 */
+ R1, /* Base reg of Mod R/M is literal 0x01 */
+ FRMOP, /* Floating point R/M field with opcode */
+ FRMEX, /* Extended floating point R/M field with opcode */
+ JUMP, /* Jump or Call flag - no operand */
+ RET, /* Return flag - no operand */
+ OA, /* literal 0x0a byte */
+ PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ AUX, /* Multi-byte op code - Auxiliary table */
+ PRE, /* Instr Prefix */
+ SEG, /* Segment Prefix */
+ OPOVER, /* Operand size override */
+ ADDOVER, /* Address size override */
+};
+
+static Optable optab0F00[8]=
+{
+ 0,0, "MOVW LDT,%e",
+ 0,0, "MOVW TR,%e",
+ 0,0, "MOVW %e,LDT",
+ 0,0, "MOVW %e,TR",
+ 0,0, "VERR %e",
+ 0,0, "VERW %e",
+};
+
+static Optable optab0F01[8]=
+{
+ 0,0, "MOVL GDTR,%e",
+ 0,0, "MOVL IDTR,%e",
+ 0,0, "MOVL %e,GDTR",
+ 0,0, "MOVL %e,IDTR",
+ 0,0, "MOVW MSW,%e", /* word */
+ 0,0, nil,
+ 0,0, "MOVW %e,MSW", /* word */
+};
+
+static Optable optab0FBA[8]=
+{
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ Ib,0, "BT%S %i,%e",
+ Ib,0, "BTS%S %i,%e",
+ Ib,0, "BTR%S %i,%e",
+ Ib,0, "BTC%S %i,%e",
+};
+
+static Optable optab0F[256]=
+{
+ RMOP,0, optab0F00,
+ RMOP,0, optab0F01,
+ RM,0, "LAR %e,%r",
+ RM,0, "LSL %e,%r",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "CLTS",
+ 0,0, nil,
+ 0,0, "INVD",
+ 0,0, "WBINVD",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ RMR,0, "MOVL %C,%e", /* [0x20] */
+ RMR,0, "MOVL %D,%e",
+ RMR,0, "MOVL %e,%C",
+ RMR,0, "MOVL %e,%D",
+ RMR,0, "MOVL %T,%e",
+ 0,0, nil,
+ RMR,0, "MOVL %e,%T",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, "WRMSR", /* [0x30] */
+ 0,0, "RDTSC",
+ 0,0, "RDMSR",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ Iwds,0, "JOS %p", /* [0x80] */
+ Iwds,0, "JOC %p",
+ Iwds,0, "JCS %p",
+ Iwds,0, "JCC %p",
+ Iwds,0, "JEQ %p",
+ Iwds,0, "JNE %p",
+ Iwds,0, "JLS %p",
+ Iwds,0, "JHI %p",
+ Iwds,0, "JMI %p",
+ Iwds,0, "JPL %p",
+ Iwds,0, "JPS %p",
+ Iwds,0, "JPC %p",
+ Iwds,0, "JLT %p",
+ Iwds,0, "JGE %p",
+ Iwds,0, "JLE %p",
+ Iwds,0, "JGT %p",
+
+ RMB,0, "SETOS %e", /* [0x90] */
+ RMB,0, "SETOC %e",
+ RMB,0, "SETCS %e",
+ RMB,0, "SETCC %e",
+ RMB,0, "SETEQ %e",
+ RMB,0, "SETNE %e",
+ RMB,0, "SETLS %e",
+ RMB,0, "SETHI %e",
+ RMB,0, "SETMI %e",
+ RMB,0, "SETPL %e",
+ RMB,0, "SETPS %e",
+ RMB,0, "SETPC %e",
+ RMB,0, "SETLT %e",
+ RMB,0, "SETGE %e",
+ RMB,0, "SETLE %e",
+ RMB,0, "SETGT %e",
+
+ 0,0, "PUSHL FS", /* [0xa0] */
+ 0,0, "POPL FS",
+ 0,0, "CPUID",
+ RM,0, "BT%S %r,%e",
+ RM,Ib, "SHLD%S %r,%i,%e",
+ RM,0, "SHLD%S %r,CL,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "PUSHL GS",
+ 0,0, "POPL GS",
+ 0,0, nil,
+ RM,0, "BTS%S %r,%e",
+ RM,Ib, "SHRD%S %r,%i,%e",
+ RM,0, "SHRD%S %r,CL,%e",
+ 0,0, nil,
+ RM,0, "IMUL%S %e,%r",
+
+ 0,0, nil,
+ 0,0, nil,
+ RMM,0, "LSS %e,%r", /* [0xb2] */
+ RM,0, "BTR%S %r,%e",
+ RMM,0, "LFS %e,%r",
+ RMM,0, "LGS %e,%r",
+ RMB,0, "MOVBZX %e,%R",
+ RM,0, "MOVWZX %e,%R",
+ 0,0, nil,
+ 0,0, nil,
+ RMOP,0, optab0FBA,
+ RM,0, "BTC%S %e,%r",
+ RM,0, "BSF%S %e,%r",
+ RM,0, "BSR%S %e,%r",
+ RMB,0, "MOVBSX %e,%R",
+ RM,0, "MOVWSX %e,%R",
+};
+
+static Optable optab80[8]=
+{
+ Ib,0, "ADDB %i,%e",
+ Ib,0, "ORB %i,%e",
+ Ib,0, "ADCB %i,%e",
+ Ib,0, "SBBB %i,%e",
+ Ib,0, "ANDB %i,%e",
+ Ib,0, "SUBB %i,%e",
+ Ib,0, "XORB %i,%e",
+ Ib,0, "CMPB %e,%i",
+};
+
+static Optable optab81[8]=
+{
+ Iwd,0, "ADD%S %i,%e",
+ Iwd,0, "OR%S %i,%e",
+ Iwd,0, "ADC%S %i,%e",
+ Iwd,0, "SBB%S %i,%e",
+ Iwd,0, "AND%S %i,%e",
+ Iwd,0, "SUB%S %i,%e",
+ Iwd,0, "XOR%S %i,%e",
+ Iwd,0, "CMP%S %e,%i",
+};
+
+static Optable optab83[8]=
+{
+ Ibs,0, "ADD%S %i,%e",
+ Ibs,0, "OR%S %i,%e",
+ Ibs,0, "ADC%S %i,%e",
+ Ibs,0, "SBB%S %i,%e",
+ Ibs,0, "AND%S %i,%e",
+ Ibs,0, "SUB%S %i,%e",
+ Ibs,0, "XOR%S %i,%e",
+ Ibs,0, "CMP%S %e,%i",
+};
+
+static Optable optabC0[8] =
+{
+ Ib,0, "ROLB %i,%e",
+ Ib,0, "RORB %i,%e",
+ Ib,0, "RCLB %i,%e",
+ Ib,0, "RCRB %i,%e",
+ Ib,0, "SHLB %i,%e",
+ Ib,0, "SHRB %i,%e",
+ 0,0, nil,
+ Ib,0, "SARB %i,%e",
+};
+
+static Optable optabC1[8] =
+{
+ Ib,0, "ROL%S %i,%e",
+ Ib,0, "ROR%S %i,%e",
+ Ib,0, "RCL%S %i,%e",
+ Ib,0, "RCR%S %i,%e",
+ Ib,0, "SHL%S %i,%e",
+ Ib,0, "SHR%S %i,%e",
+ 0,0, nil,
+ Ib,0, "SAR%S %i,%e",
+};
+
+static Optable optabD0[8] =
+{
+ 0,0, "ROLB %e",
+ 0,0, "RORB %e",
+ 0,0, "RCLB %e",
+ 0,0, "RCRB %e",
+ 0,0, "SHLB %e",
+ 0,0, "SHRB %e",
+ 0,0, nil,
+ 0,0, "SARB %e",
+};
+
+static Optable optabD1[8] =
+{
+ 0,0, "ROL%S %e",
+ 0,0, "ROR%S %e",
+ 0,0, "RCL%S %e",
+ 0,0, "RCR%S %e",
+ 0,0, "SHL%S %e",
+ 0,0, "SHR%S %e",
+ 0,0, nil,
+ 0,0, "SAR%S %e",
+};
+
+static Optable optabD2[8] =
+{
+ 0,0, "ROLB CL,%e",
+ 0,0, "RORB CL,%e",
+ 0,0, "RCLB CL,%e",
+ 0,0, "RCRB CL,%e",
+ 0,0, "SHLB CL,%e",
+ 0,0, "SHRB CL,%e",
+ 0,0, nil,
+ 0,0, "SARB CL,%e",
+};
+
+static Optable optabD3[8] =
+{
+ 0,0, "ROL%S CL,%e",
+ 0,0, "ROR%S CL,%e",
+ 0,0, "RCL%S CL,%e",
+ 0,0, "RCR%S CL,%e",
+ 0,0, "SHL%S CL,%e",
+ 0,0, "SHR%S CL,%e",
+ 0,0, nil,
+ 0,0, "SAR%S CL,%e",
+};
+
+static Optable optabD8[8+8] =
+{
+ 0,0, "FADDF %e,F0",
+ 0,0, "FMULF %e,F0",
+ 0,0, "FCOMF %e,F0",
+ 0,0, "FCOMFP %e,F0",
+ 0,0, "FSUBF %e,F0",
+ 0,0, "FSUBRF %e,F0",
+ 0,0, "FDIVF %e,F0",
+ 0,0, "FDIVRF %e,F0",
+ 0,0, "FADDD %f,F0",
+ 0,0, "FMULD %f,F0",
+ 0,0, "FCOMD %f,F0",
+ 0,0, "FCOMPD %f,F0",
+ 0,0, "FSUBD %f,F0",
+ 0,0, "FSUBRD %f,F0",
+ 0,0, "FDIVD %f,F0",
+ 0,0, "FDIVRD %f,F0",
+};
+/*
+ * optabD9 and optabDB use the following encoding:
+ * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ * else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ * the instructions for MOD == 3, follow the 8 instructions
+ * for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+ 0,0, "FMOVF %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVF F0,%e",
+ 0,0, "FMOVFP F0,%e",
+ 0,0, "FLDENV%S %e",
+ 0,0, "FLDCW %e",
+ 0,0, "FSTENV%S %e",
+ 0,0, "FSTCW %e",
+ 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/
+ 0,0, "FMOVD F1,F0",
+ 0,0, "FMOVD F2,F0",
+ 0,0, "FMOVD F3,F0",
+ 0,0, "FMOVD F4,F0",
+ 0,0, "FMOVD F5,F0",
+ 0,0, "FMOVD F6,F0",
+ 0,0, "FMOVD F7,F0",
+ 0,0, "FXCHD F0,F0",
+ 0,0, "FXCHD F1,F0",
+ 0,0, "FXCHD F2,F0",
+ 0,0, "FXCHD F3,F0",
+ 0,0, "FXCHD F4,F0",
+ 0,0, "FXCHD F5,F0",
+ 0,0, "FXCHD F6,F0",
+ 0,0, "FXCHD F7,F0",
+ 0,0, "FNOP",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FCHS", /* [0x28] */
+ 0,0, "FABS",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FTST",
+ 0,0, "FXAM",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FLD1",
+ 0,0, "FLDL2T",
+ 0,0, "FLDL2E",
+ 0,0, "FLDPI",
+ 0,0, "FLDLG2",
+ 0,0, "FLDLN2",
+ 0,0, "FLDZ",
+ 0,0, nil,
+ 0,0, "F2XM1",
+ 0,0, "FYL2X",
+ 0,0, "FPTAN",
+ 0,0, "FPATAN",
+ 0,0, "FXTRACT",
+ 0,0, "FPREM1",
+ 0,0, "FDECSTP",
+ 0,0, "FNCSTP",
+ 0,0, "FPREM",
+ 0,0, "FYL2XP1",
+ 0,0, "FSQRT",
+ 0,0, "FSINCOS",
+ 0,0, "FRNDINT",
+ 0,0, "FSCALE",
+ 0,0, "FSIN",
+ 0,0, "FCOS",
+};
+
+static Optable optabDA[8+8] =
+{
+ 0,0, "FADDL %e,F0",
+ 0,0, "FMULL %e,F0",
+ 0,0, "FCOML %e,F0",
+ 0,0, "FCOMLP %e,F0",
+ 0,0, "FSUBL %e,F0",
+ 0,0, "FSUBRL %e,F0",
+ 0,0, "FDIVL %e,F0",
+ 0,0, "FDIVRL %e,F0",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ R1,0, "FUCOMPP", /* [0x0d] */
+};
+
+static Optable optabDB[8+64] =
+{
+ 0,0, "FMOVL %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVL F0,%e",
+ 0,0, "FMOVLP F0,%e",
+ 0,0, nil,
+ 0,0, "FMOVX %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVXP F0,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FCLEX", /* [0x2a] */
+ 0,0, "FINIT",
+};
+
+static Optable optabDC[8+8] =
+{
+ 0,0, "FADDD %e,F0",
+ 0,0, "FMULD %e,F0",
+ 0,0, "FCOMD %e,F0",
+ 0,0, "FCOMDP %e,F0",
+ 0,0, "FSUBD %e,F0",
+ 0,0, "FSUBRD %e,F0",
+ 0,0, "FDIVD %e,F0",
+ 0,0, "FDIVRD %e,F0",
+ 0,0, "FADDD F0,%f",
+ 0,0, "FMULD F0,%f",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FSUBRD F0,%f",
+ 0,0, "FSUBD F0,%f",
+ 0,0, "FDIVRD F0,%f",
+ 0,0, "FDIVD F0,%f",
+};
+
+static Optable optabDD[8+8] =
+{
+ 0,0, "FMOVD %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVD F0,%e",
+ 0,0, "FMOVDP F0,%e",
+ 0,0, "FRSTOR%S %e",
+ 0,0, nil,
+ 0,0, "FSAVE%S %e",
+ 0,0, "FSTSW %e",
+ 0,0, "FFREED %f",
+ 0,0, nil,
+ 0,0, "FMOVD %f,F0",
+ 0,0, "FMOVDP %f,F0",
+ 0,0, "FUCOMD %f,F0",
+ 0,0, "FUCOMDP %f,F0",
+};
+
+static Optable optabDE[8+8] =
+{
+ 0,0, "FADDW %e,F0",
+ 0,0, "FMULW %e,F0",
+ 0,0, "FCOMW %e,F0",
+ 0,0, "FCOMWP %e,F0",
+ 0,0, "FSUBW %e,F0",
+ 0,0, "FSUBRW %e,F0",
+ 0,0, "FDIVW %e,F0",
+ 0,0, "FDIVRW %e,F0",
+ 0,0, "FADDDP F0,%f",
+ 0,0, "FMULDP F0,%f",
+ 0,0, nil,
+ R1,0, "FCOMPDP",
+ 0,0, "FSUBRDP F0,%f",
+ 0,0, "FSUBDP F0,%f",
+ 0,0, "FDIVRDP F0,%f",
+ 0,0, "FDIVDP F0,%f",
+};
+
+static Optable optabDF[8+8] =
+{
+ 0,0, "FMOVW %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVW F0,%e",
+ 0,0, "FMOVWP F0,%e",
+ 0,0, "FBLD %e",
+ 0,0, "FMOVL %e,F0",
+ 0,0, "FBSTP %e",
+ 0,0, "FMOVLP F0,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ R0,0, "FSTSW %OAX",
+};
+
+static Optable optabF6[8] =
+{
+ Ib,0, "TESTB %i,%e",
+ 0,0, nil,
+ 0,0, "NOTB %e",
+ 0,0, "NEGB %e",
+ 0,0, "MULB AL,%e",
+ 0,0, "IMULB AL,%e",
+ 0,0, "DIVB AL,%e",
+ 0,0, "IDIVB AL,%e",
+};
+
+static Optable optabF7[8] =
+{
+ Iwd,0, "TEST%S %i,%e",
+ 0,0, nil,
+ 0,0, "NOT%S %e",
+ 0,0, "NEG%S %e",
+ 0,0, "MUL%S %OAX,%e",
+ 0,0, "IMUL%S %OAX,%e",
+ 0,0, "DIV%S %OAX,%e",
+ 0,0, "IDIV%S %OAX,%e",
+};
+
+static Optable optabFE[8] =
+{
+ 0,0, "INCB %e",
+ 0,0, "DECB %e",
+};
+
+static Optable optabFF[8] =
+{
+ 0,0, "INC%S %e",
+ 0,0, "DEC%S %e",
+ JUMP,0, "CALL*%S %e",
+ JUMP,0, "CALLF*%S %e",
+ JUMP,0, "JMP*%S %e",
+ JUMP,0, "JMPF*%S %e",
+ 0,0, "PUSHL %e",
+};
+
+static Optable optable[256] =
+{
+ RMB,0, "ADDB %r,%e",
+ RM,0, "ADD%S %r,%e",
+ RMB,0, "ADDB %e,%r",
+ RM,0, "ADD%S %e,%r",
+ Ib,0, "ADDB %i,AL",
+ Iwd,0, "ADD%S %i,%OAX",
+ 0,0, "PUSHL ES",
+ 0,0, "POPL ES",
+ RMB,0, "ORB %r,%e",
+ RM,0, "OR%S %r,%e",
+ RMB,0, "ORB %e,%r",
+ RM,0, "OR%S %e,%r",
+ Ib,0, "ORB %i,AL",
+ Iwd,0, "OR%S %i,%OAX",
+ 0,0, "PUSHL CS",
+ AUX,0, optab0F,
+ RMB,0, "ADCB %r,%e",
+ RM,0, "ADC%S %r,%e",
+ RMB,0, "ADCB %e,%r",
+ RM,0, "ADC%S %e,%r",
+ Ib,0, "ADCB %i,AL",
+ Iwd,0, "ADC%S %i,%OAX",
+ 0,0, "PUSHL SS",
+ 0,0, "POPL SS",
+ RMB,0, "SBBB %r,%e",
+ RM,0, "SBB%S %r,%e",
+ RMB,0, "SBBB %e,%r",
+ RM,0, "SBB%S %e,%r",
+ Ib,0, "SBBB %i,AL",
+ Iwd,0, "SBB%S %i,%OAX",
+ 0,0, "PUSHL DS",
+ 0,0, "POPL DS",
+ RMB,0, "ANDB %r,%e",
+ RM,0, "AND%S %r,%e",
+ RMB,0, "ANDB %e,%r",
+ RM,0, "AND%S %e,%r",
+ Ib,0, "ANDB %i,AL",
+ Iwd,0, "AND%S %i,%OAX",
+ SEG,0, "ES:",
+ 0,0, "DAA",
+ RMB,0, "SUBB %r,%e",
+ RM,0, "SUB%S %r,%e",
+ RMB,0, "SUBB %e,%r",
+ RM,0, "SUB%S %e,%r",
+ Ib,0, "SUBB %i,AL",
+ Iwd,0, "SUB%S %i,%OAX",
+ SEG,0, "CS:",
+ 0,0, "DAS",
+ RMB,0, "XORB %r,%e",
+ RM,0, "XOR%S %r,%e",
+ RMB,0, "XORB %e,%r",
+ RM,0, "XOR%S %e,%r",
+ Ib,0, "XORB %i,AL",
+ Iwd,0, "XOR%S %i,%OAX",
+ SEG,0, "SS:",
+ 0,0, "AAA",
+ RMB,0, "CMPB %r,%e",
+ RM,0, "CMP%S %r,%e",
+ RMB,0, "CMPB %e,%r",
+ RM,0, "CMP%S %e,%r",
+ Ib,0, "CMPB %i,AL",
+ Iwd,0, "CMP%S %i,%OAX",
+ SEG,0, "DS:",
+ 0,0, "AAS",
+ 0,0, "INC%S %OAX",
+ 0,0, "INC%S %OCX",
+ 0,0, "INC%S %ODX",
+ 0,0, "INC%S %OBX",
+ 0,0, "INC%S %OSP",
+ 0,0, "INC%S %OBP",
+ 0,0, "INC%S %OSI",
+ 0,0, "INC%S %ODI",
+ 0,0, "DEC%S %OAX",
+ 0,0, "DEC%S %OCX",
+ 0,0, "DEC%S %ODX",
+ 0,0, "DEC%S %OBX",
+ 0,0, "DEC%S %OSP",
+ 0,0, "DEC%S %OBP",
+ 0,0, "DEC%S %OSI",
+ 0,0, "DEC%S %ODI",
+ 0,0, "PUSH%S %OAX",
+ 0,0, "PUSH%S %OCX",
+ 0,0, "PUSH%S %ODX",
+ 0,0, "PUSH%S %OBX",
+ 0,0, "PUSH%S %OSP",
+ 0,0, "PUSH%S %OBP",
+ 0,0, "PUSH%S %OSI",
+ 0,0, "PUSH%S %ODI",
+ 0,0, "POP%S %OAX",
+ 0,0, "POP%S %OCX",
+ 0,0, "POP%S %ODX",
+ 0,0, "POP%S %OBX",
+ 0,0, "POP%S %OSP",
+ 0,0, "POP%S %OBP",
+ 0,0, "POP%S %OSI",
+ 0,0, "POP%S %ODI",
+ 0,0, "PUSHA%S",
+ 0,0, "POPA%S",
+ RMM,0, "BOUND %e,%r",
+ RM,0, "ARPL %r,%e",
+ SEG,0, "FS:",
+ SEG,0, "GS:",
+ OPOVER,0, "",
+ ADDOVER,0, "",
+ Iwd,0, "PUSH%S %i",
+ RM,Iwd, "IMUL%S %e,%i,%r",
+ Ib,0, "PUSH%S %i",
+ RM,Ibs, "IMUL%S %e,%i,%r",
+ 0,0, "INSB DX,(%ODI)",
+ 0,0, "INS%S DX,(%ODI)",
+ 0,0, "OUTSB (%ASI),DX",
+ 0,0, "OUTS%S (%ASI),DX",
+ Jbs,0, "JOS %p",
+ Jbs,0, "JOC %p",
+ Jbs,0, "JCS %p",
+ Jbs,0, "JCC %p",
+ Jbs,0, "JEQ %p",
+ Jbs,0, "JNE %p",
+ Jbs,0, "JLS %p",
+ Jbs,0, "JHI %p",
+ Jbs,0, "JMI %p",
+ Jbs,0, "JPL %p",
+ Jbs,0, "JPS %p",
+ Jbs,0, "JPC %p",
+ Jbs,0, "JLT %p",
+ Jbs,0, "JGE %p",
+ Jbs,0, "JLE %p",
+ Jbs,0, "JGT %p",
+ RMOPB,0, optab80,
+ RMOP,0, optab81,
+ 0,0, nil,
+ RMOP,0, optab83,
+ RMB,0, "TESTB %r,%e",
+ RM,0, "TEST%S %r,%e",
+ RMB,0, "XCHGB %r,%e",
+ RM,0, "XCHG%S %r,%e",
+ RMB,0, "MOVB %r,%e",
+ RM,0, "MOV%S %r,%e",
+ RMB,0, "MOVB %e,%r",
+ RM,0, "MOV%S %e,%r",
+ RM,0, "MOVW %g,%e",
+ RM,0, "LEA %e,%r",
+ RM,0, "MOVW %e,%g",
+ RM,0, "POP%S %e",
+ 0,0, "NOP",
+ 0,0, "XCHG %OCX,%OAX",
+ 0,0, "XCHG %ODX,%OAX",
+ 0,0, "XCHG %OBX,%OAX",
+ 0,0, "XCHG %OSP,%OAX",
+ 0,0, "XCHG %OBP,%OAX",
+ 0,0, "XCHG %OSI,%OAX",
+ 0,0, "XCHG %ODI,%OAX",
+ 0,0, "%X", /* miserable CBW or CWDE */
+ 0,0, "%x", /* idiotic CWD or CDQ */
+ PTR,0, "CALL%S %d",
+ 0,0, "WAIT",
+ 0,0, "PUSH FLAGS",
+ 0,0, "POP FLAGS",
+ 0,0, "SAHF",
+ 0,0, "LAHF",
+ Awd,0, "MOVB %i,AL",
+ Awd,0, "MOV%S %i,%OAX",
+ Awd,0, "MOVB AL,%i",
+ Awd,0, "MOV%S %OAX,%i",
+ 0,0, "MOVSB (%ASI),(%ADI)",
+ 0,0, "MOVS%S (%ASI),(%ADI)",
+ 0,0, "CMPSB (%ASI),(%ADI)",
+ 0,0, "CMPS%S (%ASI),(%ADI)",
+ Ib,0, "TESTB %i,AL",
+ Iwd,0, "TEST%S %i,%OAX",
+ 0,0, "STOSB AL,(%ADI)",
+ 0,0, "STOS%S %OAX,(%ADI)",
+ 0,0, "LODSB (%ASI),AL",
+ 0,0, "LODS%S (%ASI),%OAX",
+ 0,0, "SCASB (%ADI),AL",
+ 0,0, "SCAS%S (%ADI),%OAX",
+ Ib,0, "MOVB %i,AL",
+ Ib,0, "MOVB %i,CL",
+ Ib,0, "MOVB %i,DL",
+ Ib,0, "MOVB %i,BL",
+ Ib,0, "MOVB %i,AH",
+ Ib,0, "MOVB %i,CH",
+ Ib,0, "MOVB %i,DH",
+ Ib,0, "MOVB %i,BH",
+ Iwd,0, "MOV%S %i,%OAX",
+ Iwd,0, "MOV%S %i,%OCX",
+ Iwd,0, "MOV%S %i,%ODX",
+ Iwd,0, "MOV%S %i,%OBX",
+ Iwd,0, "MOV%S %i,%OSP",
+ Iwd,0, "MOV%S %i,%OBP",
+ Iwd,0, "MOV%S %i,%OSI",
+ Iwd,0, "MOV%S %i,%ODI",
+ RMOPB,0, optabC0,
+ RMOP,0, optabC1,
+ Iw,0, "RET %i",
+ RET,0, "RET",
+ RM,0, "LES %e,%r",
+ RM,0, "LDS %e,%r",
+ RMB,Ib, "MOVB %i,%e",
+ RM,Iwd, "MOV%S %i,%e",
+ Iw2,Ib, "ENTER %i,%I", /* loony ENTER */
+ RET,0, "LEAVE", /* bizarre LEAVE */
+ Iw,0, "RETF %i",
+ RET,0, "RETF",
+ 0,0, "INT 3",
+ Ib,0, "INTB %i",
+ 0,0, "INTO",
+ 0,0, "IRET",
+ RMOPB,0, optabD0,
+ RMOP,0, optabD1,
+ RMOPB,0, optabD2,
+ RMOP,0, optabD3,
+ OA,0, "AAM",
+ OA,0, "AAD",
+ 0,0, nil,
+ 0,0, "XLAT",
+ FRMOP,0, optabD8,
+ FRMEX,0, optabD9,
+ FRMOP,0, optabDA,
+ FRMEX,0, optabDB,
+ FRMOP,0, optabDC,
+ FRMOP,0, optabDD,
+ FRMOP,0, optabDE,
+ FRMOP,0, optabDF,
+ Jbs,0, "LOOPNE %p",
+ Jbs,0, "LOOPE %p",
+ Jbs,0, "LOOP %p",
+ Jbs,0, "JCXZ %p",
+ Ib,0, "INB %i,AL",
+ Ib,0, "IN%S %i,%OAX",
+ Ib,0, "OUTB AL,%i",
+ Ib,0, "OUT%S %OAX,%i",
+ Iwds,0, "CALL %p",
+ Iwds,0, "JMP %p",
+ PTR,0, "JMP %d",
+ Jbs,0, "JMP %p",
+ 0,0, "INB DX,AL",
+ 0,0, "IN%S DX,%OAX",
+ 0,0, "OUTB AL,DX",
+ 0,0, "OUT%S %OAX,DX",
+ PRE,0, "LOCK",
+ 0,0, nil,
+ PRE,0, "REPNE",
+ PRE,0, "REP",
+ 0,0, "HALT",
+ 0,0, "CMC",
+ RMOPB,0, optabF6,
+ RMOP,0, optabF7,
+ 0,0, "CLC",
+ 0,0, "STC",
+ 0,0, "CLI",
+ 0,0, "STI",
+ 0,0, "CLD",
+ 0,0, "STD",
+ RMOPB,0, optabFE,
+ RMOP,0, optabFF,
+};
+
+/*
+ * get a byte of the instruction
+ */
+static int
+igetc(Instr *ip, uchar *c)
+{
+ if(ip->n+1 > sizeof(ip->mem)){
+ kwerrstr("instruction too long");
+ return -1;
+ }
+ *c = dasdata[ip->addr+ip->n];
+ ip->mem[ip->n++] = *c;
+ return 1;
+}
+
+/*
+ * get two bytes of the instruction
+ */
+static int
+igets(Instr *ip, ushort *sp)
+{
+ uchar c;
+ ushort s;
+
+ if (igetc(ip, &c) < 0)
+ return -1;
+ s = c;
+ if (igetc(ip, &c) < 0)
+ return -1;
+ s |= (c<<8);
+ *sp = s;
+ return 1;
+}
+
+/*
+ * get 4 bytes of the instruction
+ */
+static int
+igetl(Instr *ip, ulong *lp)
+{
+ ushort s;
+ long l;
+
+ if (igets(ip, &s) < 0)
+ return -1;
+ l = s;
+ if (igets(ip, &s) < 0)
+ return -1;
+ l |= (s<<16);
+ *lp = l;
+ return 1;
+}
+
+static int
+getdisp(Instr *ip, int mod, int rm, int code)
+{
+ uchar c;
+ ushort s;
+
+ if (mod > 2)
+ return 1;
+ if (mod == 1) {
+ if (igetc(ip, &c) < 0)
+ return -1;
+ if (c&0x80)
+ ip->disp = c|0xffffff00;
+ else
+ ip->disp = c&0xff;
+ } else if (mod == 2 || rm == code) {
+ if (ip->asize == 'E') {
+ if (igetl(ip, &ip->disp) < 0)
+ return -1;
+ } else {
+ if (igets(ip, &s) < 0)
+ return -1;
+ if (s&0x8000)
+ ip->disp = s|0xffff0000;
+ else
+ ip->disp = s;
+ }
+ if (mod == 0)
+ ip->base = -1;
+ }
+ return 1;
+}
+
+static int
+modrm(Instr *ip, uchar c)
+{
+ uchar rm, mod;
+
+ mod = (c>>6)&3;
+ rm = c&7;
+ ip->mod = mod;
+ ip->base = rm;
+ ip->reg = (c>>3)&7;
+ if (mod == 3) /* register */
+ return 1;
+ if (ip->asize == 0) { /* 16-bit mode */
+ switch(rm)
+ {
+ case 0:
+ ip->base = BX; ip->index = SI;
+ break;
+ case 1:
+ ip->base = BX; ip->index = DI;
+ break;
+ case 2:
+ ip->base = BP; ip->index = SI;
+ break;
+ case 3:
+ ip->base = BP; ip->index = DI;
+ break;
+ case 4:
+ ip->base = SI;
+ break;
+ case 5:
+ ip->base = DI;
+ break;
+ case 6:
+ ip->base = BP;
+ break;
+ case 7:
+ ip->base = BX;
+ break;
+ default:
+ break;
+ }
+ return getdisp(ip, mod, rm, 6);
+ }
+ if (rm == 4) { /* scummy sib byte */
+ if (igetc(ip, &c) < 0)
+ return -1;
+ ip->ss = (c>>6)&0x03;
+ ip->index = (c>>3)&0x07;
+ if (ip->index == 4)
+ ip->index = -1;
+ ip->base = c&0x07;
+ return getdisp(ip, mod, ip->base, 5);
+ }
+ return getdisp(ip, mod, rm, 5);
+}
+
+static Optable *
+mkinstr(Instr *ip, ulong pc)
+{
+ int i, n;
+ uchar c;
+ ushort s;
+ Optable *op, *obase;
+ char buf[128];
+
+ memset(ip, 0, sizeof(*ip));
+ ip->base = -1;
+ ip->index = -1;
+ ip->osize = 'L';
+ ip->asize = 'E';
+ ip->addr = pc;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ obase = optable;
+newop:
+ op = &obase[c];
+ if (op->proto == 0) {
+badop:
+ n = snprint(buf, sizeof(buf), "opcode: ??");
+ for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+ _hexify(buf+n, ip->mem[i], 1);
+ strcpy(buf+n, "??");
+ kwerrstr(buf);
+ return 0;
+ }
+ for(i = 0; i < 2 && op->operand[i]; i++) {
+ switch(op->operand[i])
+ {
+ case Ib: /* 8-bit immediate - (no sign extension)*/
+ if (igetc(ip, &c) < 0)
+ return 0;
+ ip->imm = c&0xff;
+ break;
+ case Jbs: /* 8-bit jump immediate (sign extended) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c&0xff;
+ ip->jumptype = Jbs;
+ break;
+ case Ibs: /* 8-bit immediate (sign extended) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ if (ip->osize == 'L')
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c|0xff00;
+ else
+ ip->imm = c&0xff;
+ break;
+ case Iw: /* 16-bit immediate -> imm */
+ if (igets(ip, &s) < 0)
+ return 0;
+ ip->imm = s&0xffff;
+ ip->jumptype = Iw;
+ break;
+ case Iw2: /* 16-bit immediate -> in imm2*/
+ if (igets(ip, &s) < 0)
+ return 0;
+ ip->imm2 = s&0xffff;
+ break;
+ case Iwd: /* Operand-sized immediate (no sign extension)*/
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Awd: /* Address-sized immediate (no sign extension)*/
+ if (ip->asize == 'E') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Iwds: /* Operand-sized immediate (sign extended) */
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ if (s&0x8000)
+ ip->imm = s|0xffff0000;
+ else
+ ip->imm = s&0xffff;
+ }
+ ip->jumptype = Iwds;
+ break;
+ case OA: /* literal 0x0a byte */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c != 0x0a)
+ goto badop;
+ break;
+ case R0: /* base register must be R0 */
+ if (ip->base != 0)
+ goto badop;
+ break;
+ case R1: /* base register must be R1 */
+ if (ip->base != 1)
+ goto badop;
+ break;
+ case RMB: /* R/M field with byte register (/r)*/
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ ip->osize = 'B';
+ break;
+ case RM: /* R/M field with register (/r) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case RMOPB: /* R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ c = ip->reg; /* secondary op code */
+ obase = (Optable*)op->proto;
+ ip->osize = 'B';
+ goto newop;
+ case RMOP: /* R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMOP: /* FP R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = ip->reg+8; /* 16 entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMEX: /* Extended FP R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = (c&0x3f)+8; /* 64-entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case RMR: /* R/M register only (mod = 11) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) != 0xc0) {
+ kwerrstr("invalid R/M register: %x", c);
+ return 0;
+ }
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case RMM: /* R/M register only (mod = 11) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0) {
+ kwerrstr("invalid R/M memory mode: %x", c);
+ return 0;
+ }
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->disp) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->disp = s&0xffff;
+ }
+ if (igets(ip, (ushort*)&ip->seg) < 0)
+ return 0;
+ ip->jumptype = PTR;
+ break;
+ case AUX: /* Multi-byte op code - Auxiliary table */
+ obase = (Optable*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case PRE: /* Instr Prefix */
+ ip->prefix = (char*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case SEG: /* Segment Prefix */
+ ip->segment = (char*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case OPOVER: /* Operand size override */
+ ip->osize = 'W';
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case ADDOVER: /* Address size override */
+ ip->asize = 0;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case JUMP: /* mark instruction as JUMP or RET */
+ case RET:
+ ip->jumptype = op->operand[i];
+ break;
+ default:
+ kwerrstr("bad operand type %d", op->operand[i]);
+ return 0;
+ }
+ }
+ return op;
+}
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+ va_end(arg);
+}
+
+/*
+ * if we want to call 16 bit regs AX,BX,CX,...
+ * and 32 bit regs EAX,EBX,ECX,... then
+ * change the defs of ANAME and ONAME to:
+ * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
+ * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
+ */
+#define ANAME(ip) ""
+#define ONAME(ip) ""
+
+static char *reg[] = {
+ "AX",
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+};
+
+static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+ int offset;
+
+ offset = ip->disp;
+
+ bprint(ip, "%lux(SP)", offset);
+}
+
+static void
+pea(Instr *ip)
+{
+ if (ip->mod == 3) {
+ if (ip->osize == 'B')
+ bprint(ip, breg[ip->base]);
+ else
+ bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
+ return;
+ }
+ if (ip->segment)
+ bprint(ip, ip->segment);
+ if (ip->asize == 'E' && ip->base == SP)
+ plocal(ip);
+ else {
+ bprint(ip,"%lux", ip->disp);
+ if (ip->base >= 0)
+ bprint(ip,"(%s%s)", ANAME(ip), reg[ip->base]);
+ }
+ if (ip->index >= 0)
+ bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss);
+}
+
+static void
+immediate(Instr *ip, long val)
+{
+ bprint(ip, "%lux", val);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+ if (ip->prefix)
+ bprint(ip, "%s ", ip->prefix);
+ for (; *fmt && ip->curr < ip->end; fmt++) {
+ if (*fmt != '%')
+ *ip->curr++ = *fmt;
+ else switch(*++fmt)
+ {
+ case '%':
+ *ip->curr++ = '%';
+ break;
+ case 'A':
+ bprint(ip, "%s", ANAME(ip));
+ break;
+ case 'C':
+ bprint(ip, "CR%d", ip->reg);
+ break;
+ case 'D':
+ if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "DR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'I':
+ bprint(ip, "$");
+ immediate(ip, ip->imm2);
+ break;
+ case 'O':
+ bprint(ip,"%s", ONAME(ip));
+ break;
+ case 'i':
+ bprint(ip, "$");
+ immediate(ip,ip->imm);
+ break;
+ case 'R':
+ bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
+ break;
+ case 'S':
+ bprint(ip, "%c", ip->osize);
+ break;
+ case 'T':
+ if (ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "TR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'X':
+ if (ip->osize == 'L')
+ bprint(ip,"CWDE");
+ else
+ bprint(ip, "CBW");
+ break;
+ case 'd':
+ bprint(ip,"%lux:%lux",ip->seg,ip->disp);
+ break;
+ case 'e':
+ pea(ip);
+ break;
+ case 'f':
+ bprint(ip, "F%d", ip->base);
+ break;
+ case 'g':
+ if (ip->reg < 6)
+ bprint(ip,"%s",sreg[ip->reg]);
+ else
+ bprint(ip,"???");
+ break;
+ case 'p':
+ immediate(ip, ip->imm+ip->addr+ip->n);
+ break;
+ case 'r':
+ if (ip->osize == 'B')
+ bprint(ip,"%s",breg[ip->reg]);
+ else
+ bprint(ip, reg[ip->reg]);
+ break;
+ case 'x':
+ if (ip->osize == 'L')
+ bprint(ip,"CDQ");
+ else
+ bprint(ip, "CWD");
+ break;
+ default:
+ bprint(ip, "%%%c", *fmt);
+ break;
+ }
+ }
+ *ip->curr = 0; /* there's always room for 1 byte */
+}
+
+int
+i386inst(ulong pc, char modifier, char *buf, int n)
+{
+ Instr instr;
+ Optable *op;
+
+ USED(modifier);
+ op = mkinstr(&instr, pc);
+ if (op == 0) {
+ kgerrstr(buf, n);
+ return -1;
+ }
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ prinstr(&instr, op->proto);
+ return instr.n;
+}
+
+int
+i386das(ulong pc, char *buf, int n)
+{
+ Instr instr;
+ int i;
+
+ if (mkinstr(&instr, pc) == 0) {
+ kgerrstr(buf, n);
+ return -1;
+ }
+ for(i = 0; i < instr.n && n > 2; i++) {
+ _hexify(buf, instr.mem[i], 1);
+ buf += 2;
+ n -= 2;
+ }
+ *buf = 0;
+ return instr.n;
+}
+
+int
+i386instlen(ulong pc)
+{
+ Instr i;
+
+ if (mkinstr(&i, pc))
+ return i.n;
+ return -1;
+}
+
+void
+das(uchar *x, int n)
+{
+ int l, pc;
+ char buf[128];
+/*
+ int i;
+ for(i = 0; i < n; i++)
+ print("%.2ux", x[i]);
+ print("\n");
+*/
+
+ dasdata = x;
+ pc = 0;
+ while(n > 0) {
+ i386das(pc, buf, sizeof(buf));
+ print("%.8lux %2x %-20s ", (ulong)(dasdata+pc), pc, buf);
+ l = i386inst(pc, 'i', buf, sizeof(buf));
+ print("\t%s\n", buf);
+
+ pc += l;
+ n -= l;
+ }
+}
--- /dev/null
+++ b/libinterp/dlm-9front.c
@@ -1,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define DBG if(1) print
+
+extern Dynobj* dynld(int);
+extern char* enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+ char buf[64];
+
+ if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+ return nil;
+ snprint(buf, sizeof(buf), "%s%s", pre, suf);
+ return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ Module *m;
+ void *v;
+ Runtab *r;
+ Dynobj *o;
+ char *name;
+
+ DBG("module path is %s\n", path);
+ m = nil;
+ o = dynld(fd);
+ if(o == nil){
+ DBG("%s\n", enverror());
+ goto Error;
+ }
+ v = addr("XXX", "module", o, signof(char*));
+ if(v == nil)
+ goto Error;
+ name = *(char**)v;
+ DBG("module name is %s\n", name);
+ r = addr(name, "modtab", o, signof(Runtab[]));
+ if(r == nil)
+ goto Error;
+ m = builtinmod(name, r, 0);
+ m->rt = DYNMOD;
+ m->dev = dir->dev;
+ m->dtype = dir->type;
+ m->qid = dir->qid;
+ m->mtime = dir->mtime;
+ m->path = strdup(path);
+ if(m->path == nil)
+ goto Error;
+ m->dlm = o;
+ DBG("module base is 0x%p\n", o->base);
+ return m;
+Error:
+ if(o != nil)
+ dynobjfree(o);
+ if(m != nil)
+ freemod(m);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+ void *v, (*f)(void);
+
+ if(m->ref != 1)
+ return;
+ v = addr(m->name, fn, m->dlm, signof(*f));
+ if(v != nil){
+ f = v;
+ (*f)();
+ }
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ callfn(ml->m, "end");
+}
--- /dev/null
+++ b/libmath/FPcontrol-9front.c
@@ -1,0 +1,1 @@
+#include "FPcontrol-Inferno.c"
--- /dev/null
+++ b/libmemdraw/mkfile-9front
@@ -1,0 +1,9 @@
+#
+# Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+ cload.$O\
+ draw.$O\
+ load.$O\
+ unload.$O\
+
--- /dev/null
+++ b/libmemlayer/mkfile-9front
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libsec/9front-amd64/md5block.s
@@ -1,0 +1,212 @@
+/*
+ * rfc1321 requires that I include this. The code is new. The constants
+ * all come from the rfc (hence the copyright). We trade a table for the
+ * macros in rfc. The total size is a lot less. -- presotto
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software forany particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/*
+ * SI is data
+ * a += FN(B,C,D);
+ * a += x[sh] + t[sh];
+ * a = (a << S11) | (a >> (32 - S11));
+ * a += b;
+ */
+
+#define BODY1(off,V,FN,SH,A,B,C,D)\
+ FN(B,C,D)\
+ LEAL V(A)(DI*1),A;\
+ ADDL (off)(BP),A;\
+ ROLL $SH,A;\
+ ADDL B,A;\
+
+#define BODY(off,V,FN,SH,A,B,C,D)\
+ FN(B,C,D)\
+ LEAL V(A)(DI*1),A;\
+ ADDL (off)(BP),A;\
+ ROLL $SH,A;\
+ ADDL B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+ MOVL C,DI;\
+ XORL D,DI;\
+ ANDL B,DI;\
+ XORL D,DI;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ ANDL D,DI;\
+ XORL C,DI;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL D,DI;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+ MOVL D,DI;\
+ XORL $-1,DI;\
+ ORL B,DI;\
+ XORL C,DI;\
+
+#define LEN 8
+#define STATE 16
+
+TEXT _md5block+0(SB),$0
+
+ MOVQ RARG,R8
+ MOVLQZX len+LEN(FP),BX
+ ADDQ BX,R8
+
+mainloop:
+ MOVQ state+STATE(FP),SI
+ MOVL (SI),AX
+ MOVL 4(SI),BX
+ MOVL 8(SI),CX
+ MOVL 12(SI),DX
+
+ BODY1( 0*4,0xd76aa478,FN1,S11,AX,BX,CX,DX)
+ BODY1( 1*4,0xe8c7b756,FN1,S12,DX,AX,BX,CX)
+ BODY1( 2*4,0x242070db,FN1,S13,CX,DX,AX,BX)
+ BODY1( 3*4,0xc1bdceee,FN1,S14,BX,CX,DX,AX)
+
+ BODY1( 4*4,0xf57c0faf,FN1,S11,AX,BX,CX,DX)
+ BODY1( 5*4,0x4787c62a,FN1,S12,DX,AX,BX,CX)
+ BODY1( 6*4,0xa8304613,FN1,S13,CX,DX,AX,BX)
+ BODY1( 7*4,0xfd469501,FN1,S14,BX,CX,DX,AX)
+
+ BODY1( 8*4,0x698098d8,FN1,S11,AX,BX,CX,DX)
+ BODY1( 9*4,0x8b44f7af,FN1,S12,DX,AX,BX,CX)
+ BODY1(10*4,0xffff5bb1,FN1,S13,CX,DX,AX,BX)
+ BODY1(11*4,0x895cd7be,FN1,S14,BX,CX,DX,AX)
+
+ BODY1(12*4,0x6b901122,FN1,S11,AX,BX,CX,DX)
+ BODY1(13*4,0xfd987193,FN1,S12,DX,AX,BX,CX)
+ BODY1(14*4,0xa679438e,FN1,S13,CX,DX,AX,BX)
+ BODY1(15*4,0x49b40821,FN1,S14,BX,CX,DX,AX)
+
+
+ BODY( 1*4,0xf61e2562,FN2,S21,AX,BX,CX,DX)
+ BODY( 6*4,0xc040b340,FN2,S22,DX,AX,BX,CX)
+ BODY(11*4,0x265e5a51,FN2,S23,CX,DX,AX,BX)
+ BODY( 0*4,0xe9b6c7aa,FN2,S24,BX,CX,DX,AX)
+
+ BODY( 5*4,0xd62f105d,FN2,S21,AX,BX,CX,DX)
+ BODY(10*4,0x02441453,FN2,S22,DX,AX,BX,CX)
+ BODY(15*4,0xd8a1e681,FN2,S23,CX,DX,AX,BX)
+ BODY( 4*4,0xe7d3fbc8,FN2,S24,BX,CX,DX,AX)
+
+ BODY( 9*4,0x21e1cde6,FN2,S21,AX,BX,CX,DX)
+ BODY(14*4,0xc33707d6,FN2,S22,DX,AX,BX,CX)
+ BODY( 3*4,0xf4d50d87,FN2,S23,CX,DX,AX,BX)
+ BODY( 8*4,0x455a14ed,FN2,S24,BX,CX,DX,AX)
+
+ BODY(13*4,0xa9e3e905,FN2,S21,AX,BX,CX,DX)
+ BODY( 2*4,0xfcefa3f8,FN2,S22,DX,AX,BX,CX)
+ BODY( 7*4,0x676f02d9,FN2,S23,CX,DX,AX,BX)
+ BODY(12*4,0x8d2a4c8a,FN2,S24,BX,CX,DX,AX)
+
+
+ BODY( 5*4,0xfffa3942,FN3,S31,AX,BX,CX,DX)
+ BODY( 8*4,0x8771f681,FN3,S32,DX,AX,BX,CX)
+ BODY(11*4,0x6d9d6122,FN3,S33,CX,DX,AX,BX)
+ BODY(14*4,0xfde5380c,FN3,S34,BX,CX,DX,AX)
+
+ BODY( 1*4,0xa4beea44,FN3,S31,AX,BX,CX,DX)
+ BODY( 4*4,0x4bdecfa9,FN3,S32,DX,AX,BX,CX)
+ BODY( 7*4,0xf6bb4b60,FN3,S33,CX,DX,AX,BX)
+ BODY(10*4,0xbebfbc70,FN3,S34,BX,CX,DX,AX)
+
+ BODY(13*4,0x289b7ec6,FN3,S31,AX,BX,CX,DX)
+ BODY( 0*4,0xeaa127fa,FN3,S32,DX,AX,BX,CX)
+ BODY( 3*4,0xd4ef3085,FN3,S33,CX,DX,AX,BX)
+ BODY( 6*4,0x04881d05,FN3,S34,BX,CX,DX,AX)
+
+ BODY( 9*4,0xd9d4d039,FN3,S31,AX,BX,CX,DX)
+ BODY(12*4,0xe6db99e5,FN3,S32,DX,AX,BX,CX)
+ BODY(15*4,0x1fa27cf8,FN3,S33,CX,DX,AX,BX)
+ BODY( 2*4,0xc4ac5665,FN3,S34,BX,CX,DX,AX)
+
+
+ BODY( 0*4,0xf4292244,FN4,S41,AX,BX,CX,DX)
+ BODY( 7*4,0x432aff97,FN4,S42,DX,AX,BX,CX)
+ BODY(14*4,0xab9423a7,FN4,S43,CX,DX,AX,BX)
+ BODY( 5*4,0xfc93a039,FN4,S44,BX,CX,DX,AX)
+
+ BODY(12*4,0x655b59c3,FN4,S41,AX,BX,CX,DX)
+ BODY( 3*4,0x8f0ccc92,FN4,S42,DX,AX,BX,CX)
+ BODY(10*4,0xffeff47d,FN4,S43,CX,DX,AX,BX)
+ BODY( 1*4,0x85845dd1,FN4,S44,BX,CX,DX,AX)
+
+ BODY( 8*4,0x6fa87e4f,FN4,S41,AX,BX,CX,DX)
+ BODY(15*4,0xfe2ce6e0,FN4,S42,DX,AX,BX,CX)
+ BODY( 6*4,0xa3014314,FN4,S43,CX,DX,AX,BX)
+ BODY(13*4,0x4e0811a1,FN4,S44,BX,CX,DX,AX)
+
+ BODY( 4*4,0xf7537e82,FN4,S41,AX,BX,CX,DX)
+ BODY(11*4,0xbd3af235,FN4,S42,DX,AX,BX,CX)
+ BODY( 2*4,0x2ad7d2bb,FN4,S43,CX,DX,AX,BX)
+ BODY( 9*4,0xeb86d391,FN4,S44,BX,CX,DX,AX)
+
+ ADDQ $(16*4),BP
+ MOVQ state+STATE(FP),DI
+ ADDL AX,0(DI)
+ ADDL BX,4(DI)
+ ADDL CX,8(DI)
+ ADDL DX,12(DI)
+
+ CMPL BP,R8
+ JCS mainloop
+
+ RET
--- /dev/null
+++ b/libsec/9front-amd64/mkfile
@@ -1,0 +1,16 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+ md5block\
+ sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/9front-amd64/sha1block.s
@@ -1,0 +1,197 @@
+ TEXT _sha1block+0(SB),$384
+
+/* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BSWAPDI BYTE $0x0f; BYTE $0xcf;
+
+#define BODY(off,FN,V,A,B,C,D,E)\
+ MOVL (off-64)(BP),DI;\
+ XORL (off-56)(BP),DI;\
+ XORL (off-32)(BP),DI;\
+ XORL (off-12)(BP),DI;\
+ ROLL $1,DI;\
+ MOVL DI,off(BP);\
+ LEAL V(DI)(E*1),E;\
+ MOVL A,DI;\
+ ROLL $5,DI;\
+ ADDL DI,E;\
+ FN(B,C,D)\
+ ADDL DI,E;\
+ RORL $2,B;\
+
+#define BODY0(off,FN,V,A,B,C,D,E)\
+ MOVLQZX off(BX),DI;\
+ BSWAPDI;\
+ MOVL DI,off(BP);\
+ LEAL V(DI)(E*1),E;\
+ MOVL A,DI;\
+ ROLL $5,DI;\
+ ADDL DI,E;\
+ FN(B,C,D)\
+ ADDL DI,E;\
+ RORL $2,B;\
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+ MOVL C,DI;\
+ XORL D,DI;\
+ ANDL B,DI;\
+ XORL D,DI;\
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL D,DI;\
+
+/*
+ * fn3 = ((B ^ C) & (D ^= B)) ^ B
+ * D ^= B to restore D
+ */
+#define FN3(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL B,D;\
+ ANDL D,DI;\
+ XORL B,DI;\
+ XORL B,D;\
+
+/*
+ * stack offsets
+ * void sha1block(uchar *DATA, int LEN, ulong *STATE)
+ */
+#define DATA 0
+#define LEN 8
+#define STATE 16
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define Rpdata R8
+#define WARRAY (-8-(80*4))
+#define TMP1 (-16-(80*4))
+#define TMP2 (-24-(80*4))
+#define W15 (-32-(80*4))
+#define W40 (-40-(80*4))
+#define W60 (-48-(80*4))
+#define W80 (-56-(80*4))
+#define EDATA (-64-(80*4))
+
+ MOVQ RARG, Rpdata
+ MOVLQZX len+LEN(FP),BX
+ ADDQ BX, RARG
+ MOVQ RARG,edata+EDATA(SP)
+
+ LEAQ aw15+(WARRAY+15*4)(SP),DI
+ MOVQ DI,w15+W15(SP)
+ LEAQ aw40+(WARRAY+40*4)(SP),DX
+ MOVQ DX,w40+W40(SP)
+ LEAQ aw60+(WARRAY+60*4)(SP),CX
+ MOVQ CX,w60+W60(SP)
+ LEAQ aw80+(WARRAY+80*4)(SP),DI
+ MOVQ DI,w80+W80(SP)
+
+mainloop:
+ LEAQ warray+WARRAY(SP),BP
+
+ MOVQ state+STATE(FP),DI
+ MOVL (DI),AX
+ MOVL 4(DI),BX
+ MOVL BX,tmp1+TMP1(SP)
+ MOVL 8(DI),CX
+ MOVL 12(DI),DX
+ MOVL 16(DI),SI
+
+ MOVQ Rpdata,BX
+
+loop1:
+ BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+ MOVL SI,tmp2+TMP2(SP)
+ BODY0(4,FN1,0x5a827999,SI,AX,tmp1+TMP1(SP),CX,DX)
+ MOVL tmp1+TMP1(SP),SI
+ BODY0(8,FN1,0x5a827999,DX,tmp2+TMP2(SP),AX,SI,CX)
+ BODY0(12,FN1,0x5a827999,CX,DX,tmp2+TMP2(SP),AX,SI)
+ MOVL SI,tmp1+TMP1(SP)
+ BODY0(16,FN1,0x5a827999,SI,CX,DX,tmp2+TMP2(SP),AX)
+ MOVL tmp2+TMP2(SP),SI
+
+ ADDQ $20,BX
+ ADDQ $20,BP
+ CMPQ BP,w15+W15(SP)
+ JCS loop1
+
+ BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+ ADDQ $4,BX
+ MOVQ BX,R8
+ MOVQ tmp1+TMP1(SP),BX
+
+ BODY(4,FN1,0x5a827999,SI,AX,BX,CX,DX)
+ BODY(8,FN1,0x5a827999,DX,SI,AX,BX,CX)
+ BODY(12,FN1,0x5a827999,CX,DX,SI,AX,BX)
+ BODY(16,FN1,0x5a827999,BX,CX,DX,SI,AX)
+
+ ADDQ $20,BP
+
+loop2:
+ BODY(0,FN24,0x6ed9eba1,AX,BX,CX,DX,SI)
+ BODY(4,FN24,0x6ed9eba1,SI,AX,BX,CX,DX)
+ BODY(8,FN24,0x6ed9eba1,DX,SI,AX,BX,CX)
+ BODY(12,FN24,0x6ed9eba1,CX,DX,SI,AX,BX)
+ BODY(16,FN24,0x6ed9eba1,BX,CX,DX,SI,AX)
+
+ ADDQ $20,BP
+ CMPQ BP,w40+W40(SP)
+ JCS loop2
+
+loop3:
+ BODY(0,FN3,0x8f1bbcdc,AX,BX,CX,DX,SI)
+ BODY(4,FN3,0x8f1bbcdc,SI,AX,BX,CX,DX)
+ BODY(8,FN3,0x8f1bbcdc,DX,SI,AX,BX,CX)
+ BODY(12,FN3,0x8f1bbcdc,CX,DX,SI,AX,BX)
+ BODY(16,FN3,0x8f1bbcdc,BX,CX,DX,SI,AX)
+
+ ADDQ $20,BP
+ CMPQ BP,w60+W60(SP)
+ JCS loop3
+
+loop4:
+ BODY(0,FN24,0xca62c1d6,AX,BX,CX,DX,SI)
+ BODY(4,FN24,0xca62c1d6,SI,AX,BX,CX,DX)
+ BODY(8,FN24,0xca62c1d6,DX,SI,AX,BX,CX)
+ BODY(12,FN24,0xca62c1d6,CX,DX,SI,AX,BX)
+ BODY(16,FN24,0xca62c1d6,BX,CX,DX,SI,AX)
+
+ ADDQ $20,BP
+ CMPQ BP,w80+W80(SP)
+ JCS loop4
+
+ MOVQ state+STATE(FP),DI
+ ADDL AX,0(DI)
+ ADDL BX,4(DI)
+ ADDL CX,8(DI)
+ ADDL DX,12(DI)
+ ADDL SI,16(DI)
+
+ MOVQ edata+EDATA(SP),DI
+ CMPQ data+DATA(FP),DI
+ JCS mainloop
+
+ RET
+ END
--- a/mkfile
+++ b/mkfile
@@ -94,6 +94,13 @@
@{builtin cd $j; mk $MKFLAGS $stem }
}
+&-9front:QV:
+ for (j in $DIRS utils)
+ {
+ echo '@{builtin cd' $j '; mk $MKFLAGS $stem}'
+ @{builtin cd $j; mk $MKFLAGS $stem }
+ }
+
emu/&-Posix:QV:
for j in $EMUDIRS
do
@@ -115,6 +122,13 @@
@{builtin cd $j; mk $MKFLAGS $stem }
}
+emu/&-9front:QV:
+ for (j in $EMUDIRS)
+ {
+ echo '@{builtin cd' $j '; mk $MKFLAGS $stem}'
+ @{builtin cd $j; mk $MKFLAGS $stem }
+ }
+
kernel/&-Posix:QV:
for j in $KERNEL_DIRS
do
@@ -143,6 +157,13 @@
@{builtin cd $j; mk $MKFLAGS $stem }
}
+kernel/&-9front:QV:
+ for (j in $KERNEL_DIRS)
+ {
+ echo '@{builtin cd' $j '; mk $MKFLAGS $stem}'
+ @{builtin cd $j; mk $MKFLAGS $stem }
+ }
+
# Convenience targets
Inferno-% inferno-% Inferno-386-% inferno-386-%:V:
@@ -153,6 +174,9 @@
Plan9-% plan9-%:V:
mk 'SYSHOST=Plan9' 'OBJTYPE=386' $stem
+
+9front-% 9front-%:V:
+ mk 'SYSHOST=9front' 'OBJTYPE=amd64' $stem
Irix-% irix-%:V:
mk 'SYSHOST=Irix' 'OBJTYPE=mips' $stem
--- /dev/null
+++ b/mkfiles/mkfile-9front-amd64
@@ -1,0 +1,24 @@
+TARGMODEL= 9front
+TARGSHTYPE= rc
+CPUS= 386 sparc mips power amd64
+
+O= 6
+OS= v851ok0q26
+
+AR= ar
+ARFLAGS= vu
+
+AS= 6a
+ASFLAGS=
+
+CC= 6c
+CFLAGS= -wFV -I$ROOT/9front/$OBJTYPE/include -I$ROOT/9front/include -I$ROOT/include
+ANSICPP= -p
+
+LD= 6l
+LDFLAGS=
+
+SYSLIBS=-lc
+
+YACC= yacc
+YFLAGS= -d
--- /dev/null
+++ b/mkfiles/mkhost-9front
@@ -1,0 +1,12 @@
+
+# Variables for host system type = Plan9
+
+SHELLTYPE= rc
+SHELLNAME= rc
+HOSTMODEL= 9front
+OSTARG= Inferno
+
+DATA2S= data2s
+NDATE= date -n
+KSIZE= size
+AWK= awk
--- /dev/null
+++ b/utils/acid/os-9front.c
@@ -1,0 +1,157 @@
+/*
+ * Plan9
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+int
+opentty(char *tty, int baud)
+{
+ int fd, cfd;
+ char ctty[100];
+
+ if(tty == 0)
+ tty = "/dev/eia0";
+ sprint(ctty, "%sctl", tty);
+ fd = open(tty, 2);
+ if(fd < 0)
+ return -1;
+ if(baud){
+ cfd = open(ctty, 1);
+ if(cfd < 0)
+ return fd;
+ fprint(cfd, "b%d", baud);
+ close(cfd);
+ }
+ return fd;
+}
+
+void
+detach(void)
+{
+ rfork(RFNAMEG|RFNOTEG|RFREND);
+}
+
+char *
+waitfor(int pid)
+{
+ Waitmsg *w;
+ static char buf[ERRMAX];
+
+ for(;;) {
+ w = wait();
+ if(w == nil)
+ error("wait %r");
+ if(w->pid == pid){
+ strecpy(buf, buf+ERRMAX, w->msg);
+ free(w);
+ return buf;
+ }
+ free(w);
+ }
+ /* not reached */
+}
+
+char *
+runcmd(char *cmd)
+{
+ char *argv[4];
+ int pid;
+
+ argv[0] = "/bin/rc";
+ argv[1] = "-c";
+ argv[2] = cmd;
+ argv[3] = 0;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("fork %r");
+ case 0:
+ exec("/bin/rc", argv);
+ exits(0);
+ default:
+ return waitfor(pid);
+ }
+ /* not reached */
+}
+
+void
+catcher(void *junk, char *s)
+{
+ USED(junk);
+
+ if(strstr(s, "interrupt")) {
+ gotint = 1;
+ noted(NCONT);
+ }
+ noted(NDFLT);
+}
+
+void (*notefunc)(void *, char *);
+
+void
+setup_os_notify(void)
+{
+ notify(catcher);
+}
+
+int
+nproc(char **argv)
+{
+ char buf[128];
+ int pid, i, fd;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("new: fork %r");
+ case 0:
+ rfork(RFNAMEG|RFNOTEG);
+
+ sprint(buf, "/proc/%d/ctl", getpid());
+ fd = open(buf, ORDWR);
+ if(fd < 0)
+ fatal("new: open %s: %r", buf);
+ write(fd, "hang", 4);
+ close(fd);
+
+ close(0);
+ close(1);
+ close(2);
+ for(i = 3; i < NFD; i++)
+ close(i);
+
+ open("/dev/cons", OREAD);
+ open("/dev/cons", OWRITE);
+ open("/dev/cons", OWRITE);
+ exec(argv[0], argv);
+ fatal("new: exec %s: %r");
+ default:
+ install(pid);
+ msg(pid, "waitstop");
+ notes(pid);
+ sproc(pid);
+ dostop(pid);
+ break;
+ }
+
+ return pid;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+int
+remote_write(int fd, char *buf, int bytes)
+{
+ return write(fd, buf, bytes);
+}
--- /dev/null
+++ b/utils/c2l/9front.c
@@ -1,0 +1,108 @@
+#include "cc.h"
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ int p;
+ Waitmsg *w;
+
+ if((w = wait()) == nil)
+ return -1;
+ else{
+ p = w->pid;
+ *s = 0;
+ if(w->msg[0])
+ *s = 1;
+ free(w);
+ return p;
+ }
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return exec(path, argv);
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(ulong n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void*, ulong)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void*)
+{
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
+
+void
+setmalloctag(void*, uintptr)
+{
+}
--- /dev/null
+++ b/utils/cc/9front.c
@@ -1,0 +1,114 @@
+#include "cc.h"
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ int p;
+ Waitmsg *w;
+
+ if((w = wait()) == nil)
+ return -1;
+ else{
+ p = w->pid;
+ *s = 0;
+ if(w->msg[0])
+ *s = 1;
+ free(w);
+ return p;
+ }
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return exec(path, argv);
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(ulong n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void*, ulong)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void*)
+{
+}
+
+int
+myaccess(char *f)
+{
+ return access(f, AEXIST);
+}
+
+void
+setmalloctag(void*, uintptr)
+{
+}
--- /dev/null
+++ b/utils/iar/9front.c
@@ -1,0 +1,7 @@
+#include <lib9.h>
+
+char *
+myctime(long x)
+{
+ return ctime(x);
+}
--- /dev/null
+++ b/utils/mk/mkfile-9front
@@ -1,0 +1,3 @@
+#
+# install rule for Inferno/Plan9 - use the default
+#
--- a/utils/mkfile
+++ b/utils/mkfile
@@ -92,6 +92,15 @@
} || test ! -e $j
}
+%-9front:QV:
+ for (j in $ALWAYS)
+ {
+ test -d $j && {
+ echo '@{cd' $j '; mk $MKFLAGS $stem}'
+ @{cd $j; mk $MKFLAGS $stem }
+ } || test ! -e $j
+ }
+
%-Posix:QV:
for j in $ALWAYS $NOTPLAN9
do
--- /dev/null
+++ b/utils/srclist/9front.c
@@ -1,0 +1,7 @@
+#include "lib9.h"
+
+char*
+mygetwd(char *path, int len)
+{
+ return getwd(path, len);
+}