Re: [PATCH v11 18/23] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()

2024-04-03 Thread Peter Maydell
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()

2024-04-02 Thread Jinjie Ruan via



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()

2024-04-02 Thread Jinjie Ruan via



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()

2024-04-02 Thread Peter Maydell
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()

2024-03-30 Thread Jinjie Ruan via
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 {
+