diff -Nru /sys/src/cmd/aux/realemu/arg.c /sys/src/cmd/aux/realemu/arg.c
--- /sys/src/cmd/aux/realemu/arg.c Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/arg.c Fri Feb 19 00:00:00 2016
@@ -0,0 +1,163 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+#define ause(cpu) (cpu->abuf + (cpu->iabuf++ % nelem(cpu->abuf)))
+
+Iarg*
+adup(Iarg *x)
+{
+ Iarg *a;
+
+ a = ause(x->cpu);
+ *a = *x;
+ return a;
+}
+
+Iarg*
+areg(Cpu *cpu, uchar len, uchar reg)
+{
+ Iarg *a;
+
+ a = ause(cpu);
+ a->cpu = cpu;
+ a->tag = TREG;
+ a->len = len;
+ a->reg = reg;
+ return a;
+}
+
+Iarg*
+amem(Cpu *cpu, uchar len, uchar sreg, ulong off)
+{
+ Iarg *a;
+
+ a = ause(cpu);
+ a->cpu = cpu;
+ a->tag = TMEM;
+ a->len = len;
+ a->sreg = sreg;
+ a->seg = cpu->reg[sreg];
+ a->off = off;
+ return a;
+}
+
+Iarg*
+afar(Iarg *mem, uchar len, uchar alen)
+{
+ Iarg *a, *p;
+
+ p = adup(mem);
+ p->len = alen;
+ a = amem(mem->cpu, len, R0S, ar(p));
+ p->off += alen;
+ p->len = 2;
+ a->seg = ar(p);
+ return a;
+}
+
+Iarg*
+acon(Cpu *cpu, uchar len, ulong val)
+{
+ Iarg *a;
+
+ a = ause(cpu);
+ a->cpu = cpu;
+ a->tag = TCON;
+ a->len = len;
+ a->val = val;
+ return a;
+}
+
+ulong
+ar(Iarg *a)
+{
+ ulong w, o;
+ Bus *io;
+
+ switch(a->tag){
+ default:
+ abort();
+ case TMEM:
+ o = ((a->seg<<4) + (a->off & 0xFFFF)) & 0xFFFFF;
+ io = a->cpu->mem + (o>>16);
+ w = io->r(io->aux, o, a->len);
+ break;
+ case TREG:
+ w = a->cpu->reg[a->reg];
+ break;
+ case TREG|TH:
+ w = a->cpu->reg[a->reg] >> 8;
+ break;
+ case TCON:
+ w = a->val;
+ break;
+ }
+ switch(a->len){
+ default:
+ abort();
+ case 1:
+ w &= 0xFF;
+ break;
+ case 2:
+ w &= 0xFFFF;
+ break;
+ case 4:
+ break;
+ }
+ return w;
+}
+
+long
+ars(Iarg *a)
+{
+ ulong w = ar(a);
+ switch(a->len){
+ default:
+ abort();
+ case 1:
+ return (char)w;
+ case 2:
+ return (short)w;
+ case 4:
+ return (long)w;
+ }
+}
+
+void
+aw(Iarg *a, ulong w)
+{
+ ulong *p, o;
+ Cpu *cpu;
+ Bus *io;
+
+ cpu = a->cpu;
+ switch(a->tag){
+ default:
+ abort();
+ case TMEM:
+ o = ((a->seg<<4) + (a->off & 0xFFFF)) & 0xFFFFF;
+ io = cpu->mem + (o>>16);
+ io->w(io->aux, o, w, a->len);
+ break;
+ case TREG:
+ p = cpu->reg + a->reg;
+ switch(a->len){
+ case 4:
+ *p = w;
+ break;
+ case 2:
+ *p = (*p & ~0xFFFF) | (w & 0xFFFF);
+ break;
+ case 1:
+ *p = (*p & ~0xFF) | (w & 0xFF);
+ break;
+ }
+ break;
+ case TREG|TH:
+ p = cpu->reg + a->reg;
+ *p = (*p & ~0xFF00) | (w & 0xFF)<<8;
+ break;
+ }
+}
diff -Nru /sys/src/cmd/aux/realemu/dat.h /sys/src/cmd/aux/realemu/dat.h
--- /sys/src/cmd/aux/realemu/dat.h Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/dat.h Fri Feb 19 00:00:00 2016
@@ -0,0 +1,363 @@
+typedef struct Iarg Iarg;
+typedef struct Inst Inst;
+typedef struct Bus Bus;
+typedef struct Cpu Cpu;
+typedef struct Pit Pit;
+
+enum {
+ RAX,
+ RCX,
+ RDX,
+ RBX,
+ RSP,
+ RBP,
+ RSI,
+ RDI,
+
+ RES,
+ RCS,
+ RSS,
+ RDS,
+ RFS,
+ RGS,
+
+ R0S, /* 0 segment */
+
+ RIP,
+ RFL,
+
+ NREG,
+};
+
+struct Iarg
+{
+ Cpu *cpu;
+
+ uchar tag;
+ uchar len;
+ uchar atype;
+
+ union {
+ uchar reg;
+ struct {
+ uchar sreg;
+ ulong seg, off;
+ };
+ ulong val;
+ };
+};
+
+struct Inst
+{
+ uchar op;
+ uchar code;
+ uchar olen;
+ uchar alen;
+
+ Iarg *a1, *a2, *a3;
+
+ uchar rep;
+
+ uchar mod;
+ uchar reg;
+ uchar rm;
+
+ uchar scale;
+ uchar index;
+ uchar base;
+
+ uchar sreg;
+ uchar dsreg;
+
+ ulong off;
+ long disp;
+};
+
+struct Bus
+{
+ void *aux;
+ ulong (*r)(void *aux, ulong off, int len);
+ void (*w)(void *aux, ulong off, ulong data, int len);
+};
+
+struct Cpu
+{
+ ulong reg[NREG];
+
+ /* instruction counter */
+ ulong ic;
+
+ /* mem[16], one entry for each 64k block */
+ Bus *mem;
+
+ /* port[1], in/out */
+ Bus *port;
+
+ int trap;
+ ulong oldip;
+ jmp_buf jmp;
+
+ /* default operand, address and stack pointer length */
+ uchar olen, alen, slen;
+
+ /* argument buffers */
+ ulong iabuf;
+ Iarg abuf[0x80];
+};
+
+struct Pit
+{
+ ulong count;
+
+ /* set by setgate(), cleared by clockpit() */
+ uchar gateraised;
+
+ /* signals */
+ uchar gate;
+ uchar out;
+
+ /* mode and flags */
+ uchar count0;
+
+ uchar bcd;
+ uchar amode;
+ uchar omode;
+
+ /* latch for wpit initial count */
+ uchar wcount;
+ uchar wlatched;
+ uchar wlatch[2];
+
+ /* latch for rpit status/count */
+ uchar rcount;
+ uchar rlatched;
+ uchar rlatch[2];
+};
+
+/* processor flags */
+enum {
+ CF = 1<<0, /* carry flag */
+ PF = 1<<2, /* parity flag */
+ AF = 1<<4, /* aux carry flag */
+ ZF = 1<<6, /* zero flag */
+ SF = 1<<7, /* sign flag */
+ TF = 1<<8, /* trap flag */
+ IF = 1<<9, /* interrupts enabled flag */
+ DF = 1<<10, /* direction flag */
+ OF = 1<<11, /* overflow flag */
+ IOPL= 3<<12, /* I/O privelege level */
+ NT = 1<<14, /* nested task */
+ RF = 1<<16, /* resume flag */
+ VM = 1<<17, /* virtual-8086 mode */
+ AC = 1<<18, /* alignment check */
+ VIF = 1<<19, /* virtual interrupt flag */
+ VIP = 1<<20, /* virtual interrupt pending */
+ ID = 1<<21, /* ID flag */
+};
+
+/* interrupts/traps */
+enum {
+ EDIV0,
+ EDEBUG,
+ ENMI,
+ EBRK,
+ EINTO,
+ EBOUND,
+ EBADOP,
+ ENOFPU,
+ EDBLF,
+ EFPUSEG,
+ EBADTSS,
+ ENP,
+ ESTACK,
+ EGPF,
+ EPF,
+
+ EHALT = 256, /* pseudo-interrupts */
+ EMEM,
+ EIO,
+};
+
+/* argument tags */
+enum {
+ TREG,
+ TMEM,
+ TCON,
+
+ TH = 0x80, /* special flag for AH,BH,CH,DH */
+};
+
+/* argument types */
+enum {
+ ANONE, /* no argument */
+ A0, /* constant 0 */
+ A1, /* constant 1 */
+ A2, /* constant 2 */
+ A3, /* constant 3 */
+ A4, /* constant 4 */
+ AAp, /* 32-bit or 48-bit direct address */
+ AEb, /* r/m8 from modrm byte */
+ AEv, /* r/m16 or r/m32 from modrm byte */
+ AEw, /* r/m16 */
+ AFv, /* flag word */
+ AGb, /* r8 from modrm byte */
+ AGv, /* r16 or r32 from modrm byte */
+ AGw, /* r/m16 */
+ AIb, /* immediate byte */
+ AIc, /* immediate byte sign-extended */
+ AIw, /* immediate 16-bit word */
+ AIv, /* immediate 16-bit or 32-bit word */
+ AJb, /* relative offset byte */
+ AJv, /* relative offset 16-bit or 32-bit word */
+ AJr, /* r/m16 or r/m32 register */
+ AM, /* memory address from modrm */
+ AMa, /* something for bound */
+ AMa2,
+ AMp, /* 32-bit or 48-bit memory address */
+ AOb, /* immediate word-sized offset to a byte */
+ AOv, /* immediate word-size offset to a word */
+ ASw, /* segment register selected by r field of modrm */
+ AXb, /* byte at DS:SI */
+ AXv, /* word at DS:SI */
+ AYb, /* byte at ES:DI */
+ AYv, /* word at ES:DI */
+
+ AAL,
+ ACL,
+ ADL,
+ ABL,
+ AAH,
+ ACH,
+ ADH,
+ ABH,
+
+ AAX,
+ ACX,
+ ADX,
+ ABX,
+ ASP,
+ ABP,
+ ASI,
+ ADI,
+
+ AES,
+ ACS,
+ ASS,
+ ADS,
+ AFS,
+ AGS,
+
+ NATYPE,
+};
+
+/* operators */
+enum {
+ OBAD,
+ O0F,
+ OAAA,
+ OAAD,
+ OAAM,
+ OAAS,
+ OADC,
+ OADD,
+ OAND,
+ OARPL,
+ OASIZE,
+ OBOUND,
+ OBT,
+ OBTS,
+ OBTR,
+ OBTC,
+ OBSF,
+ OBSR,
+ OCALL,
+ OCBW,
+ OCLC,
+ OCLD,
+ OCLI,
+ OCMC,
+ OCMOV,
+ OCMP,
+ OCMPS,
+ OCPUID,
+ OCWD,
+ ODAA,
+ ODAS,
+ ODEC,
+ ODIV,
+ OENTER,
+ OGP1,
+ OGP2,
+ OGP3b,
+ OGP3v,
+ OGP4,
+ OGP5,
+ OGP8,
+ OGP10,
+ OGP12,
+ OHLT,
+ OIDIV,
+ OIMUL,
+ OIN,
+ OINC,
+ OINS,
+ OINT,
+ OIRET,
+ OJUMP,
+ OLAHF,
+ OLEA,
+ OLEAVE,
+ OLFP,
+ OLOCK,
+ OLODS,
+ OLOOP,
+ OLOOPNZ,
+ OLOOPZ,
+ OMOV,
+ OMOVS,
+ OMOVZX,
+ OMOVSX,
+ OMUL,
+ ONEG,
+ ONOP,
+ ONOT,
+ OOR,
+ OOSIZE,
+ OOUT,
+ OOUTS,
+ OPOP,
+ OPOPA,
+ OPOPF,
+ OPUSH,
+ OPUSHA,
+ OPUSHF,
+ ORCL,
+ ORCR,
+ OREPE,
+ OREPNE,
+ ORET,
+ ORETF,
+ OROL,
+ OROR,
+ OSAHF,
+ OSAR,
+ OSBB,
+ OSCAS,
+ OSEG,
+ OSET,
+ OSHL,
+ OSHLD,
+ OSHR,
+ OSHRD,
+ OSTC,
+ OSTD,
+ OSTI,
+ OSTOS,
+ OSUB,
+ OTEST,
+ OWAIT,
+ OXCHG,
+ OXLAT,
+ OXOR,
+ NUMOP,
+};
diff -Nru /sys/src/cmd/aux/realemu/decode.c /sys/src/cmd/aux/realemu/decode.c
--- /sys/src/cmd/aux/realemu/decode.c Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/decode.c Fri Feb 19 00:00:00 2016
@@ -0,0 +1,625 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct Optab Optab;
+struct Optab {
+ uchar op;
+ uchar a1, a2, a3;
+};
+
+static Optab optab[256] = {
+//00
+ {OADD, AEb, AGb}, {OADD, AEv, AGv}, {OADD, AGb, AEb}, {OADD, AGv, AEv},
+ {OADD, AAL, AIb}, {OADD, AAX, AIv}, {OPUSH, AES, }, {OPOP, AES },
+ {OOR, AEb, AGb}, {OOR, AEv, AGv}, {OOR, AGb, AEb}, {OOR, AGv, AEv},
+ {OOR, AAL, AIb}, {OOR, AAX, AIv}, {OPUSH, ACS, }, {O0F, },
+//10
+ {OADC, AEb, AGb}, {OADC, AEv, AGv}, {OADC, AGb, AEb}, {OADC, AGv, AEv},
+ {OADC, AAL, AIb}, {OADC, AAX, AIv}, {OPUSH, ASS, }, {OPOP, ASS, },
+ {OSBB, AEb, AGb}, {OSBB, AEv, AGv}, {OSBB, AGb, AEb}, {OSBB, AGv, AEv},
+ {OSBB, AAL, AIb}, {OSBB, AAX, AIv}, {OPUSH, ADS, }, {OPOP, ADS, },
+//20
+ {OAND, AEb, AGb}, {OAND, AEv, AGv}, {OAND, AGb, AEb}, {OAND, AGv, AEv},
+ {OAND, AAL, AIb}, {OAND, AAX, AIv}, {OSEG, AES, }, {ODAA, },
+ {OSUB, AEb, AGb}, {OSUB, AEv, AGv}, {OSUB, AGb, AEb}, {OSUB, AGv, AEv},
+ {OSUB, AAL, AIb}, {OSUB, AAX, AIv}, {OSEG, ACS, }, {ODAS, },
+//30
+ {OXOR, AEb, AGb}, {OXOR, AEv, AGv}, {OXOR, AGb, AEb}, {OXOR, AGv, AEv},
+ {OXOR, AAL, AIb}, {OXOR, AAX, AIv}, {OSEG, ASS, }, {OAAA, },
+ {OCMP, AEb, AGb}, {OCMP, AEv, AGv}, {OCMP, AGb, AEb}, {OCMP, AGv, AEv},
+ {OCMP, AAL, AIb}, {OCMP, AAX, AIv}, {OSEG, ADS, }, {OAAS, },
+//40
+ {OINC, AAX, }, {OINC, ACX, }, {OINC, ADX, }, {OINC, ABX, },
+ {OINC, ASP, }, {OINC, ABP, }, {OINC, ASI, }, {OINC, ADI, },
+ {ODEC, AAX, }, {ODEC, ACX, }, {ODEC, ADX, }, {ODEC, ABX, },
+ {ODEC, ASP, }, {ODEC, ABP, }, {ODEC, ASI, }, {ODEC, ADI, },
+//50
+ {OPUSH, AAX, }, {OPUSH, ACX, }, {OPUSH, ADX, }, {OPUSH, ABX, },
+ {OPUSH, ASP, }, {OPUSH, ABP, }, {OPUSH, ASI, }, {OPUSH, ADI, },
+ {OPOP, AAX, }, {OPOP, ACX, }, {OPOP, ADX, }, {OPOP, ABX, },
+ {OPOP, ASP, }, {OPOP, ABP, }, {OPOP, ASI, }, {OPOP, ADI, },
+//60
+ {OPUSHA, }, {OPOPA, }, {OBOUND,AGv,AMa,AMa2}, {OARPL, AEw, AGw},
+ {OSEG, AFS, }, {OSEG, AGS, }, {OOSIZE, }, {OASIZE, },
+ {OPUSH, AIv, }, {OIMUL,AGv,AEv,AIv},{OPUSH, AIb, }, {OIMUL,AGv,AEv,AIb},
+ {OINS, AYb, ADX}, {OINS, AYv, ADX}, {OOUTS, ADX, AXb}, {OOUTS, ADX, AXv},
+//70
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+//80
+ {OGP1, AEb, AIb}, {OGP1, AEv, AIv}, {OGP1, AEb, AIb}, {OGP1, AEv, AIc},
+ {OTEST, AEb, AGb}, {OTEST, AEv, AGv}, {OXCHG, AEb, AGb}, {OXCHG, AEv, AGv},
+ {OMOV, AEb, AGb}, {OMOV, AEv, AGv}, {OMOV, AGb, AEb}, {OMOV, AGv, AEv},
+ {OMOV, AEw, ASw}, {OLEA, AGv, AM }, {OMOV, ASw, AEw}, {OGP10, },
+//90
+ {ONOP, }, {OXCHG, ACX, AAX}, {OXCHG, ADX, AAX}, {OXCHG, ABX, AAX},
+ {OXCHG, ASP, AAX}, {OXCHG, ABP, AAX}, {OXCHG, ASI, AAX}, {OXCHG, ADI, AAX},
+ {OCBW, }, {OCWD, }, {OCALL, AAp, }, {OWAIT, },
+ {OPUSHF,AFv, }, {OPOPF, AFv, }, {OSAHF, AAH, }, {OLAHF, AAH, },
+//A0
+ {OMOV, AAL, AOb}, {OMOV, AAX, AOv}, {OMOV, AOb, AAL}, {OMOV, AOv, AAX},
+ {OMOVS, AYb, AXb}, {OMOVS, AYv, AXv}, {OCMPS, AYb, AXb}, {OCMPS, AYv, AXv},
+ {OTEST, AAL, AIb}, {OTEST, AAX, AIv}, {OSTOS, AYb, AAL}, {OSTOS, AYv, AAX},
+ {OLODS, AAL, AXb}, {OLODS, AAX, AXv}, {OSCAS, AYb, AAL}, {OSCAS, AYv, AAX},
+//B0
+ {OMOV, AAL, AIb}, {OMOV, ACL, AIb}, {OMOV, ADL, AIb}, {OMOV, ABL, AIb},
+ {OMOV, AAH, AIb}, {OMOV, ACH, AIb}, {OMOV, ADH, AIb}, {OMOV, ABH, AIb},
+ {OMOV, AAX, AIv}, {OMOV, ACX, AIv}, {OMOV, ADX, AIv}, {OMOV, ABX, AIv},
+ {OMOV, ASP, AIv}, {OMOV, ABP, AIv}, {OMOV, ASI, AIv}, {OMOV, ADI, AIv},
+//C0
+ {OGP2, AEb, AIb}, {OGP2, AEv, AIb}, {ORET, AIw, }, {ORET, A0, },
+ {OLFP,AES,AGv,AMp},{OLFP,ADS,AGv,AMp},{OGP12, AEb, AIb}, {OGP12, AEv, AIv},
+ {OENTER,AIw, AIb}, {OLEAVE, }, {ORETF, AIw, }, {ORETF, A0, },
+ {OINT, A3, }, {OINT, AIb, }, {OINT, A4, }, {OIRET, },
+//D0
+ {OGP2, AEb, A1 }, {OGP2, AEv, A1 }, {OGP2, AEb, ACL}, {OGP2, AEv, ACL},
+ {OAAM, AIb, }, {OAAD, AIb, }, {OBAD, }, {OXLAT, AAL, ABX},
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//E0
+ {OLOOPNZ,AJb, }, {OLOOPZ,AJb, }, {OLOOP, AJb, }, {OJUMP, AJb, },
+ {OIN, AAL, AIb}, {OIN, AAX, AIb}, {OOUT, AIb, AAL}, {OOUT, AIb, AAX},
+ {OCALL, AJv, }, {OJUMP, AJv, }, {OJUMP, AAp, }, {OJUMP, AJb, },
+ {OIN, AAL, ADX}, {OIN, AAX, ADX}, {OOUT, ADX, AAL}, {OOUT, ADX, AAX},
+//F0
+ {OLOCK, }, {OBAD, }, {OREPNE, }, {OREPE, },
+ {OHLT, }, {OCMC, }, {OGP3b, }, {OGP3v, },
+ {OCLC, }, {OSTC, }, {OCLI, }, {OSTI, },
+ {OCLD, }, {OSTD, }, {OGP4, }, {OGP5, },
+};
+
+static Optab optab0F[256] = {
+//00
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//10 - mostly floating point and quadword moves
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//20 - doubleword <-> control register moves, other arcana
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//30 - wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//40 - conditional moves
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+//50 - floating point, mmx stuff
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//60 - floating point, mmx stuff
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//70 - floating point, mmx stuff
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//80 - long-displacement jumps
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+//90 - conditional byte set
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+//A0
+ {OPUSH, AFS, }, {OPOP, AFS, }, {OCPUID, }, {OBT, AEv, AGv},
+ {OSHLD,AEv,AGv,AIb}, {OSHLD,AEv,AGv,ACL}, {OBAD, }, {OBAD, },
+ {OPUSH, AGS, }, {OPOP, AGS, }, {OBAD, }, {OBTS, AEv, AGv},
+ {OSHRD,AEv,AGv,AIb}, {OSHRD,AEv,AGv,ACL}, {OBAD, }, {OIMUL, AGv,AGv,AEv},
+//B0 - mostly arcana
+ {OBAD, }, {OBAD, }, {OLFP,ASS,AGv,AMp},{OBTR,AEv,AGv },
+ {OLFP,AFS,AGv,AMp},{OLFP,AGS,AGv,AMp},{OMOVZX,AGv,AEb }, {OMOVZX,AGv,AEw },
+ {OBAD, }, {OBAD, }, {OGP8, }, {OBAD, },
+ {OBSF,AGv,AEv }, {OBSR,AGv,AEv }, {OMOVSX,AGv,AEb }, {OMOVSX,AGv,AEw },
+//C0 - more arcana
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//D0 - mmx
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//E0 - mmx
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//F0 - mmx
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+/* some operands map to whole groups; group numbers from intel opcode map */
+/* args filled in already (in OGP1 entries) */
+static Optab optabgp1[8] = {
+ {OADD, }, {OOR, }, {OADC, }, {OSBB, },
+ {OAND, }, {OSUB, }, {OXOR, }, {OCMP, },
+};
+
+/* args filled in already (in OGP2 entries) */
+static Optab optabgp2[8] = {
+ {OROL, }, {OROR, }, {ORCL, }, {ORCR, },
+ {OSHL, }, {OSHR, }, {OBAD, }, {OSAR, },
+};
+
+static Optab optabgp3b[8] = {
+ {OTEST, AEb, AIb}, {OBAD, }, {ONOT, AEb, }, {ONEG, AEb, },
+ {OMUL,AAX,AAL,AEb},{OIMUL,AAX,AAL,AEb},{ODIV, AEb, }, {OIDIV, AEb, },
+};
+
+static Optab optabgp3v[8] = {
+ {OTEST, AEv, AIv}, {OBAD, }, {ONOT, AEv, }, {ONEG, AEv, },
+ {OMUL,AAX,AAX,AEv},{OIMUL,AAX,AAX,AEv},{ODIV, AEv, }, {OIDIV, AEv, },
+};
+
+static Optab optabgp4[8] = {
+ {OINC, AEb, }, {ODEC, AEb, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+static Optab optabgp5[8] = {
+ {OINC, AEv, }, {ODEC, AEv, }, {OCALL, AEv, }, {OCALL, AMp },
+ {OJUMP, AEv, }, {OJUMP, AMp, }, {OPUSH, AEv, }, {OBAD, },
+};
+
+static Optab optabgp8[8] = {
+ {OMOV, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBT, AEv, AIb }, {OBTS, AEv, AIb }, {OBTR, AEv, AIb }, {OBTC, AEv, AIb },
+};
+
+static Optab optabgp10[8] = {
+ {OPOP, AEv, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+static Optab optabgp12[8] = {
+ {OMOV, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+/* optabg6 unimplemented - mostly segment manipulation */
+/* optabg7 unimplemented - more segment manipulation */
+/* optabg8 unimplemented - bit tests */
+
+/*
+ * most of optabg9 - optabg16 decode differently depending on the mod value of
+ * the modrm byte. they're mostly arcane instructions so they're not
+ * implemented.
+ */
+
+static Optab *optabgp[NUMOP] = {
+ [OGP1] optabgp1,
+ [OGP2] optabgp2,
+ [OGP3b] optabgp3b,
+ [OGP3v] optabgp3v,
+ [OGP4] optabgp4,
+ [OGP5] optabgp5,
+ [OGP8] optabgp8,
+ [OGP10] optabgp10,
+ [OGP12] optabgp12,
+};
+
+static uchar modrmarg[NATYPE] = {
+ [AEb] 1,
+ [AEw] 1,
+ [AEv] 1,
+ [AGb] 1,
+ [AGw] 1,
+ [AGv] 1,
+ [AM] 1,
+ [AMp] 1,
+ [AMa] 1,
+ [AMa2] 1,
+ [ASw] 1,
+ [AJr] 1,
+};
+
+static void
+getmodrm16(Iarg *ip, Inst *i)
+{
+ Iarg *p;
+ uchar b;
+
+ b = ar(ip); ip->off++;
+
+ i->mod = b>>6;
+ i->reg = (b>>3)&7;
+ i->rm = b&7;
+
+ if(i->mod == 3)
+ return;
+
+ switch(i->rm){
+ case 0:
+ i->off = ar(areg(ip->cpu, 2, RBX)) + ar(areg(ip->cpu, 2, RSI));
+ i->off &= 0xFFFF;
+ break;
+ case 1:
+ i->off = ar(areg(ip->cpu, 2, RBX)) + ar(areg(ip->cpu, 2, RDI));
+ i->off &= 0xFFFF;
+ break;
+ case 2:
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 2, RBP)) + ar(areg(ip->cpu, 2, RSI));
+ i->off &= 0xFFFF;
+ break;
+ case 3:
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 2, RBP)) + ar(areg(ip->cpu, 2, RDI));
+ i->off &= 0xFFFF;
+ break;
+ case 4:
+ i->off = ar(areg(ip->cpu, 2, RSI));
+ break;
+ case 5:
+ i->off = ar(areg(ip->cpu, 2, RDI));
+ break;
+ case 6:
+ if(i->mod == 0){
+ p = adup(ip); ip->off += 2;
+ p->len = 2;
+ i->off = ar(p);
+ return;
+ }
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 2, RBP));
+ break;
+ case 7:
+ i->off = ar(areg(ip->cpu, 2, RBX));
+ break;
+ }
+ switch(i->mod){
+ case 1:
+ i->off += (i->disp = ars(ip)); ip->off++;
+ i->off &= 0xFFFF;
+ break;
+ case 2:
+ p = adup(ip); ip->off += 2;
+ p->len = 2;
+ i->off += (i->disp = ars(p));
+ i->off &= 0xFFFF;
+ break;
+ }
+}
+
+static void
+getmodrm32(Iarg *ip, Inst *i)
+{
+ static uchar scaler[] = {1, 2, 4, 8};
+ Iarg *p;
+ uchar b;
+
+ b = ar(ip); ip->off++;
+
+ i->mod = b>>6;
+ i->reg = (b>>3)&7;
+ i->rm = b&7;
+
+ if(i->mod == 3)
+ return;
+
+ switch(i->rm){
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ i->off = ar(areg(ip->cpu, 4, i->rm + RAX));
+ break;
+ case 4:
+ b = ar(ip); ip->off++;
+ i->scale = b>>6;
+ i->index = (b>>3)&7;
+ i->base = b&7;
+
+ if(i->base != 5){
+ i->off = ar(areg(ip->cpu, 4, i->base + RAX));
+ break;
+ }
+ case 5:
+ if(i->mod == 0){
+ p = adup(ip); ip->off += 4;
+ p->len = 4;
+ i->off = ar(p);
+ } else {
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 4, RBP));
+ }
+ break;
+ }
+
+ if(i->rm == 4 && i->index != 4)
+ i->off += ar(areg(ip->cpu, 4, i->index + RAX)) * scaler[i->scale];
+
+ switch(i->mod){
+ case 1:
+ i->off += (i->disp = ars(ip)); ip->off++;
+ break;
+ case 2:
+ p = adup(ip); ip->off += 4;
+ p->len = 4;
+ i->off += (i->disp = ars(p));
+ break;
+ }
+}
+
+static Iarg*
+getarg(Iarg *ip, Inst *i, uchar atype)
+{
+ Iarg *a;
+ uchar len, reg;
+
+ len = i->olen;
+ switch(atype){
+ default:
+ abort();
+
+ case A0:
+ case A1:
+ case A2:
+ case A3:
+ case A4:
+ a = acon(ip->cpu, len, atype - A0);
+ break;
+
+ case AEb:
+ len = 1;
+ if(0){
+ case AEw:
+ len = 2;
+ }
+ case AEv:
+ if(i->mod == 3){
+ reg = i->rm;
+ goto REG;
+ }
+ goto MEM;
+
+ case AM:
+ case AMp:
+ case AMa:
+ case AMa2:
+ if(i->mod == 3)
+ trap(ip->cpu, EBADOP);
+ MEM:
+ a = amem(ip->cpu, len, i->sreg, i->off);
+ if(atype == AMa2)
+ a->off += i->olen;
+ break;
+
+ case AGb:
+ len = 1;
+ if(0){
+ case AGw:
+ len = 2;
+ }
+ case AGv:
+ reg = i->reg;
+ REG:
+ a = areg(ip->cpu, len, reg + RAX);
+ if(len == 1 && reg >= 4){
+ a->reg -= 4;
+ a->tag |= TH;
+ }
+ break;
+
+ case AIb:
+ case AIc:
+ len = 1;
+ if(0){
+ case AIw:
+ len = 2;
+ }
+ case AIv:
+ a = adup(ip); ip->off += len;
+ a->len = len;
+ break;
+
+ case AJb:
+ len = 1;
+ case AJv:
+ a = adup(ip); ip->off += len;
+ a->len = len;
+ a->off = ip->off + ars(a);
+ break;
+
+ case AJr:
+ if(i->mod != 3)
+ trap(ip->cpu, EBADOP);
+ a = adup(ip);
+ a->off = ar(areg(ip->cpu, i->olen, i->rm + RAX));
+ break;
+
+ case AAp:
+ a = afar(ip, ip->len, len); ip->off += 2+len;
+ break;
+
+ case AOb:
+ len = 1;
+ case AOv:
+ a = adup(ip); ip->off += i->alen;
+ a->len = i->alen;
+ a = amem(ip->cpu, len, i->sreg, ar(a));
+ break;
+
+ case ASw:
+ reg = i->reg;
+ SREG:
+ a = areg(ip->cpu, 2, reg + RES);
+ break;
+
+ case AXb:
+ len = 1;
+ case AXv:
+ a = amem(ip->cpu, len, i->sreg, ar(areg(ip->cpu, i->alen, RSI)));
+ break;
+
+ case AYb:
+ len = 1;
+ case AYv:
+ a = amem(ip->cpu, len, RES, ar(areg(ip->cpu, i->alen, RDI)));
+ break;
+
+ case AFv:
+ a = areg(ip->cpu, len, RFL);
+ break;
+
+ case AAL:
+ case ACL:
+ case ADL:
+ case ABL:
+ case AAH:
+ case ACH:
+ case ADH:
+ case ABH:
+ len = 1;
+ reg = atype - AAL;
+ goto REG;
+
+ case AAX:
+ case ACX:
+ case ADX:
+ case ABX:
+ case ASP:
+ case ABP:
+ case ASI:
+ case ADI:
+ reg = atype - AAX;
+ goto REG;
+
+ case AES:
+ case ACS:
+ case ASS:
+ case ADS:
+ case AFS:
+ case AGS:
+ reg = atype - AES;
+ goto SREG;
+ }
+ a->atype = atype;
+ return a;
+}
+
+static int
+otherlen(int a)
+{
+ if(a == 2)
+ return 4;
+ else if(a == 4)
+ return 2;
+ abort();
+ return 0;
+}
+
+void
+decode(Iarg *ip, Inst *i)
+{
+ Optab *t, *t2;
+ Cpu *cpu;
+
+ cpu = ip->cpu;
+
+ i->op = 0;
+ i->rep = 0;
+ i->sreg = 0;
+ i->dsreg = RDS;
+ i->olen = cpu->olen;
+ i->alen = cpu->alen;
+ i->a1 = i->a2 = i->a3 = nil;
+
+ for(;;){
+ i->code = ar(ip); ip->off++;
+ t = optab + i->code;
+ switch(t->op){
+ case OOSIZE:
+ i->olen = otherlen(cpu->olen);
+ continue;
+ case OASIZE:
+ i->alen = otherlen(cpu->alen);
+ continue;
+ case OREPE:
+ case OREPNE:
+ i->rep = t->op;
+ continue;
+ case OLOCK:
+ continue;
+ case OSEG:
+ i->sreg = t->a1-AES+RES;
+ continue;
+ case O0F:
+ i->code = ar(ip); ip->off++;
+ t = optab0F + i->code;
+ break;
+ }
+ break;
+ }
+ t2 = optabgp[t->op];
+ if(t2 || modrmarg[t->a1] || modrmarg[t->a2] || modrmarg[t->a3])
+ if(i->alen == 2)
+ getmodrm16(ip, i);
+ else
+ getmodrm32(ip, i);
+ if(i->sreg == 0)
+ i->sreg = i->dsreg;
+
+ for(;;){
+ if(t->a1)
+ i->a1 = getarg(ip, i, t->a1);
+ if(t->a2)
+ i->a2 = getarg(ip, i, t->a2);
+ if(t->a3)
+ i->a3 = getarg(ip, i, t->a3);
+ if(t2 == nil)
+ break;
+ t = t2 + i->reg;
+ t2 = nil;
+ }
+ i->op = t->op;
+}
diff -Nru /sys/src/cmd/aux/realemu/fmt.c /sys/src/cmd/aux/realemu/fmt.c
--- /sys/src/cmd/aux/realemu/fmt.c Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/fmt.c Fri Feb 19 00:00:00 2016
@@ -0,0 +1,385 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+static char *opstr[] = { /* Edit s/O(.*),/[O\1]= "\1",/g */
+ [OBAD]= "BAD",
+ [O0F]= "0F",
+ [OAAA]= "AAA",
+ [OAAD]= "AAD",
+ [OAAM]= "AAM",
+ [OAAS]= "AAS",
+ [OADC]= "ADC",
+ [OADD]= "ADD",
+ [OAND]= "AND",
+ [OARPL]= "ARPL",
+ [OASIZE]= "ASIZE",
+ [OBOUND]= "BOUND",
+ [OBT]= "BT",
+ [OBTC]= "BTC",
+ [OBTR]= "BTR",
+ [OBTS]= "BTS",
+ [OBSF]= "BSF",
+ [OBSR]= "BSR",
+ [OCALL]= "CALL",
+ [OCBW]= "CBW",
+ [OCLC]= "CLC",
+ [OCLD]= "CLD",
+ [OCLI]= "CLI",
+ [OCMC]= "CMC",
+ [OCMOV]= "CMOV",
+ [OCMP]= "CMP",
+ [OCMPS]= "CMPS",
+ [OCWD]= "CWD",
+ [ODAA]= "DAA",
+ [ODAS]= "DAS",
+ [ODEC]= "DEC",
+ [ODIV]= "DIV",
+ [OENTER]= "ENTER",
+ [OGP1]= "GP1",
+ [OGP2]= "GP2",
+ [OGP3b]= "GP3b",
+ [OGP3v]= "GP3v",
+ [OGP4]= "GP4",
+ [OGP5]= "GP5",
+ [OHLT]= "HLT",
+ [OIDIV]= "IDIV",
+ [OIMUL]= "IMUL",
+ [OIN]= "IN",
+ [OINC]= "INC",
+ [OINS]= "INS",
+ [OINT]= "INT",
+ [OIRET]= "IRET",
+ [OJUMP]= "JUMP",
+ [OLAHF]= "LAHF",
+ [OLFP]= "LFP",
+ [OLEA]= "LEA",
+ [OLEAVE]= "LEAVE",
+ [OLOCK]= "LOCK",
+ [OLODS]= "LODS",
+ [OLOOP]= "LOOP",
+ [OLOOPNZ]= "LOOPNZ",
+ [OLOOPZ]= "LOOPZ",
+ [OMOV]= "MOV",
+ [OMOVS]= "MOVS",
+ [OMOVZX]= "MOVZX",
+ [OMOVSX]= "MOVSX",
+ [OMUL]= "MUL",
+ [ONEG]= "NEG",
+ [ONOP]= "NOP",
+ [ONOT]= "NOT",
+ [OOR]= "OR",
+ [OOSIZE]= "OSIZE",
+ [OOUT]= "OUT",
+ [OOUTS]= "OUTS",
+ [OPOP]= "POP",
+ [OPOPA]= "POPA",
+ [OPOPF]= "POPF",
+ [OPUSH]= "PUSH",
+ [OPUSHA]= "PUSHA",
+ [OPUSHF]= "PUSHF",
+ [ORCL]= "RCL",
+ [ORCR]= "RCR",
+ [OREPE]= "REPE",
+ [OREPNE]= "REPNE",
+ [ORET]= "RET",
+ [ORETF]= "RETF",
+ [OROL]= "ROL",
+ [OROR]= "ROR",
+ [OSAHF]= "SAHF",
+ [OSAR]= "SAR",
+ [OSBB]= "SBB",
+ [OSCAS]= "SCAS",
+ [OSEG]= "SEG",
+ [OSET]= "SET",
+ [OSHL]= "SHL",
+ [OSHLD]= "SHLD",
+ [OSHR]= "SHR",
+ [OSHRD]= "SHRD",
+ [OSTC]= "STC",
+ [OSTD]= "STD",
+ [OSTI]= "STI",
+ [OSTOS]= "STOS",
+ [OSUB]= "SUB",
+ [OTEST]= "TEST",
+ [OWAIT]= "WAIT",
+ [OXCHG]= "XCHG",
+ [OXLAT]= "XLAT",
+ [OXOR]= "XOR",
+};
+
+static char *memstr16[] = {
+ "BX+SI",
+ "BX+DI",
+ "BP+SI",
+ "BP+DI",
+ "SI",
+ "DI",
+ "BP",
+ "BX",
+};
+
+static char *memstr32[] = {
+ "EAX",
+ "ECX",
+ "EDX",
+ "EBX",
+ "0",
+ "EBP",
+ "ESI",
+ "EDI",
+};
+
+static int
+argconv(char *p, Inst *i, Iarg *a)
+{
+ jmp_buf jmp;
+ char *s;
+
+ s = p;
+ switch(a->tag){
+ default:
+ abort();
+
+ case TCON:
+ return sprint(p, "%lud", a->val);
+ case TREG:
+ case TREG|TH:
+ switch(a->len){
+ case 1:
+ return sprint(p, "%c%c", "ACDB"[a->reg], "LH"[(a->tag & TH) != 0]);
+ case 4:
+ *p++ = 'E';
+ case 2:
+ p += sprint(p, "%c%c",
+ "ACDBSBSDECSDFGIF"[a->reg],
+ "XXXXPPIISSSSSSPL"[a->reg]);
+ return p - s;
+ }
+ case TMEM:
+ break;
+ }
+
+ /* setup trap jump in case we dereference bad memory */
+ memmove(jmp, a->cpu->jmp, sizeof jmp);
+ if(setjmp(a->cpu->jmp)){
+ p += sprint(p, "<%.4lux:%.4lux>", a->seg, a->off);
+ goto out;
+ }
+
+ switch(a->atype){
+ default:
+ abort();
+
+ case AAp:
+ p += sprint(p, "[%.4lux:%.4lux]", a->seg, a->off);
+ break;
+
+ case AJb:
+ case AJv:
+ p += sprint(p, "[%.4lux]", a->off);
+ break;
+
+ case AIc:
+ p += sprint(p, "$%.2lx", ars(a));
+ break;
+ case AIb:
+ case AIw:
+ case AIv:
+ p += sprint(p, "$%.*lux", (int)a->len*2, ar(a));
+ break;
+
+ case AMp:
+ *p++ = '*';
+ case AEb:
+ case AEw:
+ case AEv:
+ case AM:
+ case AMa:
+ case AMa2:
+ case AOb:
+ case AOv:
+ if(i->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]);
+ if(a->atype == AOb || a->atype == AOv || (i->mod == 0 &&
+ (i->alen == 2 && i->rm == 6) ||
+ (i->alen == 4 && ((i->rm == 5) ||
+ (i->rm == 4 && i->index == 4 && i->base == 5))))){
+ p += sprint(p, "[%.*lux]", (int)i->alen*2, a->off);
+ break;
+ }
+ *p++ = '[';
+ if(i->alen == 2)
+ p += sprint(p, "%s", memstr16[i->rm]);
+ else{
+ if(i->rm == 4){
+ if(i->index != 4)
+ p += sprint(p, "%c*%s+", "1248"[i->scale], memstr32[i->index]);
+ if(i->base != 5)
+ p += sprint(p, "%s", memstr32[i->base]);
+ else{
+ if(i->mod == 0)
+ p += sprint(p, "%.4lux", i->off);
+ else
+ p += sprint(p, "EBP");
+ }
+ } else
+ p += sprint(p, "%s", memstr32[i->rm]);
+ }
+ if(i->mod != 0)
+ p += sprint(p, "%+lx", i->disp);
+ *p++ = ']';
+ break;
+
+ case AXb:
+ case AXv:
+ if(a->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]);
+ p += sprint(p, "[SI]");
+ break;
+ case AYb:
+ case AYv:
+ if(a->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]);
+ p += sprint(p, "[DI]");
+ break;
+ }
+
+out:
+ memmove(a->cpu->jmp, jmp, sizeof jmp);
+ *p = 0;
+ return p - s;
+}
+
+static char *jmpstr[] = {
+ "JO", "JNO", "JC", "JNC", "JZ", "JNZ", "JBE", "JA",
+ "JS", "JNS", "JP", "JNP", "JL", "JGE", "JLE", "JG",
+};
+
+int
+instfmt(Fmt *fmt)
+{
+ Inst *i;
+ char *p, buf[256];
+
+ i = va_arg(fmt->args, Inst*);
+ p = buf;
+
+ if(i->olen == 4)
+ p += sprint(p, "O32: ");
+ if(i->alen == 4)
+ p += sprint(p, "A32: ");
+ if(i->rep)
+ p += sprint(p, "%s: ", opstr[i->rep]);
+
+ if(i->op == OXLAT && i->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]);
+
+ if(i->op == OJUMP){
+ switch(i->code){
+ case 0xE3:
+ p += sprint(p, "%s ", "JCXZ");
+ break;
+ case 0xEB:
+ case 0xE9:
+ case 0xEA:
+ case 0xFF:
+ p += sprint(p, "%s ", "JMP");
+ break;
+ default:
+ p += sprint(p, "%s ", jmpstr[i->code&0xF]);
+ break;
+ }
+ } else
+ p += sprint(p, "%s ", opstr[i->op]);
+
+
+ for(;;){
+ if(i->a1 == nil)
+ break;
+ p += argconv(p, i, i->a1);
+ if(i->a2 == nil)
+ break;
+ *p++ = ',';
+ *p++ = ' ';
+ p += argconv(p, i, i->a2);
+ if(i->a3 == nil)
+ break;
+ *p++ = ',';
+ *p++ = ' ';
+ p += argconv(p, i, i->a3);
+ break;
+ }
+ *p = 0;
+ fmtstrcpy(fmt, buf);
+ return 0;
+}
+
+int
+flagfmt(Fmt *fmt)
+{
+ char buf[16];
+ ulong f;
+
+ f = va_arg(fmt->args, ulong);
+ sprint(buf, "%c%c%c%c%c%c%c",
+ (f & CF) ? 'C' : 'c',
+ (f & SF) ? 'S' : 's',
+ (f & ZF) ? 'Z' : 'z',
+ (f & OF) ? 'O' : 'o',
+ (f & PF) ? 'P' : 'p',
+ (f & DF) ? 'D' : 'd',
+ (f & IF) ? 'I' : 'i');
+ fmtstrcpy(fmt, buf);
+ return 0;
+}
+
+int
+cpufmt(Fmt *fmt)
+{
+ char buf[512];
+ jmp_buf jmp;
+ Cpu *cpu;
+ Inst i;
+
+ cpu = va_arg(fmt->args, Cpu*);
+
+ memmove(jmp, cpu->jmp, sizeof jmp);
+ if(setjmp(cpu->jmp) == 0)
+ decode(amem(cpu, 1, RCS, cpu->reg[RIP]), &i);
+ memmove(cpu->jmp, jmp, sizeof jmp);
+
+ snprint(buf, sizeof(buf),
+ "%.6lux "
+ "%.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux "
+ "%.4lux %.4lux %.4lux %.4lux "
+ "%J %.4lux %.2ux %I",
+
+ cpu->ic,
+
+ cpu->reg[RAX],
+ cpu->reg[RBX],
+ cpu->reg[RCX],
+ cpu->reg[RDX],
+
+ cpu->reg[RDI],
+ cpu->reg[RSI],
+
+ cpu->reg[RBP],
+ cpu->reg[RSP],
+
+ cpu->reg[RDS],
+ cpu->reg[RES],
+ cpu->reg[RSS],
+ cpu->reg[RCS],
+
+ cpu->reg[RFL],
+ cpu->reg[RIP],
+
+ i.code,
+ &i);
+
+ fmtstrcpy(fmt, buf);
+ return 0;
+}
diff -Nru /sys/src/cmd/aux/realemu/fns.h /sys/src/cmd/aux/realemu/fns.h
--- /sys/src/cmd/aux/realemu/fns.h Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/fns.h Fri Feb 19 00:00:00 2016
@@ -0,0 +1,31 @@
+/* arg */
+Iarg *adup(Iarg *x);
+Iarg *areg(Cpu *cpu, uchar len, uchar reg);
+Iarg *amem(Cpu *cpu, uchar len, uchar sreg, ulong off);
+Iarg *afar(Iarg *mem, uchar len, uchar alen);
+Iarg *acon(Cpu *cpu, uchar len, ulong val);
+ulong ar(Iarg *a);
+long ars(Iarg *a);
+void aw(Iarg *a, ulong w);
+
+/* decode */
+void decode(Iarg *ip, Inst *i);
+
+/* xec */
+void trap(Cpu *cpu, int e);
+int intr(Cpu *cpu, int v);
+int xec(Cpu *cpu, int n);
+
+#pragma varargck type "I" Inst*
+#pragma varargck type "J" ulong
+#pragma varargck type "C" Cpu*
+
+int instfmt(Fmt *fmt);
+int flagfmt(Fmt *fmt);
+int cpufmt(Fmt *fmt);
+
+/* pit */
+void clockpit(Pit *pit, vlong cycles);
+void setgate(Pit *ch, uchar gate);
+uchar rpit(Pit *pit, uchar addr);
+void wpit(Pit *pit, uchar addr, uchar data);
diff -Nru /sys/src/cmd/aux/realemu/loadcom.c /sys/src/cmd/aux/realemu/loadcom.c
--- /sys/src/cmd/aux/realemu/loadcom.c Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/loadcom.c Fri Feb 19 00:00:00 2016
@@ -0,0 +1,43 @@
+#include <u.h>
+#include <libc.h>
+
+#include "/386/include/ureg.h"
+
+static uchar buf[0xFF01];
+
+void
+main(int argc, char *argv[])
+{
+ struct Ureg u;
+ int fd, rreg, rmem, len;
+
+ ARGBEGIN {
+ } ARGEND;
+
+ if(argc == 0){
+ fprint(2, "usage:\t%s file.com\n", argv0);
+ exits("usage");
+ }
+ if((fd = open(*argv, OREAD)) < 0)
+ sysfatal("open: %r");
+
+ if((rreg = open("/dev/realmode", OWRITE)) < 0)
+ sysfatal("open realmode: %r");
+ if((rmem = open("/dev/realmodemem", OWRITE)) < 0)
+ sysfatal("open realmodemem: %r");
+ if((len = readn(fd, buf, sizeof buf)) < 2)
+ sysfatal("file too small");
+
+ memset(&u, 0, sizeof u);
+ u.cs = u.ds = u.es = u.fs = u.gs = 0x1000;
+ u.ss = 0x0000;
+ u.sp = 0xfffe;
+ u.pc = 0x0100;
+
+ seek(rmem, (u.cs<<4) + u.pc, 0);
+ if(write(rmem, buf, len) != len)
+ sysfatal("write mem: %r");
+
+ if(write(rreg, &u, sizeof u) != sizeof u)
+ sysfatal("write reg: %r");
+}
diff -Nru /sys/src/cmd/aux/realemu/main.c /sys/src/cmd/aux/realemu/main.c
--- /sys/src/cmd/aux/realemu/main.c Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/main.c Fri Feb 19 00:00:00 2016
@@ -0,0 +1,796 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+/* for fs */
+#include <auth.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+
+#include "/386/include/ureg.h"
+
+enum {
+ MEMSIZE = 0x100000,
+
+ RMBUF = 0x9000,
+ RMCODE = 0x8000,
+
+ PITHZ = 1193182,
+ PITNS = 1000000000/PITHZ,
+};
+
+static Cpu cpu;
+static uchar memory[MEMSIZE+4];
+static uchar pageregtmp[0x10];
+static int portfd[5];
+static int realmemfd;
+static int cputrace;
+static int porttrace;
+static Pit pit[3];
+static uchar rtcaddr;
+
+static vlong pitclock;
+
+static void
+startclock(void)
+{
+ pitclock = nsec();
+}
+
+static void
+runclock(void)
+{
+ vlong now, dt;
+
+ now = nsec();
+ dt = now - pitclock;
+ if(dt >= PITNS){
+ clockpit(pit, dt/PITNS);
+ pitclock = now;
+ }
+}
+
+static ulong
+gw1(uchar *p)
+{
+ return p[0];
+}
+static ulong
+gw2(uchar *p)
+{
+ return (ulong)p[0] | (ulong)p[1]<<8;
+}
+static ulong
+gw4(uchar *p)
+{
+ return (ulong)p[0] | (ulong)p[1]<<8 | (ulong)p[2]<<16 | (ulong)p[3]<<24;
+}
+static ulong (*gw[5])(uchar *p) = {
+ [1] gw1,
+ [2] gw2,
+ [4] gw4,
+};
+
+static void
+pw1(uchar *p, ulong w)
+{
+ p[0] = w & 0xFF;
+}
+static void
+pw2(uchar *p, ulong w)
+{
+ p[0] = w & 0xFF;
+ p[1] = (w>>8) & 0xFF;
+}
+static void
+pw4(uchar *p, ulong w)
+{
+ p[0] = w & 0xFF;
+ p[1] = (w>>8) & 0xFF;
+ p[2] = (w>>16) & 0xFF;
+ p[3] = (w>>24) & 0xFF;
+}
+static void (*pw[5])(uchar *p, ulong w) = {
+ [1] pw1,
+ [2] pw2,
+ [4] pw4,
+};
+
+static ulong
+rbad(void *, ulong off, int)
+{
+ fprint(2, "bad mem read %.5lux\n", off);
+ trap(&cpu, EMEM);
+
+ /* not reached */
+ return 0;
+}
+
+static void
+wbad(void *, ulong off, ulong, int)
+{
+ fprint(2, "bad mem write %.5lux\n", off);
+ trap(&cpu, EMEM);
+}
+
+static ulong
+rmem(void *, ulong off, int len)
+{
+ return gw[len](memory + off);
+}
+
+static void
+wmem(void *, ulong off, ulong w, int len)
+{
+ pw[len](memory + off, w);
+}
+
+static ulong
+rrealmem(void *, ulong off, int len)
+{
+ uchar data[4];
+
+ if(pread(realmemfd, data, len, off) != len){
+ fprint(2, "bad real mem read %.5lux: %r\n", off);
+ trap(&cpu, EMEM);
+ }
+ return gw[len](data);
+}
+
+static void
+wrealmem(void *, ulong off, ulong w, int len)
+{
+ uchar data[4];
+
+ pw[len](data, w);
+ if(pwrite(realmemfd, data, len, off) != len){
+ fprint(2, "bad real mem write %.5lux: %r\n", off);
+ trap(&cpu, EMEM);
+ }
+}
+
+
+static ulong
+rport(void *, ulong p, int len)
+{
+ uchar data[4];
+ ulong w;
+
+ switch(p){
+ case 0x20: /* PIC 1 */
+ case 0x21:
+ w = 0;
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ runclock();
+ w = rpit(pit, p - 0x40);
+ break;
+ case 0x60: /* keyboard data output buffer */
+ w = 0;
+ break;
+ case 0x61: /* keyboard controller port b */
+ runclock();
+ w = pit[2].out<<5 | pit[2].gate;
+ break;
+ case 0x62: /* PPI (XT only) */
+ runclock();
+ w = pit[2].out<<5;
+ break;
+ case 0x63: /* PPI (XT only) read dip switches */
+ w = 0;
+ break;
+ case 0x65: /* A20 gate */
+ w = 1 << 2;
+ break;
+ case 0x70: /* RTC addr */
+ w = rtcaddr;
+ break;
+ case 0x71: /* RTC data */
+ w = 0xFF;
+ break;
+ case 0x80: /* extra dma registers (temp) */
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x88:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ w = pageregtmp[p-0x80];
+ break;
+ case 0x92: /* A20 gate (system control port a) */
+ w = 1 << 1;
+ break;
+ case 0xa0: /* PIC 2 */
+ case 0xa1:
+ w = 0;
+ break;
+ default:
+ if(pread(portfd[len], data, len, p) != len){
+ fprint(2, "bad %d bit port read %.4lux: %r\n", len*8, p);
+ trap(&cpu, EIO);
+ }
+ w = gw[len](data);
+ }
+ if(porttrace)
+ fprint(2, "rport %.4lux %.*lux\n", p, len<<1, w);
+ return w;
+}
+
+static void
+wport(void *, ulong p, ulong w, int len)
+{
+ uchar data[4];
+
+ if(porttrace)
+ fprint(2, "wport %.4lux %.*lux\n", p, len<<1, w);
+
+ switch(p){
+ case 0x20: /* PIC 1 */
+ case 0x21:
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ runclock();
+ wpit(pit, p - 0x40, w);
+ break;
+ case 0x60: /* keyboard controller data port */
+ break;
+ case 0x61: /* keyboard controller port B */
+ setgate(&pit[2], w & 1);
+ break;
+ case 0x62: /* PPI (XT only) */
+ case 0x63:
+ case 0x64: /* KB controller input buffer (ISA, EISA) */
+ case 0x65: /* A20 gate (bit 2) */
+ break;
+ case 0x70: /* RTC addr */
+ rtcaddr = w & 0xFF;
+ break;
+ case 0x71: /* RTC data */
+ break;
+ case 0x80:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x88:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ pageregtmp[p-0x80] = w & 0xFF;
+ break;
+ case 0x92: /* system control port a */
+ case 0x94: /* system port enable setup register */
+ case 0x96:
+ break;
+ case 0xA0: /* PIC 2 */
+ case 0xA1:
+ break;
+
+ default:
+ pw[len](data, w);
+ if(pwrite(portfd[len], data, len, p) != len){
+ fprint(2, "bad %d bit port write %.4lux: %r\n", len*8, p);
+ trap(&cpu, EIO);
+ }
+ }
+}
+
+static Bus memio[] = {
+ /* 0 */ memory, rmem, wmem, /* RAM: IVT, BIOS data area */
+ /* 1 */ memory, rmem, wmem, /* custom */
+ /* 2 */ nil, rbad, wbad,
+ /* 3 */ nil, rbad, wbad,
+ /* 4 */ nil, rbad, wbad,
+ /* 5 */ nil, rbad, wbad,
+ /* 6 */ nil, rbad, wbad,
+ /* 7 */ nil, rbad, wbad,
+ /* 8 */ nil, rbad, wbad,
+ /* 9 */ memory, rmem, wmem, /* RAM: extended BIOS data area */
+ /* A */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */
+ /* B */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */
+ /* C */ memory, rmem, wmem, /* ROM: VGA BIOS */
+ /* D */ nil, rbad, wbad,
+ /* E */ memory, rmem, wmem, /* ROM: BIOS */
+ /* F */ memory, rmem, wbad, /* ROM: BIOS */
+};
+
+static Bus portio = {
+ nil, rport, wport,
+};
+
+static void
+cpuinit(void)
+{
+ int i;
+
+ fmtinstall('I', instfmt);
+ fmtinstall('J', flagfmt);
+ fmtinstall('C', cpufmt);
+
+ if((portfd[1] = open("#P/iob", ORDWR)) < 0)
+ sysfatal("open iob: %r");
+ if((portfd[2] = open("#P/iow", ORDWR)) < 0)
+ sysfatal("open iow: %r");
+ if((portfd[4] = open("#P/iol", ORDWR)) < 0)
+ sysfatal("open iol: %r");
+
+ if((realmemfd = open("#P/realmodemem", ORDWR)) < 0)
+ sysfatal("open realmodemem: %r");
+
+ for(i=0; i<nelem(memio); i++){
+ ulong off;
+
+ if(memio[i].r != rmem)
+ continue;
+
+ off = (ulong)i << 16;
+ seek(realmemfd, off, 0);
+ if(readn(realmemfd, memory + off, 0x10000) != 0x10000)
+ sysfatal("read real mem %lux: %r\n", off);
+ }
+
+ cpu.ic = 0;
+ cpu.mem = memio;
+ cpu.port = &portio;
+ cpu.alen = cpu.olen = cpu.slen = 2;
+}
+
+static char Ebusy[] = "device is busy";
+static char Eintr[] = "interrupted";
+static char Eperm[] = "permission denied";
+static char Eio[] = "i/o error";
+static char Emem[] = "bad memory access";
+static char Enonexist[] = "file does not exist";
+static char Ebadspec[] = "bad attach specifier";
+static char Ewalk[] = "walk in non directory";
+static char Ebadureg[] = "write a Ureg";
+static char Ebadoff[] = "invalid offset";
+static char Ebadtrap[] = "bad trap";
+
+static char *trapstr[] = {
+ [EDIV0] "division by zero",
+ [EDEBUG] "debug exception",
+ [ENMI] "not maskable interrupt",
+ [EBRK] "breakpoint",
+ [EINTO] "into overflow",
+ [EBOUND] "bounds check",
+ [EBADOP] "bad opcode",
+ [ENOFPU] "no fpu installed",
+ [EDBLF] "double fault",
+ [EFPUSEG] "fpu segment overflow",
+ [EBADTSS] "invalid task state segment",
+ [ENP] "segment not present",
+ [ESTACK] "stack fault",
+ [EGPF] "general protection fault",
+ [EPF] "page fault",
+};
+
+static int flushed(void *);
+
+#define GETUREG(x) gw[sizeof(u->x)]((uchar*)&u->x)
+#define PUTUREG(x,y) pw[sizeof(u->x)]((uchar*)&u->x,y)
+
+static char*
+realmode(Cpu *cpu, struct Ureg *u, void *r)
+{
+ char *err;
+ int i;
+
+ cpu->reg[RDI] = GETUREG(di);
+ cpu->reg[RSI] = GETUREG(si);
+ cpu->reg[RBP] = GETUREG(bp);
+ cpu->reg[RBX] = GETUREG(bx);
+ cpu->reg[RDX] = GETUREG(dx);
+ cpu->reg[RCX] = GETUREG(cx);
+ cpu->reg[RAX] = GETUREG(ax);
+
+ cpu->reg[RGS] = GETUREG(gs);
+ cpu->reg[RFS] = GETUREG(fs);
+ cpu->reg[RES] = GETUREG(es);
+ cpu->reg[RDS] = GETUREG(ds);
+
+ cpu->reg[RFL] = GETUREG(flags);
+
+ if(i = GETUREG(trap)){
+ cpu->reg[RSS] = 0x0000;
+ cpu->reg[RSP] = 0x7C00;
+ cpu->reg[RCS] = (RMCODE>>4)&0xF000;
+ cpu->reg[RIP] = RMCODE & 0xFFFF;
+ memory[RMCODE] = 0xf4; /* HLT instruction */
+ if(intr(cpu, i) < 0)
+ return Ebadtrap;
+ } else {
+ cpu->reg[RSS] = GETUREG(ss);
+ cpu->reg[RSP] = GETUREG(sp);
+ cpu->reg[RCS] = GETUREG(cs);
+ cpu->reg[RIP] = GETUREG(pc);
+ }
+
+ startclock();
+ for(;;){
+ if(cputrace)
+ fprint(2, "%C\n", cpu);
+ switch(i = xec(cpu, (porttrace | cputrace) ? 1 : 100000)){
+ case -1:
+ if(flushed(r)){
+ err = Eintr;
+ break;
+ }
+ runclock();
+ continue;
+
+ /* normal interrupts */
+ default:
+ if(intr(cpu, i) < 0){
+ err = Ebadtrap;
+ break;
+ }
+ continue;
+
+ /* pseudo-interrupts */
+ case EHALT:
+ err = nil;
+ break;
+ case EIO:
+ err = Eio;
+ break;
+ case EMEM:
+ err = Emem;
+ break;
+
+ /* processor traps */
+ case EDIV0:
+ case EDEBUG:
+ case ENMI:
+ case EBRK:
+ case EINTO:
+ case EBOUND:
+ case EBADOP:
+ case ENOFPU:
+ case EDBLF:
+ case EFPUSEG:
+ case EBADTSS:
+ case ENP:
+ case ESTACK:
+ case EGPF:
+ case EPF:
+ PUTUREG(trap, i);
+ err = trapstr[i];
+ break;
+ }
+
+ break;
+ }
+
+ if(err)
+ fprint(2, "%s\n%C\n", err, cpu);
+
+ PUTUREG(di, cpu->reg[RDI]);
+ PUTUREG(si, cpu->reg[RSI]);
+ PUTUREG(bp, cpu->reg[RBP]);
+ PUTUREG(bx, cpu->reg[RBX]);
+ PUTUREG(dx, cpu->reg[RDX]);
+ PUTUREG(cx, cpu->reg[RCX]);
+ PUTUREG(ax, cpu->reg[RAX]);
+
+ PUTUREG(gs, cpu->reg[RGS]);
+ PUTUREG(fs, cpu->reg[RFS]);
+ PUTUREG(es, cpu->reg[RES]);
+ PUTUREG(ds, cpu->reg[RDS]);
+
+ PUTUREG(flags, cpu->reg[RFL]);
+
+ PUTUREG(pc, cpu->reg[RIP]);
+ PUTUREG(cs, cpu->reg[RCS]);
+ PUTUREG(sp, cpu->reg[RSP]);
+ PUTUREG(ss, cpu->reg[RSS]);
+
+ return err;
+}
+
+enum {
+ Qroot,
+ Qcall,
+ Qmem,
+ Nqid,
+};
+
+static struct Qtab {
+ char *name;
+ int mode;
+ int type;
+ int length;
+} qtab[Nqid] = {
+ "/",
+ DMDIR|0555,
+ QTDIR,
+ 0,
+
+ "realmode",
+ 0666,
+ 0,
+ 0,
+
+ "realmodemem",
+ 0666,
+ 0,
+ MEMSIZE,
+};
+
+static int
+fillstat(ulong qid, Dir *d)
+{
+ struct Qtab *t;
+
+ memset(d, 0, sizeof(Dir));
+ d->uid = "realemu";
+ d->gid = "realemu";
+ d->muid = "";
+ d->qid = (Qid){qid, 0, 0};
+ d->atime = time(0);
+ t = qtab + qid;
+ d->name = t->name;
+ d->qid.type = t->type;
+ d->mode = t->mode;
+ d->length = t->length;
+ return 1;
+}
+
+static void
+fsattach(Req *r)
+{
+ char *spec;
+
+ spec = r->ifcall.aname;
+ if(spec && spec[0]){
+ respond(r, Ebadspec);
+ return;
+ }
+ r->fid->qid = (Qid){Qroot, 0, QTDIR};
+ r->ofcall.qid = r->fid->qid;
+ respond(r, nil);
+}
+
+static void
+fsstat(Req *r)
+{
+ fillstat((ulong)r->fid->qid.path, &r->d);
+ r->d.name = estrdup9p(r->d.name);
+ r->d.uid = estrdup9p(r->d.uid);
+ r->d.gid = estrdup9p(r->d.gid);
+ r->d.muid = estrdup9p(r->d.muid);
+ respond(r, nil);
+}
+
+static char*
+fswalk1(Fid *fid, char *name, Qid *qid)
+{
+ int i;
+ ulong path;
+
+ path = fid->qid.path;
+ switch(path){
+ case Qroot:
+ if (strcmp(name, "..") == 0) {
+ *qid = (Qid){Qroot, 0, QTDIR};
+ fid->qid = *qid;
+ return nil;
+ }
+ for(i = fid->qid.path; i<Nqid; i++){
+ if(strcmp(name, qtab[i].name) != 0)
+ continue;
+ *qid = (Qid){i, 0, 0};
+ fid->qid = *qid;
+ return nil;
+ }
+ return Enonexist;
+
+ default:
+ return Ewalk;
+ }
+}
+
+static void
+fsopen(Req *r)
+{
+ static int need[4] = { 4, 2, 6, 1 };
+ struct Qtab *t;
+ int n;
+
+ t = qtab + r->fid->qid.path;
+ n = need[r->ifcall.mode & 3];
+ if((n & t->mode) != n)
+ respond(r, Eperm);
+ else
+ respond(r, nil);
+}
+
+static int
+readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
+{
+ int i, m, n;
+ long pos;
+ Dir d;
+
+ n = 0;
+ pos = 0;
+ for (i = 1; i < Nqid; i++){
+ fillstat(i, &d);
+ m = convD2M(&d, &buf[n], blen-n);
+ if(off <= pos){
+ if(m <= BIT16SZ || m > cnt)
+ break;
+ n += m;
+ cnt -= m;
+ }
+ pos += m;
+ }
+ return n;
+}
+
+static Channel *reqchan;
+
+static void
+cpuproc(void *)
+{
+ static struct Ureg rmu;
+ ulong path;
+ vlong o;
+ ulong n;
+ char *p;
+ Req *r;
+
+ threadsetname("cpuproc");
+
+ while(r = recvp(reqchan)){
+ if(flushed(r)){
+ respond(r, Eintr);
+ continue;
+ }
+
+ path = r->fid->qid.path;
+
+ p = r->ifcall.data;
+ n = r->ifcall.count;
+ o = r->ifcall.offset;
+
+ switch(((int)r->ifcall.type<<8)|path){
+ case (Tread<<8) | Qmem:
+ readbuf(r, memory, MEMSIZE);
+ respond(r, nil);
+ break;
+
+ case (Tread<<8) | Qcall:
+ readbuf(r, &rmu, sizeof rmu);
+ respond(r, nil);
+ break;
+
+ case (Twrite<<8) | Qmem:
+ if(o < 0 || o >= MEMSIZE || o+n > MEMSIZE){
+ respond(r, Ebadoff);
+ break;
+ }
+ memmove(memory + o, p, n);
+ r->ofcall.count = n;
+ respond(r, nil);
+ break;
+
+ case (Twrite<<8) | Qcall:
+ if(n != sizeof rmu){
+ respond(r, Ebadureg);
+ break;
+ }
+ memmove(&rmu, p, n);
+ if(p = realmode(&cpu, &rmu, r)){
+ respond(r, p);
+ break;
+ }
+ r->ofcall.count = n;
+ respond(r, nil);
+ break;
+ }
+ }
+}
+
+static Channel *flushchan;
+
+static int
+flushed(void *r)
+{
+ return nbrecvp(flushchan) == r;
+}
+
+static void
+fsflush(Req *r)
+{
+ nbsendp(flushchan, r->oldreq);
+ respond(r, nil);
+}
+
+static void
+dispatch(Req *r)
+{
+ if(!nbsendp(reqchan, r))
+ respond(r, Ebusy);
+}
+
+static void
+fsread(Req *r)
+{
+ switch((ulong)r->fid->qid.path){
+ case Qroot:
+ r->ofcall.count = readtopdir(r->fid, (void*)r->ofcall.data, r->ifcall.offset,
+ r->ifcall.count, r->ifcall.count);
+ respond(r, nil);
+ break;
+ default:
+ dispatch(r);
+ }
+}
+
+static void
+fsend(Srv*)
+{
+ threadexitsall(nil);
+}
+
+static Srv fs = {
+ .attach= fsattach,
+ .walk1= fswalk1,
+ .open= fsopen,
+ .read= fsread,
+ .write= dispatch,
+ .stat= fsstat,
+ .flush= fsflush,
+ .end= fsend,
+};
+
+static void
+usage(void)
+{
+ fprint(2, "usgae:\t%s [-Dpt] [-s srvname] [-m mountpoint]\n", argv0);
+ exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ char *mnt = "/dev";
+ char *srv = nil;
+
+ ARGBEGIN{
+ case 'D':
+ chatty9p++;
+ break;
+ case 'p':
+ porttrace = 1;
+ break;
+ case 't':
+ cputrace = 1;
+ break;
+ case 's':
+ srv = EARGF(usage());
+ mnt = nil;
+ break;
+ case 'm':
+ mnt = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ cpuinit();
+
+ reqchan = chancreate(sizeof(Req*), 8);
+ flushchan = chancreate(sizeof(Req*), 8);
+ procrfork(cpuproc, nil, 16*1024, RFNAMEG|RFNOTEG);
+ threadpostmountsrv(&fs, srv, mnt, MBEFORE);
+}
diff -Nru /sys/src/cmd/aux/realemu/mkfile /sys/src/cmd/aux/realemu/mkfile
--- /sys/src/cmd/aux/realemu/mkfile Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/mkfile Fri Feb 19 00:00:00 2016
@@ -0,0 +1,9 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin/aux
+
+TARG=realemu
+OFILES=decode.$O arg.$O xec.$O fmt.$O pit.$O main.$O
+HFILES=dat.h fns.h
+
+</sys/src/cmd/mkone
diff -Nru /sys/src/cmd/aux/realemu/notes /sys/src/cmd/aux/realemu/notes
--- /sys/src/cmd/aux/realemu/notes Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/notes Fri Feb 19 00:00:00 2016
@@ -0,0 +1,22 @@
+realmode emulator. binds itself over /dev and provides /dev/realmode
+and /dev/realmodemem to be used with aux/vga -m vesa ...
+
+the command option -t enables instruction tracing to stderr.
+
+requires a updated vgavesa driver to use /dev/realmode instead of
+a direct realmode() call.
+
+patch can be found at: /n/sources/patch/vesa-softscreen-resize
+
+a list with graphics cards that have been successfully enabled
+with the aux/vga and realemu can be found in the vgalist file.
+
+bug reports / suggestions or failed attempts email to:
+
+cinap_lenrek AT gmx DOT de
+
+contributors:
+
+i stole some code from rsc's 8i /n/sources/contrib/rsc/8i, so thanks russ! :)
+
+patient testers from irc: sl, Fish-
diff -Nru /sys/src/cmd/aux/realemu/pit.c /sys/src/cmd/aux/realemu/pit.c
--- /sys/src/cmd/aux/realemu/pit.c Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/pit.c Fri Feb 19 00:00:00 2016
@@ -0,0 +1,357 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+enum {
+ AC0 = 0,
+ AC1,
+ AC2,
+ Actl,
+
+ Readback = 3,
+
+ RBC0 = 1<<1,
+ RBC1 = 1<<2,
+ RBC2 = 1<<3,
+ RBlatchstatus = 1<<4,
+ RBlatchcount = 1<<5,
+
+ AMlatchcount = 0,
+ AMloonly,
+ AMhionly,
+ AMlohi,
+
+ OM0 = 0,
+ OM1,
+ OM2,
+ OM3,
+ OM4,
+ OM5,
+ OM2b,
+ OM3b,
+};
+
+static void
+latchstatus(Pit *ch)
+{
+ if(ch->rlatched)
+ return;
+ ch->rlatch[0] = ch->bcd | ch->omode<<1 | ch->amode<<4 | ch->count0<<6 | ch->out<<7;
+ ch->rcount = 0;
+ ch->rlatched = 1;
+}
+
+static void
+latchcount(Pit *ch)
+{
+ ulong w;
+
+ if(ch->rlatched)
+ return;
+ w = ch->count & 0xFFFF;
+ if(ch->bcd)
+ w = (w % 10) + ((w/10) % 10)<<4 + ((w/100) % 10)<<8 + ((w/1000) % 10)<<12;
+ ch->rlatch[0] = w & 0xFF;
+ ch->rlatch[1] = (w >> 8) & 0xFF;
+ ch->rcount = 0;
+ ch->rlatched = 1;
+ switch(ch->amode){
+ case AMhionly:
+ ch->rcount++;
+ break;
+ case AMlohi:
+ ch->rlatched++;
+ break;
+ }
+}
+
+static void
+setcount(Pit *ch)
+{
+ ulong w;
+
+ w = (ulong)ch->wlatch[0] | (ulong)ch->wlatch[1] << 8;
+ if(ch->bcd)
+ w = (w & 0xF) + 10*((w >> 4)&0xF) + 100*((w >> 8)&0xF) + 1000*((w >> 12)&0xF);
+ ch->count = w;
+ ch->count0 = 0;
+}
+
+static int
+deccount(Pit *ch, vlong *cycles)
+{
+ if(ch->count0){
+ *cycles = 0;
+ return 0;
+ } else {
+ vlong passed, remain;
+
+ passed = *cycles;
+ if(ch->count == 0){
+ ch->count = ch->bcd ? 9999 : 0xFFFF;
+ passed--;
+ }
+ if(passed <= ch->count){
+ remain = 0;
+ ch->count -= passed;
+ } else {
+ remain = passed - ch->count;
+ ch->count = 0;
+ }
+ *cycles = remain;
+ return ch->count == 0;
+ }
+}
+
+void
+setgate(Pit *ch, uchar gate)
+{
+ if(ch->gate == 0 && gate)
+ ch->gateraised = 1;
+ ch->gate = gate;
+}
+
+static void
+clockpit1(Pit *ch, vlong *cycles)
+{
+ switch(ch->omode){
+ case OM0: /* Interrupt On Terminal Count */
+ if(ch->count0){
+ setcount(ch);
+ ch->out = 0;
+ Next:
+ --*cycles;
+ return;
+ }
+ if(ch->gate && deccount(ch, cycles)){
+ ch->out = 1;
+ return;
+ }
+ break;
+
+ case OM1: /* Hardware Re-triggerable One-shot */
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ ch->out = 0;
+ goto Next;
+ }
+ if(deccount(ch, cycles) && ch->out == 0){
+ ch->out = 1;
+ return;
+ }
+ break;
+
+ case OM2: /* Rate Generator */
+ case OM2b:
+ ch->out = 1;
+ if(ch->count0){
+ setcount(ch);
+ goto Next;
+ }
+ if(ch->gate == 0)
+ break;
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ goto Next;
+ }
+ if(deccount(ch, cycles)){
+ setcount(ch);
+ ch->out = 0;
+ return;
+ }
+ break;
+
+ case OM3: /* Square Wave Generator */
+ case OM3b:
+ if(ch->count0){
+ setcount(ch);
+ goto Next;
+ }
+ if(ch->gate == 0)
+ break;
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ goto Next;
+ }
+ if(deccount(ch, cycles)){
+ setcount(ch);
+ ch->out ^= 1;
+ return;
+ }
+ break;
+
+ case OM4: /* Software Triggered Strobe */
+ ch->out = 1;
+ if(ch->count0){
+ setcount(ch);
+ goto Next;
+ }
+ if(ch->gate && deccount(ch, cycles)){
+ ch->out = 0;
+ return;
+ }
+ break;
+
+ case OM5: /* Hardware Triggered Strobe */
+ ch->out = 1;
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ goto Next;
+ }
+ if(deccount(ch, cycles)){
+ ch->out = 0;
+ return;
+ }
+ break;
+ }
+ *cycles = 0;
+}
+
+void
+clockpit(Pit *pit, vlong cycles)
+{
+ Pit *ch;
+ int i;
+
+ if(cycles <= 0)
+ return;
+ for(i = 0; i<Actl; i++){
+ ch = pit + i;
+ if(ch->wlatched){
+ vlong c;
+
+ switch(ch->omode){
+ case OM3:
+ case OM3b:
+ c = cycles * 2;
+ break;
+ default:
+ c = cycles;
+ }
+ while(c > 0)
+ clockpit1(ch, &c);
+ }
+ ch->gateraised = 0;
+ }
+}
+
+uchar
+rpit(Pit *pit, uchar addr)
+{
+ Pit *ch;
+ uchar data;
+
+ if(addr >= Actl)
+ return 0;
+ ch = pit + addr;
+ if(ch->rlatched){
+ data = ch->rlatch[ch->rcount & 1];
+ ch->rlatched--;
+ } else {
+ data = 0;
+ switch(ch->amode){
+ case AMloonly:
+ data = ch->count & 0xFF;
+ break;
+ case AMhionly:
+ data = (ch->count >> 8) & 0xFF;
+ break;
+ case AMlohi:
+ data = (ch->count >> ((ch->rcount & 1)<<3)) & 0xFF;
+ break;
+ }
+ }
+ ch->rcount++;
+ if(0) fprint(2, "rpit %p: %.2x %.2x\n", pit, (int)addr, (int)data);
+ return data;
+}
+
+void
+wpit(Pit *pit, uchar addr, uchar data)
+{
+ Pit *ch;
+
+ if(0) fprint(2, "wpit %p: %.2x %.2x\n", pit, (int)addr, (int)data);
+ if(addr > Actl)
+ return;
+ if(addr == Actl){
+ uchar sc, amode, omode, bcd;
+
+ bcd = (data & 1);
+ omode = (data >> 1) & 7;
+ amode = (data >> 4) & 3;
+ sc = (data >> 6) & 3;
+
+ if(sc == Readback){
+ ch = nil;
+ for(;;){
+ if(data & RBC0){
+ ch = pit;
+ break;
+ }
+ if(data & RBC1){
+ ch = pit + 1;
+ break;
+ }
+ if(data & RBC2){
+ ch = pit + 2;
+ break;
+ }
+ break;
+ }
+ if(ch == nil)
+ return;
+ if((data & RBlatchcount) == 0)
+ latchcount(ch);
+ if((data & RBlatchstatus) == 0)
+ latchstatus(ch);
+ return;
+ }
+
+ ch = pit + sc;
+ if(amode == AMlatchcount){
+ latchcount(ch);
+ return;
+ }
+ ch->bcd = bcd;
+
+ ch->amode = amode;
+ ch->omode = omode;
+
+ ch->rlatched = 0;
+ ch->rcount = 0;
+ ch->rlatch[0] = 0;
+ ch->rlatch[1] = 0;
+
+ ch->wlatched = 0;
+ ch->wcount = 0;
+ ch->wlatch[0] = 0;
+ ch->wlatch[1] = 0;
+
+ ch->count0 = 1;
+ ch->out = !!omode;
+ return;
+ }
+
+ ch = pit + addr;
+ switch(ch->amode){
+ case AMloonly:
+ case AMhionly:
+ ch->wlatch[ch->amode - AMloonly] = data;
+ ch->wcount++;
+ break;
+ case AMlohi:
+ ch->wlatch[ch->wcount++ & 1] = data;
+ if(ch->wcount < 2)
+ return;
+ break;
+ }
+ ch->wlatched = ch->wcount;
+ ch->wcount = 0;
+ ch->count0 = 1;
+}
diff -Nru /sys/src/cmd/aux/realemu/vgalist /sys/src/cmd/aux/realemu/vgalist
--- /sys/src/cmd/aux/realemu/vgalist Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/vgalist Fri Feb 19 00:00:00 2016
@@ -0,0 +1,9 @@
+#vid did bios wired product name
+100b 0030 5.30 STI NSC Geode GX2
+5533 8c2e 1.0 - T23 / S3 savage
+1002 791e 01.00 - ATI RS690
+10de 002c B1 STI NVidia RivaTNT
+15ad 0405 2.0 - VMware
+- - 1.26 - Bochs
+102b 0519 00 STI Matrox MILLENNIUM
+5333 8901 Rev E - S3 Trio64V2/DX/GX
diff -Nru /sys/src/cmd/aux/realemu/xec.c /sys/src/cmd/aux/realemu/xec.c
--- /sys/src/cmd/aux/realemu/xec.c Thu Jan 1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/xec.c Fri Feb 19 00:00:00 2016
@@ -0,0 +1,1363 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+#define sign(s) (1UL<<((s)-1))
+#define mask(s) (sign(s)|(sign(s)-1))
+
+static void
+push(Iarg *sp, Iarg *a)
+{
+ Iarg *p;
+
+ p = amem(sp->cpu, a->len, RSS, ar(sp));
+ p->off -= a->len;
+ p->off &= mask(sp->len*8);
+ aw(p, ar(a));
+ aw(sp, p->off);
+}
+
+static void
+pop(Iarg *sp, Iarg *a)
+{
+ Iarg *p;
+
+ p = amem(sp->cpu, a->len, RSS, ar(sp));
+ aw(a, ar(p));
+ aw(sp, p->off + a->len);
+}
+
+static void
+jump(Iarg *to)
+{
+ Cpu *cpu;
+
+ cpu = to->cpu;
+ switch(to->atype){
+ default:
+ abort();
+ case AMp:
+ to = afar(to, 1, to->len);
+ case AAp:
+ cpu->reg[RCS] = to->seg;
+ case AJb:
+ case AJv:
+ cpu->reg[RIP] = to->off;
+ break;
+ case AEv:
+ cpu->reg[RIP] = ar(to);
+ break;
+ }
+}
+
+static void
+opcall(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ switch(i->a1->atype){
+ default:
+ abort();
+ case AAp:
+ case AMp:
+ push(sp, areg(cpu, i->olen, RCS));
+ case AJv:
+ case AEv:
+ push(sp, areg(cpu, i->olen, RIP));
+ break;
+ }
+ jump(i->a1);
+}
+
+static void
+opint(Cpu *cpu, Inst *i)
+{
+ cpu->trap = ar(i->a1);
+ longjmp(cpu->jmp, 1);
+}
+
+static void
+opiret(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ if(i->olen != 2)
+ trap(cpu, EBADOP);
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, 2, RIP));
+ pop(sp, areg(cpu, 2, RCS));
+ pop(sp, areg(cpu, 2, RFL));
+}
+
+static void
+opret(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+ ulong c;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, i->olen, RIP));
+ if(c = ar(i->a1))
+ aw(sp, ar(sp) + c);
+}
+
+static void
+opretf(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+ ulong c;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, i->olen, RIP));
+ pop(sp, areg(cpu, i->olen, RCS));
+ if(c = ar(i->a1))
+ aw(sp, ar(sp) + c);
+}
+
+static void
+openter(Cpu *cpu, Inst *i)
+{
+ Iarg *sp, *bp;
+ ulong oframe, nframe;
+ int j, n;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ bp = areg(cpu, cpu->slen, RBP);
+ push(sp, bp);
+ oframe = ar(bp);
+ nframe = ar(sp);
+ n = ar(i->a2) % 32;
+ if(n > 0){
+ for(j=1; j<n; j++){
+ aw(bp, oframe - i->olen*j);
+ push(sp, bp);
+ }
+ push(sp, acon(cpu, i->olen, nframe));
+ }
+ aw(bp, nframe);
+ aw(sp, nframe - ar(i->a1));
+}
+
+static void
+opleave(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ aw(sp, ar(areg(cpu, cpu->slen, RBP)));
+ pop(sp, areg(cpu, i->olen, RBP));
+}
+
+static void
+oppush(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ if(i->a1->len == 1) /* 0x6A push imm8 */
+ push(sp, acon(cpu, i->olen, ar(i->a1)));
+ else
+ push(sp, i->a1);
+}
+
+static void
+oppop(Cpu *cpu, Inst *i)
+{
+ pop(areg(cpu, cpu->slen, RSP), i->a1);
+}
+
+static void
+oppusha(Cpu *cpu, Inst *i)
+{
+ Iarg *sp, *osp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ osp = acon(cpu, i->olen, ar(sp));
+ push(sp, areg(cpu, i->olen, RAX));
+ push(sp, areg(cpu, i->olen, RCX));
+ push(sp, areg(cpu, i->olen, RDX));
+ push(sp, areg(cpu, i->olen, RBX));
+ push(sp, osp);
+ push(sp, areg(cpu, i->olen, RBP));
+ push(sp, areg(cpu, i->olen, RSI));
+ push(sp, areg(cpu, i->olen, RDI));
+}
+
+static void
+oppopa(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, i->olen, RDI));
+ pop(sp, areg(cpu, i->olen, RSI));
+ pop(sp, areg(cpu, i->olen, RBP));
+ pop(sp, areg(cpu, i->olen, RBX)); // RSP
+ pop(sp, areg(cpu, i->olen, RBX));
+ pop(sp, areg(cpu, i->olen, RDX));
+ pop(sp, areg(cpu, i->olen, RCX));
+ pop(sp, areg(cpu, i->olen, RAX));
+}
+
+static void
+oppushf(Cpu *cpu, Inst *i)
+{
+ push(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
+}
+
+static void
+oppopf(Cpu *cpu, Inst *i)
+{
+ ulong *f, o;
+
+ f = cpu->reg + RFL;
+ o = *f;
+ pop(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
+ *f &= ~(VM|RF);
+ *f |= (o & (VM|RF));
+}
+
+static void
+oplahf(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, cpu->reg[RFL]);
+}
+
+static void
+opsahf(Cpu *cpu, Inst *i)
+{
+ enum { MASK = SF|ZF|AF|PF|CF };
+ ulong *f;
+
+ f = cpu->reg + RFL;
+ *f &= ~MASK;
+ *f |= (ar(i->a1) & MASK);
+}
+
+static void
+opcli(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] &= ~IF;
+}
+
+static void
+opsti(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] |= IF;
+}
+
+static void
+opcld(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] &= ~DF;
+}
+
+static void
+opstd(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] |= DF;
+}
+
+static void
+opclc(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] &= ~CF;
+}
+
+static void
+opstc(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] |= CF;
+}
+
+static void
+opcmc(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] ^= CF;
+}
+
+static void
+parity(ulong *f, ulong r)
+{
+ static ulong tab[8] = {
+ 0x96696996,
+ 0x69969669,
+ 0x69969669,
+ 0x96696996,
+ 0x69969669,
+ 0x96696996,
+ 0x96696996,
+ 0x69969669,
+ };
+ r &= 0xFF;
+ if((tab[r/32] >> (r%32)) & 1)
+ *f &= ~PF;
+ else
+ *f |= PF;
+}
+
+static ulong
+test(ulong *f, long r, int s)
+{
+ *f &= ~(CF|SF|ZF|OF|PF);
+ r &= mask(s);
+ if(r == 0)
+ *f |= ZF;
+ if(r & sign(s))
+ *f |= SF;
+ parity(f, r);
+ return r;
+}
+
+static void
+opshl(Cpu *cpu, Inst *i)
+{
+ ulong *f, r, a, h;
+ int s, n;
+
+ if((n = ar(i->a2) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ r = test(f, a<<n, s);
+ h = sign(s);
+ aw(i->a1, r);
+ if((a<<(n-1)) & h)
+ *f |= CF;
+ if(n == 1 && ((a^r) & h))
+ *f |= OF;
+}
+
+static void
+opshr(Cpu *cpu, Inst *i)
+{
+ ulong *f, a;
+ int s, n;
+
+ if((n = ar(i->a2) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, a>>n, s));
+ if(a & sign(n))
+ *f |= CF;
+ if(n == 1 && (a & sign(s)))
+ *f |= OF;
+}
+
+static void
+opsar(Cpu *cpu, Inst *i)
+{
+ ulong *f;
+ long a;
+ int n;
+
+ if((n = ar(i->a2) & 31) == 0)
+ return;
+ a = ars(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, a>>n, i->a1->len*8));
+ if(a & sign(n))
+ *f |= CF;
+}
+
+static void
+opshld(Cpu *cpu, Inst *i)
+{
+ ulong *f, a;
+ int s, n;
+
+ if((n = ar(i->a3) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, (a<<n)|(ar(i->a2)>>(s-n)), s));
+ if((a<<(n-1)) & sign(s))
+ *f |= CF;
+}
+
+static void
+opshrd(Cpu *cpu, Inst *i)
+{
+ ulong *f, a;
+ int s, n;
+
+ if((n = ar(i->a3) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, (a>>n)|(ar(i->a2)<<(s-n)), s));
+ if(a & sign(n))
+ *f |= CF;
+}
+
+
+static void
+oprcl(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) % (s+1);
+ a = ar(i->a1);
+ r = (a<<n) | ((a>>(s-n))>>1);
+ f = cpu->reg + RFL;
+ if(*f & CF)
+ r |= sign(n);
+ aw(i->a1, r);
+ *f &= ~(CF|OF);
+ if((a>>(s-n)) & 1)
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+oprcr(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r, h;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) % (s+1);
+ a = ar(i->a1);
+ h = a<<(s-n);
+ r = (a>>n) | (h<<1);
+ f = cpu->reg + RFL;
+ if(*f & CF)
+ r |= 1<<(s-n);
+ aw(i->a1, r);
+ *f &= ~(CF|OF);
+ if(h & sign(s))
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+oprol(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) & (s-1);
+ a = ar(i->a1);
+ r = (a<<n) | (a>>(s-n));
+ f = cpu->reg + RFL;
+ aw(i->a1, r);
+ *f &= ~(CF|OF);
+ if(r & 1)
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+opror(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) & (s-1);
+ a = ar(i->a1);
+ r = (a>>n) | (a<<(s-n));
+ aw(i->a1, r);
+ f = cpu->reg + RFL;
+ *f &= ~(CF|OF);
+ if(r & sign(s))
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+opbittest(Cpu *cpu, Inst *i)
+{
+ ulong a, m;
+ int n, s;
+ Iarg *x;
+
+ n = ar(i->a2);
+ x = i->a1;
+ s = x->len*8;
+ if(x->tag == TMEM){
+ x = adup(x);
+ x->off += (n / s) * x->len;
+ x->off &= mask(i->alen*8);
+ }
+ a = ar(x);
+ n &= s-1;
+ m = 1<<n;
+ if(a & m)
+ cpu->reg[RFL] |= CF;
+ else
+ cpu->reg[RFL] &= ~CF;
+ switch(i->op){
+ case OBT:
+ break;
+ case OBTS:
+ aw(x, a | m);
+ break;
+ case OBTR:
+ aw(x, a & ~m);
+ break;
+ case OBTC:
+ aw(x, a ^ m);
+ break;
+ }
+}
+
+static void
+opbitscan(Cpu *cpu, Inst *i)
+{
+ ulong a;
+
+ if((a = ar(i->a2)) == 0)
+ cpu->reg[RFL] |= ZF;
+ else {
+ int j;
+
+ if(i->op == OBSF){
+ for(j = 0; (a & (1<<j)) == 0; j++)
+ ;
+ } else {
+ for(j = i->a2->len*8-1; (a & (1<<j)) == 0; j--)
+ ;
+ }
+ aw(i->a1, j);
+ cpu->reg[RFL] &= ~ZF;
+ }
+}
+
+static void
+opand(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8));
+}
+
+static void
+opor(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, test(cpu->reg + RFL, ars(i->a1) | ars(i->a2), i->a1->len*8));
+}
+
+static void
+opxor(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, test(cpu->reg + RFL, ars(i->a1) ^ ars(i->a2), i->a1->len*8));
+}
+
+static void
+opnot(Cpu *, Inst *i)
+{
+ aw(i->a1, ~ar(i->a1));
+}
+
+static void
+optest(Cpu *cpu, Inst *i)
+{
+ test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8);
+}
+
+static ulong
+add(ulong *f, long a, long b, int c, int s)
+{
+ ulong r, cc, m, n;
+
+ *f &= ~(AF|CF|SF|ZF|OF|PF);
+
+ n = sign(s);
+ m = mask(s);
+ r = a + b + c;
+ r &= m;
+ if(r == 0)
+ *f |= ZF;
+ if(r & n)
+ *f |= SF;
+ cc = (a & b) | (~r & (a | b));
+ if(cc & n)
+ *f |= CF;
+ if((cc ^ (cc >> 1)) & (n>>1))
+ *f |= OF;
+ parity(f, r);
+ return r;
+}
+
+static ulong
+sub(ulong *f, long a, long b, int c, int s)
+{
+ ulong r, bc, n;
+
+ *f &= ~(AF|CF|SF|ZF|OF|PF);
+
+ r = a - b - c;
+ n = sign(s);
+ r &= mask(s);
+ if(r == 0)
+ *f |= ZF;
+ if(r & n)
+ *f |= SF;
+ a = ~a;
+ bc = (a & b) | (r & (a | b));
+ if(bc & n)
+ *f |= CF;
+ if((bc ^ (bc >> 1)) & (n>>1))
+ *f |= OF;
+ parity(f, r);
+ return r;
+}
+
+static void
+opadd(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, add(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
+}
+
+static void
+opadc(Cpu *cpu, Inst *i)
+{
+ ulong *f = cpu->reg + RFL;
+
+ aw(i->a1, add(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
+}
+
+static void
+opsub(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
+}
+
+static void
+opsbb(Cpu *cpu, Inst *i)
+{
+ ulong *f = cpu->reg + RFL;
+
+ aw(i->a1, sub(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
+}
+
+static void
+opneg(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, sub(cpu->reg + RFL, 0, ars(i->a1), 0, i->a1->len*8));
+}
+
+static void
+opcmp(Cpu *cpu, Inst *i)
+{
+ sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8);
+}
+
+static void
+opinc(Cpu *cpu, Inst *i)
+{
+ ulong *f, o;
+
+ f = cpu->reg + RFL;
+ o = *f;
+ aw(i->a1, add(f, ars(i->a1), 1, 0, i->a1->len*8));
+ *f = (*f & ~CF) | (o & CF);
+}
+
+static void
+opdec(Cpu *cpu, Inst *i)
+{
+ ulong *f, o;
+
+ f = cpu->reg + RFL;
+ o = *f;
+ aw(i->a1, sub(f, ars(i->a1), 1, 0, i->a1->len*8));
+ *f = (*f & ~CF) | (o & CF);
+}
+
+static void
+opmul(Cpu *cpu, Inst *i)
+{
+ Iarg *la, *ha;
+ ulong l, h, m;
+ uvlong r;
+ int s;
+
+ s = i->a2->len*8;
+ m = mask(s);
+ r = ar(i->a2) * ar(i->a3);
+ l = r & m;
+ h = (r >> s) & m;
+ if(i->a1->atype != AAX)
+ abort();
+ la = areg(cpu, i->a2->len, RAX);
+ if(s == 8){
+ ha = adup(la);
+ ha->tag |= TH;
+ } else
+ ha = areg(cpu, i->a2->len, RDX);
+ aw(la, l);
+ aw(ha, h);
+ if(h)
+ cpu->reg[RFL] |= (CF|OF);
+ else
+ cpu->reg[RFL] &= ~(CF|OF);
+}
+
+static void
+opimul(Cpu *cpu, Inst *i)
+{
+ ulong l, h, m, n;
+ vlong r;
+ int s;
+
+ s = i->a2->len*8;
+ m = mask(s);
+ n = sign(s);
+ r = ars(i->a2) * ars(i->a3);
+ h = (r >> s) & m;
+ l = r & m;
+ if(i->a1->atype == AAX){
+ Iarg *la, *ha;
+
+ la = areg(cpu, i->a2->len, RAX);
+ if(s == 8){
+ ha = adup(la);
+ ha->tag |= TH;
+ }else
+ ha = areg(cpu, i->a2->len, RDX);
+ aw(la, l);
+ aw(ha, h);
+ } else
+ aw(i->a1, l);
+ if((r > (vlong)n-1) || (r < -(vlong)n))
+ cpu->reg[RFL] |= (CF|OF);
+ else
+ cpu->reg[RFL] &= ~(CF|OF);
+}
+
+static void
+opdiv(Cpu *cpu, Inst *i)
+{
+ Iarg *qa, *ra;
+ uvlong n, q;
+ ulong m, r, d;
+ int s;
+
+ s = i->a1->len*8;
+ m = mask(s);
+ d = ar(i->a1);
+ if(d == 0)
+ trap(cpu, EDIV0);
+ if(s == 8){
+ qa = areg(cpu, 1, RAX);
+ ra = adup(qa);
+ ra->tag |= TH;
+ } else {
+ qa = areg(cpu, i->olen, RAX);
+ ra = areg(cpu, i->olen, RDX);
+ }
+ n = (uvlong)ar(ra)<<s | (uvlong)ar(qa);
+ q = n/d;
+ if(q > m)
+ trap(cpu, EDIV0);
+ r = n%d;
+ aw(ra, r);
+ aw(qa, q);
+}
+
+static void
+opidiv(Cpu *cpu, Inst *i)
+{
+ Iarg *qa, *ra;
+ vlong n, q, min, max;
+ long r, d;
+ int s;
+
+ s = i->a1->len*8;
+ d = ars(i->a1);
+ if(d == 0)
+ trap(cpu, EDIV0);
+ if(s == 8){
+ qa = areg(cpu, 1, RAX);
+ ra = adup(qa);
+ ra->tag |= TH;
+ } else {
+ qa = areg(cpu, i->olen, RAX);
+ ra = areg(cpu, i->olen, RDX);
+ }
+ n = (vlong)ars(ra)<<s | (uvlong)ars(qa);
+ q = n/d;
+ r = n%d;
+
+ max = sign(s)-1;
+ min = ~max;
+
+ if(q > max || q < min)
+ trap(cpu, EDIV0);
+
+ aw(ra, r);
+ aw(qa, q);
+}
+
+static int
+cctrue(Cpu *cpu, Inst *i)
+{
+ enum { SO = 1<<16, /* pseudo-flag SF != OF */ };
+ static ulong test[] = {
+ OF, /* JO, JNO */
+ CF, /* JC, JNC */
+ ZF, /* JZ, JNZ */
+ CF|ZF, /* JBE,JA */
+ SF, /* JS, JNS */
+ PF, /* JP, JNP */
+ SO, /* JL, JGE */
+ SO|ZF, /* JLE,JG */
+ };
+ ulong f, t;
+ uchar c;
+
+ c = i->code;
+ switch(c){
+ case 0xE3: /* JCXZ */
+ return ar(areg(cpu, i->alen, RCX)) == 0;
+ case 0xEB: /* JMP */
+ case 0xE9:
+ case 0xEA:
+ case 0xFF:
+ return 1;
+ default:
+ f = cpu->reg[RFL];
+ if(((f&SF)!=0) ^ ((f&OF)!=0))
+ f |= SO;
+ t = test[(c>>1)&7];
+ return ((t&f) != 0) ^ (c&1);
+ }
+}
+
+static void
+opjump(Cpu *cpu, Inst *i)
+{
+ if(cctrue(cpu, i))
+ jump(i->a1);
+}
+
+static void
+opset(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, cctrue(cpu, i));
+}
+
+static void
+oploop(Cpu *cpu, Inst *i)
+{
+ Iarg *cx;
+ ulong c;
+
+ switch(i->op){
+ default:
+ abort();
+ case OLOOPNZ:
+ if(cpu->reg[RFL] & ZF)
+ return;
+ break;
+ case OLOOPZ:
+ if((cpu->reg[RFL] & ZF) == 0)
+ return;
+ break;
+ case OLOOP:
+ break;
+ }
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx) - 1;
+ aw(cx, c);
+ if(c)
+ jump(i->a1);
+}
+
+static void
+oplea(Cpu *, Inst *i)
+{
+ aw(i->a1, i->a2->off);
+}
+
+static void
+opmov(Cpu *, Inst *i)
+{
+ aw(i->a1, ar(i->a2));
+}
+
+static void
+opcbw(Cpu *cpu, Inst *i)
+{
+ aw(areg(cpu, i->olen, RAX), ars(areg(cpu, i->olen>>1, RAX)));
+}
+
+static void
+opcwd(Cpu *cpu, Inst *i)
+{
+ aw(areg(cpu, i->olen, RDX), ars(areg(cpu, i->olen, RAX))>>(i->olen*8-1));
+}
+
+static void
+opmovsx(Cpu *, Inst *i)
+{
+ aw(i->a1, ars(i->a2));
+}
+
+static void
+opxchg(Cpu *, Inst *i)
+{
+ ulong x;
+
+ x = ar(i->a1);
+ aw(i->a1, ar(i->a2));
+ aw(i->a2, x);
+}
+
+static void
+oplfp(Cpu *, Inst *i)
+{
+ Iarg *p;
+
+ p = afar(i->a3, i->olen, i->olen);
+ aw(i->a1, p->seg);
+ aw(i->a2, p->off);
+}
+
+static void
+opbound(Cpu *cpu, Inst *i)
+{
+ ulong p, s, e;
+
+ p = ar(i->a1);
+ s = ar(i->a2);
+ e = ar(i->a3);
+ if((p < s) || (p >= e))
+ trap(cpu, EBOUND);
+}
+
+static void
+opxlat(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, ar(amem(cpu, i->a1->len, i->sreg, ar(areg(cpu, i->alen, i->a2->reg)) + ar(i->a1))));
+}
+
+static void
+opcpuid(Cpu *cpu, Inst *)
+{
+ static struct {
+ ulong level;
+
+ ulong ax;
+ ulong bx;
+ ulong cx;
+ ulong dx;
+ } tab[] = {
+ 0,
+ 5,
+ 0x756e6547, /* Genu */
+ 0x6c65746e, /* ntel */
+ 0x49656e69, /* ineI */
+ 1,
+ 4<<8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 2,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 3,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ };
+
+ int i;
+
+ for(i=0; i<nelem(tab); i++){
+ if(tab[i].level == cpu->reg[RAX]){
+ cpu->reg[RAX] = tab[i].ax;
+ cpu->reg[RBX] = tab[i].bx;
+ cpu->reg[RCX] = tab[i].cx;
+ cpu->reg[RDX] = tab[i].dx;
+ return;
+ }
+ }
+ trap(cpu, EBADOP);
+}
+
+static void
+opmovs(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *d, *s;
+ ulong c, m;
+ int n;
+
+ m = mask(i->alen*8);
+ d = adup(i->a1);
+ s = adup(i->a2);
+ n = s->len;
+ if(cpu->reg[RFL] & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ while(c){
+ aw(d, ar(s));
+ d->off += n;
+ d->off &= m;
+ s->off += n;
+ s->off &= m;
+ c--;
+ }
+ aw(areg(cpu, i->alen, RDI), d->off);
+ aw(areg(cpu, i->alen, RSI), s->off);
+ if(cx)
+ aw(cx, 0);
+}
+
+static void
+oplods(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *s;
+ ulong c, m;
+ int n;
+
+ m = mask(i->alen*8);
+ s = adup(i->a2);
+ n = s->len;
+ if(cpu->reg[RFL] & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ if(c){
+ s->off += n*(c-1);
+ s->off &= m;
+ aw(i->a1, ar(s));
+ s->off += n;
+ s->off &= m;
+ }
+ aw(areg(cpu, i->alen, RSI), s->off);
+ if(cx)
+ aw(cx, 0);
+}
+
+static void
+opstos(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *d;
+ ulong c, a, m;
+ int n;
+
+ m = mask(i->alen*8);
+ d = adup(i->a1);
+ n = d->len;
+ if(cpu->reg[RFL] & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ a = ar(i->a2);
+ while(c){
+ aw(d, a);
+ d->off += n;
+ d->off &= m;
+ c--;
+ }
+ aw(areg(cpu, i->alen, RDI), d->off);
+ if(cx)
+ aw(cx, c);
+}
+
+static int
+repcond(ulong *f, int rep)
+{
+ if(rep == OREPNE)
+ return (*f & ZF) == 0;
+ return (*f & ZF) != 0;
+}
+
+static void
+opscas(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *d;
+ ulong *f, c, m;
+ long a;
+ int n, z;
+
+ m = mask(i->alen*8);
+ d = adup(i->a1);
+ n = d->len;
+ z = n*8;
+ f = cpu->reg + RFL;
+ if(*f & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ a = ars(i->a2);
+ while(c){
+ sub(f, a, ars(d), 0, z);
+ d->off += n;
+ d->off &= m;
+ c--;
+ if(!repcond(f, i->rep))
+ break;
+ }
+ aw(areg(cpu, i->alen, RDI), d->off);
+ if(cx)
+ aw(cx, c);
+}
+
+static void
+opcmps(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *s, *d;
+ ulong *f, c, m;
+ int n, z;
+
+ m = mask(i->alen*8);
+ d = adup(i->a1);
+ s = adup(i->a2);
+ n = s->len;
+ z = n*8;
+ f = cpu->reg + RFL;
+ if(*f & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ while(c){
+ sub(f, ars(s), ars(d), 0, z);
+ s->off += n;
+ s->off &= m;
+ d->off += n;
+ d->off &= m;
+ c--;
+ if(!repcond(f, i->rep))
+ break;
+ }
+ aw(areg(cpu, i->alen, RDI), d->off);
+ aw(areg(cpu, i->alen, RSI), s->off);
+ if(cx)
+ aw(cx, c);
+}
+
+static void
+opin(Cpu *cpu, Inst *i)
+{
+ Bus *io;
+
+ io = cpu->port;
+ aw(i->a1, io->r(io->aux, ar(i->a2) & 0xFFFF, i->a1->len));
+}
+
+static void
+opout(Cpu *cpu, Inst *i)
+{
+ Bus *io;
+
+ io = cpu->port;
+ io->w(io->aux, ar(i->a1) & 0xFFFF, ar(i->a2), i->a2->len);
+}
+
+static void
+opnop(Cpu *, Inst *)
+{
+}
+
+static void
+ophlt(Cpu *cpu, Inst *)
+{
+ trap(cpu, EHALT);
+}
+
+static void (*exctab[NUMOP])(Cpu *cpu, Inst*) = {
+ [OINT] = opint,
+ [OIRET] = opiret,
+
+ [OCALL] = opcall,
+ [OJUMP] = opjump,
+ [OSET] = opset,
+
+ [OLOOP] = oploop,
+ [OLOOPZ] = oploop,
+ [OLOOPNZ] = oploop,
+
+ [ORET] = opret,
+ [ORETF] = opretf,
+
+ [OENTER] = openter,
+ [OLEAVE] = opleave,
+
+ [OPUSH] = oppush,
+ [OPOP] = oppop,
+
+ [OPUSHF] = oppushf,
+ [OPOPF] = oppopf,
+ [OLAHF] = oplahf,
+ [OSAHF] = opsahf,
+
+ [OPUSHA] = oppusha,
+ [OPOPA] = oppopa,
+
+ [OCLI] = opcli,
+ [OSTI] = opsti,
+ [OCLC] = opclc,
+ [OSTC] = opstc,
+ [OCMC] = opcmc,
+ [OCLD] = opcld,
+ [OSTD] = opstd,
+
+ [OSHL] = opshl,
+ [OSHR] = opshr,
+ [OSAR] = opsar,
+
+ [OSHLD] = opshld,
+ [OSHRD] = opshrd,
+
+ [ORCL] = oprcl,
+ [ORCR] = oprcr,
+ [OROL] = oprol,
+ [OROR] = opror,
+
+ [OBT] = opbittest,
+ [OBTS] = opbittest,
+ [OBTR] = opbittest,
+ [OBTC] = opbittest,
+
+ [OBSF] = opbitscan,
+ [OBSR] = opbitscan,
+
+ [OAND] = opand,
+ [OOR] = opor,
+ [OXOR] = opxor,
+ [ONOT] = opnot,
+ [OTEST] = optest,
+
+ [OADD] = opadd,
+ [OADC] = opadc,
+ [OSUB] = opsub,
+ [OSBB] = opsbb,
+ [ONEG] = opneg,
+ [OCMP] = opcmp,
+
+ [OINC] = opinc,
+ [ODEC] = opdec,
+
+ [OMUL] = opmul,
+ [OIMUL] = opimul,
+ [ODIV] = opdiv,
+ [OIDIV] = opidiv,
+
+ [OLEA] = oplea,
+ [OMOV] = opmov,
+ [OCBW] = opcbw,
+ [OCWD] = opcwd,
+ [OMOVZX] = opmov,
+ [OMOVSX] = opmovsx,
+ [OXCHG] = opxchg,
+ [OLFP] = oplfp,
+ [OBOUND] = opbound,
+ [OXLAT] = opxlat,
+
+ [OCPUID] = opcpuid,
+
+ [OMOVS] = opmovs,
+ [OLODS] = oplods,
+ [OSTOS] = opstos,
+ [OSCAS] = opscas,
+ [OCMPS] = opcmps,
+
+ [OIN] = opin,
+ [OOUT] = opout,
+
+ [ONOP] = opnop,
+ [OHLT] = ophlt,
+};
+
+void
+trap(Cpu *cpu, int e)
+{
+ cpu->reg[RIP] = cpu->oldip;
+ cpu->trap = e;
+ longjmp(cpu->jmp, 1);
+}
+
+int
+intr(Cpu *cpu, int v)
+{
+ Iarg *sp, *ip, *cs, *iv;
+
+ if(v < 0 || v > 0xff || cpu->olen != 2)
+ return -1;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ cs = areg(cpu, 2, RCS);
+ ip = areg(cpu, 2, RIP);
+
+ iv = amem(cpu, 2, R0S, v * 4);
+
+ push(sp, areg(cpu, 2, RFL));
+ push(sp, cs);
+ push(sp, ip);
+
+ cpu->reg[RIP] = ar(iv);
+ iv->off += 2;
+ cpu->reg[RCS] = ar(iv);
+ return 0;
+}
+
+int
+xec(Cpu *cpu, int n)
+{
+ if(setjmp(cpu->jmp))
+ return cpu->trap;
+ while(n--){
+ void (*f)(Cpu *, Inst *);
+ Iarg *ip;
+ Inst i;
+
+ cpu->ic++;
+
+ ip = amem(cpu, 1, RCS, cpu->oldip = cpu->reg[RIP]);
+ decode(ip, &i);
+ cpu->reg[RIP] = ip->off;
+ if((f = exctab[i.op]) == nil)
+ trap(cpu, EBADOP);
+ f(cpu, &i);
+ }
+ return n;
+}
--- /n/sources/plan9/sys/src/cmd/aux/mkfile Thu Aug 16 22:50:45 2012
+++ /sys/src/cmd/aux/mkfile Fri Feb 19 00:00:00 2016
@@ -52,7 +52,8 @@
flashfs\
gps\
na\
- vga
+ vga\
+ realemu
all:V: $DIRS
--- /sys/man/8/realemu Fri Feb 19 21:15:30 2016
+++ /sys/man/8/realemu Fri Feb 19 00:00:00 2016
@@ -0,0 +1,108 @@
+.TH REALEMU 8
+.SH NAME
+realemu \- software emulation of /dev/realmode
+.SH SYNOPSIS
+.B aux/realemu
+[
+.B -Dpt
+] [
+.B -s
+.I srvname
+] [
+.B -m
+.I mountpoint
+]
+.SH DESCRIPTION
+.PP
+Originally, kernel provided
+.B /dev/realmode
+files with the
+.IR arch (3)
+device to access and call the
+.SM BIOS.
+.PP
+Interrupts had to be disabled and the processor was switched in the
+legacy 16-bit
+.SM realmode
+with memory protection disabled to execute
+.SM BIOS
+code.
+.PP
+This is problematic in case the
+.SM BIOS
+reprograms hardware currently
+used by the operating system or when it reenables interrupts or just
+crashes. This will freeze or reboot the machine with no way to
+recover or diagnose the problem.
+.PP
+To avoid this,
+.I realemu
+is used to emulate the execution of the
+.SM BIOS
+routines by interpreting the machine instructions and intercepting
+dangerous actions that would compromise the systems stability.
+.PP
+Running
+.I realemu
+with no arguments, it mounts itself before
+.B /dev
+and
+replaces the original
+.B /dev/realmode
+file in the current namespace.
+.PP
+Then programs like
+.IR vga (8)
+can use it to make their
+.SM BIOS
+calls.
+.PP
+The
+.B D
+flag will enable debug messages for 9P. The
+.B p
+and
+.B t
+flags
+control tracing of i/o port access and cpu instructions to
+stderr (fd 2).
+.PP
+When a
+.I srvname
+is given with the
+.B s
+argument, the default
+.I mountpoint
+is ignored and a
+.SM 9P
+channel is created in
+.B /srv
+that can be used to mount
+the filesystem from another namespace. If a
+.I mountpoint
+is given before
+the
+.I srvname
+argument then it is ignored, otherwise it will be used.
+.SH EXAMPLES
+The
+.I realemu
+process is only needed when accessing
+.B /dev/realmode.
+To invoke a subshell so that
+.I realemu
+exits normally after
+.B aux/vga
+completes:
+.IP
+.EX
+% @{rfork n; aux/realemu; aux/vga -m vesa -l $vgasize}
+.EE
+.SH SOURCE
+.B /sys/src/cmd/aux/realemu
+.SH "SEE ALSO"
+.IR vga (8),
+.IR arch (3)
+.SH HISTORY
+.I Realemu
+first appeared in 9front (April, 2011).
|