Skip to content

Commit

Permalink
Compile an entire block at a time
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed May 27, 2018
1 parent 723ecb1 commit bff119e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 42 deletions.
6 changes: 3 additions & 3 deletions emu/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,10 @@ __no_instrument DECODER_RET glue(DECODER_NAME, OP_SIZE)(DECODER_ARGS) {
case 0x66:
#if OP_SIZE == 32
TRACELN("entering 16 bit mode");
RETURN(glue(DECODER_NAME, 16)(DECODER_PASS_ARGS));
return glue(DECODER_NAME, 16)(DECODER_PASS_ARGS);
#else
TRACELN("entering 32 bit mode");
RETURN(glue(DECODER_NAME, 32)(DECODER_PASS_ARGS));
return glue(DECODER_NAME, 32)(DECODER_PASS_ARGS);
#endif

case 0x67: TRACEI("address size prefix (ignored)"); goto restart;
Expand Down Expand Up @@ -730,5 +730,5 @@ __no_instrument DECODER_RET glue(DECODER_NAME, OP_SIZE)(DECODER_ARGS) {
UNDEFINED;
}
TRACELN("");
RETURN(-1); // everything is ok.
FINISH;
}
66 changes: 35 additions & 31 deletions emu/gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@
#include "emu/cpuid.h"
#include "emu/interrupt.h"

#define DECLARE_LOCALS \
dword_t saved_ip = state->ip; \
dword_t addr_offset = 0; \
bool end_block = false; \
bool seg_gs = false

#define FINISH \
return !end_block

#define TRACEIP() TRACE("%d %08x\t", current->pid, state->ip);

#define _READIMM(name, size) \
tlb_read(tlb, state->ip, &name, size/8); \
state->ip += size/8

#define READMODRM if (!modrm_decode32(&state->ip, tlb, &modrm)) { gg_here(interrupt, INT_GPF); return false; }
#define READADDR _READIMM(addr_offset, 32)
#define SEG_GS() seg_gs = true

// This should stay in sync with the definition of .gadget_array in gadgets.h
enum arg {
arg_reg_a, arg_reg_c, arg_reg_d, arg_reg_b, arg_reg_sp, arg_reg_bp, arg_reg_si, arg_reg_di,
Expand Down Expand Up @@ -42,7 +61,7 @@ typedef void (*gadget_t)();
#define gagg(g, i, a, b) do { ga(g, i); GEN(a); GEN(b); } while (0)
#define gz(g, z) ga(g, sz(z))
#define gg_here(g, a) ggg(g, a, state->ip)
#define UNDEFINED do { gg_here(interrupt, INT_UNDEFINED); return; } while (0)
#define UNDEFINED do { gg_here(interrupt, INT_UNDEFINED); return false; } while (0)

static inline int sz(int size) {
switch (size) {
Expand All @@ -56,7 +75,7 @@ static inline int sz(int size) {
// this really wants to use all the locals of the decoder, which we can do
// really nicely in gcc using nested functions, but that won't work in clang,
// so we explicitly pass 500 arguments. sorry for the mess
static inline void gen_op(struct gen_state *state, gadget_t *gadgets, enum arg arg, struct modrm *modrm, uint64_t *imm, int size, dword_t saved_ip, bool seg_gs, dword_t addr_offset) {
static inline bool gen_op(struct gen_state *state, gadget_t *gadgets, enum arg arg, struct modrm *modrm, uint64_t *imm, int size, dword_t saved_ip, bool seg_gs, dword_t addr_offset) {
size = sz(size);
gadgets = gadgets + size * arg_count;

Expand Down Expand Up @@ -103,10 +122,11 @@ static inline void gen_op(struct gen_state *state, gadget_t *gadgets, enum arg a
GEN(*imm);
else if (arg == arg_mem)
GEN(saved_ip);
return true;
}
#define op(type, thing, z) do { \
extern gadget_t type##_gadgets[]; \
gen_op(state, type##_gadgets, arg_##thing, &modrm, &imm, z, saved_ip, seg_gs, addr_offset); \
if (!gen_op(state, type##_gadgets, arg_##thing, &modrm, &imm, z, saved_ip, seg_gs, addr_offset)) return false; \
} while (0)

#define load(thing, z) op(load, thing, z)
Expand All @@ -115,23 +135,6 @@ static inline void gen_op(struct gen_state *state, gadget_t *gadgets, enum arg a
#define los(o, src, dst, z) load(dst, z); op(o, src, z); store(dst, z)
#define lo(o, src, dst, z) load(dst, z); op(o, src, z)

#define DECLARE_LOCALS \
dword_t saved_ip = state->ip; \
dword_t addr_offset = 0; \
bool seg_gs = false

#define RETURN(thing) (void) (thing); return

#define TRACEIP() TRACE("%d %08x\t", current->pid, state->ip);

#define _READIMM(name, size) \
tlb_read(tlb, state->ip, &name, size/8); \
state->ip += size/8

#define READMODRM if (!modrm_decode32(&state->ip, tlb, &modrm)) { gg_here(interrupt, INT_GPF); return; }
#define READADDR _READIMM(addr_offset, 32)
#define SEG_GS() seg_gs = true

#define MOV(src, dst,z) load(src, z); store(dst, z)
#define MOVZX(src, dst,zs,zd) load(src, zs); gz(zero_extend, zs); store(dst, zd)
#define MOVSX(src, dst,zs,zd) load(src, zs); gz(sign_extend, zs); store(dst, zd)
Expand All @@ -155,13 +158,17 @@ static inline void gen_op(struct gen_state *state, gadget_t *gadgets, enum arg a
#define INC(val,z) load(val, z); gz(inc, z); store(val, z)
#define DEC(val,z) load(val, z); gz(dec, z); store(val, z)

#define JMP(loc) load(loc, OP_SIZE); g(jmp_indir)
#define JMP_REL(off) gg(jmp, state->ip + off)
#define JCXZ_REL(off) ggg(jcxz, state->ip + off, state->ip)
#define J_REL(cc, off) gagg(jmp, cond_##cc, state->ip + off, state->ip)
#define JN_REL(cc, off) gagg(jmp, cond_##cc, state->ip, state->ip + off)
#define CALL(loc) load(loc, OP_SIZE); ggg(call_indir, saved_ip, state->ip)
#define CALL_REL(off) gggg(call, saved_ip, state->ip + off, state->ip)
#define JMP(loc) load(loc, OP_SIZE); g(jmp_indir); end_block = true
#define JMP_REL(off) gg(jmp, state->ip + off); end_block = true
#define JCXZ_REL(off) ggg(jcxz, state->ip + off, state->ip); end_block = true
#define J_REL(cc, off) gagg(jmp, cond_##cc, state->ip + off, state->ip); end_block = true
#define JN_REL(cc, off) gagg(jmp, cond_##cc, state->ip, state->ip + off); end_block = true
#define CALL(loc) load(loc, OP_SIZE); ggg(call_indir, saved_ip, state->ip); end_block = true
#define CALL_REL(off) gggg(call, saved_ip, state->ip + off, state->ip); end_block = true
#define RET_NEAR_IMM(imm) ggg(ret, saved_ip, 4 + imm); end_block = true
#define RET_NEAR() RET_NEAR_IMM(0); end_block = true
#define INT(code) gg_here(interrupt, (uint8_t) code); end_block = true

#define SET(cc, dst) ga(set, cond_##cc); store(dst, 8)
#define SETN(cc, dst) ga(setn, cond_##cc); store(dst, 8)
// wins the prize for the most annoying instruction to generate
Expand All @@ -177,9 +184,6 @@ static inline void gen_op(struct gen_state *state, gadget_t *gadgets, enum arg a
load(src, z); store(dst, z); \
state->block->code[start - 1] = (state->size - start) * sizeof(long); \
} while (0)
#define RET_NEAR_IMM(imm) ggg(ret, saved_ip, 4 + imm)
#define RET_NEAR() RET_NEAR_IMM(0)
#define INT(code) gg_here(interrupt, (uint8_t) code)

#define PUSHF() UNDEFINED
#define POPF() UNDEFINED
Expand Down Expand Up @@ -271,7 +275,7 @@ static inline void gen_op(struct gen_state *state, gadget_t *gadgets, enum arg a
#define FIDIV(val,z) UNDEFINED
#define FDIVM(val,z) UNDEFINED

#define DECODER_RET void
#define DECODER_RET int
#define DECODER_NAME gen_step
#define DECODER_ARGS struct gen_state *state, struct tlb *tlb
#define DECODER_PASS_ARGS state, tlb
Expand Down
4 changes: 2 additions & 2 deletions emu/gen.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct gen_state {
};

void gen(struct gen_state *state, unsigned long thing);
void gen_step32(struct gen_state *state, struct tlb *tlb);
void gen_step16(struct gen_state *state, struct tlb *tlb);
int gen_step32(struct gen_state *state, struct tlb *tlb);
int gen_step16(struct gen_state *state, struct tlb *tlb);

#endif
3 changes: 2 additions & 1 deletion emu/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
\
extFloat80_t ftmp;

#define RETURN(thing) return (thing)
#define FINISH \
return -1 // everything is ok.

#define UNDEFINED { cpu->eip = saved_ip; return INT_UNDEFINED; }

Expand Down
19 changes: 14 additions & 5 deletions emu/jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ void gen(struct gen_state *state, unsigned long thing) {
state->block->code[state->size++] = thing;
}

int cpu_step32(struct cpu_state *cpu, struct tlb *tlb) {
// assembler function
extern int jit_enter(struct jit_block *block, struct cpu_state *cpu, struct tlb *tlb);
// assembler function
int jit_enter(struct jit_block *block, struct cpu_state *cpu, struct tlb *tlb);

int cpu_step32(struct cpu_state *cpu, struct tlb *tlb) {
struct gen_state state;
gen_start(cpu->eip, &state);
gen_step32(&state, tlb);
Expand All @@ -60,15 +60,24 @@ int cpu_step32(struct cpu_state *cpu, struct tlb *tlb) {
return interrupt;
}

// TODO rewrite
void cpu_run(struct cpu_state *cpu) {
int i = 0;
struct tlb tlb = {.mem = cpu->mem};
tlb_flush(&tlb);
read_wrlock(&cpu->mem->lock);
int changes = cpu->mem->changes;

while (true) {
int interrupt = cpu_step32(cpu, &tlb);
struct gen_state state;
gen_start(cpu->eip, &state);
bool in_block = true;
while (in_block)
in_block = gen_step32(&state, &tlb);
gen_end(&state);
struct jit_block *block = state.block;
int interrupt = jit_enter(block, cpu, &tlb);
jit_block_free(block);

if (interrupt == INT_NONE && i++ >= 100000) {
i = 0;
interrupt = INT_TIMER;
Expand Down

0 comments on commit bff119e

Please sign in to comment.