From: Brian Cain <brian.cain@oss.qualcomm.com>
To: qemu-devel@nongnu.org
Cc: brian.cain@oss.qualcomm.com, richard.henderson@linaro.org,
philmd@linaro.org, matheus.bernardino@oss.qualcomm.com,
ale@rev.ng, anjo@rev.ng, marco.liebel@oss.qualcomm.com,
ltaylorsimpson@gmail.com, alex.bennee@linaro.org,
quic_mburton@quicinc.com, sid.manning@oss.qualcomm.com,
Brian Cain <bcain@quicinc.com>, Sid Manning <sidneym@quicinc.com>,
Michael Lambert <mlambert@quicinc.com>
Subject: [PATCH v2 40/40] target/hexagon: Add hex_interrupts support
Date: Mon, 1 Sep 2025 20:47:15 -0700 [thread overview]
Message-ID: <20250902034715.1947718-41-brian.cain@oss.qualcomm.com> (raw)
In-Reply-To: <20250902034715.1947718-1-brian.cain@oss.qualcomm.com>
From: Brian Cain <bcain@quicinc.com>
Co-authored-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Co-authored-by: Sid Manning <sidneym@quicinc.com>
Co-authored-by: Michael Lambert <mlambert@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 1 +
target/hexagon/hex_interrupts.h | 15 ++
target/hexagon/cpu.c | 2 +
target/hexagon/hex_interrupts.c | 327 ++++++++++++++++++++++++++++++++
4 files changed, 345 insertions(+)
create mode 100644 target/hexagon/hex_interrupts.h
create mode 100644 target/hexagon/hex_interrupts.c
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index f25b483188..d369e104ae 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -192,6 +192,7 @@ struct ArchCPU {
bool short_circuit;
#ifndef CONFIG_USER_ONLY
uint32_t num_tlbs;
+ uint32_t l2vic_base_addr;
#endif
};
diff --git a/target/hexagon/hex_interrupts.h b/target/hexagon/hex_interrupts.h
new file mode 100644
index 0000000000..17a243946c
--- /dev/null
+++ b/target/hexagon/hex_interrupts.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright(c) 2022-2025 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEX_INTERRUPTS_H
+#define HEX_INTERRUPTS_H
+
+bool hex_check_interrupts(CPUHexagonState *env);
+void hex_clear_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type);
+void hex_raise_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type);
+void hex_interrupt_update(CPUHexagonState *env);
+
+#endif
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index eb3adebb60..c128f47ad3 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -59,6 +59,8 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
static const Property hexagon_cpu_properties[] = {
#if !defined(CONFIG_USER_ONLY)
DEFINE_PROP_UINT32("jtlb-entries", HexagonCPU, num_tlbs, MAX_TLB_ENTRIES),
+ DEFINE_PROP_UINT32("l2vic-base-addr", HexagonCPU, l2vic_base_addr,
+ 0xffffffffULL),
#endif
DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false),
DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0,
diff --git a/target/hexagon/hex_interrupts.c b/target/hexagon/hex_interrupts.c
new file mode 100644
index 0000000000..b555565e55
--- /dev/null
+++ b/target/hexagon/hex_interrupts.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright(c) 2022-2025 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "cpu_helper.h"
+#include "exec/cpu-interrupt.h"
+#include "hex_interrupts.h"
+#include "macros.h"
+#include "sys_macros.h"
+#include "system/cpus.h"
+
+static bool hex_is_qualified_for_int(CPUHexagonState *env, int int_num);
+
+static bool get_syscfg_gie(CPUHexagonState *env)
+{
+ target_ulong syscfg = arch_get_system_reg(env, HEX_SREG_SYSCFG);
+ return GET_SYSCFG_FIELD(SYSCFG_GIE, syscfg);
+}
+
+static bool get_ssr_ex(CPUHexagonState *env)
+{
+ target_ulong ssr = arch_get_system_reg(env, HEX_SREG_SSR);
+ return GET_SSR_FIELD(SSR_EX, ssr);
+}
+
+static bool get_ssr_ie(CPUHexagonState *env)
+{
+ target_ulong ssr = arch_get_system_reg(env, HEX_SREG_SSR);
+ return GET_SSR_FIELD(SSR_IE, ssr);
+}
+
+/* Do these together so we only have to call hexagon_modify_ssr once */
+static void set_ssr_ex_cause(CPUHexagonState *env, int ex, uint32_t cause)
+{
+ target_ulong old = arch_get_system_reg(env, HEX_SREG_SSR);
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, ex);
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause);
+ target_ulong new = arch_get_system_reg(env, HEX_SREG_SSR);
+ hexagon_modify_ssr(env, new, old);
+}
+
+static bool get_iad_bit(CPUHexagonState *env, int int_num)
+{
+ target_ulong ipendad = arch_get_system_reg(env, HEX_SREG_IPENDAD);
+ target_ulong iad = GET_FIELD(IPENDAD_IAD, ipendad);
+ return extract32(iad, int_num, 1);
+}
+
+static void set_iad_bit(CPUHexagonState *env, int int_num, int val)
+{
+ target_ulong ipendad = arch_get_system_reg(env, HEX_SREG_IPENDAD);
+ target_ulong iad = GET_FIELD(IPENDAD_IAD, ipendad);
+ iad = deposit32(iad, int_num, 1, val);
+ fSET_FIELD(ipendad, IPENDAD_IAD, iad);
+ arch_set_system_reg(env, HEX_SREG_IPENDAD, ipendad);
+}
+
+static uint32_t get_ipend(CPUHexagonState *env)
+{
+ target_ulong ipendad = arch_get_system_reg(env, HEX_SREG_IPENDAD);
+ return GET_FIELD(IPENDAD_IPEND, ipendad);
+}
+
+static inline bool get_ipend_bit(CPUHexagonState *env, int int_num)
+{
+ target_ulong ipendad = arch_get_system_reg(env, HEX_SREG_IPENDAD);
+ target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ return extract32(ipend, int_num, 1);
+}
+
+static void clear_ipend(CPUHexagonState *env, uint32_t mask)
+{
+ target_ulong ipendad = arch_get_system_reg(env, HEX_SREG_IPENDAD);
+ target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend &= ~mask;
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ arch_set_system_reg(env, HEX_SREG_IPENDAD, ipendad);
+}
+
+static void set_ipend(CPUHexagonState *env, uint32_t mask)
+{
+ target_ulong ipendad = arch_get_system_reg(env, HEX_SREG_IPENDAD);
+ target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend |= mask;
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ arch_set_system_reg(env, HEX_SREG_IPENDAD, ipendad);
+}
+
+static void set_ipend_bit(CPUHexagonState *env, int int_num, int val)
+{
+ target_ulong ipendad = arch_get_system_reg(env, HEX_SREG_IPENDAD);
+ target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend = deposit32(ipend, int_num, 1, val);
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ arch_set_system_reg(env, HEX_SREG_IPENDAD, ipendad);
+}
+
+static bool get_imask_bit(CPUHexagonState *env, int int_num)
+{
+ target_ulong imask = arch_get_system_reg(env, HEX_SREG_IMASK);
+ return extract32(imask, int_num, 1);
+}
+
+static uint32_t get_prio(CPUHexagonState *env)
+{
+ target_ulong stid = arch_get_system_reg(env, HEX_SREG_STID);
+ return extract32(stid, reg_field_info[STID_PRIO].offset,
+ reg_field_info[STID_PRIO].width);
+}
+
+static void set_elr(CPUHexagonState *env, target_ulong val)
+{
+ arch_set_system_reg(env, HEX_SREG_ELR, val);
+}
+
+static bool get_schedcfgen(CPUHexagonState *env)
+{
+ target_ulong schedcfg = arch_get_system_reg(env, HEX_SREG_SCHEDCFG);
+ return extract32(schedcfg, reg_field_info[SCHEDCFG_EN].offset,
+ reg_field_info[SCHEDCFG_EN].width);
+}
+
+static bool is_lowest_prio(CPUHexagonState *env, int int_num)
+{
+ uint32_t my_prio = get_prio(env);
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ CPUHexagonState *hex_env = cpu_env(cs);
+ if (!hex_is_qualified_for_int(hex_env, int_num)) {
+ continue;
+ }
+
+ /* Note that lower values indicate *higher* priority */
+ if (my_prio < get_prio(hex_env)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool hex_is_qualified_for_int(CPUHexagonState *env, int int_num)
+{
+ bool syscfg_gie = get_syscfg_gie(env);
+ bool iad = get_iad_bit(env, int_num);
+ bool ssr_ie = get_ssr_ie(env);
+ bool ssr_ex = get_ssr_ex(env);
+ bool imask = get_imask_bit(env, int_num);
+
+ return syscfg_gie && !iad && ssr_ie && !ssr_ex && !imask;
+}
+
+static void clear_pending_locks(CPUHexagonState *env)
+{
+ g_assert(bql_locked());
+ if (env->k0_lock_state == HEX_LOCK_WAITING) {
+ env->k0_lock_state = HEX_LOCK_UNLOCKED;
+ }
+ if (env->tlb_lock_state == HEX_LOCK_WAITING) {
+ env->tlb_lock_state = HEX_LOCK_UNLOCKED;
+ }
+}
+
+static bool should_not_exec(CPUHexagonState *env)
+{
+ return (get_exe_mode(env) == HEX_EXE_MODE_WAIT);
+}
+
+static void restore_state(CPUHexagonState *env, bool int_accepted)
+{
+ CPUState *cs = env_cpu(env);
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI);
+ if (!int_accepted && should_not_exec(env)) {
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+ }
+}
+
+static void hex_accept_int(CPUHexagonState *env, int int_num)
+{
+ CPUState *cs = env_cpu(env);
+ target_ulong evb = arch_get_system_reg(env, HEX_SREG_EVB);
+ const int exe_mode = get_exe_mode(env);
+ const bool in_wait_mode = exe_mode == HEX_EXE_MODE_WAIT;
+
+ set_ipend_bit(env, int_num, 0);
+ set_iad_bit(env, int_num, 1);
+ set_ssr_ex_cause(env, 1, HEX_CAUSE_INT0 | int_num);
+ cs->exception_index = HEX_EVENT_INT0 + int_num;
+ env->cause_code = HEX_EVENT_INT0 + int_num;
+ clear_pending_locks(env);
+ if (in_wait_mode) {
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread " TARGET_FMT_ld " resuming, exiting WAIT mode\n",
+ __func__, env->threadId);
+ set_elr(env, env->wait_next_pc);
+ clear_wait_mode(env);
+ cs->halted = false;
+ } else if (env->k0_lock_state == HEX_LOCK_WAITING) {
+ g_assert_not_reached();
+ } else {
+ set_elr(env, env->gpr[HEX_REG_PC]);
+ }
+ env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2);
+ if (get_ipend(env) == 0) {
+ restore_state(env, true);
+ }
+}
+
+
+bool hex_check_interrupts(CPUHexagonState *env)
+{
+ CPUState *cs = env_cpu(env);
+ bool int_handled = false;
+ bool ssr_ex = get_ssr_ex(env);
+ int max_ints = 32;
+ bool schedcfgen;
+
+ /* Early exit if nothing pending */
+ if (get_ipend(env) == 0) {
+ restore_state(env, false);
+ return false;
+ }
+
+ BQL_LOCK_GUARD();
+ /* Only check priorities when schedcfgen is set */
+ schedcfgen = get_schedcfgen(env);
+ for (int i = 0; i < max_ints; i++) {
+ if (!get_iad_bit(env, i) && get_ipend_bit(env, i)) {
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] pc = 0x" TARGET_FMT_lx " found int %d\n", __func__,
+ env->threadId, env->gpr[HEX_REG_PC], i);
+ if (hex_is_qualified_for_int(env, i) &&
+ (!schedcfgen || is_lowest_prio(env, i))) {
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] int %d handled_\n",
+ __func__, env->threadId, i);
+ hex_accept_int(env, i);
+ int_handled = true;
+ break;
+ }
+ bool syscfg_gie = get_syscfg_gie(env);
+ bool iad = get_iad_bit(env, i);
+ bool ssr_ie = get_ssr_ie(env);
+ bool imask = get_imask_bit(env, i);
+
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] int %d not handled, qualified: %d, "
+ "schedcfg_en: %d, low prio %d\n",
+ __func__, env->threadId, i,
+ hex_is_qualified_for_int(env, i), schedcfgen,
+ is_lowest_prio(env, i));
+
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] int %d not handled, GIE %d, iad %d, "
+ "SSR:IE %d, SSR:EX: %d, imask bit %d\n",
+ __func__, env->threadId, i, syscfg_gie, iad, ssr_ie,
+ ssr_ex, imask);
+ }
+ }
+
+ /*
+ * If we didn't handle the interrupt and it wasn't
+ * because we were in EX state, then we won't be able
+ * to execute the interrupt on this CPU unless something
+ * changes in the CPU state. Clear the interrupt_request bits
+ * while preserving the IPEND bits, and we can re-assert the
+ * interrupt_request bit(s) when we execute one of those instructions.
+ */
+ if (!int_handled && !ssr_ex) {
+ restore_state(env, int_handled);
+ } else if (int_handled) {
+ assert(!cs->halted);
+ }
+
+ return int_handled;
+}
+
+void hex_clear_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type)
+{
+ if (mask == 0) {
+ return;
+ }
+
+ /*
+ * Notify all CPUs that the interrupt has happened
+ */
+ BQL_LOCK_GUARD();
+ clear_ipend(env, mask);
+ hex_interrupt_update(env);
+}
+
+void hex_raise_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type)
+{
+ g_assert(bql_locked());
+ if (mask == 0) {
+ return;
+ }
+
+ /*
+ * Notify all CPUs that the interrupt has happened
+ */
+ set_ipend(env, mask);
+ hex_interrupt_update(env);
+}
+
+void hex_interrupt_update(CPUHexagonState *env)
+{
+ CPUState *cs;
+
+ g_assert(bql_locked());
+ if (get_ipend(env) != 0) {
+ CPU_FOREACH(cs) {
+ CPUHexagonState *hex_env = cpu_env(cs);
+ const int exe_mode = get_exe_mode(hex_env);
+ if (exe_mode != HEX_EXE_MODE_OFF) {
+ cs->interrupt_request |= CPU_INTERRUPT_SWI;
+ cpu_resume(cs);
+ }
+ }
+ }
+}
--
2.34.1
prev parent reply other threads:[~2025-09-02 3:49 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-02 3:46 [PATCH v2 00/40] hexagon system emulation v2, part 1/3 Brian Cain
2025-09-02 3:46 ` [PATCH v2 01/40] docs: Add hexagon sysemu docs Brian Cain
2025-09-02 3:46 ` [PATCH v2 02/40] docs/system: Add hexagon CPU emulation Brian Cain
2025-09-02 3:46 ` [PATCH v2 03/40] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
2025-09-02 3:46 ` [PATCH v2 04/40] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
2025-09-02 3:46 ` [PATCH v2 05/40] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
2025-09-02 3:46 ` [PATCH v2 06/40] target/hexagon: Make gen_exception_end_tb non-static Brian Cain
2025-09-02 3:46 ` [PATCH v2 07/40] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain via
2025-09-02 3:46 ` [PATCH v2 08/40] target/hexagon: Add system event, cause codes Brian Cain
2025-09-02 3:46 ` [PATCH v2 09/40] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
2025-09-02 3:46 ` [PATCH v2 10/40] target/hexagon: Add memory order definition Brian Cain
2025-09-02 3:46 ` [PATCH v2 11/40] target/hexagon: Add a placeholder fp exception Brian Cain
2025-09-02 3:46 ` [PATCH v2 12/40] target/hexagon: Add guest, system reg number defs Brian Cain
2025-09-02 3:46 ` [PATCH v2 13/40] target/hexagon: Add guest, system reg number state Brian Cain
2025-09-02 3:46 ` [PATCH v2 14/40] target/hexagon: Add TCG values for sreg, greg Brian Cain
2025-09-02 3:46 ` [PATCH v2 15/40] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
2025-09-02 3:46 ` [PATCH v2 16/40] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
2025-09-02 3:46 ` [PATCH v2 17/40] target/hexagon: Define DCache states Brian Cain
2025-09-02 3:46 ` [PATCH v2 18/40] target/hexagon: Add new macro definitions for sysemu Brian Cain
2025-09-02 3:46 ` [PATCH v2 19/40] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
2025-09-02 3:46 ` [PATCH v2 20/40] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
2025-09-02 3:46 ` [PATCH v2 21/40] target/hexagon: Add vmstate representation Brian Cain
2025-09-02 3:46 ` [PATCH v2 22/40] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
2025-09-02 3:46 ` [PATCH v2 23/40] target/hexagon: Define register fields for system regs Brian Cain
2025-09-02 3:46 ` [PATCH v2 24/40] target/hexagon: Implement do_raise_exception() Brian Cain
2025-09-02 3:47 ` [PATCH v2 25/40] target/hexagon: Add system reg insns Brian Cain
2025-09-02 3:47 ` [PATCH v2 26/40] target/hexagon: Add sysemu TCG overrides Brian Cain
2025-09-02 3:47 ` [PATCH v2 27/40] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
2025-09-02 3:47 ` [PATCH v2 28/40] target/hexagon: Add TCG overrides for int handler insts Brian Cain
2025-09-02 3:47 ` [PATCH v2 29/40] target/hexagon: Add TCG overrides for thread ctl Brian Cain
2025-09-02 3:47 ` [PATCH v2 30/40] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
2025-09-02 3:47 ` [PATCH v2 31/40] target/hexagon: Add sreg_{read,write} helpers Brian Cain
2025-09-02 3:47 ` [PATCH v2 32/40] target/hexagon: Add locks, id, next_PC to state Brian Cain
2025-09-02 3:47 ` [PATCH v2 33/40] target/hexagon: Add a TLB count property Brian Cain
2025-09-02 3:47 ` [PATCH v2 34/40] target/hexagon: Add {TLB, k0}lock, cause code, wait_next_pc Brian Cain via
2025-09-02 3:47 ` [PATCH v2 35/40] target/hexagon: Add stubs for modify_ssr/get_exe_mode Brian Cain
2025-09-02 3:47 ` [PATCH v2 36/40] target/hexagon: Add gdb support for sys regs Brian Cain
2025-09-02 3:47 ` [PATCH v2 37/40] target/hexagon: Add initial MMU model Brian Cain
2025-09-02 3:47 ` [PATCH v2 38/40] target/hexagon: Add clear_wait_mode() definition Brian Cain
2025-09-02 3:47 ` [PATCH v2 39/40] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
2025-09-02 3:47 ` Brian Cain [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250902034715.1947718-41-brian.cain@oss.qualcomm.com \
--to=brian.cain@oss.qualcomm.com \
--cc=ale@rev.ng \
--cc=alex.bennee@linaro.org \
--cc=anjo@rev.ng \
--cc=bcain@quicinc.com \
--cc=ltaylorsimpson@gmail.com \
--cc=marco.liebel@oss.qualcomm.com \
--cc=matheus.bernardino@oss.qualcomm.com \
--cc=mlambert@quicinc.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=quic_mburton@quicinc.com \
--cc=richard.henderson@linaro.org \
--cc=sid.manning@oss.qualcomm.com \
--cc=sidneym@quicinc.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).