Signed-off-by: Emilio G. Cota <c...@braap.org> --- aie-helper.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++ include/exec/cpu-defs.h | 5 ++ include/qemu/aie-helper.h | 21 ++++++ 3 files changed, 205 insertions(+) create mode 100644 aie-helper.c create mode 100644 include/qemu/aie-helper.h
diff --git a/aie-helper.c b/aie-helper.c new file mode 100644 index 0000000..8bc8955 --- /dev/null +++ b/aie-helper.c @@ -0,0 +1,179 @@ +/* + * To be included directly from the target's helper.c + */ +#include "qemu/aie.h" + +#ifdef CONFIG_USER_ONLY +static inline hwaddr h_get_ld_phys(CPUArchState *env, target_ulong vaddr) +{ + return vaddr; +} + +static inline hwaddr h_get_st_phys(CPUArchState *env, target_ulong vaddr) +{ + return vaddr; +} +#else +/* these need to be macros due to GETRA() */ +#define h_get_ld_phys(env, vaddr) \ + helper_ret_get_ld_phys(env, vaddr, cpu_mmu_index(env), GETRA()) +#define h_get_st_phys(env, vaddr) \ + helper_ret_get_st_phys(env, vaddr, cpu_mmu_index(env), GETRA()) +#endif /* CONFIG_USER_ONLY */ + +static inline void h_aie_lock(CPUArchState *env, hwaddr paddr) +{ + AIEEntry *entry = aie_entry_get_lock(paddr); + + env->aie_entry = entry; + env->aie_locked = true; +} + +static inline void h_aie_unlock(CPUArchState *env) +{ + assert(env->aie_entry && env->aie_locked); + qemu_mutex_unlock(&env->aie_entry->lock); + env->aie_locked = false; +} + +static inline void h_aie_unlock__done(CPUArchState *env) +{ + h_aie_unlock(env); + env->aie_entry = NULL; +} + +void HELPER(aie_llsc_st_tracking_enable)(CPUArchState *env) +{ + CPUState *other_cs; + + if (likely(atomic_read(&env->aie_llsc_st_tracking))) { + return; + } + CPU_FOREACH(other_cs) { + CPUArchState *other_env = other_cs->env_ptr; + + atomic_set(&other_env->aie_llsc_st_tracking, true); + } +} + +void HELPER(aie_ld_lock)(CPUArchState *env, target_ulong vaddr) +{ + hwaddr paddr; + + assert(!env->aie_locked); + paddr = h_get_ld_phys(env, vaddr); + h_aie_lock(env, paddr); +} + +void HELPER(aie_st_lock)(CPUArchState *env, target_ulong vaddr) +{ + hwaddr paddr; + + assert(!env->aie_locked); + paddr = h_get_st_phys(env, vaddr); + h_aie_lock(env, paddr); +} + +void HELPER(aie_insert_lock)(CPUArchState *env, target_ulong vaddr) +{ + AIEEntry *entry; + hwaddr paddr; + + assert(!env->aie_locked); + paddr = h_get_ld_phys(env, vaddr); + entry = aie_entry_get_lock(paddr); + + tiny_set_insert(&entry->ts, current_cpu); + env->aie_entry = entry; + env->aie_locked = true; +} + +uint32_t HELPER(aie_contains_lock)(CPUArchState *env) +{ + AIEEntry *entry = env->aie_entry; + + /* clrex could arrive between ldrex and strex due to preemption */ + if (unlikely(entry == NULL)) { + return -1; + } + qemu_mutex_lock(&entry->lock); + env->aie_locked = true; + if (tiny_set_contains(&entry->ts, current_cpu)) { + tiny_set_remove_all(&entry->ts); + return 0; + } + qemu_mutex_unlock(&entry->lock); + env->aie_locked = false; + env->aie_entry = NULL; + return -1; +} + +void HELPER(aie_unlock)(CPUArchState *env) +{ + h_aie_unlock(env); +} + +void HELPER(aie_unlock__done)(CPUArchState *env) +{ + h_aie_unlock__done(env); +} + +void HELPER(aie_clear)(CPUArchState *env) +{ + AIEEntry *entry = env->aie_entry; + + assert(!env->aie_locked); + if (!entry) { + return; + } + + qemu_mutex_lock(&env->aie_entry->lock); + tiny_set_remove(&entry->ts, current_cpu); + qemu_mutex_unlock(&env->aie_entry->lock); + env->aie_entry = NULL; +} + +void HELPER(aie_ld_pre)(CPUArchState *env, target_ulong vaddr) +{ + if (likely(!env->aie_lock_enabled) || env->aie_locked) { + return; + } + helper_aie_ld_lock(env, vaddr); +} + +void HELPER(aie_st_pre)(CPUArchState *env, target_ulong vaddr) +{ + if (unlikely(env->aie_lock_enabled)) { + if (env->aie_locked) { + return; + } + helper_aie_st_lock(env, vaddr); + } else { + hwaddr paddr = h_get_st_phys(env, vaddr); + + if (unlikely(aie_entry_exists(paddr))) { + h_aie_lock(env, paddr); + } + } +} + +void HELPER(aie_llsc_st_pre)(CPUArchState *env, target_ulong vaddr) +{ + hwaddr paddr; + + assert(!env->aie_locked); + if (!env->aie_llsc_st_tracking) { + return; + } + paddr = h_get_st_phys(env, vaddr); + if (unlikely(aie_entry_exists(paddr))) { + h_aie_lock(env, paddr); + } +} + +void HELPER(aie_llsc_st_post)(CPUArchState *env) +{ + if (unlikely(env->aie_locked)) { + h_aie_unlock__done(env); + } +} diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 67aa0a0..8891f16 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -27,6 +27,7 @@ #include <inttypes.h> #include "qemu/osdep.h" #include "qemu/queue.h" +#include "qemu/aie.h" #ifndef CONFIG_USER_ONLY #include "exec/hwaddr.h" #endif @@ -135,5 +136,9 @@ typedef struct CPUIOTLBEntry { #define CPU_COMMON \ /* soft mmu support */ \ CPU_COMMON_TLB \ + AIEEntry *aie_entry; \ + bool aie_locked; \ + bool aie_lock_enabled; \ + bool aie_llsc_st_tracking; \ #endif diff --git a/include/qemu/aie-helper.h b/include/qemu/aie-helper.h new file mode 100644 index 0000000..7605e07 --- /dev/null +++ b/include/qemu/aie-helper.h @@ -0,0 +1,21 @@ +#ifdef TARGET_ARM +#define AIE_VADDR_TCG_TYPE glue(i, TARGET_VIRT_ADDR_SPACE_BITS) +#else +#define AIE_VADDR_TCG_TYPE tl +#endif /* TARGET_ARM */ + +DEF_HELPER_2(aie_ld_pre, void, env, AIE_VADDR_TCG_TYPE) +DEF_HELPER_2(aie_st_pre, void, env, AIE_VADDR_TCG_TYPE) +DEF_HELPER_2(aie_llsc_st_pre, void, env, AIE_VADDR_TCG_TYPE) +DEF_HELPER_1(aie_llsc_st_post, void, env) +DEF_HELPER_1(aie_llsc_st_tracking_enable, void, env) + +DEF_HELPER_2(aie_ld_lock, void, env, AIE_VADDR_TCG_TYPE) +DEF_HELPER_2(aie_st_lock, void, env, AIE_VADDR_TCG_TYPE) +DEF_HELPER_2(aie_insert_lock, void, env, AIE_VADDR_TCG_TYPE) +DEF_HELPER_1(aie_contains_lock, i32, env) +DEF_HELPER_1(aie_unlock, void, env) +DEF_HELPER_1(aie_unlock__done, void, env) +DEF_HELPER_1(aie_clear, void, env) + +#undef AIE_VADDR_TCG_TYPE -- 1.8.3