From: Brian Cain <bc...@quicinc.com>

Signed-off-by: Brian Cain <brian.c...@oss.qualcomm.com>
---
 target/hexagon/cpu.h        |  1 +
 target/hexagon/cpu_helper.h |  3 ++
 target/hexagon/cpu.c        | 18 ++++++-
 target/hexagon/cpu_helper.c | 94 +++++++++++++++++++++++++++++++++++++
 target/hexagon/op_helper.c  |  4 +-
 5 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index d369e104ae..a0448eba44 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -209,6 +209,7 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState 
*env,
 uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg);
 uint32_t hexagon_sreg_read(CPUHexagonState *env, uint32_t reg);
 void hexagon_gdb_sreg_write(CPUHexagonState *env, uint32_t reg, uint32_t val);
+void hexagon_cpu_soft_reset(CPUHexagonState *env);
 #endif
 
 typedef HexagonCPU ArchCPU;
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index 6f0c6697ad..95a0cc0788 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -17,6 +17,9 @@ void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, 
uint32_t);
 void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
 int get_exe_mode(CPUHexagonState *env);
 void clear_wait_mode(CPUHexagonState *env);
+void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause);
+void hexagon_start_threads(CPUHexagonState *env, uint32_t mask);
+void hexagon_stop_thread(CPUHexagonState *env);
 
 static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg,
                                        uint32_t val)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index c128f47ad3..e35ac92402 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -32,6 +32,7 @@
 #ifndef CONFIG_USER_ONLY
 #include "sys_macros.h"
 #include "accel/tcg/cpu-ldst.h"
+#include "qemu/main-loop.h"
 #endif
 
 static void hexagon_v66_cpu_init(Object *obj) { }
@@ -312,9 +313,23 @@ static void mmu_reset(CPUHexagonState *env)
         memset(env->hex_tlb, 0, sizeof(*env->hex_tlb));
     }
 }
+
+void hexagon_cpu_soft_reset(CPUHexagonState *env)
+{
+    BQL_LOCK_GUARD();
+    arch_set_system_reg(env, HEX_SREG_SSR, 0);
+    hexagon_ssr_set_cause(env, HEX_CAUSE_RESET);
+
+    HexagonCPU *cpu = env_archcpu(env);
+    if (cpu->globalregs) {
+        target_ulong evb = arch_get_system_reg(env, HEX_SREG_EVB);
+        arch_set_thread_reg(env, HEX_REG_PC, evb);
+    } else {
+        arch_set_thread_reg(env, HEX_REG_PC, cpu->boot_addr);
+    }
+}
 #endif
 
-
 static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
@@ -337,6 +352,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType 
type)
 
     mmu_reset(env);
     arch_set_system_reg(env, HEX_SREG_HTID, cs->cpu_index);
+    hexagon_cpu_soft_reset(env);
     memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS);
     memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS);
     env->threadId = cs->cpu_index;
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 00f47e5a07..74ce59adf4 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -89,8 +89,102 @@ void clear_wait_mode(CPUHexagonState *env)
     }
 }
 
+void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause)
+{
+    g_assert(bql_locked());
+
+    const uint32_t old = arch_get_system_reg(env, HEX_SREG_SSR);
+    SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, 1);
+    SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause);
+    const uint32_t new = arch_get_system_reg(env, HEX_SREG_SSR);
+
+    hexagon_modify_ssr(env, new, old);
+}
+
+
 int get_exe_mode(CPUHexagonState *env)
 {
     g_assert_not_reached();
 }
+
+static void set_enable_mask(CPUHexagonState *env)
+{
+    g_assert(bql_locked());
+
+    const uint32_t modectl = arch_get_system_reg(env, HEX_SREG_MODECTL);
+    uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+    thread_enabled_mask |= 0x1 << env->threadId;
+    SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
+}
+
+static uint32_t clear_enable_mask(CPUHexagonState *env)
+{
+    g_assert(bql_locked());
+
+    const uint32_t modectl = arch_get_system_reg(env, HEX_SREG_MODECTL);
+    uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+    thread_enabled_mask &= ~(0x1 << env->threadId);
+    SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
+    return thread_enabled_mask;
+}
+static void do_start_thread(CPUState *cs, run_on_cpu_data tbd)
+{
+    BQL_LOCK_GUARD();
+
+    CPUHexagonState *env = cpu_env(cs);
+
+    hexagon_cpu_soft_reset(env);
+
+    set_enable_mask(env);
+
+    cs->halted = 0;
+    cs->exception_index = HEX_EVENT_NONE;
+    cpu_resume(cs);
+}
+
+void hexagon_start_threads(CPUHexagonState *current_env, uint32_t mask)
+{
+    CPUState *cs;
+    CPU_FOREACH(cs) {
+        CPUHexagonState *env = cpu_env(cs);
+        if (!(mask & (0x1 << env->threadId))) {
+            continue;
+        }
+
+        if (current_env->threadId != env->threadId) {
+            async_safe_run_on_cpu(cs, do_start_thread, RUN_ON_CPU_NULL);
+        }
+    }
+}
+
+/*
+ * When we have all threads stopped, the return
+ * value to the shell is register 2 from thread 0.
+ */
+static target_ulong get_thread0_r2(void)
+{
+    CPUState *cs;
+    CPU_FOREACH(cs) {
+        CPUHexagonState *thread = cpu_env(cs);
+        if (thread->threadId == 0) {
+            return thread->gpr[2];
+        }
+    }
+    g_assert_not_reached();
+}
+
+void hexagon_stop_thread(CPUHexagonState *env)
+
+{
+    BQL_LOCK_GUARD();
+
+    uint32_t thread_enabled_mask = clear_enable_mask(env);
+    CPUState *cs = env_cpu(env);
+    cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+    if (!thread_enabled_mask) {
+        /* All threads are stopped, exit */
+        exit(get_thread0_r2());
+    }
+}
+
 #endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 74f8c1bf4f..4b1fc23a15 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1455,12 +1455,12 @@ uint32_t HELPER(iassignr)(CPUHexagonState *env, 
uint32_t src)
 
 void HELPER(start)(CPUHexagonState *env, uint32_t imask)
 {
-    g_assert_not_reached();
+    hexagon_start_threads(env, imask);
 }
 
 void HELPER(stop)(CPUHexagonState *env)
 {
-    g_assert_not_reached();
+    hexagon_stop_thread(env);
 }
 
 void HELPER(wait)(CPUHexagonState *env, target_ulong PC)
-- 
2.34.1


Reply via email to