tcg: Prepare safe tb_jmp_cache lookup out of tb_lock

Ensure atomicity of CPU's 'tb_jmp_cache' access for future translation
block lookup out of 'tb_lock'.

Note that this patch does *not* make CPU's TLB invalidation safe if it
is done from some other thread while the CPU is in its execution loop.

Backports commit 89a16b1e4294e3664667a151c2f70c84dfac6fd9 from qemu
This commit is contained in:
Sergey Fedorov 2018-02-25 23:25:32 -05:00 committed by Lioncash
parent 371101a184
commit 9eb02a540d
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
2 changed files with 9 additions and 5 deletions

View file

@ -175,7 +175,7 @@ static TranslationBlock *tb_find_slow(CPUState *cpu,
found:
/* we add the TB in the virtual pc hash table */
cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
atomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
return tb;
}
@ -194,7 +194,8 @@ static inline TranslationBlock *tb_find_fast(CPUState *cpu,
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
// Unicorn: commented out
//tb_lock();
tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
// Unicorn: atomic_read used instead of atomic_rcu_read
tb = atomic_read(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]);
if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
tb->flags != flags)) {
tb = tb_find_slow(cpu, pc, cs_base, flags);

View file

@ -904,6 +904,7 @@ void tb_flush(CPUState *cpu)
{
struct uc_struct* uc = cpu->uc;
TCGContext *tcg_ctx = uc->tcg_ctx;
int i;
#if defined(DEBUG_FLUSH)
printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
@ -918,7 +919,9 @@ void tb_flush(CPUState *cpu)
}
tcg_ctx->tb_ctx.nb_tbs = 0;
memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache));
for (i = 0; i < TB_JMP_CACHE_SIZE; ++i) {
atomic_set(&cpu->tb_jmp_cache[i], NULL);
}
cpu->tb_flushed = true;
memset(tcg_ctx->tb_ctx.tb_phys_hash, 0, sizeof(tcg_ctx->tb_ctx.tb_phys_hash));
@ -1092,8 +1095,8 @@ void tb_phys_invalidate(struct uc_struct *uc,
/* remove the TB from the hash list */
h = tb_jmp_cache_hash_func(tb->pc);
if (cpu->tb_jmp_cache[h] == tb) {
cpu->tb_jmp_cache[h] = NULL;
if (atomic_read(&cpu->tb_jmp_cache[h]) == tb) {
atomic_set(&cpu->tb_jmp_cache[h], NULL);
}
/* suppress this TB from the two jump lists */