Assign env->hvx to the right context when SSR:XA changes.

Signed-off-by: Brian Cain <[email protected]>
---
 target/hexagon/cpu_helper.h |  1 +
 target/hexagon/cpu.c        |  5 +++
 target/hexagon/cpu_helper.c | 72 +++++++++++++++++++++++++++++++++++++
 target/hexagon/machine.c    | 12 +++++++
 4 files changed, 90 insertions(+)

diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index 12512efd74f..afb4df59f80 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -15,6 +15,7 @@ void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t 
start_addr,
                                uint32_t length, uintptr_t retaddr);
 uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
 void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
+unsigned hexagon_hvx_select_context(CPUHexagonState *env, uint32_t ssr);
 int get_cpu_mode(const CPUHexagonState *env);
 int get_exe_mode(const CPUHexagonState *env);
 void clear_wait_mode(CPUHexagonState *env);
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index a62191cf3fb..472e7535d4f 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -320,6 +320,9 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
     CPUHexagonState *env = cpu_env(cs);
     vaddr pc = env->gpr[HEX_REG_PC];
     uint32_t hex_flags = 0;
+#ifndef CONFIG_USER_ONLY
+    HexagonCPU *cpu;
+#endif
 
     if (pc == env->gpr[HEX_REG_SA0]) {
         hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1);
@@ -330,10 +333,12 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState 
*cs)
     }
 
 #ifndef CONFIG_USER_ONLY
+    cpu = env_archcpu(env);
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
                            cpu_mmu_index(env_cpu(env), false));
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED,
+                           cpu->hvx_ctx[0] &&
                            GET_SSR_FIELD(SSR_XE, env->t_sreg[HEX_SREG_SSR]));
 #else
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 9ce260d7448..1b06b41da5d 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -11,6 +11,7 @@
 #include "hw/core/boards.h"
 #include "hw/hexagon/hexagon.h"
 #include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon_hvx_context.h"
 #include "hex_interrupts.h"
 #include "hex_mmu.h"
 #include "system/runstate.h"
@@ -246,6 +247,65 @@ void hexagon_resume_threads(CPUHexagonState *current_env, 
uint32_t mask)
     }
 }
 
+static unsigned hexagon_hvx_context_count(HexagonCPU *cpu)
+{
+    unsigned n;
+
+    for (n = 0; n < HVX_CONTEXTS_MAX; n++) {
+        if (!cpu->hvx_ctx[n]) {
+            break;
+        }
+    }
+    return n;
+}
+
+static unsigned hexagon_hvx_context_index(HexagonCPU *cpu, uint8_t xa)
+{
+    unsigned n = hexagon_hvx_context_count(cpu);
+
+    if (n == 0) {
+        return 0;
+    }
+    return xa % n;
+}
+
+/*
+ * Diagnostic only.  Called separately from hexagon_hvx_select_context()
+ * so migration post_load, where other CPUs' env->hvx may still be stale,
+ * doesn't trip a false positive.
+ */
+static void hexagon_hvx_check_overcommit(CPUHexagonState *env, unsigned idx)
+{
+    CPUState *cs;
+    unsigned users = 0;
+
+    CPU_FOREACH(cs) {
+        CPUHexagonState *other = cpu_env(cs);
+
+        if (other->hvx == env->hvx &&
+            GET_SSR_FIELD(SSR_XE, other->t_sreg[HEX_SREG_SSR])) {
+            users++;
+        }
+    }
+
+    if (users > 1) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "HVX context %u is enabled for %u hardware threads "
+                      "at once, which is undefined\n", idx, users);
+    }
+}
+
+unsigned hexagon_hvx_select_context(CPUHexagonState *env, uint32_t ssr)
+{
+    HexagonCPU *cpu = env_archcpu(env);
+    unsigned idx = hexagon_hvx_context_index(cpu, GET_SSR_FIELD(SSR_XA, ssr));
+
+    if (cpu->hvx_ctx[0]) {
+        env->hvx = &cpu->hvx_ctx[idx]->regs;
+    }
+    return idx;
+}
+
 void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
 {
     bool old_EX, old_UM, old_GM, old_IE;
@@ -269,6 +329,18 @@ void hexagon_modify_ssr(CPUHexagonState *env, uint32_t 
new, uint32_t old)
         hex_mmu_mode_change(env);
     }
 
+    bool xa_changed = GET_SSR_FIELD(SSR_XA, new) != GET_SSR_FIELD(SSR_XA, old);
+    bool xe_changed = GET_SSR_FIELD(SSR_XE, new) != GET_SSR_FIELD(SSR_XE, old);
+
+    if (xa_changed || xe_changed) {
+        unsigned idx = xa_changed
+            ? hexagon_hvx_select_context(env, new)
+            : hexagon_hvx_context_index(env_archcpu(env),
+                                        GET_SSR_FIELD(SSR_XA, new));
+
+        hexagon_hvx_check_overcommit(env, idx);
+    }
+
     old_asid = GET_SSR_FIELD(SSR_ASID, old);
     new_asid = GET_SSR_FIELD(SSR_ASID, new);
     if (new_asid != old_asid) {
diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c
index bf4646f4a8b..179b6f53a2a 100644
--- a/target/hexagon/machine.c
+++ b/target/hexagon/machine.c
@@ -7,11 +7,23 @@
 #include "qemu/osdep.h"
 #include "migration/vmstate.h"
 #include "cpu.h"
+#include "cpu_helper.h"
+
+static int hexagon_cpu_post_load(void *opaque, int version_id)
+{
+    HexagonCPU *cpu = opaque;
+    CPUHexagonState *env = &cpu->env;
+
+    hexagon_hvx_select_context(env, env->t_sreg[HEX_SREG_SSR]);
+
+    return 0;
+}
 
 const VMStateDescription vmstate_hexagon_cpu = {
     .name = "cpu",
     .version_id = 2,
     .minimum_version_id = 2,
+    .post_load = hexagon_cpu_post_load,
     .fields = (const VMStateField[]) {
         VMSTATE_UINT32_ARRAY(env.gpr, HexagonCPU, TOTAL_PER_THREAD_REGS),
         VMSTATE_UINT32_ARRAY(env.pred, HexagonCPU, NUM_PREGS),
-- 
2.34.1

Reply via email to