typedef ulong Reg; /* * Various routines depend on this order. In particular, * the order of RAX..RDI is used by pushseg, popseg, * increg, decreg, pushreg, popreg, pusha, popa, */ enum { RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, RES, RCS, RSS, RDS, RFS, RGS, NREG, RAL = 0, RCL, RDL, RBL, RAH, RCH, RDH, RBH, }; /* 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 */ SFOF = 1<<31, /* pseudo-flag, not stored, means SF == OF */ }; #define FLAGMASK (CF|PF|AF|ZF|SF|TF|IF|DF|OF|IOPL|NT|RF|VM|AC|VIF|VIP|ID) #define FLAGSET (0x00000002) typedef struct Cpu Cpu; typedef struct Wordop Wordop; typedef struct Inst Inst; struct Cpu { int (*inb)(int); int (*inw)(int); long (*inl)(int); void (*outb)(int, int); void (*outw)(int, int); void (*outl)(int, long); void (*trap)(Cpu*, Inst*, int); ulong present64k; uchar *mem; /* memory; best to segattach in middle of nowhere */ ulong npc; /* next pc, cs */ ushort ncs; Reg reg[NREG]; ulong flags; /* processor flags */ ulong pc; uchar trace; uchar nflag; int instcount; ulong addr; /* internal */ jmp_buf jmp; jmp_buf exitjmp; int opsize; int addrsize; Inst *inst; /* currently-executing instruction */ }; enum { /* argument types */ ANONE, /* no argument */ A0, /* constant 0 */ A1, /* constant 1 */ A3, /* constant 3 */ A4, /* constant 4 */ AAp, /* 32-bit or 48-bit direct address */ AEb, /* r/m8 from modrm byte */ AEp, /* call indirect through memory */ 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, /* registers; should be in same order as RAL, etc. */ ACL, ADL, ABL, AAH, ACH, ADH, ABH, AAX,/* registers; should be in same order as RAX, etc. */ ACX, ADX, ABX, ASP, ABP, ASI, ADI, AES, ACS, ASS, ADS, AFS, AGS, NAMODE, }; enum { /* operators */ OBAD, O0F, OAAA, OAAD, OAAM, OAAS, OADC, OADD, OAND, OARPL, OASIZE, OBOUND, OBT, OBTS, OCALL, OCBW, OCLC, OCLD, OCLI, OCMC, OCMOV, OCMP, OCMPS, OCWD, ODAA, ODAS, ODEC, ODIV, OENTER, OGP1, OGP2, OGP3b, OGP3v, OGP4, OGP5, OHLT, OIDIV, OIMUL, OIN, OINC, OINS, OINT, OIRET, OJUMP, OLAHF, OLEA, OLEAVE, OLFP, OLOCK, OLODS, OLOOP, OLOOPNZ, OLOOPZ, OMOV, OMOVS, 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, }; typedef struct Iarg Iarg; struct Iarg { long val; /* value of argument */ void (*w)(Cpu*, int, ulong, long); /* write function */ void (*p)(Cpu*, Inst*, Iarg*); /* post-instruction callback */ ushort seg; uchar sreg; ulong off; int atype; }; struct Inst { uchar op; /* instruction pseudo-opcode (OFOO) */ uchar i; /* first byte of instruction */ uchar rop; uchar mod; uchar rm; uchar havemodrm; uchar repeat; /* repeat prefix */ uchar opsize; /* operand size */ uchar addrsize; /* address size */ uchar sreg; /* segment register to use */ int seg; /* segment to use */ ulong spc; /* program counter for start of inst */ ulong epc; /* program counter for end of inst */ ulong off; /* memory address from modrm */ long disp; /* displacement from modrm */ Iarg arg1; Iarg arg2; Iarg arg3; }; struct Wordop { long (*rreg)(Cpu*, int, ulong); /* ulong ignored; to match fetch */ void (*wreg)(Cpu*, int, ulong, long); ulong (*fetch)(Cpu*, int, ulong); long (*fetchs)(Cpu*, int, ulong); void (*store)(Cpu*, int, ulong, long); int len; /* bytes: 1, 2, 4 */ }; enum { TDIV0 = 0, /* software interrupts */ TBADOP = 256, /* pseudo-interrupts */ THALT, TGP0, TSEGFAULT, }; extern Wordop wop8, wop16, wop32; extern void putflags(Cpu*, int, ulong, long); /* int,ulong ignored */ extern void bumpesdi(Cpu*, Inst*, Iarg*); extern void bumpdssi(Cpu*, Inst*, Iarg*); extern void trap(Cpu*, int); extern int instfmt(Fmt*); extern int pcfmt(Fmt*); extern void nextinst(Cpu*, Inst*); extern void run(Cpu*); extern void sreg(Cpu*, char**, int); extern void dumpreg(Cpu*); extern void push(Cpu*, int, long); #pragma varargck type "I" Inst* #pragma varargck type "P" Cpu*