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);
>>>       }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.