Re: [PATCH v11 18/23] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
On Wed, 3 Apr 2024 at 04:16, Jinjie Ruan wrote: > On 2024/4/3 0:12, Peter Maydell wrote: > >> @@ -776,7 +811,11 @@ static uint64_t icv_iar_read(CPUARMState *env, const > >> ARMCPRegInfo *ri) > >> if (thisgrp == grp && icv_hppi_can_preempt(cs, lr)) { > >> intid = ich_lr_vintid(lr); > >> if (!gicv3_intid_is_special(intid)) { > >> -icv_activate_irq(cs, idx, grp); > >> +if (!(lr & ICH_LR_EL2_NMI)) { > > > > This is missing checks on both whether the GIC has NMI support and > > on whether the SCTLR NMI bit is set (compare pseudocode > > VirtualReadIAR1()). I suggest defining a > > > > bool nmi = cs->gic->nmi_support && > > (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_NMI) && > > (lr & ICH_LR_EL2_NMI); > > The nmi_support check is redundant, as if FEAT_GICv3_NMI is unsupported, > the ICH_LR_EL2.NMI is RES0, so if ICH_LR_EL2.NMI is 1, FEAT_GICv3_NMI > has been surely realized. As far as I can see you haven't changed ich_lr_write() to enforce that, though, so the guest can write 1 to the NMI bit even if the GIC doesn't support FEAT_GICv3_NMI. If you want to skip checking nmi_support here you need to enforce that the NMI bit in the LR is 0 in ich_lr_write(). thanks -- PMM
Re: [PATCH v11 18/23] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
On 2024/4/3 0:12, Peter Maydell wrote: > On Sat, 30 Mar 2024 at 10:33, Jinjie Ruan wrote: >> >> Implement icv_nmiar1_read() for icc_nmiar1_read(), so add definition for >> ICH_LR_EL2.NMI and ICH_AP1R_EL2.NMI bit. >> >> If FEAT_GICv3_NMI is supported, ich_ap_write() should consider >> ICV_AP1R_EL1.NMI >> bit. In icv_activate_irq() and icv_eoir_write(), the ICV_AP1R_EL1.NMI bit >> should be set or clear according to the Non-maskable property. And the RPR >> priority should also update the NMI bit according to the APR priority NMI >> bit. >> >> By the way, add gicv3_icv_nmiar1_read trace event. >> >> If the hpp irq is a NMI, the icv iar read should return 1022 and trap for >> NMI again >> >> Signed-off-by: Jinjie Ruan >> Reviewed-by: Richard Henderson >> --- >> v11: >> - Deal with NMI in the callers instead of ich_highest_active_virt_prio(). >> - Set either NMI or a group-priority bit, not both. >> - Only set AP NMI bits in the 0 reg. >> - Handle NMI in hppvi_index(), icv_hppi_can_preempt() and icv_eoir_write(). >> v10: >> - Rename ICH_AP1R_EL2_NMI to ICV_AP1R_EL1_NMI. >> - Add ICV_RPR_EL1_NMI definition. >> - Set ICV_RPR_EL1.NMI according to the ICV_AP1R_EL1.NMI in >> ich_highest_active_virt_prio(). >> v9: >> - Correct the INTID_NMI logic. >> v8: >> - Fix an unexpected interrupt bug when sending VNMI by running qemu VM. >> v7: >> - Add Reviewed-by. >> v6: >> - Implement icv_nmiar1_read(). >> --- >> hw/intc/arm_gicv3_cpuif.c | 97 ++- >> hw/intc/gicv3_internal.h | 4 ++ >> hw/intc/trace-events | 1 + >> 3 files changed, 91 insertions(+), 11 deletions(-) >> >> diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c >> index f99f2570a6..a7bc44b30c 100644 >> --- a/hw/intc/arm_gicv3_cpuif.c >> +++ b/hw/intc/arm_gicv3_cpuif.c >> @@ -157,6 +157,10 @@ static int ich_highest_active_virt_prio(GICv3CPUState >> *cs) >> int i; >> int aprmax = ich_num_aprs(cs); >> >> +if (cs->gic->nmi_support && cs->ich_apr[GICV3_G1NS][0] & >> ICV_AP1R_EL1_NMI) { >> +return 0x80; > > This should be 0, not 0x80 -- see the register description for > ICH_LR_EL2 Priority field: when NMI is 1, the virtual interrupt's > priority is treated as 0x0. > >> +} >> + >> for (i = 0; i < aprmax; i++) { >> uint32_t apr = cs->ich_apr[GICV3_G0][i] | >> cs->ich_apr[GICV3_G1NS][i]; >> @@ -191,6 +195,7 @@ static int hppvi_index(GICv3CPUState *cs) >> * correct behaviour. >> */ >> int prio = 0xff; >> +bool nmi = false; >> >> if (!(cs->ich_vmcr_el2 & (ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1))) { >> /* Both groups disabled, definitely nothing to do */ >> @@ -200,6 +205,11 @@ static int hppvi_index(GICv3CPUState *cs) >> for (i = 0; i < cs->num_list_regs; i++) { >> uint64_t lr = cs->ich_lr_el2[i]; >> int thisprio; >> +bool thisnmi = false; >> + >> +if (cs->gic->nmi_support) { >> +thisnmi = lr & ICH_LR_EL2_NMI; >> +} > > You could write this a little more concisely as > bool thisnmi = cs->gic_nmi_support && (lr & ICH_LR_EL2_NMI); > >> if (ich_lr_state(lr) != ICH_LR_EL2_STATE_PENDING) { >> /* Not Pending */ >> @@ -219,9 +229,13 @@ static int hppvi_index(GICv3CPUState *cs) >> >> thisprio = ich_lr_prio(lr); >> >> -if (thisprio < prio) { >> +if ((thisprio < prio) || ((thisprio == prio) && (thisnmi & >> (!nmi { >> prio = thisprio; >> idx = i; >> + >> +if (cs->gic->nmi_support) { >> +nmi = thisnmi; >> +} > > You don't need to check nmi_support here because if nmi_support > is false then thisnmi will also be false, and so we will never > set nmi to anything other than false. > >> } >> } >> >> @@ -326,6 +340,12 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, >> uint64_t lr) >> return true; >> } >> >> +if ((prio & mask) == (rprio & mask) && >> +cs->gic->nmi_support && (lr & ICH_LR_EL2_NMI) && >> +(!(cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI))) { >> +return true; >> +} >> + >> return false; >> } > > This isn't the only change needed to icv_hppi_can_preempt(): > virtual NMIs are never masked by the MPR, so that check also > must be changed. If we pull out a variable: > > bool is_nmi = cs->gic->nmi_support && (lr & ICH_LR_EL2_NMI); > > we can use that both to gate the vpmr check: > > if (!is_nmi && prio >= vpmr) { > > and also in the priority check you have here. > >> @@ -736,13 +765,19 @@ static void icv_activate_irq(GICv3CPUState *cs, int >> idx, int grp) >> */ >> uint32_t mask = icv_gprio_mask(cs, grp); >> int prio = ich_lr_prio(cs->ich_lr_el2[idx]) & mask; >> +bool nmi = cs->ich_lr_el2[idx] & ICH_LR_EL2_NMI; >> int aprbit = prio >> (8 - cs->vprebits); >> int regno = aprbit / 32; >> int regbit = aprbit % 32;
Re: [PATCH v11 18/23] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
On 2024/4/3 0:12, Peter Maydell wrote: > On Sat, 30 Mar 2024 at 10:33, Jinjie Ruan wrote: >> >> Implement icv_nmiar1_read() for icc_nmiar1_read(), so add definition for >> ICH_LR_EL2.NMI and ICH_AP1R_EL2.NMI bit. >> >> If FEAT_GICv3_NMI is supported, ich_ap_write() should consider >> ICV_AP1R_EL1.NMI >> bit. In icv_activate_irq() and icv_eoir_write(), the ICV_AP1R_EL1.NMI bit >> should be set or clear according to the Non-maskable property. And the RPR >> priority should also update the NMI bit according to the APR priority NMI >> bit. >> >> By the way, add gicv3_icv_nmiar1_read trace event. >> >> If the hpp irq is a NMI, the icv iar read should return 1022 and trap for >> NMI again >> >> Signed-off-by: Jinjie Ruan >> Reviewed-by: Richard Henderson >> --- >> v11: >> - Deal with NMI in the callers instead of ich_highest_active_virt_prio(). >> - Set either NMI or a group-priority bit, not both. >> - Only set AP NMI bits in the 0 reg. >> - Handle NMI in hppvi_index(), icv_hppi_can_preempt() and icv_eoir_write(). >> v10: >> - Rename ICH_AP1R_EL2_NMI to ICV_AP1R_EL1_NMI. >> - Add ICV_RPR_EL1_NMI definition. >> - Set ICV_RPR_EL1.NMI according to the ICV_AP1R_EL1.NMI in >> ich_highest_active_virt_prio(). >> v9: >> - Correct the INTID_NMI logic. >> v8: >> - Fix an unexpected interrupt bug when sending VNMI by running qemu VM. >> v7: >> - Add Reviewed-by. >> v6: >> - Implement icv_nmiar1_read(). >> --- >> hw/intc/arm_gicv3_cpuif.c | 97 ++- >> hw/intc/gicv3_internal.h | 4 ++ >> hw/intc/trace-events | 1 + >> 3 files changed, 91 insertions(+), 11 deletions(-) >> >> diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c >> index f99f2570a6..a7bc44b30c 100644 >> --- a/hw/intc/arm_gicv3_cpuif.c >> +++ b/hw/intc/arm_gicv3_cpuif.c >> @@ -157,6 +157,10 @@ static int ich_highest_active_virt_prio(GICv3CPUState >> *cs) >> int i; >> int aprmax = ich_num_aprs(cs); >> >> +if (cs->gic->nmi_support && cs->ich_apr[GICV3_G1NS][0] & >> ICV_AP1R_EL1_NMI) { >> +return 0x80; > > This should be 0, not 0x80 -- see the register description for > ICH_LR_EL2 Priority field: when NMI is 1, the virtual interrupt's > priority is treated as 0x0. > >> +} >> + >> for (i = 0; i < aprmax; i++) { >> uint32_t apr = cs->ich_apr[GICV3_G0][i] | >> cs->ich_apr[GICV3_G1NS][i]; >> @@ -191,6 +195,7 @@ static int hppvi_index(GICv3CPUState *cs) >> * correct behaviour. >> */ >> int prio = 0xff; >> +bool nmi = false; >> >> if (!(cs->ich_vmcr_el2 & (ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1))) { >> /* Both groups disabled, definitely nothing to do */ >> @@ -200,6 +205,11 @@ static int hppvi_index(GICv3CPUState *cs) >> for (i = 0; i < cs->num_list_regs; i++) { >> uint64_t lr = cs->ich_lr_el2[i]; >> int thisprio; >> +bool thisnmi = false; >> + >> +if (cs->gic->nmi_support) { >> +thisnmi = lr & ICH_LR_EL2_NMI; >> +} > > You could write this a little more concisely as > bool thisnmi = cs->gic_nmi_support && (lr & ICH_LR_EL2_NMI); If the following if check continues, the operations are unnecessary, so I think it's more appropriate to put it as thisprio operations do it. > >> if (ich_lr_state(lr) != ICH_LR_EL2_STATE_PENDING) { >> /* Not Pending */ >> @@ -219,9 +229,13 @@ static int hppvi_index(GICv3CPUState *cs) >> >> thisprio = ich_lr_prio(lr); >> >> -if (thisprio < prio) { >> +if ((thisprio < prio) || ((thisprio == prio) && (thisnmi & >> (!nmi { >> prio = thisprio; >> idx = i; >> + >> +if (cs->gic->nmi_support) { >> +nmi = thisnmi; >> +} > > You don't need to check nmi_support here because if nmi_support > is false then thisnmi will also be false, and so we will never > set nmi to anything other than false. > >> } >> } >> >> @@ -326,6 +340,12 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, >> uint64_t lr) >> return true; >> } >> >> +if ((prio & mask) == (rprio & mask) && >> +cs->gic->nmi_support && (lr & ICH_LR_EL2_NMI) && >> +(!(cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI))) { >> +return true; >> +} >> + >> return false; >> } > > This isn't the only change needed to icv_hppi_can_preempt(): > virtual NMIs are never masked by the MPR, so that check also > must be changed. If we pull out a variable: > > bool is_nmi = cs->gic->nmi_support && (lr & ICH_LR_EL2_NMI); > > we can use that both to gate the vpmr check: > > if (!is_nmi && prio >= vpmr) { > > and also in the priority check you have here. > >> @@ -736,13 +765,19 @@ static void icv_activate_irq(GICv3CPUState *cs, int >> idx, int grp) >> */ >> uint32_t mask = icv_gprio_mask(cs, grp); >> int prio = ich_lr_prio(cs->ich_lr_el2[idx]) & mask; >> +bool nmi =
Re: [PATCH v11 18/23] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
On Sat, 30 Mar 2024 at 10:33, Jinjie Ruan wrote: > > Implement icv_nmiar1_read() for icc_nmiar1_read(), so add definition for > ICH_LR_EL2.NMI and ICH_AP1R_EL2.NMI bit. > > If FEAT_GICv3_NMI is supported, ich_ap_write() should consider > ICV_AP1R_EL1.NMI > bit. In icv_activate_irq() and icv_eoir_write(), the ICV_AP1R_EL1.NMI bit > should be set or clear according to the Non-maskable property. And the RPR > priority should also update the NMI bit according to the APR priority NMI bit. > > By the way, add gicv3_icv_nmiar1_read trace event. > > If the hpp irq is a NMI, the icv iar read should return 1022 and trap for > NMI again > > Signed-off-by: Jinjie Ruan > Reviewed-by: Richard Henderson > --- > v11: > - Deal with NMI in the callers instead of ich_highest_active_virt_prio(). > - Set either NMI or a group-priority bit, not both. > - Only set AP NMI bits in the 0 reg. > - Handle NMI in hppvi_index(), icv_hppi_can_preempt() and icv_eoir_write(). > v10: > - Rename ICH_AP1R_EL2_NMI to ICV_AP1R_EL1_NMI. > - Add ICV_RPR_EL1_NMI definition. > - Set ICV_RPR_EL1.NMI according to the ICV_AP1R_EL1.NMI in > ich_highest_active_virt_prio(). > v9: > - Correct the INTID_NMI logic. > v8: > - Fix an unexpected interrupt bug when sending VNMI by running qemu VM. > v7: > - Add Reviewed-by. > v6: > - Implement icv_nmiar1_read(). > --- > hw/intc/arm_gicv3_cpuif.c | 97 ++- > hw/intc/gicv3_internal.h | 4 ++ > hw/intc/trace-events | 1 + > 3 files changed, 91 insertions(+), 11 deletions(-) > > diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c > index f99f2570a6..a7bc44b30c 100644 > --- a/hw/intc/arm_gicv3_cpuif.c > +++ b/hw/intc/arm_gicv3_cpuif.c > @@ -157,6 +157,10 @@ static int ich_highest_active_virt_prio(GICv3CPUState > *cs) > int i; > int aprmax = ich_num_aprs(cs); > > +if (cs->gic->nmi_support && cs->ich_apr[GICV3_G1NS][0] & > ICV_AP1R_EL1_NMI) { > +return 0x80; This should be 0, not 0x80 -- see the register description for ICH_LR_EL2 Priority field: when NMI is 1, the virtual interrupt's priority is treated as 0x0. > +} > + > for (i = 0; i < aprmax; i++) { > uint32_t apr = cs->ich_apr[GICV3_G0][i] | > cs->ich_apr[GICV3_G1NS][i]; > @@ -191,6 +195,7 @@ static int hppvi_index(GICv3CPUState *cs) > * correct behaviour. > */ > int prio = 0xff; > +bool nmi = false; > > if (!(cs->ich_vmcr_el2 & (ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1))) { > /* Both groups disabled, definitely nothing to do */ > @@ -200,6 +205,11 @@ static int hppvi_index(GICv3CPUState *cs) > for (i = 0; i < cs->num_list_regs; i++) { > uint64_t lr = cs->ich_lr_el2[i]; > int thisprio; > +bool thisnmi = false; > + > +if (cs->gic->nmi_support) { > +thisnmi = lr & ICH_LR_EL2_NMI; > +} You could write this a little more concisely as bool thisnmi = cs->gic_nmi_support && (lr & ICH_LR_EL2_NMI); > if (ich_lr_state(lr) != ICH_LR_EL2_STATE_PENDING) { > /* Not Pending */ > @@ -219,9 +229,13 @@ static int hppvi_index(GICv3CPUState *cs) > > thisprio = ich_lr_prio(lr); > > -if (thisprio < prio) { > +if ((thisprio < prio) || ((thisprio == prio) && (thisnmi & (!nmi > { > prio = thisprio; > idx = i; > + > +if (cs->gic->nmi_support) { > +nmi = thisnmi; > +} You don't need to check nmi_support here because if nmi_support is false then thisnmi will also be false, and so we will never set nmi to anything other than false. > } > } > > @@ -326,6 +340,12 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, > uint64_t lr) > return true; > } > > +if ((prio & mask) == (rprio & mask) && > +cs->gic->nmi_support && (lr & ICH_LR_EL2_NMI) && > +(!(cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI))) { > +return true; > +} > + > return false; > } This isn't the only change needed to icv_hppi_can_preempt(): virtual NMIs are never masked by the MPR, so that check also must be changed. If we pull out a variable: bool is_nmi = cs->gic->nmi_support && (lr & ICH_LR_EL2_NMI); we can use that both to gate the vpmr check: if (!is_nmi && prio >= vpmr) { and also in the priority check you have here. > @@ -736,13 +765,19 @@ static void icv_activate_irq(GICv3CPUState *cs, int > idx, int grp) > */ > uint32_t mask = icv_gprio_mask(cs, grp); > int prio = ich_lr_prio(cs->ich_lr_el2[idx]) & mask; > +bool nmi = cs->ich_lr_el2[idx] & ICH_LR_EL2_NMI; > int aprbit = prio >> (8 - cs->vprebits); > int regno = aprbit / 32; > int regbit = aprbit % 32; > > cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT; > cs->ich_lr_el2[idx] |= ICH_LR_EL2_STATE_ACTIVE_BIT; > -cs->ich_apr[grp][regno] |= (1 << regbit); > + > +if (cs->gic->nmi_support && nmi) { >
[PATCH v11 18/23] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
Implement icv_nmiar1_read() for icc_nmiar1_read(), so add definition for ICH_LR_EL2.NMI and ICH_AP1R_EL2.NMI bit. If FEAT_GICv3_NMI is supported, ich_ap_write() should consider ICV_AP1R_EL1.NMI bit. In icv_activate_irq() and icv_eoir_write(), the ICV_AP1R_EL1.NMI bit should be set or clear according to the Non-maskable property. And the RPR priority should also update the NMI bit according to the APR priority NMI bit. By the way, add gicv3_icv_nmiar1_read trace event. If the hpp irq is a NMI, the icv iar read should return 1022 and trap for NMI again Signed-off-by: Jinjie Ruan Reviewed-by: Richard Henderson --- v11: - Deal with NMI in the callers instead of ich_highest_active_virt_prio(). - Set either NMI or a group-priority bit, not both. - Only set AP NMI bits in the 0 reg. - Handle NMI in hppvi_index(), icv_hppi_can_preempt() and icv_eoir_write(). v10: - Rename ICH_AP1R_EL2_NMI to ICV_AP1R_EL1_NMI. - Add ICV_RPR_EL1_NMI definition. - Set ICV_RPR_EL1.NMI according to the ICV_AP1R_EL1.NMI in ich_highest_active_virt_prio(). v9: - Correct the INTID_NMI logic. v8: - Fix an unexpected interrupt bug when sending VNMI by running qemu VM. v7: - Add Reviewed-by. v6: - Implement icv_nmiar1_read(). --- hw/intc/arm_gicv3_cpuif.c | 97 ++- hw/intc/gicv3_internal.h | 4 ++ hw/intc/trace-events | 1 + 3 files changed, 91 insertions(+), 11 deletions(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index f99f2570a6..a7bc44b30c 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -157,6 +157,10 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs) int i; int aprmax = ich_num_aprs(cs); +if (cs->gic->nmi_support && cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI) { +return 0x80; +} + for (i = 0; i < aprmax; i++) { uint32_t apr = cs->ich_apr[GICV3_G0][i] | cs->ich_apr[GICV3_G1NS][i]; @@ -191,6 +195,7 @@ static int hppvi_index(GICv3CPUState *cs) * correct behaviour. */ int prio = 0xff; +bool nmi = false; if (!(cs->ich_vmcr_el2 & (ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1))) { /* Both groups disabled, definitely nothing to do */ @@ -200,6 +205,11 @@ static int hppvi_index(GICv3CPUState *cs) for (i = 0; i < cs->num_list_regs; i++) { uint64_t lr = cs->ich_lr_el2[i]; int thisprio; +bool thisnmi = false; + +if (cs->gic->nmi_support) { +thisnmi = lr & ICH_LR_EL2_NMI; +} if (ich_lr_state(lr) != ICH_LR_EL2_STATE_PENDING) { /* Not Pending */ @@ -219,9 +229,13 @@ static int hppvi_index(GICv3CPUState *cs) thisprio = ich_lr_prio(lr); -if (thisprio < prio) { +if ((thisprio < prio) || ((thisprio == prio) && (thisnmi & (!nmi { prio = thisprio; idx = i; + +if (cs->gic->nmi_support) { +nmi = thisnmi; +} } } @@ -326,6 +340,12 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr) return true; } +if ((prio & mask) == (rprio & mask) && +cs->gic->nmi_support && (lr & ICH_LR_EL2_NMI) && +(!(cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI))) { +return true; +} + return false; } @@ -550,7 +570,11 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icv_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value); -cs->ich_apr[grp][regno] = value & 0xU; +if (cs->gic->nmi_support) { +cs->ich_apr[grp][regno] = value & (0xU | ICV_AP1R_EL1_NMI); +} else { +cs->ich_apr[grp][regno] = value & 0xU; +} gicv3_cpuif_virt_irq_fiq_update(cs); return; @@ -697,7 +721,12 @@ static void icv_ctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, static uint64_t icv_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); -int prio = ich_highest_active_virt_prio(cs); +uint64_t prio = ich_highest_active_virt_prio(cs); + +if (cs->gic->nmi_support && +cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI) { +prio |= ICV_RPR_EL1_NMI; +} trace_gicv3_icv_rpr_read(gicv3_redist_affid(cs), prio); return prio; @@ -736,13 +765,19 @@ static void icv_activate_irq(GICv3CPUState *cs, int idx, int grp) */ uint32_t mask = icv_gprio_mask(cs, grp); int prio = ich_lr_prio(cs->ich_lr_el2[idx]) & mask; +bool nmi = cs->ich_lr_el2[idx] & ICH_LR_EL2_NMI; int aprbit = prio >> (8 - cs->vprebits); int regno = aprbit / 32; int regbit = aprbit % 32; cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT; cs->ich_lr_el2[idx] |= ICH_LR_EL2_STATE_ACTIVE_BIT; -cs->ich_apr[grp][regno] |= (1 << regbit); + +if (cs->gic->nmi_support && nmi) { +cs->ich_apr[grp][regno] |= ICV_AP1R_EL1_NMI; +} else { +