Skip to content

Commit

Permalink
CPU refactor, sine cera
Browse files Browse the repository at this point in the history
  • Loading branch information
saagarjha committed Jun 7, 2020
1 parent 5557974 commit 49d72be
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 83 deletions.
4 changes: 2 additions & 2 deletions emu/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
struct cpu_state;
struct tlb;
void cpu_run(struct cpu_state *cpu);
int cpu_step32(struct cpu_state *cpu, struct tlb *tlb);
int cpu_step16(struct cpu_state *cpu, struct tlb *tlb);
int cpu_step_to_interrupt(struct cpu_state *cpu, struct tlb *tlb);

union mm_reg {
qword_t qw;
Expand All @@ -30,6 +29,7 @@ static_assert(sizeof(union mm_reg) == 8, "mm_reg size");
struct cpu_state {
struct mem *mem;
struct jit *jit;
long cycle;

// general registers
// assumes little endian (as does literally everything)
Expand Down
128 changes: 49 additions & 79 deletions jit/jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,34 +160,26 @@ static void jit_free_jetsam(struct jit *jit) {

int jit_enter(struct jit_block *block, struct jit_frame *frame, struct tlb *tlb);

#if 1

static inline size_t jit_cache_hash(addr_t ip) {
return (ip ^ (ip >> 12)) % JIT_CACHE_SIZE;
}

void cpu_run(struct cpu_state *cpu) {
struct tlb tlb;
tlb_init(&tlb, cpu->mem);
int cpu_step_to_interrupt(struct cpu_state *cpu, struct tlb *tlb) {
struct jit *jit = cpu->mem->jit;
struct jit_block *cache[JIT_CACHE_SIZE] = {};
struct jit_frame frame = {.cpu = *cpu};
for (size_t i = 0; i < JIT_RETURN_CACHE_SIZE; i++)
frame.ret_cache[i] = 0;
struct jit_frame frame = {.cpu = *cpu, .ret_cache = {}};

int i = 0;
read_wrlock(&cpu->mem->lock);
unsigned changes = cpu->mem->changes;
int interrupt = INT_NONE;

while (true) {
while (interrupt == INT_NONE) {
addr_t ip = frame.cpu.eip;
size_t cache_index = jit_cache_hash(ip);
struct jit_block *block = cache[cache_index];
if (block == NULL || block->addr != ip) {
lock(&jit->lock);
block = jit_lookup(jit, ip);
if (block == NULL) {
block = jit_block_compile(ip, &tlb);
block = jit_block_compile(ip, tlb);
jit_insert(jit, block);
} else {
TRACE("%d %08x --- missed cache\n", current->pid, ip);
Expand Down Expand Up @@ -219,78 +211,32 @@ void cpu_run(struct cpu_state *cpu) {
// block may be jetsam, but that's ok, because it can't be freed until
// every thread on this jit is not executing anything

TRACE("%d %08x --- cycle %d\n", current->pid, ip, i);
int interrupt = jit_enter(block, &frame, &tlb);
if (interrupt == INT_NONE && ++i % (1 << 10) == 0)
interrupt = INT_TIMER;
if (interrupt != INT_NONE) {
*cpu = frame.cpu;
cpu->trapno = interrupt;
read_wrunlock(&cpu->mem->lock);
handle_interrupt(interrupt);

jit = cpu->mem->jit;
lock(&jit->lock);
if (!list_empty(&jit->jetsam)) {
// write-lock the mem to wait until other jit threads get to
// this point, so they will all clear out their block pointers
// TODO: use RCU for better performance
unlock(&jit->lock);
write_wrlock(&cpu->mem->lock);
lock(&jit->lock);
jit_free_jetsam(jit);
write_wrunlock(&cpu->mem->lock);
}
unlock(&jit->lock);
read_wrlock(&cpu->mem->lock);
TRACE("%d %08x --- cycle %ld\n", current->pid, ip, cpu->cycle);

tlb.mem = cpu->mem;
if (cpu->mem->changes != changes)
tlb_flush(&tlb);
changes = cpu->mem->changes;
frame.cpu = *cpu;
frame.last_block = NULL;
last_block = NULL;
// jit blocks might have been invalidated, flush caches
memset(frame.ret_cache, 0, sizeof(frame.ret_cache));
memset(cache, 0, sizeof(cache));
}
interrupt = jit_enter(block, &frame, tlb);
*cpu = frame.cpu;
if (interrupt == INT_NONE && ++cpu->cycle % (1 << 10) == 0)
interrupt = INT_TIMER;
}
}

#else

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);
if (interrupt == INT_NONE && i++ >= 100000) {
i = 0;
interrupt = INT_TIMER;
}
if (interrupt != INT_NONE) {
cpu->trapno = interrupt;
read_wrunlock(&cpu->mem->lock);
handle_interrupt(interrupt);
read_wrlock(&cpu->mem->lock);
if (tlb.mem != cpu->mem)
tlb.mem = cpu->mem;
if (cpu->mem->changes != changes) {
tlb_flush(&tlb);
changes = cpu->mem->changes;
}
}
jit = cpu->mem->jit;
lock(&jit->lock);
if (!list_empty(&jit->jetsam)) {
// write-lock the mem to wait until other jit threads get to
// this point, so they will all clear out their block pointers
// TODO: use RCU for better performance
unlock(&jit->lock);
write_wrlock(&cpu->mem->lock);
lock(&jit->lock);
jit_free_jetsam(jit);
write_wrunlock(&cpu->mem->lock);
}
}
unlock(&jit->lock);

#endif
return interrupt;
}

// really only here for ptraceomatic
int cpu_step32(struct cpu_state *cpu, struct tlb *tlb) {
static int cpu_step(struct cpu_state *cpu, struct tlb *tlb) {
struct gen_state state;
gen_start(cpu->eip, &state);
gen_step32(&state, tlb);
Expand All @@ -304,5 +250,29 @@ int cpu_step32(struct cpu_state *cpu, struct tlb *tlb) {
read_wrunlock(&cpu->mem->lock);
*cpu = frame.cpu;
jit_block_free(NULL, block);
if (interrupt == INT_NONE && cpu->tf)
interrupt = INT_DEBUG;
return interrupt;
}

void cpu_run(struct cpu_state *cpu) {
struct tlb tlb;
tlb_init(&tlb, cpu->mem);

read_wrlock(&cpu->mem->lock);
unsigned changes = cpu->mem->changes;

while (true) {
int interrupt = (cpu->tf ? cpu_step : cpu_step_to_interrupt)(cpu, &tlb);
if (interrupt != INT_NONE) {
read_wrunlock(&cpu->mem->lock);
handle_interrupt(cpu->trapno = interrupt);
read_wrlock(&cpu->mem->lock);

tlb.mem = cpu->mem;
if (cpu->mem->changes != changes)
tlb_flush(&tlb);
changes = cpu->mem->changes;
}
}
}
5 changes: 3 additions & 2 deletions tools/ptraceomatic.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ static void step_tracing(struct cpu_state *cpu, struct tlb *tlb, int pid, int se
// step fake cpu
cpu->tf = 1;
unsigned changes = cpu->mem->changes;
int interrupt = cpu_step32(cpu, tlb);
int interrupt = cpu_step_to_interrupt(cpu, tlb);
if (interrupt != INT_NONE) {
cpu->trapno = interrupt;
// hack to clean up before the exit syscall
Expand Down Expand Up @@ -490,6 +490,7 @@ int main(int argc, char *const argv[]) {
prepare_tracee(pid);

struct cpu_state *cpu = &current->cpu;
cpu->tf = true;
struct tlb tlb;
tlb_init(&tlb, cpu->mem);
int undefined_flags = 2;
Expand All @@ -500,7 +501,7 @@ int main(int argc, char *const argv[]) {
printk("failure: resetting cpu\n");
*cpu = old_cpu;
__asm__("int3");
cpu_step32(cpu, &tlb);
cpu_step_to_interrupt(cpu, &tlb);
}
undefined_flags = undefined_flags_mask(cpu, &tlb);
old_cpu = *cpu;
Expand Down

0 comments on commit 49d72be

Please sign in to comment.