Basic implementation of uc_ctl

This commit is contained in:
2021-11-01 00:39:36 +01:00
parent b07baede63
commit 3dd2e0f95d
19 changed files with 459 additions and 52 deletions

View File

@@ -980,6 +980,99 @@ static void tb_htable_init(struct uc_struct *uc)
qht_init(&uc->tcg_ctx->tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);
}
// GVA to GPA (GPA -> HVA via page_find, HVA->HPA via host mmu)
// Unicorn: Why addr - 1?
// 0: INC ecx
// 1: DEC edx <--- We put exit here, then the range of TB is [0, 1)
//
// While tb_invalidate_phys_range invalides [start, end)
//
// This function is designed to used with g_tree_foreach
static inline gboolean uc_exit_invalidate_iter(gpointer key, gpointer val, gpointer data) {
uint64_t exit = *((uint64_t*)key);
uc_engine* uc = (uc_engine*)data;
tb_page_addr_t start, end;
if (exit != 0) {
end = get_page_addr_code(uc->cpu->env_ptr, exit);
start = (end-1) ;
end = end & (target_ulong)(-1);
tb_invalidate_phys_range(uc, start, end);
}
return false;
}
static void uc_invalidate_tb(struct uc_struct *uc, uint64_t start_addr, size_t len) {
tb_page_addr_t start, end;
// GVA to GPA (GPA -> HVA via page_find, HVA->HPA via host mmu)
start = get_page_addr_code(uc->cpu->env_ptr, start_addr) & (target_ulong)(-1);
// For 32bit target.
end = (start + len) & (target_ulong)(-1);
// We get a wrap?
if (start > end) {
return;
}
tb_invalidate_phys_range(uc, start, end);
}
static TranslationBlock* uc_gen_tb(struct uc_struct *uc, uint64_t addr) {
TranslationBlock *tb;
target_ulong cs_base, pc;
CPUState *cpu = uc->cpu;
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
uint32_t flags;
uint32_t hash;
uint32_t cflags = cpu->cflags_next_tb;
if (cflags == -1) {
cflags = curr_cflags();
}
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
// Unicorn: Our hack here.
pc = addr;
hash = tb_jmp_cache_hash_func(env->uc, pc);
tb = cpu->tb_jmp_cache[hash];
cflags &= ~CF_CLUSTER_MASK;
cflags |= cpu->cluster_index << CF_CLUSTER_SHIFT;
if (likely(tb &&
tb->pc == pc &&
tb->cs_base == cs_base &&
tb->flags == flags &&
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
(tb_cflags(tb) & (CF_HASH_MASK | CF_INVALID)) == cflags)) {
return tb;
}
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
cpu->tb_jmp_cache[hash] = tb;
if (tb != NULL) {
return tb;
}
if (tb == NULL) {
mmap_lock();
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
mmap_unlock();
/* We add the TB in the virtual pc hash table for the fast lookup */
cpu->tb_jmp_cache[hash] = tb;
}
return tb;
}
/* Must be called before using the QEMU cpus. 'tb_size' is the size
(in bytes) allocated to the translation buffer. Zero means default
size. */
@@ -1000,6 +1093,9 @@ void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size)
tcg_prologue_init(uc->tcg_ctx);
/* cpu_interrupt_handler is not used in uc1 */
uc->l1_map = g_malloc0(sizeof(void *) * V_L1_MAX_SIZE);
/* Invalidate / Cache TBs */
uc->uc_invalidate_tb = uc_invalidate_tb;
uc->uc_gen_tb = uc_gen_tb;
}
/* call with @p->lock held */

View File

@@ -58,7 +58,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
/* Unicorn: early check to see if the address of this block is
* the "run until" address. */
if (tb->pc == cpu->uc->addr_end) {
if (uc_addr_is_exit(uc, tb->pc)) {
// This should catch that instruction is at the end
// and generate appropriate halting code.
gen_tb_start(tcg_ctx, db->tb);