Because atomic_read/atomic_set does not work on platforms that only support 32-bit atomic writes, we need volatile_read/volatile_set.
This patch fixes up Sergey's series to use volatile_read/volatile_set instead of atomic_read/atomic_set. Because volatile_read/volatile_set can cause torn writes, the invalidation mechanism for SPARC targets is changed to use flags instead of cs_base. Torn writes are not a problem for targets that don't use cs_base at all, because 0xffffffff00000000 or 0x00000000ffffffff cs_bases cannot be confused with the cs_base of a valid translation block. The patch also includes two fixes, respectively using atomic_rcu_read in tb_find and fixing computation of the hash index in tb_phys_invalidate. Signed-off-by: Paolo Bonzini <[email protected]> diff --git a/cpu-exec.c b/cpu-exec.c index fd43de8..4068110 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -238,10 +238,10 @@ 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 && + if (volatile_read(&tb->pc) == desc->pc && tb->page_addr[0] == desc->phys_page1 && - tb->cs_base == desc->cs_base && - tb->flags == desc->flags) { + volatile_read(&tb->cs_base) == desc->cs_base && + volatile_read(&tb->flags) == desc->flags) { /* check next page if needed */ if (tb->page_addr[1] == -1) { return true; @@ -292,10 +292,10 @@ static inline TranslationBlock *tb_find(CPUState *cpu, always be the same before a given translated block is executed. */ cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); - tb = atomic_read(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]); - if (unlikely(!tb || atomic_read(&tb->pc) != pc || - atomic_read(&tb->cs_base) != cs_base || - atomic_read(&tb->flags) != flags)) { + tb = atomic_rcu_read(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]); + if (unlikely(!tb || volatile_read(&tb->pc) != pc || + volatile_read(&tb->cs_base) != cs_base || + volatile_read(&tb->flags) != flags)) { tb = tb_htable_lookup(cpu, pc, cs_base, flags); if (!tb) { diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 8f0afcd..35e963b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -262,9 +262,9 @@ static inline void tb_mark_invalid(TranslationBlock *tb) uint32_t flags = 0; cpu_get_invalid_tb_cpu_state(&pc, &cs_base, &flags); - atomic_set(&tb->pc, pc); - atomic_set(&tb->cs_base, cs_base); - atomic_set(&tb->flags, flags); + volatile_set(&tb->pc, pc); + volatile_set(&tb->cs_base, cs_base); + volatile_set(&tb->flags, flags); } static inline bool tb_is_invalid(TranslationBlock *tb) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e327a35..3278d8a 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -753,14 +753,17 @@ static inline void cpu_get_invalid_tb_cpu_state(target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { - *cs_base = -1; /* npc must be a multible of 4 */ + /* TB_FLAG_MMU_MASK is not a valid MMU index, which makes it is an + * impossible flag combination for valid TBs. + */ + *flags = TB_FLAG_MMU_MASK; } static inline bool cpu_tb_cpu_state_is_invalidated(target_ulong pc, target_ulong cs_base, uint32_t flags) { - return cs_base == -1; + return flags == TB_FLAG_MMU_MASK; } static inline bool tb_fpu_enabled(int tb_flags) diff --git a/translate-all.c b/translate-all.c index 6156bdc..187f782 100644 --- a/translate-all.c +++ b/translate-all.c @@ -990,11 +990,15 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) uint32_t h; tb_page_addr_t phys_pc; + /* Compute hash index before tb->flags is possibly destroyed + * by tb_mark_invalid. + */ + phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + h = tb_hash_func(phys_pc, tb->pc, tb->flags); + tb_mark_invalid(tb); /* 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); qht_remove(&tcg_ctx.tb_ctx.htable, tb, h); /* remove the TB from the page list */
