Re: [PATCH 09/11] target/hexagon: implement direct-to-guest interrupt delivery
Pierrick Bouvier <[email protected]>
| Newsgroups | org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
On 8/20/2026 2:59 PM, Brian Cain wrote: > > On 8/20/2026 1:57 PM, Pierrick Bouvier wrote: >> On 8/18/2026 6:31 PM, Brian Cain wrote: >>> Interrupts 3 through 5 are routed to guest mode when CCR:GIE and the >>> matching CCR:VV bit are set. Enter through GEVB rather than EVB, >>> record the pre-entry state in GSR and the return address in GELR, and >>> read the vector ID from the l2vic. >>> >>> Signed-off-by: Brian Cain <[email protected]> >>> --- >>> target/hexagon/reg_fields_def.h.inc | 7 +++ >>> target/hexagon/cpu.c | 5 ++ >>> target/hexagon/hex_interrupts.c | 87 ++++++++++++++++++++++++++--- >>> 3 files changed, 92 insertions(+), 7 deletions(-) >>> >>> diff --git a/target/hexagon/reg_fields_def.h.inc b/target/hexagon/ >>> reg_fields_def.h.inc >>> index d2c706d56b5..29497fbcc4d 100644 >>> --- a/target/hexagon/reg_fields_def.h.inc >>> +++ b/target/hexagon/reg_fields_def.h.inc >>> @@ -136,6 +136,13 @@ DEF_REG_FIELD(CCR_VV1, 29, 1) >>> DEF_REG_FIELD(CCR_VV2, 30, 1) >>> DEF_REG_FIELD(CCR_VV3, 31, 1) >>> +/* GSR fields */ >>> +DEF_REG_FIELD(GSR_CAUSE, 0, 16) >>> +DEF_REG_FIELD(GSR_CFI, 28, 1) >>> +DEF_REG_FIELD(GSR_SS, 29, 1) >>> +DEF_REG_FIELD(GSR_IE, 30, 1) >>> +DEF_REG_FIELD(GSR_UM, 31, 1) >>> + >>> /* ISDB ST fields */ >>> DEF_REG_FIELD(ISDBST_WAITRUN, 24, 8) >>> DEF_REG_FIELD(ISDBST_ONOFF, 16, 8) >>> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c >>> index 0a677840bcb..efaf569c6f8 100644 >>> --- a/target/hexagon/cpu.c >>> +++ b/target/hexagon/cpu.c >>> @@ -475,6 +475,11 @@ static void hexagon_cpu_realize(DeviceState >>> *dev, Error **errp) >>> error_setg(errp, "hexagon cpu requires 'tlb' link property >>> to be set"); >>> return; >>> } >>> + if (!HEXAGON_CPU(dev)->l2vic) { >>> + error_setg(errp, >>> + "hexagon cpu requires 'l2vic' link property to be >>> set"); >>> + return; >>> + } >>> #endif >>> qemu_init_vcpu(cs); >>> diff --git a/target/hexagon/hex_interrupts.c b/target/hexagon/ >>> hex_interrupts.c >>> index 3534481da24..ea1ba0903dd 100644 >>> --- a/target/hexagon/hex_interrupts.c >>> +++ b/target/hexagon/hex_interrupts.c >>> @@ -11,6 +11,7 @@ >>> #include "cpu_helper.h" >>> #include "exec/cpu-interrupt.h" >>> #include "hex_interrupts.h" >>> +#include "hw/intc/hex-l2vic.h" >>> #include "macros.h" >>> #include "sys_macros.h" >>> #include "system/cpus.h" >>> @@ -215,19 +216,75 @@ static void restore_state(CPUHexagonState *env, >>> bool int_accepted) >>> } >>> } >>> +static bool int_should_dtg(CPUHexagonState *env, int int_num) >>> +{ >> What does dtg means? > > "dtg" is "direct-to-guest" interrupts. This is an architectural feature > to raise interrupts directly in the guest instead of the monitor/VMM, > saving the latency of having to manually propagate interrupts to the guest. > > Maybe this is a good case for a clarifying comment on `int_should_dtg()`? > Yes it would help to add the paragraph above to describe what it is. >> >>> + uint32_t ccr = env->t_sreg[HEX_SREG_CCR]; >>> + >>> + switch (int_num) { >>> + case 3: >>> + if (!GET_FIELD(CCR_VV1, ccr)) { >>> + return false; >>> + } >>> + break; >>> + case 4: >>> + if (!GET_FIELD(CCR_VV2, ccr)) { >>> + return false; >>> + } >>> + break; >>> + case 5: >>> + if (!GET_FIELD(CCR_VV3, ccr)) { >>> + return false; >>> + } >>> + break; >>> + default: >>> + return false; >>> + } >>> + >>> + return GET_FIELD(CCR_GIE, ccr); >>> +} >>> + >>> +static void guest_interrupt_entry(CPUHexagonState *env, uint32_t cause, >>> + uint32_t event_pc) >>> +{ >>> + uint32_t old_ssr = env->t_sreg[HEX_SREG_SSR]; >>> + uint32_t new_ssr = old_ssr; >>> + uint32_t ccr = env->t_sreg[HEX_SREG_CCR]; >>> + uint32_t gsr = 0; >>> + >>> + gsr = deposit32(gsr, reg_field_info[GSR_CAUSE].offset, >>> + reg_field_info[GSR_CAUSE].width, cause); >>> + gsr = deposit32(gsr, reg_field_info[GSR_SS].offset, >>> + reg_field_info[GSR_SS].width, >>> + GET_SSR_FIELD(SSR_SS, old_ssr)); >>> + gsr = deposit32(gsr, reg_field_info[GSR_UM].offset, >>> + reg_field_info[GSR_UM].width, >>> + !GET_SSR_FIELD(SSR_GM, old_ssr)); >>> + gsr = deposit32(gsr, reg_field_info[GSR_IE].offset, >>> + reg_field_info[GSR_IE].width, >>> + GET_FIELD(CCR_GIE, ccr)); >>> + env->greg[HEX_GREG_GSR] = gsr; >>> + >>> + fSET_FIELD(new_ssr, SSR_SS, 0); >>> + fSET_FIELD(new_ssr, SSR_GM, 1); >>> + env->t_sreg[HEX_SREG_SSR] = new_ssr; >>> + hexagon_modify_ssr(env, new_ssr, old_ssr); >>> + >>> + SET_SYSTEM_FIELD(env, HEX_SREG_CCR, CCR_GIE, 0); >>> + env->greg[HEX_GREG_GELR] = event_pc; >>> + env->gpr[HEX_REG_PC] = env->t_sreg[HEX_SREG_GEVB] | >>> + (HEX_EVENT_INT0 << 2); >>> +} >>> + >>> static void hex_accept_int(CPUHexagonState *env, int int_num) >>> { >>> CPUState *cs = env_cpu(env); >>> HexagonCPU *cpu = env_archcpu(env); >>> - uint32_t evb = >>> - hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB, >>> - env->threadId); >>> const int exe_mode = get_exe_mode(env); >>> const bool in_wait_mode = exe_mode == HEX_EXE_MODE_WAIT; >>> + uint32_t elr; >>> 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); >>> @@ -235,15 +292,31 @@ static void hex_accept_int(CPUHexagonState >>> *env, int int_num) >>> 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); >>> + elr = 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]); >>> + elr = env->gpr[HEX_REG_PC]; >>> + } >>> + >>> + if (int_should_dtg(env, int_num)) { >>> + int vic_group = int_num - 2; >>> + uint32_t vid_packed = l2vic_read_vid(cpu->l2vic, vic_group / >>> 2); >>> + uint32_t vid = extract32(vid_packed, >>> + (vic_group & 1) ? 16 : 0, 16); >>> + >>> + guest_interrupt_entry(env, vid, elr); >>> + } else { >>> + uint32_t evb = >>> + hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB, >>> + env->threadId); >>> + >>> + set_ssr_ex_cause(env, 1, HEX_CAUSE_INT0 | int_num); >>> + set_elr(env, elr); >>> + env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2); >>> } >>> - env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2); >>> if (get_ipend(env) == 0) { >>> restore_state(env, true); >>> }