diff --git a/qemu/accel/tcg/cpu-exec.c b/qemu/accel/tcg/cpu-exec.c index 22fe9540..7d6903d9 100644 --- a/qemu/accel/tcg/cpu-exec.c +++ b/qemu/accel/tcg/cpu-exec.c @@ -111,57 +111,58 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles, tb_free(env->uc, tb); } +struct tb_desc { + target_ulong pc; + target_ulong cs_base; + CPUArchState *env; + tb_page_addr_t phys_page1; + uint32_t flags; +}; + +static bool tb_cmp(const void *p, const void *d) +{ + const TranslationBlock *tb = p; + const struct tb_desc *desc = d; + + if (tb->pc == desc->pc && + tb->page_addr[0] == desc->phys_page1 && + tb->cs_base == desc->cs_base && + tb->flags == desc->flags) { + /* check next page if needed */ + if (tb->page_addr[1] == -1) { + return true; + } else { + tb_page_addr_t phys_page2; + target_ulong virt_page2; + + virt_page2 = (desc->pc & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + phys_page2 = get_page_addr_code(desc->env, virt_page2); + if (tb->page_addr[1] == phys_page2) { + return true; + } + } + } + return false; +} + TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc, target_ulong cs_base, uint32_t flags) { TCGContext *tcg_ctx = cpu->uc->tcg_ctx; - CPUArchState *env = (CPUArchState *)cpu->env_ptr; - TranslationBlock *tb, **tb_hash_head, **ptb1; + tb_page_addr_t phys_pc; + struct tb_desc desc; uint32_t h; - tb_page_addr_t phys_pc, phys_page1; /* find translated block using physical mappings */ - phys_pc = get_page_addr_code(env, pc); - phys_page1 = phys_pc & TARGET_PAGE_MASK; + desc.env = (CPUArchState *)cpu->env_ptr; + desc.cs_base = cs_base; + desc.flags = flags; + desc.pc = pc; + phys_pc = get_page_addr_code(desc.env, pc); + desc.phys_page1 = phys_pc & TARGET_PAGE_MASK; h = tb_hash_func(phys_pc, pc, flags); - /* Start at head of the hash entry */ - ptb1 = tb_hash_head = &tcg_ctx->tb_ctx.tb_phys_hash[h]; - tb = *ptb1; - - while (tb) { - if (tb->pc == pc && - tb->page_addr[0] == phys_page1 && - tb->cs_base == cs_base && - tb->flags == flags && - !(atomic_read(&tb->cflags) & CF_INVALID)) { - - if (tb->page_addr[1] == -1) { - /* done, we have a match */ - break; - } else { - /* check next page if needed */ - target_ulong virt_page2 = (pc & TARGET_PAGE_MASK) + - TARGET_PAGE_SIZE; - tb_page_addr_t phys_page2 = get_page_addr_code(env, virt_page2); - - if (tb->page_addr[1] == phys_page2) { - break; - } - } - } - - ptb1 = &tb->phys_hash_next; - tb = *ptb1; - } - - if (tb) { - /* Move the TB to the head of the list */ - *ptb1 = tb->phys_hash_next; - tb->phys_hash_next = *tb_hash_head; - *tb_hash_head = tb; - } - return tb; + return qht_lookup(&tcg_ctx->tb_ctx.htable, tb_cmp, &desc, h); } void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr) diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 198a21d2..d412fdfa 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -833,6 +833,14 @@ static inline void code_gen_alloc(struct uc_struct *uc, size_t tb_size) tcg_ctx->tb_ctx.tbs = g_new(TranslationBlock *, tcg_ctx->tb_ctx.tbs_size); } +static void tb_htable_init(struct uc_struct *uc) +{ + unsigned int mode = QHT_MODE_AUTO_RESIZE; + TCGContext *tcg_ctx = uc->tcg_ctx; + + qht_init(&tcg_ctx->tb_ctx.htable, CODE_GEN_HTABLE_SIZE, mode); +} + /* Must be called before using the QEMU cpus. 'tb_size' is the size (in bytes) allocated to the translation buffer. Zero means default size. */ @@ -844,6 +852,7 @@ void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size) tcg_ctx = uc->tcg_ctx; tcg_ctx->uc = uc; page_init(uc); + tb_htable_init(uc); code_gen_alloc(uc, tb_size); #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE) /* There's no guest base to take into account, so go ahead and @@ -969,7 +978,7 @@ void tb_flush(CPUState *cpu) atomic_mb_set(&cpu->tb_flushed, true); tcg_ctx->tb_ctx.nb_tbs = 0; - memset(tcg_ctx->tb_ctx.tb_phys_hash, 0, sizeof(tcg_ctx->tb_ctx.tb_phys_hash)); + qht_reset_size(&tcg_ctx->tb_ctx.htable, CODE_GEN_HTABLE_SIZE); page_flush_tb(uc); tcg_ctx->code_gen_ptr = tcg_ctx->code_gen_buffer; @@ -990,61 +999,47 @@ void tb_flush(CPUState *cpu) * * Called with tb_lock held. */ -static void tb_invalidate_check(target_ulong address) +static void +do_tb_invalidate_check(struct qht *ht, void *p, uint32_t hash, void *userp) { - TranslationBlock *tb; - int i; + TranslationBlock *tb = p; + target_ulong addr = *(target_ulong *)userp; + if (!(addr + TARGET_PAGE_SIZE <= tb->pc || addr >= tb->pc + tb->size)) { + printf("ERROR invalidate: address=" TARGET_FMT_lx + " PC=%08lx size=%04x\n", addr, (long)tb->pc, tb->size); + } +} + +/* verify that all the pages have correct rights for code */ +static void tb_invalidate_check(struct uc_struct *uc, target_ulong address) +{ address &= TARGET_PAGE_MASK; - for (i = 0; i < CODE_GEN_PHYS_HASH_SIZE; i++) { - for (tb = tcg_ctx->tb_ctx.tb_phys_hash[i]; tb != NULL; - tb = tb->phys_hash_next) { - if (!(address + TARGET_PAGE_SIZE <= tb->pc || - address >= tb->pc + tb->size)) { - printf("ERROR invalidate: address=" TARGET_FMT_lx - " PC=%08lx size=%04x\n", - address, (long)tb->pc, tb->size); - } - } + qht_iter(&uc->tcg_ctx->tb_ctx.htable, do_tb_invalidate_check, &address); +} + +static void +do_tb_page_check(struct qht *ht, void *p, uint32_t hash, void *userp) +{ + TranslationBlock *tb = p; + int flags1, flags2; + + flags1 = page_get_flags(tb->pc); + flags2 = page_get_flags(tb->pc + tb->size - 1); + if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { + printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", + (long)tb->pc, tb->size, flags1, flags2); } } /* verify that all the pages have correct rights for code */ static void tb_page_check(struct uc_struct *uc) { - TranslationBlock *tb; - int i, flags1, flags2; - TCGContext *tcg_ctx = uc->tcg_ctx; - - for (i = 0; i < CODE_GEN_PHYS_HASH_SIZE; i++) { - for (tb = tcg_ctx->tb_ctx.tb_phys_hash[i]; tb != NULL; - tb = tb->phys_hash_next) { - flags1 = page_get_flags(tb->pc); - flags2 = page_get_flags(tb->pc + tb->size - 1); - if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { - printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", - (long)tb->pc, tb->size, flags1, flags2); - } - } - } + qht_iter(&uc->tcg_ctx->tb_ctx.htable, do_tb_page_check, NULL); } #endif /* CONFIG_USER_ONLY */ -static inline void tb_hash_remove(TranslationBlock **ptb, TranslationBlock *tb) -{ - TranslationBlock *tb1; - - for (;;) { - tb1 = *ptb; - if (tb1 == tb) { - *ptb = tb1->phys_hash_next; - break; - } - ptb = &tb1->phys_hash_next; - } -} - static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb) { TranslationBlock *tb1; @@ -1139,7 +1134,7 @@ void tb_phys_invalidate(struct uc_struct *uc, /* remove the TB from the hash list */ phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); h = tb_hash_func(phys_pc, tb->pc, tb->flags); - tb_hash_remove(&tcg_ctx->tb_ctx.tb_phys_hash[h], tb); + qht_remove(&tcg_ctx->tb_ctx.htable, tb, h); /* remove the TB from the page list */ if (tb->page_addr[0] != page_addr) { @@ -1284,7 +1279,6 @@ static void tb_link_page(struct uc_struct *uc, { TCGContext *tcg_ctx = uc->tcg_ctx; uint32_t h; - TranslationBlock **ptb; /* add in the page list */ tb_alloc_page(uc, tb, 0, phys_pc & TARGET_PAGE_MASK); @@ -1296,9 +1290,7 @@ static void tb_link_page(struct uc_struct *uc, /* add in the hash table */ h = tb_hash_func(phys_pc, tb->pc, tb->flags); - ptb = &tcg_ctx->tb_ctx.tb_phys_hash[h]; - tb->phys_hash_next = *ptb; - *ptb = tb; + qht_insert(&tcg_ctx->tb_ctx.htable, tb, h); #ifdef CONFIG_USER_ONLY if (DEBUG_TB_CHECK_GATE) { diff --git a/qemu/include/exec/exec-all.h b/qemu/include/exec/exec-all.h index 3ff909a4..14ed7ef4 100644 --- a/qemu/include/exec/exec-all.h +++ b/qemu/include/exec/exec-all.h @@ -231,8 +231,6 @@ struct TranslationBlock { #define CF_INVALID 0x80000 /* TB is stale. Setters must acquire tb_lock */ struct tb_tc tc; - /* next matching tb for physical address. */ - struct TranslationBlock *phys_hash_next; /* original tb when cflags has CF_NOCACHE */ struct TranslationBlock *orig_tb; /* first and second physical page containing code. The lower bit diff --git a/qemu/include/exec/tb-context.h b/qemu/include/exec/tb-context.h index 7b9d0735..24092c64 100644 --- a/qemu/include/exec/tb-context.h +++ b/qemu/include/exec/tb-context.h @@ -21,9 +21,10 @@ #define QEMU_TB_CONTEXT_H #include "qemu/thread.h" +#include "qemu/qht.h" -#define CODE_GEN_PHYS_HASH_BITS 15 -#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) +#define CODE_GEN_HTABLE_BITS 15 +#define CODE_GEN_HTABLE_SIZE (1 << CODE_GEN_HTABLE_BITS) typedef struct TranslationBlock TranslationBlock; typedef struct TBContext TBContext; @@ -31,7 +32,7 @@ typedef struct TBContext TBContext; struct TBContext { TranslationBlock **tbs; - TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; + struct qht htable; size_t tbs_size; int nb_tbs; diff --git a/qemu/include/exec/tb-hash.h b/qemu/include/exec/tb-hash.h index f4b4fb74..d11dea1a 100644 --- a/qemu/include/exec/tb-hash.h +++ b/qemu/include/exec/tb-hash.h @@ -20,7 +20,6 @@ #ifndef EXEC_TB_HASH_H #define EXEC_TB_HASH_H -#include "exec/exec-all.h" #include "exec/tb-hash-xx.h" #ifdef CONFIG_SOFTMMU @@ -61,7 +60,7 @@ static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) static inline uint32_t tb_hash_func(tb_page_addr_t phys_pc, target_ulong pc, uint32_t flags) { - return tb_hash_func5(phys_pc, pc, flags) & (CODE_GEN_PHYS_HASH_SIZE - 1); + return tb_hash_func5(phys_pc, pc, flags); } #endif diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index cba7f339..9de1434c 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -69,6 +69,7 @@ static void release_common(void *t) TCGOpDef* def = &s->tcg_op_defs[0]; g_free(def->args_ct); g_free(def->sorted_args); + qht_destroy(&s->tb_ctx.htable); g_free(s->tcg_op_defs); for (po = s->pool_first; po; po = to) {