From: Brian Cain <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
target/hexagon/cpu.h | 7 +++
target/hexagon/cpu_helper.h | 3 ++
target/hexagon/cpu.c | 26 +++++++++-
target/hexagon/cpu_helper.c | 100 ++++++++++++++++++++++++++++++++++++
target/hexagon/op_helper.c | 4 +-
5 files changed, 136 insertions(+), 4 deletions(-)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 0017be9dff7..1a3c9014455 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -207,6 +207,13 @@ G_NORETURN void
hexagon_raise_exception_err(CPUHexagonState *env,
uint32_t exception,
uintptr_t pc);
+#ifndef CONFIG_USER_ONLY
+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;
void hexagon_translate_init(void);
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index d15385daf83..72f83d62a54 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -17,5 +17,8 @@ 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);
#endif
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 938492897fd..20c4b82a970 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -33,6 +33,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) { }
@@ -316,6 +317,26 @@ static void hexagon_restore_state_to_opc(CPUState *cs,
}
+#ifndef CONFIG_USER_ONLY
+void hexagon_cpu_soft_reset(CPUHexagonState *env)
+{
+ BQL_LOCK_GUARD();
+ env->t_sreg[HEX_SREG_SSR] = 0;
+ hexagon_ssr_set_cause(env, HEX_CAUSE_RESET);
+
+ HexagonCPU *cpu = env_archcpu(env);
+ if (cpu->globalregs) {
+ uint32_t evb =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
+ env->threadId);
+ env->gpr[HEX_REG_PC] = evb;
+ } else {
+ env->gpr[HEX_REG_PC] = cpu->boot_addr;
+ }
+}
+#endif
+
+
static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
{
CPUState *cs = CPU(obj);
@@ -343,9 +364,10 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType
type)
HexagonCPU *cpu = HEXAGON_CPU(cs);
env->t_sreg[HEX_SREG_HTID] = cpu->htid;
env->threadId = cpu->htid;
- env->gpr[HEX_REG_PC] = cpu->boot_addr;
-#endif
+ hexagon_cpu_soft_reset(env);
env->cause_code = HEX_EVENT_NONE;
+ env->gpr[HEX_REG_PC] = cpu->boot_addr;
+#endif
}
static void hexagon_cpu_disas_set_info(const CPUState *cs,
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 6fbf5fc8e2f..c251790e5a5 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -10,6 +10,7 @@
#include "system/cpus.h"
#include "hw/core/boards.h"
#include "hw/hexagon/hexagon.h"
+#include "system/runstate.h"
#include "exec/cpu-interrupt.h"
#include "exec/target_page.h"
#include "accel/tcg/cpu-ldst.h"
@@ -79,7 +80,106 @@ void clear_wait_mode(CPUHexagonState *env)
}
}
+void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause)
+{
+ g_assert(bql_locked());
+
+ const uint32_t old = env->t_sreg[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 = env->t_sreg[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());
+
+ HexagonCPU *cpu = env_archcpu(env);
+ const uint32_t modectl = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+ env->threadId) : 0;
+ 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());
+
+ HexagonCPU *cpu = env_archcpu(env);
+ const uint32_t modectl = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+ env->threadId) : 0;
+ 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 uint32_t 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, request shutdown */
+ qemu_system_shutdown_request_with_code(
+ SHUTDOWN_CAUSE_GUEST_SHUTDOWN, get_thread0_r2());
+ }
+}
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 6ae07cc68e5..82605f1d4aa 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1476,12 +1476,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