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);
>>>       }


Reply via email to