#ifndef VX32_IMPL_H #define VX32_IMPL_H #include #include #include // Parameters tweakable for performance #define VXPROCSMAX 256 // Max # of vxprocs per host proc #define VXCODEALIGN 16 // Alignment for translated code #define VXCODEBUFSIZE (1024*1024) // Code buffer size (XX make variabale) #define VXENTRYHASHLEN 32768 // # entrypoints in entry hash table // VX memory access permissions have a granularity of 4KB pages. #define VXPAGESHIFT 12 #define VXPAGESIZE (1 << VXPAGESHIFT) // 4KB #define VXPAGETRUNC(v) ((uint32_t)(v) & ~(VXPAGESIZE-1)) #define VXPAGEROUND(v) VXPAGETRUNC((uint32_t)(v) + (VXPAGESIZE-1)) // The x86 EFLAGS TF bit #define EFLAGS_TF 0x100 // VX signal handler return values #define VXSIG_ERROR 0 #define VXSIG_SINGLESTEP 1 #define VXSIG_TRAP 2 #define VXSIG_SAVE_EAX 0x04 #define VXSIG_SAVE_ECX 0x08 #define VXSIG_SAVE_EDX 0x10 #define VXSIG_SAVE_EBX 0x20 #define VXSIG_SAVE_ESP 0x40 #define VXSIG_SAVE_EBP 0x80 #define VXSIG_SAVE_ESI 0x100 #define VXSIG_SAVE_EDI 0x200 #define VXSIG_SAVE_EFLAGS 0x400 #define VXSIG_SAVE_ALL 0x7FC #define VXSIG_ADD_COUNT_TO_ESP 0x800 #define VXSIG_SAVE_EBX_AS_EIP 0x1000 #define VXSIG_INC_ECX 0x2000 #define VXSIG_COUNT_SHIFT 16 // This is an mmap() flag that we need on 64-bit hosts // to map our translation state in the low 4GB of address space. // On 32-bit hosts of course it doesn't exist and isn't needed. #ifndef MAP_32BIT #define MAP_32BIT 0 #endif #define VX_MMAP_FLAGS MAP_32BIT // XX for FreeBSD #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON #endif // LDT selectors that we set up on x86-64 hosts // to allow us to run 32-bit code in compatibility mode. #define FLATCODE (0+4+3) // 4 = LDT, 3 = RPL #define FLATDATA (8+4+3) typedef struct vxinsn vxinsn; // Translated instruction struct vxinsn { uint8_t itype; uint8_t srcofs; // Offset in original vx32 code uint8_t dstofs; // Offset in translated x86 code uint8_t dstlen; // Dest x86 code size for this insn }; // Instruction types for vxinsn.itype #define VXI_NOTRANS 0x00 // Simple, no translation required #define VXI_JUMP 0x02 // Direct jump/branch #define VXI_CALL 0x03 // Direct call #define VXI_JUMP8 0x04 // 8-bit jump/branch #define VXI_JUMPIND 0x05 // Indirect jump #define VXI_CALLIND 0x06 // Indirect call #define VXI_RETURN 0x07 // Return #define VXI_RETURN_IMM 0x08 // Return with immediate pop count #define VXI_TRAP 0x09 // Trapping instruction #define VXI_ENDFRAG 0x0A // Terminate this fragment #define VXI_LOOP 0x0B // Loop #define VXI_LOOPZ 0x0C // Loopz/loope #define VXI_LOOPNZ 0x0D // Loopnz/loopne // Limits for vxinsn.srcofs and vxinsn.dstofs #define VXSRCOFS_MAX 255 #define VXDSTOFS_MAX 255 // Each translated fragment consists of: // - A struct vxfrag header // - A translation summary table containing ninsn vxinsn structs. // - The translated code fragment itself, as laid out in the table. // - Any trampoline code required by jumps within the fragment. typedef struct vxfrag { uint32_t eip; // Original EIP in emulated vx32 code uint8_t ninsn; // Number of translated vx32 insns struct vxinsn insn[0]; // Beginning of vxinsn table } vxfrag; // Macro to find the beginning of translated code in a fragment #define FRAGCODE(f) ((uint8_t*)&(f)->insn[(f)->ninsn]) #define VXEMU_MAGIC 0xbaf07d5c // The vx32-EIP-to-translated-entrypoint hash table // consists of vxentry structures. // Each vxentry maps a EIP value in the original vx32 code // to a corresponding EIP in translated code. // Empty entries are indicated by *dstip* being 0. // (Zero is theoretically, though unlikely in practice, a valid vx32 EIP.) typedef struct vxentry { uint32_t srceip; uint32_t dsteip; } vxentry; #ifdef __APPLE__ struct i386_thread_state; int vx32_getcontext(struct i386_thread_state*); #endif #ifdef __linux__ int vx32_getcontext(mcontext_t*); #endif // Emulation state for vx32-to-x86 translation. // This is the header for a variable-length structure; // the variable-length part is the vx32 EIP lookup hash table (etab), // followed by the instruction translation buffer. // While running a particular vxproc, // we always keep the %ds,%es,%ss segment registers loaded with a data segment // that allows access only to the emulated address space region, and // we always keep the %fs register loaded with a special data segment // whose base and limit correspond to the address and size of this state area. // This way the emulation code can always access the emulation state // at fixed displacements without having to use any general-purpose registers. struct vxemu { uint32_t magic; // Back pointer to vxproc vxproc *proc; vxmmap *mem; // Data segment and vxemu selectors for this vx32 process uint32_t datasel; uint32_t emusel; // Cache of what the last modify_ldt set up. uintptr_t ldt_base; uint32_t ldt_size; // Pointer to this vxemu struct itself, // for use when accessing vxemu struct via %fs segment register. uint32_t emuptr; // vx32 virtual CPU state vxcpu cpu; uint32_t cpu_trap; // pending trap uint32_t saved_trap; // trap to trigger after single-step int nsinglestep; #if defined(__FreeBSD__) || defined(__linux__) mcontext_t *trapenv; #elif defined(__APPLE__) struct i386_thread_state *trapenv; #else sigjmp_buf *trapenv; #endif // General emulation state uint32_t emuflags; // Emulation flags (see below) uint32_t jmpinfo; // for jump insn backpatching // Max # of instructions to execute before returning uint32_t insncount; // Instruction scanning/translation state struct vxfrag *txfrag; // frag currently under construction uint8_t *ininst; // current instruction being scanned // Last guest fragment translated (debugging) uint8_t *guestfrag; uint8_t *guestfragend; // Save area for host segment registers while running VX code uint16_t host_ss; // host ss uint16_t host_ds; // host ds uint16_t host_es; // host es uint16_t host_vs; // host fs/gs (which is os-dependent) #ifdef __i386 // x86-32 // Save area for the host's esp while running emulated code uint32_t host_esp; #else // x86-64 // Save area for the host's rsp while running emulated code uint64_t host_rsp; // Far pointers for switching to and from 32-bit compatibility mode struct { uint32_t ofs; uint16_t sel; } runptr, retptr; #endif // x86-64 // Translated code buffer. // We write code frags into it from the bottom up, increasing codefree. // Each frag consists of a vxfrag, a translation summary, and the code. // We also keep a table of offsets of all the vxfrag headers, // starting at the top of the codebuf and working down, via codetab. // The frag header offsets are thus stored in opposite order // as the target code fragments themselves, // and the codefree and codefrags pointers work towared each other // until they collide, at which point the translation buffer is reset. void *codebuf; void *codefree; void *codetab; void *codetop; // Hash table for looking up entrypoints in original code uint32_t etablen; // Number of entries (power of two) uint32_t etabmask; // etablen-1 uint32_t etabcnt; // Number of entries currently in use struct vxentry etab[0]; // Must be last! }; // Hash function for entrypoint hash table. // Keep it consistent with assembly code in x86asm.S! #define etabhash(va) (((((va) >> 10) + (va)) >> 10) - (va)) // Emulation flags (emuflags) #define EMU_FP 0x01 // Enable SSE2 scalar floating-point #define EMU_VFP 0x02 // Enable vector floating-point #define EMU_VINT 0x04 // Enable vector integer arithmetic int vxemu_init(vxproc*); void vxemu_free(vxemu*); int vxemu_map(vxemu*, vxmmap*); void vxemu_flush(vxemu*); int vxrun(vxemu*, uint32_t dsteip); void vxrun_nullfrag(void); void vxrun_setup(vxemu*); void vxrun_cleanup(vxemu*); void vxprint(char*, ...); int vx32_sighandler(int, siginfo_t*, void*); int vxemu_sighandler(vxemu*, uint32_t); #define USED(x) if(x){} /* shut up gcc not-used warning */ #endif // VX32_IMPL_H