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