* [PATCH v13 01/24] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 02/24] target/arm: Add PSTATE.ALLINT Jinjie Ruan via
` (24 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
FEAT_NMI defines another three new bits in HCRX_EL2: TALLINT, HCRX_VINMI and
HCRX_VFNMI. When the feature is enabled, allow these bits to be written in
HCRX_EL2.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v12:
- Remove the redundant blank line.
v9:
- Declare cpu variable to reuse latter.
v4:
- Update the comment for FEAT_NMI in hcrx_write().
- Update the commit message, s/thress/three/g.
v3:
- Add Reviewed-by.
- Add HCRX_VINMI and HCRX_VFNMI support in HCRX_EL2.
- Upate the commit messsage.
---
target/arm/cpu-features.h | 5 +++++
target/arm/helper.c | 8 +++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index e5758d9fbc..b300d0446d 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -681,6 +681,11 @@ static inline bool isar_feature_aa64_sme(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0;
}
+static inline bool isar_feature_aa64_nmi(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, NMI) != 0;
+}
+
static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id)
{
return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 1;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3f3a5b55d4..408922c94d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6183,13 +6183,19 @@ bool el_is_in_host(CPUARMState *env, int el)
static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ ARMCPU *cpu = env_archcpu(env);
uint64_t valid_mask = 0;
/* FEAT_MOPS adds MSCEn and MCE2 */
- if (cpu_isar_feature(aa64_mops, env_archcpu(env))) {
+ if (cpu_isar_feature(aa64_mops, cpu)) {
valid_mask |= HCRX_MSCEN | HCRX_MCE2;
}
+ /* FEAT_NMI adds TALLINT, VINMI and VFNMI */
+ if (cpu_isar_feature(aa64_nmi, cpu)) {
+ valid_mask |= HCRX_TALLINT | HCRX_VINMI | HCRX_VFNMI;
+ }
+
/* Clear RES0 bits. */
env->cp15.hcrx_el2 = value & valid_mask;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 02/24] target/arm: Add PSTATE.ALLINT
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 01/24] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 03/24] target/arm: Add support for FEAT_NMI, Non-maskable Interrupt Jinjie Ruan via
` (23 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
When PSTATE.ALLINT is set, an IRQ or FIQ interrupt that is targeted to
ELx, with or without superpriority is masked. As Richard suggested, place
ALLINT bit in PSTATE in env->pstate.
In the pseudocode, AArch64.ExceptionReturn() calls SetPSTATEFromPSR(), which
treats PSTATE.ALLINT as one of the bits which are reinstated from SPSR to
PSTATE regardless of whether this is an illegal exception return or not. So
handle PSTATE.ALLINT the same way as PSTATE.DAIF in the illegal_return exit
path of the exception_return helper. With the change, exception entry and
return are automatically handled.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Handle PSTATE.ALLINT the same way as PSTATE.DAIF in the illegal_return
exit path.
- Update the commit message.
- Add Reviewed-by.
v5:
- Remove the ALLINT comment, as it is covered by "all other bits".
- Add Reviewed-by.
v4:
- Keep PSTATE.ALLINT in env->pstate but not env->allint.
- Update the commit message.
v3:
- Remove ALLINT dump in aarch64_cpu_dump_state().
- Update the commit message.
---
target/arm/cpu.h | 1 +
target/arm/tcg/helper-a64.c | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index bc0c84873f..de740d223f 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1430,6 +1430,7 @@ void pmu_init(ARMCPU *cpu);
#define PSTATE_D (1U << 9)
#define PSTATE_BTYPE (3U << 10)
#define PSTATE_SSBS (1U << 12)
+#define PSTATE_ALLINT (1U << 13)
#define PSTATE_IL (1U << 20)
#define PSTATE_SS (1U << 21)
#define PSTATE_PAN (1U << 22)
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
index ebaa7f00df..29f3ef274a 100644
--- a/target/arm/tcg/helper-a64.c
+++ b/target/arm/tcg/helper-a64.c
@@ -892,8 +892,8 @@ illegal_return:
*/
env->pstate |= PSTATE_IL;
env->pc = new_pc;
- spsr &= PSTATE_NZCV | PSTATE_DAIF;
- spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
+ spsr &= PSTATE_NZCV | PSTATE_DAIF | PSTATE_ALLINT;
+ spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF | PSTATE_ALLINT);
pstate_write(env, spsr);
if (!arm_singlestep_active(env)) {
env->pstate &= ~PSTATE_SS;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 03/24] target/arm: Add support for FEAT_NMI, Non-maskable Interrupt
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 01/24] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 02/24] target/arm: Add PSTATE.ALLINT Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 04/24] target/arm: Implement ALLINT MSR (immediate) Jinjie Ruan via
` (22 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Add support for FEAT_NMI. NMI (FEAT_NMI) is an mandatory feature in
ARMv8.8-A and ARM v9.3-A.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v3:
- Add Reviewed-by.
- Adjust to before the MSR patches.
---
target/arm/internals.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index dd3da211a3..516e0584bf 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1229,6 +1229,9 @@ static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id)
if (isar_feature_aa64_mte(id)) {
valid |= PSTATE_TCO;
}
+ if (isar_feature_aa64_nmi(id)) {
+ valid |= PSTATE_ALLINT;
+ }
return valid;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 04/24] target/arm: Implement ALLINT MSR (immediate)
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (2 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 03/24] target/arm: Add support for FEAT_NMI, Non-maskable Interrupt Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 05/24] target/arm: Support MSR access to ALLINT Jinjie Ruan via
` (21 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Add ALLINT MSR (immediate) to decodetree, in which the CRm is 0b000x. The
EL0 check is necessary to ALLINT, and the EL1 check is necessary when
imm == 1. So implement it inline for EL2/3, or EL1 with imm==0. Avoid the
unconditional write to pc and use raise_exception_ra to unwind.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v10:
- Correct the exception_target_el(env) to 2, since it is a hypervisor trap
from EL1 to EL2.
v7:
- Add Reviewed-by.
v6:
- Fix DISAS_TOO_MANY to DISAS_UPDATE_EXIT and add the comment.
v5:
- Drop the & 1 in trans_MSR_i_ALLINT().
- Simplify and merge msr_i_allint() and allint_check().
- Rename msr_i_allint() to msr_set_allint_el1().
v4:
- Fix the ALLINT MSR (immediate) decodetree implementation.
- Remove arm_is_el2_enabled() check in allint_check().
- Update env->allint to env->pstate.
- Only call allint_check() when imm == 1.
- Simplify the allint_check() to not pass "op" and extract.
- Implement it inline for EL2/3, or EL1 with imm==0.
- Pass (a->imm & 1) * PSTATE_ALLINT (i64) to simplfy the ALLINT set/clear.
v3:
- Remove EL0 check in allint_check().
- Add TALLINT check for EL1 in allint_check().
- Remove unnecessarily arm_rebuild_hflags() in msr_i_allint helper.
---
target/arm/tcg/a64.decode | 1 +
target/arm/tcg/helper-a64.c | 12 ++++++++++++
target/arm/tcg/helper-a64.h | 1 +
target/arm/tcg/translate-a64.c | 19 +++++++++++++++++++
4 files changed, 33 insertions(+)
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 8a20dce3c8..0e7656fd15 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -207,6 +207,7 @@ MSR_i_DIT 1101 0101 0000 0 011 0100 .... 010 11111 @msr_i
MSR_i_TCO 1101 0101 0000 0 011 0100 .... 100 11111 @msr_i
MSR_i_DAIFSET 1101 0101 0000 0 011 0100 .... 110 11111 @msr_i
MSR_i_DAIFCLEAR 1101 0101 0000 0 011 0100 .... 111 11111 @msr_i
+MSR_i_ALLINT 1101 0101 0000 0 001 0100 000 imm:1 000 11111
MSR_i_SVCR 1101 0101 0000 0 011 0100 0 mask:2 imm:1 011 11111
# MRS, MSR (register), SYS, SYSL. These are all essentially the
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
index 29f3ef274a..0ea8668ab4 100644
--- a/target/arm/tcg/helper-a64.c
+++ b/target/arm/tcg/helper-a64.c
@@ -66,6 +66,18 @@ void HELPER(msr_i_spsel)(CPUARMState *env, uint32_t imm)
update_spsel(env, imm);
}
+void HELPER(msr_set_allint_el1)(CPUARMState *env)
+{
+ /* ALLINT update to PSTATE. */
+ if (arm_hcrx_el2_eff(env) & HCRX_TALLINT) {
+ raise_exception_ra(env, EXCP_UDEF,
+ syn_aa64_sysregtrap(0, 1, 0, 4, 1, 0x1f, 0), 2,
+ GETPC());
+ }
+
+ env->pstate |= PSTATE_ALLINT;
+}
+
static void daif_check(CPUARMState *env, uint32_t op,
uint32_t imm, uintptr_t ra)
{
diff --git a/target/arm/tcg/helper-a64.h b/target/arm/tcg/helper-a64.h
index 575a5dab7d..0518165399 100644
--- a/target/arm/tcg/helper-a64.h
+++ b/target/arm/tcg/helper-a64.h
@@ -22,6 +22,7 @@ DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_2(msr_i_spsel, void, env, i32)
DEF_HELPER_2(msr_i_daifset, void, env, i32)
DEF_HELPER_2(msr_i_daifclear, void, env, i32)
+DEF_HELPER_1(msr_set_allint_el1, void, env)
DEF_HELPER_3(vfp_cmph_a64, i64, f16, f16, ptr)
DEF_HELPER_3(vfp_cmpeh_a64, i64, f16, f16, ptr)
DEF_HELPER_3(vfp_cmps_a64, i64, f32, f32, ptr)
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 340265beb0..21758b290d 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2036,6 +2036,25 @@ static bool trans_MSR_i_DAIFCLEAR(DisasContext *s, arg_i *a)
return true;
}
+static bool trans_MSR_i_ALLINT(DisasContext *s, arg_i *a)
+{
+ if (!dc_isar_feature(aa64_nmi, s) || s->current_el == 0) {
+ return false;
+ }
+
+ if (a->imm == 0) {
+ clear_pstate_bits(PSTATE_ALLINT);
+ } else if (s->current_el > 1) {
+ set_pstate_bits(PSTATE_ALLINT);
+ } else {
+ gen_helper_msr_set_allint_el1(tcg_env);
+ }
+
+ /* Exit the cpu loop to re-evaluate pending IRQs. */
+ s->base.is_jmp = DISAS_UPDATE_EXIT;
+ return true;
+}
+
static bool trans_MSR_i_SVCR(DisasContext *s, arg_MSR_i_SVCR *a)
{
if (!dc_isar_feature(aa64_sme, s) || a->mask == 0) {
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 05/24] target/arm: Support MSR access to ALLINT
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (3 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 04/24] target/arm: Implement ALLINT MSR (immediate) Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 06/24] target/arm: Add support for Non-maskable Interrupt Jinjie Ruan via
` (20 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Support ALLINT msr access as follow:
mrs <xt>, ALLINT // read allint
msr ALLINT, <xt> // write allint with imm
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v9:
- Move nmi_reginfo and related functions inside an existing ifdef
TARGET_AARCH64 to solve the --target-list=aarch64-softmmu,arm-softmmu
compilation problem.
- Check 'isread' when writing to ALLINT.
v5:
- Add Reviewed-by.
v4:
- Remove arm_is_el2_enabled() check in allint_check().
- Change to env->pstate instead of env->allint.
v3:
- Remove EL0 check in aa64_allint_access() which alreay checks in .access
PL1_RW.
- Use arm_hcrx_el2_eff() in aa64_allint_access() instead of env->cp15.hcrx_el2.
- Make ALLINT msr access function controlled by aa64_nmi.
---
target/arm/helper.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 408922c94d..5ed3eacbea 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7496,6 +7496,37 @@ static const ARMCPRegInfo rme_mte_reginfo[] = {
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 14, .opc2 = 5,
.access = PL3_W, .type = ARM_CP_NOP },
};
+
+static void aa64_allint_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ env->pstate = (env->pstate & ~PSTATE_ALLINT) | (value & PSTATE_ALLINT);
+}
+
+static uint64_t aa64_allint_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return env->pstate & PSTATE_ALLINT;
+}
+
+static CPAccessResult aa64_allint_access(CPUARMState *env,
+ const ARMCPRegInfo *ri, bool isread)
+{
+ if (!isread && arm_current_el(env) == 1 &&
+ (arm_hcrx_el2_eff(env) & HCRX_TALLINT)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return CP_ACCESS_OK;
+}
+
+static const ARMCPRegInfo nmi_reginfo[] = {
+ { .name = "ALLINT", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .opc2 = 0, .crn = 4, .crm = 3,
+ .type = ARM_CP_NO_RAW,
+ .access = PL1_RW, .accessfn = aa64_allint_access,
+ .fieldoffset = offsetof(CPUARMState, pstate),
+ .writefn = aa64_allint_write, .readfn = aa64_allint_read,
+ .resetfn = arm_cp_reset_ignore },
+};
#endif /* TARGET_AARCH64 */
static void define_pmu_regs(ARMCPU *cpu)
@@ -9890,6 +9921,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (cpu_isar_feature(aa64_nv2, cpu)) {
define_arm_cp_regs(cpu, nv2_reginfo);
}
+
+ if (cpu_isar_feature(aa64_nmi, cpu)) {
+ define_arm_cp_regs(cpu, nmi_reginfo);
+ }
#endif
if (cpu_isar_feature(any_predinv, cpu)) {
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 06/24] target/arm: Add support for Non-maskable Interrupt
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (4 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 05/24] target/arm: Support MSR access to ALLINT Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 07/24] target/arm: Add support for NMI in arm_phys_excp_target_el() Jinjie Ruan via
` (19 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
This only implements the external delivery method via the GICv3.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v12:
- Correct the comment style in arm_cpu_initfn().
v10:
- In arm_cpu_exec_interrupt(), if SCTLR_ELx.NMI is 0, NMI -> IRQ,
VINMI -> VIRQ, VFNMI -> VFIQ.
- Make arm_cpu_update_virq() and arm_cpu_update_vfiq() check that it is not a
VINMI/VFNMI, so only set 1 bit in interrupt_request, not 2.
v9:
- Update the GPIOs passed in the arm_cpu_kvm_set_irq, and update the comment.
- Definitely not merge VINMI and VFNMI into EXCP_VNMI.
- Update VINMI and VFNMI when writing HCR_EL2 or HCRX_EL2.
v8:
- Fix the rcu stall after sending a VNMI in qemu VM.
v7:
- Add Reviewed-by.
v6:
- env->cp15.hcr_el2 -> arm_hcr_el2_eff().
- env->cp15.hcrx_el2 -> arm_hcrx_el2_eff().
- Not include VF && VFNMI in CPU_INTERRUPT_VNMI.
v4:
- Accept NMI unconditionally for arm_cpu_has_work() but add comment.
- Change from & to && for EXCP_IRQ or EXCP_FIQ.
- Refator nmi mask in arm_excp_unmasked().
- Also handle VNMI in arm_cpu_exec_interrupt() and arm_cpu_set_irq().
- Rename virtual to Virtual.
v3:
- Not include CPU_INTERRUPT_NMI when FEAT_NMI not enabled
- Add ARM_CPU_VNMI.
- Refator nmi mask in arm_excp_unmasked().
- Test SCTLR_ELx.NMI for ALLINT mask for NMI.
---
target/arm/cpu-qom.h | 5 +-
target/arm/cpu.c | 147 ++++++++++++++++++++++++++++++++++++++---
target/arm/cpu.h | 6 ++
target/arm/helper.c | 33 +++++++--
target/arm/internals.h | 18 +++++
5 files changed, 193 insertions(+), 16 deletions(-)
diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 8e032691db..b497667d61 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -36,11 +36,14 @@ DECLARE_CLASS_CHECKERS(AArch64CPUClass, AARCH64_CPU,
#define ARM_CPU_TYPE_SUFFIX "-" TYPE_ARM_CPU
#define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
-/* Meanings of the ARMCPU object's four inbound GPIO lines */
+/* Meanings of the ARMCPU object's seven inbound GPIO lines */
#define ARM_CPU_IRQ 0
#define ARM_CPU_FIQ 1
#define ARM_CPU_VIRQ 2
#define ARM_CPU_VFIQ 3
+#define ARM_CPU_NMI 4
+#define ARM_CPU_VINMI 5
+#define ARM_CPU_VFNMI 6
/* For M profile, some registers are banked secure vs non-secure;
* these are represented as a 2-element array where the first element
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index ab8d007a86..d2dfd36fd4 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -122,6 +122,13 @@ void arm_restore_state_to_opc(CPUState *cs,
}
#endif /* CONFIG_TCG */
+/*
+ * With SCTLR_ELx.NMI == 0, IRQ with Superpriority is masked identically with
+ * IRQ without Superpriority. Moreover, if the GIC is configured so that
+ * FEAT_GICv3_NMI is only set if FEAT_NMI is set, then we won't ever see
+ * CPU_INTERRUPT_*NMI anyway. So we might as well accept NMI here
+ * unconditionally.
+ */
static bool arm_cpu_has_work(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
@@ -129,6 +136,7 @@ static bool arm_cpu_has_work(CPUState *cs)
return (cpu->power_state != PSCI_OFF)
&& cs->interrupt_request &
(CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
+ | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI
| CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR
| CPU_INTERRUPT_EXITTB);
}
@@ -668,6 +676,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
CPUARMState *env = cpu_env(cs);
bool pstate_unmasked;
bool unmasked = false;
+ bool allIntMask = false;
/*
* Don't take exceptions if they target a lower EL.
@@ -678,13 +687,36 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
return false;
}
+ if (cpu_isar_feature(aa64_nmi, env_archcpu(env)) &&
+ env->cp15.sctlr_el[target_el] & SCTLR_NMI && cur_el == target_el) {
+ allIntMask = env->pstate & PSTATE_ALLINT ||
+ ((env->cp15.sctlr_el[target_el] & SCTLR_SPINTMASK) &&
+ (env->pstate & PSTATE_SP));
+ }
+
switch (excp_idx) {
+ case EXCP_NMI:
+ pstate_unmasked = !allIntMask;
+ break;
+
+ case EXCP_VINMI:
+ if (!(hcr_el2 & HCR_IMO) || (hcr_el2 & HCR_TGE)) {
+ /* VINMIs are only taken when hypervized. */
+ return false;
+ }
+ return !allIntMask;
+ case EXCP_VFNMI:
+ if (!(hcr_el2 & HCR_FMO) || (hcr_el2 & HCR_TGE)) {
+ /* VFNMIs are only taken when hypervized. */
+ return false;
+ }
+ return !allIntMask;
case EXCP_FIQ:
- pstate_unmasked = !(env->daif & PSTATE_F);
+ pstate_unmasked = (!(env->daif & PSTATE_F)) && (!allIntMask);
break;
case EXCP_IRQ:
- pstate_unmasked = !(env->daif & PSTATE_I);
+ pstate_unmasked = (!(env->daif & PSTATE_I)) && (!allIntMask);
break;
case EXCP_VFIQ:
@@ -692,13 +724,13 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
/* VFIQs are only taken when hypervized. */
return false;
}
- return !(env->daif & PSTATE_F);
+ return !(env->daif & PSTATE_F) && (!allIntMask);
case EXCP_VIRQ:
if (!(hcr_el2 & HCR_IMO) || (hcr_el2 & HCR_TGE)) {
/* VIRQs are only taken when hypervized. */
return false;
}
- return !(env->daif & PSTATE_I);
+ return !(env->daif & PSTATE_I) && (!allIntMask);
case EXCP_VSERR:
if (!(hcr_el2 & HCR_AMO) || (hcr_el2 & HCR_TGE)) {
/* VIRQs are only taken when hypervized. */
@@ -804,6 +836,48 @@ static bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
/* The prioritization of interrupts is IMPLEMENTATION DEFINED. */
+ if (cpu_isar_feature(aa64_nmi, env_archcpu(env)) &&
+ (arm_sctlr(env, cur_el) & SCTLR_NMI)) {
+ if (interrupt_request & CPU_INTERRUPT_NMI) {
+ excp_idx = EXCP_NMI;
+ target_el = arm_phys_excp_target_el(cs, excp_idx, cur_el, secure);
+ if (arm_excp_unmasked(cs, excp_idx, target_el,
+ cur_el, secure, hcr_el2)) {
+ goto found;
+ }
+ }
+ if (interrupt_request & CPU_INTERRUPT_VINMI) {
+ excp_idx = EXCP_VINMI;
+ target_el = 1;
+ if (arm_excp_unmasked(cs, excp_idx, target_el,
+ cur_el, secure, hcr_el2)) {
+ goto found;
+ }
+ }
+ if (interrupt_request & CPU_INTERRUPT_VFNMI) {
+ excp_idx = EXCP_VFNMI;
+ target_el = 1;
+ if (arm_excp_unmasked(cs, excp_idx, target_el,
+ cur_el, secure, hcr_el2)) {
+ goto found;
+ }
+ }
+ } else {
+ /*
+ * NMI disabled: interrupts with superpriority are handled
+ * as if they didn't have it
+ */
+ if (interrupt_request & CPU_INTERRUPT_NMI) {
+ interrupt_request |= CPU_INTERRUPT_HARD;
+ }
+ if (interrupt_request & CPU_INTERRUPT_VINMI) {
+ interrupt_request |= CPU_INTERRUPT_VIRQ;
+ }
+ if (interrupt_request & CPU_INTERRUPT_VFNMI) {
+ interrupt_request |= CPU_INTERRUPT_VFIQ;
+ }
+ }
+
if (interrupt_request & CPU_INTERRUPT_FIQ) {
excp_idx = EXCP_FIQ;
target_el = arm_phys_excp_target_el(cs, excp_idx, cur_el, secure);
@@ -867,7 +941,8 @@ void arm_cpu_update_virq(ARMCPU *cpu)
CPUARMState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- bool new_state = (env->cp15.hcr_el2 & HCR_VI) ||
+ bool new_state = ((arm_hcr_el2_eff(env) & HCR_VI) &&
+ !(arm_hcrx_el2_eff(env) & HCRX_VINMI)) ||
(env->irq_line_state & CPU_INTERRUPT_VIRQ);
if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VIRQ) != 0)) {
@@ -888,7 +963,8 @@ void arm_cpu_update_vfiq(ARMCPU *cpu)
CPUARMState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- bool new_state = (env->cp15.hcr_el2 & HCR_VF) ||
+ bool new_state = ((arm_hcr_el2_eff(env) & HCR_VF) &&
+ !(arm_hcrx_el2_eff(env) & HCRX_VFNMI)) ||
(env->irq_line_state & CPU_INTERRUPT_VFIQ);
if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VFIQ) != 0)) {
@@ -900,6 +976,48 @@ void arm_cpu_update_vfiq(ARMCPU *cpu)
}
}
+void arm_cpu_update_vinmi(ARMCPU *cpu)
+{
+ /*
+ * Update the interrupt level for VINMI, which is the logical OR of
+ * the HCRX_EL2.VINMI bit and the input line level from the GIC.
+ */
+ CPUARMState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
+
+ bool new_state = ((arm_hcr_el2_eff(env) & HCR_VI) &&
+ (arm_hcrx_el2_eff(env) & HCRX_VINMI)) ||
+ (env->irq_line_state & CPU_INTERRUPT_VINMI);
+
+ if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VINMI) != 0)) {
+ if (new_state) {
+ cpu_interrupt(cs, CPU_INTERRUPT_VINMI);
+ } else {
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_VINMI);
+ }
+ }
+}
+
+void arm_cpu_update_vfnmi(ARMCPU *cpu)
+{
+ /*
+ * Update the interrupt level for VFNMI, which is the HCRX_EL2.VFNMI bit.
+ */
+ CPUARMState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
+
+ bool new_state = (arm_hcr_el2_eff(env) & HCR_VF) &&
+ (arm_hcrx_el2_eff(env) & HCRX_VFNMI);
+
+ if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VFNMI) != 0)) {
+ if (new_state) {
+ cpu_interrupt(cs, CPU_INTERRUPT_VFNMI);
+ } else {
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_VFNMI);
+ }
+ }
+}
+
void arm_cpu_update_vserr(ARMCPU *cpu)
{
/*
@@ -929,7 +1047,9 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level)
[ARM_CPU_IRQ] = CPU_INTERRUPT_HARD,
[ARM_CPU_FIQ] = CPU_INTERRUPT_FIQ,
[ARM_CPU_VIRQ] = CPU_INTERRUPT_VIRQ,
- [ARM_CPU_VFIQ] = CPU_INTERRUPT_VFIQ
+ [ARM_CPU_VFIQ] = CPU_INTERRUPT_VFIQ,
+ [ARM_CPU_NMI] = CPU_INTERRUPT_NMI,
+ [ARM_CPU_VINMI] = CPU_INTERRUPT_VINMI,
};
if (!arm_feature(env, ARM_FEATURE_EL2) &&
@@ -955,8 +1075,12 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level)
case ARM_CPU_VFIQ:
arm_cpu_update_vfiq(cpu);
break;
+ case ARM_CPU_VINMI:
+ arm_cpu_update_vinmi(cpu);
+ break;
case ARM_CPU_IRQ:
case ARM_CPU_FIQ:
+ case ARM_CPU_NMI:
if (level) {
cpu_interrupt(cs, mask[irq]);
} else {
@@ -1350,12 +1474,13 @@ static void arm_cpu_initfn(Object *obj)
#else
/* Our inbound IRQ and FIQ lines */
if (kvm_enabled()) {
- /* VIRQ and VFIQ are unused with KVM but we add them to maintain
- * the same interface as non-KVM CPUs.
+ /*
+ * VIRQ, VFIQ, NMI, VINMI are unused with KVM but we add
+ * them to maintain the same interface as non-KVM CPUs.
*/
- qdev_init_gpio_in(DEVICE(cpu), arm_cpu_kvm_set_irq, 4);
+ qdev_init_gpio_in(DEVICE(cpu), arm_cpu_kvm_set_irq, 6);
} else {
- qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 4);
+ qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 6);
}
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index de740d223f..08a6bc50de 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -61,6 +61,9 @@
#define EXCP_DIVBYZERO 23 /* v7M DIVBYZERO UsageFault */
#define EXCP_VSERR 24
#define EXCP_GPC 25 /* v9 Granule Protection Check Fault */
+#define EXCP_NMI 26
+#define EXCP_VINMI 27
+#define EXCP_VFNMI 28
/* NB: add new EXCP_ defines to the array in arm_log_exception() too */
#define ARMV7M_EXCP_RESET 1
@@ -80,6 +83,9 @@
#define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2
#define CPU_INTERRUPT_VFIQ CPU_INTERRUPT_TGT_EXT_3
#define CPU_INTERRUPT_VSERR CPU_INTERRUPT_TGT_INT_0
+#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_4
+#define CPU_INTERRUPT_VINMI CPU_INTERRUPT_TGT_EXT_0
+#define CPU_INTERRUPT_VFNMI CPU_INTERRUPT_TGT_INT_1
/* The usual mapping for an AArch64 system register to its AArch32
* counterpart is for the 32 bit world to have access to the lower
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5ed3eacbea..b82792f251 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6042,15 +6042,19 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
* and the state of the input lines from the GIC. (This requires
* that we have the BQL, which is done by marking the
* reginfo structs as ARM_CP_IO.)
- * Note that if a write to HCR pends a VIRQ or VFIQ it is never
- * possible for it to be taken immediately, because VIRQ and
- * VFIQ are masked unless running at EL0 or EL1, and HCR
- * can only be written at EL2.
+ * Note that if a write to HCR pends a VIRQ or VFIQ or VINMI or
+ * VFNMI, it is never possible for it to be taken immediately
+ * because VIRQ, VFIQ, VINMI and VFNMI are masked unless running
+ * at EL0 or EL1, and HCR can only be written at EL2.
*/
g_assert(bql_locked());
arm_cpu_update_virq(cpu);
arm_cpu_update_vfiq(cpu);
arm_cpu_update_vserr(cpu);
+ if (cpu_isar_feature(aa64_nmi, cpu)) {
+ arm_cpu_update_vinmi(cpu);
+ arm_cpu_update_vfnmi(cpu);
+ }
}
static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
@@ -6198,6 +6202,23 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* Clear RES0 bits. */
env->cp15.hcrx_el2 = value & valid_mask;
+
+ /*
+ * Updates to VINMI and VFNMI require us to update the status of
+ * virtual NMI, which are the logical OR of these bits
+ * and the state of the input lines from the GIC. (This requires
+ * that we have the BQL, which is done by marking the
+ * reginfo structs as ARM_CP_IO.)
+ * Note that if a write to HCRX pends a VINMI or VFNMI it is never
+ * possible for it to be taken immediately, because VINMI and
+ * VFNMI are masked unless running at EL0 or EL1, and HCRX
+ * can only be written at EL2.
+ */
+ if (cpu_isar_feature(aa64_nmi, cpu)) {
+ g_assert(bql_locked());
+ arm_cpu_update_vinmi(cpu);
+ arm_cpu_update_vfnmi(cpu);
+ }
}
static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -6213,6 +6234,7 @@ static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri,
static const ARMCPRegInfo hcrx_el2_reginfo = {
.name = "HCRX_EL2", .state = ARM_CP_STATE_AA64,
+ .type = ARM_CP_IO,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 2,
.access = PL2_RW, .writefn = hcrx_write, .accessfn = access_hxen,
.nv2_redirect_offset = 0xa0,
@@ -10795,6 +10817,9 @@ void arm_log_exception(CPUState *cs)
[EXCP_DIVBYZERO] = "v7M DIVBYZERO UsageFault",
[EXCP_VSERR] = "Virtual SERR",
[EXCP_GPC] = "Granule Protection Check",
+ [EXCP_NMI] = "NMI",
+ [EXCP_VINMI] = "Virtual IRQ NMI",
+ [EXCP_VFNMI] = "Virtual FIQ NMI",
};
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 516e0584bf..b53f5e8ff2 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1109,6 +1109,24 @@ void arm_cpu_update_virq(ARMCPU *cpu);
*/
void arm_cpu_update_vfiq(ARMCPU *cpu);
+/**
+ * arm_cpu_update_vinmi: Update CPU_INTERRUPT_VINMI bit in cs->interrupt_request
+ *
+ * Update the CPU_INTERRUPT_VINMI bit in cs->interrupt_request, following
+ * a change to either the input VNMI line from the GIC or the HCRX_EL2.VINMI.
+ * Must be called with the BQL held.
+ */
+void arm_cpu_update_vinmi(ARMCPU *cpu);
+
+/**
+ * arm_cpu_update_vfnmi: Update CPU_INTERRUPT_VFNMI bit in cs->interrupt_request
+ *
+ * Update the CPU_INTERRUPT_VFNMI bit in cs->interrupt_request, following
+ * a change to the HCRX_EL2.VFNMI.
+ * Must be called with the BQL held.
+ */
+void arm_cpu_update_vfnmi(ARMCPU *cpu);
+
/**
* arm_cpu_update_vserr: Update CPU_INTERRUPT_VSERR bit
*
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 07/24] target/arm: Add support for NMI in arm_phys_excp_target_el()
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (5 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 06/24] target/arm: Add support for Non-maskable Interrupt Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 08/24] target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI Jinjie Ruan via
` (18 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
According to Arm GIC section 4.6.3 Interrupt superpriority, the interrupt
with superpriority is always IRQ, never FIQ, so handle NMI same as IRQ in
arm_phys_excp_target_el().
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v4:
- Add Reviewed-by.
v3:
- Remove nmi_is_irq flag in CPUARMState.
- Handle NMI same as IRQ in arm_phys_excp_target_el().
---
target/arm/helper.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index b82792f251..d9814433e1 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -10759,6 +10759,7 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
hcr_el2 = arm_hcr_el2_eff(env);
switch (excp_idx) {
case EXCP_IRQ:
+ case EXCP_NMI:
scr = ((env->cp15.scr_el3 & SCR_IRQ) == SCR_IRQ);
hcr = hcr_el2 & HCR_IMO;
break;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 08/24] target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (6 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 07/24] target/arm: Add support for NMI in arm_phys_excp_target_el() Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 09/24] target/arm: Handle PSTATE.ALLINT on taking an exception Jinjie Ruan via
` (17 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Add IS and FS bit in ISR_EL1 and handle the read. With CPU_INTERRUPT_NMI or
CPU_INTERRUPT_VINMI, both CPSR_I and ISR_IS must be set. With
CPU_INTERRUPT_VFNMI, both CPSR_F and ISR_FS must be set.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v9:
- CPU_INTERRUPT_VNMI -> CPU_INTERRUPT_VINMI.
- Handle CPSR_F and ISR_FS according to CPU_INTERRUPT_VFNMI instead of
CPU_INTERRUPT_VFIQ and HCRX_EL2.VFNMI.
- Update the commit message.
v7:
- env->cp15.hcrx_el2 -> arm_hcrx_el2_eff().
- Add Reviewed-by.
v6:
- Verify that HCR_EL2.VF is set before checking VFNMI.
v4;
- Also handle VNMI.
v3:
- CPU_INTERRUPT_NMI do not set FIQ, so remove it.
- With CPU_INTERRUPT_NMI, both CPSR_I and ISR_IS must be set.
---
target/arm/cpu.h | 2 ++
target/arm/helper.c | 13 +++++++++++++
2 files changed, 15 insertions(+)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 08a6bc50de..97997dbd08 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1398,6 +1398,8 @@ void pmu_init(ARMCPU *cpu);
#define CPSR_N (1U << 31)
#define CPSR_NZCV (CPSR_N | CPSR_Z | CPSR_C | CPSR_V)
#define CPSR_AIF (CPSR_A | CPSR_I | CPSR_F)
+#define ISR_FS (1U << 9)
+#define ISR_IS (1U << 10)
#define CPSR_IT (CPSR_IT_0_1 | CPSR_IT_2_7)
#define CACHED_CPSR_BITS (CPSR_T | CPSR_AIF | CPSR_GE | CPSR_IT | CPSR_Q \
diff --git a/target/arm/helper.c b/target/arm/helper.c
index d9814433e1..0e7eefd7e5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2021,16 +2021,29 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
ret |= CPSR_I;
}
+ if (cs->interrupt_request & CPU_INTERRUPT_VINMI) {
+ ret |= ISR_IS;
+ ret |= CPSR_I;
+ }
} else {
if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
ret |= CPSR_I;
}
+
+ if (cs->interrupt_request & CPU_INTERRUPT_NMI) {
+ ret |= ISR_IS;
+ ret |= CPSR_I;
+ }
}
if (hcr_el2 & HCR_FMO) {
if (cs->interrupt_request & CPU_INTERRUPT_VFIQ) {
ret |= CPSR_F;
}
+ if (cs->interrupt_request & CPU_INTERRUPT_VFNMI) {
+ ret |= ISR_FS;
+ ret |= CPSR_F;
+ }
} else {
if (cs->interrupt_request & CPU_INTERRUPT_FIQ) {
ret |= CPSR_F;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 09/24] target/arm: Handle PSTATE.ALLINT on taking an exception
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (7 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 08/24] target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 10/24] hw/intc/arm_gicv3: Add external IRQ lines for NMI Jinjie Ruan via
` (16 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Set or clear PSTATE.ALLINT on taking an exception to ELx according to the
SCTLR_ELx.SPINTMASK bit.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v9:
- Not check SCTLR_NMI in arm_cpu_do_interrupt_aarch64().
v3:
- Add Reviewed-by.
---
target/arm/helper.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0e7eefd7e5..65f2ddfa56 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11729,6 +11729,14 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
}
}
+ if (cpu_isar_feature(aa64_nmi, cpu)) {
+ if (!(env->cp15.sctlr_el[new_el] & SCTLR_SPINTMASK)) {
+ new_mode |= PSTATE_ALLINT;
+ } else {
+ new_mode &= ~PSTATE_ALLINT;
+ }
+ }
+
pstate_write(env, PSTATE_DAIF | new_mode);
env->aarch64 = true;
aarch64_restore_sp(env, new_el);
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 10/24] hw/intc/arm_gicv3: Add external IRQ lines for NMI
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (8 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 09/24] target/arm: Handle PSTATE.ALLINT on taking an exception Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 11/24] hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU Jinjie Ruan via
` (15 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Augment the GICv3's QOM device interface by adding one
new set of sysbus IRQ line, to signal NMI to each CPU.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v11:
- Add new Reviewed-by.
v4:
- Add Reviewed-by.
v3:
- Add support for VNMI.
---
hw/intc/arm_gicv3_common.c | 6 ++++++
include/hw/intc/arm_gic_common.h | 2 ++
include/hw/intc/arm_gicv3_common.h | 2 ++
3 files changed, 10 insertions(+)
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index cb55c72681..c52f060026 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -299,6 +299,12 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->cpu[i].parent_vfiq);
}
+ for (i = 0; i < s->num_cpu; i++) {
+ sysbus_init_irq(sbd, &s->cpu[i].parent_nmi);
+ }
+ for (i = 0; i < s->num_cpu; i++) {
+ sysbus_init_irq(sbd, &s->cpu[i].parent_vnmi);
+ }
memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
"gicv3_dist", 0x10000);
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
index 7080375008..97fea4102d 100644
--- a/include/hw/intc/arm_gic_common.h
+++ b/include/hw/intc/arm_gic_common.h
@@ -71,6 +71,8 @@ struct GICState {
qemu_irq parent_fiq[GIC_NCPU];
qemu_irq parent_virq[GIC_NCPU];
qemu_irq parent_vfiq[GIC_NCPU];
+ qemu_irq parent_nmi[GIC_NCPU];
+ qemu_irq parent_vnmi[GIC_NCPU];
qemu_irq maintenance_irq[GIC_NCPU];
/* GICD_CTLR; for a GIC with the security extensions the NS banked version
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index 4e2fb518e7..7324c7d983 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -155,6 +155,8 @@ struct GICv3CPUState {
qemu_irq parent_fiq;
qemu_irq parent_virq;
qemu_irq parent_vfiq;
+ qemu_irq parent_nmi;
+ qemu_irq parent_vnmi;
/* Redistributor */
uint32_t level; /* Current IRQ level */
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 11/24] hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (9 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 10/24] hw/intc/arm_gicv3: Add external IRQ lines for NMI Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 12/24] target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64() Jinjie Ruan via
` (14 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Wire the new NMI and VINMI interrupt line from the GIC to each CPU if it
is not GICv2.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
v13:
- Adjust to after "hw/intc/arm_gicv3: Add external IRQ lines for NMI" to fix
the unexpected error with patchseries at this point.
- Only connect these up if vms->gic_version is not VIRT_GIC_VERSION_2 to fix
the gic-version=2 unexpected error.
v9:
- Rename ARM_CPU_VNMI to ARM_CPU_VINMI.
- Update the commit message.
v4:
- Add Reviewed-by.
v3:
- Also add VNMI wire.
---
hw/arm/virt.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a9a913aead..dca509d082 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -821,7 +821,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
/* Wire the outputs from each CPU's generic timer and the GICv3
* maintenance interrupt signal to the appropriate GIC PPI inputs,
- * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
+ * and the GIC's IRQ/FIQ/VIRQ/VFIQ/NMI/VINMI interrupt outputs to the
+ * CPU's inputs.
*/
for (i = 0; i < smp_cpus; i++) {
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
@@ -865,6 +866,13 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+
+ if (vms->gic_version != VIRT_GIC_VERSION_2) {
+ sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_NMI));
+ sysbus_connect_irq(gicbusdev, i + 5 * smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VINMI));
+ }
}
fdt_add_gic_node(vms);
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 12/24] target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64()
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (10 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 11/24] hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 13/24] hw/intc/arm_gicv3: Add has-nmi property to GICv3 device Jinjie Ruan via
` (13 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
According to Arm GIC section 4.6.3 Interrupt superpriority, the interrupt
with superpriority is always IRQ, never FIQ, so the NMI exception trap entry
behave like IRQ. And VINMI(vIRQ with Superpriority) can be raised from the
GIC or come from the hcrx_el2.HCRX_VINMI bit, VFNMI(vFIQ with Superpriority)
come from the hcrx_el2.HCRX_VFNMI bit.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v9:
- Update the commit message.
- Handle VINMI and VFNMI.
v7:
- Add Reviewed-by.
v6:
- Not combine VFNMI with CPU_INTERRUPT_VNMI.
v4:
- Also handle VNMI in arm_cpu_do_interrupt_aarch64().
v3:
- Remove the FIQ NMI handle.
---
target/arm/helper.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 65f2ddfa56..0455f20ccc 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11649,10 +11649,13 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
break;
case EXCP_IRQ:
case EXCP_VIRQ:
+ case EXCP_NMI:
+ case EXCP_VINMI:
addr += 0x80;
break;
case EXCP_FIQ:
case EXCP_VFIQ:
+ case EXCP_VFNMI:
addr += 0x100;
break;
case EXCP_VSERR:
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 13/24] hw/intc/arm_gicv3: Add has-nmi property to GICv3 device
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (11 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 12/24] target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64() Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 14/24] hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3 Jinjie Ruan via
` (12 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Add a property has-nmi to the GICv3 device, and use this to set
the NMI bit in the GICD_TYPER register. This isn't visible to
guests yet because the property defaults to false and we won't
set it in the board code until we've landed all of the changes
needed to implement FEAT_GICV3_NMI.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v12:
- Update the subject and commit message.
- Add Reviewed-by.
v10:
- Adjust to before add irq non-maskable property.
v4:
- Add Reviewed-by.
---
hw/intc/arm_gicv3_common.c | 1 +
hw/intc/arm_gicv3_dist.c | 2 ++
hw/intc/gicv3_internal.h | 1 +
include/hw/intc/arm_gicv3_common.h | 1 +
4 files changed, 5 insertions(+)
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index c52f060026..2d2cea6858 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -569,6 +569,7 @@ static Property arm_gicv3_common_properties[] = {
DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0),
+ DEFINE_PROP_BOOL("has-nmi", GICv3State, nmi_support, 0),
DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
/*
* Compatibility property: force 8 bits of physical priority, even
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 35e850685c..22ddc0d666 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -389,6 +389,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
* by GICD_TYPER.IDbits)
* MBIS == 0 (message-based SPIs not supported)
* SecurityExtn == 1 if security extns supported
+ * NMI = 1 if Non-maskable interrupt property is supported
* CPUNumber == 0 since for us ARE is always 1
* ITLinesNumber == (((max SPI IntID + 1) / 32) - 1)
*/
@@ -402,6 +403,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
bool dvis = s->revision >= 4;
*data = (1 << 25) | (1 << 24) | (dvis << 18) | (sec_extn << 10) |
+ (s->nmi_support << GICD_TYPER_NMI_SHIFT) |
(s->lpi_enable << GICD_TYPER_LPIS_SHIFT) |
(0xf << 19) | itlinesnumber;
return true;
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 29d5cdc1b6..8f4ebed2f4 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -68,6 +68,7 @@
#define GICD_CTLR_E1NWF (1U << 7)
#define GICD_CTLR_RWP (1U << 31)
+#define GICD_TYPER_NMI_SHIFT 9
#define GICD_TYPER_LPIS_SHIFT 17
/* 16 bits EventId */
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index 7324c7d983..4358c5319c 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -249,6 +249,7 @@ struct GICv3State {
uint32_t num_irq;
uint32_t revision;
bool lpi_enable;
+ bool nmi_support;
bool security_extn;
bool force_8bit_prio;
bool irq_reset_nonsecure;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 14/24] hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (12 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 13/24] hw/intc/arm_gicv3: Add has-nmi property to GICv3 device Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 15/24] hw/intc/arm_gicv3: Add irq non-maskable property Jinjie Ruan via
` (11 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
So far, there is no FEAT_GICv3_NMI support in the in-kernel GIC, so make it
an error to try to set has-nmi=true for the KVM GICv3.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/intc/arm_gicv3_kvm.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 77eb37e131..00a383079b 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -805,6 +805,11 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
return;
}
+ if (s->nmi_support) {
+ error_setg(errp, "NMI is not supported with the in-kernel GIC");
+ return;
+ }
+
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
for (i = 0; i < s->num_cpu; i++) {
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 15/24] hw/intc/arm_gicv3: Add irq non-maskable property
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (13 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 14/24] hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3 Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 16/24] hw/intc/arm_gicv3_redist: Implement GICR_INMIR0 Jinjie Ruan via
` (10 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
A SPI, PPI or SGI interrupt can have non-maskable property. So maintain
non-maskable property in PendingIrq and GICR/GICD. Since add new device
state, it also needs to be migrated, so also save NMI info in
vmstate_gicv3_cpu and vmstate_gicv3.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v12:
- nmi_needed -> gicv3_cpu_nmi_needed.
- needed_nmi -> gicv3_nmi_needed.
- Add Reviewed-by.
v11:
- Put vmstate_gicv3_cpu_nmi and vmstate_gicv3_gicd_nmi into existing list.
- Remove the excess != 0.
v10:
- superprio -> nmi, gicr_isuperprio -> gicr_inmir0.
- Save NMI state in vmstate_gicv3_cpu and vmstate_gicv3.
- Update the commit message.
v3:
- Place this ahead of implement GICR_INMIR.
- Add Acked-by.
---
hw/intc/arm_gicv3_common.c | 38 ++++++++++++++++++++++++++++++
include/hw/intc/arm_gicv3_common.h | 4 ++++
2 files changed, 42 insertions(+)
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 2d2cea6858..9810558b07 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -164,6 +164,24 @@ const VMStateDescription vmstate_gicv3_gicv4 = {
}
};
+static bool gicv3_cpu_nmi_needed(void *opaque)
+{
+ GICv3CPUState *cs = opaque;
+
+ return cs->gic->nmi_support;
+}
+
+static const VMStateDescription vmstate_gicv3_cpu_nmi = {
+ .name = "arm_gicv3_cpu/nmi",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = gicv3_cpu_nmi_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(gicr_inmir0, GICv3CPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_gicv3_cpu = {
.name = "arm_gicv3_cpu",
.version_id = 1,
@@ -196,6 +214,7 @@ static const VMStateDescription vmstate_gicv3_cpu = {
&vmstate_gicv3_cpu_virt,
&vmstate_gicv3_cpu_sre_el1,
&vmstate_gicv3_gicv4,
+ &vmstate_gicv3_cpu_nmi,
NULL
}
};
@@ -238,6 +257,24 @@ const VMStateDescription vmstate_gicv3_gicd_no_migration_shift_bug = {
}
};
+static bool gicv3_nmi_needed(void *opaque)
+{
+ GICv3State *cs = opaque;
+
+ return cs->nmi_support;
+}
+
+const VMStateDescription vmstate_gicv3_gicd_nmi = {
+ .name = "arm_gicv3/gicd_nmi",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = gicv3_nmi_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(nmi, GICv3State, GICV3_BMP_SIZE),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_gicv3 = {
.name = "arm_gicv3",
.version_id = 1,
@@ -266,6 +303,7 @@ static const VMStateDescription vmstate_gicv3 = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_gicv3_gicd_no_migration_shift_bug,
+ &vmstate_gicv3_gicd_nmi,
NULL
}
};
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index 4358c5319c..88533749eb 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -146,6 +146,7 @@ typedef struct {
int irq;
uint8_t prio;
int grp;
+ bool nmi;
} PendingIrq;
struct GICv3CPUState {
@@ -172,6 +173,7 @@ struct GICv3CPUState {
uint32_t gicr_ienabler0;
uint32_t gicr_ipendr0;
uint32_t gicr_iactiver0;
+ uint32_t gicr_inmir0;
uint32_t edge_trigger; /* ICFGR0 and ICFGR1 even bits */
uint32_t gicr_igrpmodr0;
uint32_t gicr_nsacr;
@@ -275,6 +277,7 @@ struct GICv3State {
GIC_DECLARE_BITMAP(active); /* GICD_ISACTIVER */
GIC_DECLARE_BITMAP(level); /* Current level */
GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
+ GIC_DECLARE_BITMAP(nmi); /* GICD_INMIR */
uint8_t gicd_ipriority[GICV3_MAXIRQ];
uint64_t gicd_irouter[GICV3_MAXIRQ];
/* Cached information: pointer to the cpu i/f for the CPUs specified
@@ -314,6 +317,7 @@ GICV3_BITMAP_ACCESSORS(pending)
GICV3_BITMAP_ACCESSORS(active)
GICV3_BITMAP_ACCESSORS(level)
GICV3_BITMAP_ACCESSORS(edge_trigger)
+GICV3_BITMAP_ACCESSORS(nmi)
#define TYPE_ARM_GICV3_COMMON "arm-gicv3-common"
typedef struct ARMGICv3CommonClass ARMGICv3CommonClass;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 16/24] hw/intc/arm_gicv3_redist: Implement GICR_INMIR0
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (14 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 15/24] hw/intc/arm_gicv3: Add irq non-maskable property Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 17/24] hw/intc/arm_gicv3: Implement GICD_INMIR Jinjie Ruan via
` (9 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Add GICR_INMIR0 register and support access GICR_INMIR0.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v11:
- Add new Reviewed-by.
v10:
- gicr_isuperprio -> gicr_inmir0.
v6:
- Add Reviewed-by.
v4:
- Make the GICR_INMIR0 implementation more clearer.
---
hw/intc/arm_gicv3_redist.c | 19 +++++++++++++++++++
hw/intc/gicv3_internal.h | 1 +
2 files changed, 20 insertions(+)
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 8153525849..ed1f9d1e44 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -35,6 +35,15 @@ static int gicr_ns_access(GICv3CPUState *cs, int irq)
return extract32(cs->gicr_nsacr, irq * 2, 2);
}
+static void gicr_write_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
+ uint32_t *reg, uint32_t val)
+{
+ /* Helper routine to implement writing to a "set" register */
+ val &= mask_group(cs, attrs);
+ *reg = val;
+ gicv3_redist_update(cs);
+}
+
static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
uint32_t *reg, uint32_t val)
{
@@ -406,6 +415,10 @@ static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset,
*data = value;
return MEMTX_OK;
}
+ case GICR_INMIR0:
+ *data = cs->gic->nmi_support ?
+ gicr_read_bitmap_reg(cs, attrs, cs->gicr_inmir0) : 0;
+ return MEMTX_OK;
case GICR_ICFGR0:
case GICR_ICFGR1:
{
@@ -555,6 +568,12 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
gicv3_redist_update(cs);
return MEMTX_OK;
}
+ case GICR_INMIR0:
+ if (cs->gic->nmi_support) {
+ gicr_write_bitmap_reg(cs, attrs, &cs->gicr_inmir0, value);
+ }
+ return MEMTX_OK;
+
case GICR_ICFGR0:
/* Register is all RAZ/WI or RAO/WI bits */
return MEMTX_OK;
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 8f4ebed2f4..21697ecf39 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -110,6 +110,7 @@
#define GICR_ICFGR1 (GICR_SGI_OFFSET + 0x0C04)
#define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00)
#define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00)
+#define GICR_INMIR0 (GICR_SGI_OFFSET + 0x0F80)
/* VLPI redistributor registers, offsets from VLPI_base */
#define GICR_VPROPBASER (GICR_VLPI_OFFSET + 0x70)
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 17/24] hw/intc/arm_gicv3: Implement GICD_INMIR
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (15 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 16/24] hw/intc/arm_gicv3_redist: Implement GICR_INMIR0 Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 18/24] hw/intc/arm_gicv3: Add NMI handling CPU interface registers Jinjie Ruan via
` (8 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Add GICD_INMIR, GICD_INMIRnE register and support access GICD_INMIR0.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v11:
- Add new Reviewed-by.
v10:
- superprio -> nmi.
v4:
- Make the GICD_INMIR implementation more clearer.
- Udpate the commit message.
v3:
- Add Reviewed-by.
---
hw/intc/arm_gicv3_dist.c | 34 ++++++++++++++++++++++++++++++++++
hw/intc/gicv3_internal.h | 2 ++
2 files changed, 36 insertions(+)
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 22ddc0d666..d8207acb22 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -89,6 +89,29 @@ static int gicd_ns_access(GICv3State *s, int irq)
return extract32(s->gicd_nsacr[irq / 16], (irq % 16) * 2, 2);
}
+static void gicd_write_bitmap_reg(GICv3State *s, MemTxAttrs attrs,
+ uint32_t *bmp, maskfn *maskfn,
+ int offset, uint32_t val)
+{
+ /*
+ * Helper routine to implement writing to a "set" register
+ * (GICD_INMIR, etc).
+ * Semantics implemented here:
+ * RAZ/WI for SGIs, PPIs, unimplemented IRQs
+ * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI.
+ * offset should be the offset in bytes of the register from the start
+ * of its group.
+ */
+ int irq = offset * 8;
+
+ if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+ return;
+ }
+ val &= mask_group_and_nsacr(s, attrs, maskfn, irq);
+ *gic_bmp_ptr32(bmp, irq) = val;
+ gicv3_update(s, irq, 32);
+}
+
static void gicd_write_set_bitmap_reg(GICv3State *s, MemTxAttrs attrs,
uint32_t *bmp,
maskfn *maskfn,
@@ -545,6 +568,11 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
/* RAZ/WI since affinity routing is always enabled */
*data = 0;
return true;
+ case GICD_INMIR ... GICD_INMIR + 0x7f:
+ *data = (!s->nmi_support) ? 0 :
+ gicd_read_bitmap_reg(s, attrs, s->nmi, NULL,
+ offset - GICD_INMIR);
+ return true;
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
{
uint64_t r;
@@ -754,6 +782,12 @@ static bool gicd_writel(GICv3State *s, hwaddr offset,
case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf:
/* RAZ/WI since affinity routing is always enabled */
return true;
+ case GICD_INMIR ... GICD_INMIR + 0x7f:
+ if (s->nmi_support) {
+ gicd_write_bitmap_reg(s, attrs, s->nmi, NULL,
+ offset - GICD_INMIR, value);
+ }
+ return true;
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
{
uint64_t r;
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 21697ecf39..8d793243f4 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -52,6 +52,8 @@
#define GICD_SGIR 0x0F00
#define GICD_CPENDSGIR 0x0F10
#define GICD_SPENDSGIR 0x0F20
+#define GICD_INMIR 0x0F80
+#define GICD_INMIRnE 0x3B00
#define GICD_IROUTER 0x6000
#define GICD_IDREGS 0xFFD0
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 18/24] hw/intc/arm_gicv3: Add NMI handling CPU interface registers
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (16 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 17/24] hw/intc/arm_gicv3: Implement GICD_INMIR Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 19/24] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read() Jinjie Ruan via
` (7 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Add the NMIAR CPU interface registers which deal with acknowledging NMI.
When introduce NMI interrupt, there are some updates to the semantics for the
register ICC_IAR1_EL1 and ICC_HPPIR1_EL1. For ICC_IAR1_EL1 register, it
should return 1022 if the intid has non-maskable property. And for
ICC_NMIAR1_EL1 register, it should return 1023 if the intid do not have
non-maskable property. Howerever, these are not necessary for ICC_HPPIR1_EL1
register.
And the APR and RPR has NMI bits which should be handled correctly.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Add Reviewed-by.
v12:
- pPriority<63> = ICC_AP1R_EL1NS<63> if HaveNMIExt() and HaveEL(EL3) and
(IsNonSecure(), fix the wrong writing.
- Do not check nmi_support repetitively in icc_hppi_can_preempt()
and icc_activate_irq().
- Check hppi.nmi after check icc_hppi_can_preempt() for icc_iar1_read() and
icc_nmiar1_read().
v11:
- Handle NMI priority in icc_highest_active_prio() and handle NMI RPR in
icc_rpr_read() separately.
- Only set NMI bit for a NMI and and ordinary priority bit for a non-NMI in
icc_activate_irq().
- Only clear APR bit for AP1R0 in icc_drop_prio().
- Check special INTID_* in callers instead of passing two extra boolean args
for ack functions.
- Handle NMI in icc_hppi_can_preempt() and icc_highest_active_group().
- Also check icc_hppi_can_preempt() for icc_nmiar1_read().
v10:
- is_nmi -> nmi.
- is_hppi -> hppi.
- Exchange the order of nmi and hppi parameters.
- superprio -> nmi.
- Handle APR and RPR NMI bits.
- Update the commit message, super priority -> non-maskable property.
v7:
- Add Reviewed-by.
v4:
- Define ICC_NMIAR1_EL1 only if FEAT_GICv3_NMI is implemented.
- Check sctrl_elx.SCTLR_NMI to return 1022 for icc_iar1_read().
- Add gicv3_icc_nmiar1_read() trace event.
- Do not check icc_hppi_can_preempt() for icc_nmiar1_read().
- Add icv_nmiar1_read() and call it when EL2Enabled() and HCR_EL2.IMO == '1'
---
hw/intc/arm_gicv3_cpuif.c | 137 ++++++++++++++++++++++++++++++++++++--
hw/intc/gicv3_internal.h | 5 ++
hw/intc/trace-events | 1 +
3 files changed, 138 insertions(+), 5 deletions(-)
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index e1a60d8c15..a5a1ef93ca 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -795,6 +795,13 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
return intid;
}
+static uint64_t icv_nmiar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ /* todo */
+ uint64_t intid = INTID_SPURIOUS;
+ return intid;
+}
+
static uint32_t icc_fullprio_mask(GICv3CPUState *cs)
{
/*
@@ -832,6 +839,23 @@ static int icc_highest_active_prio(GICv3CPUState *cs)
*/
int i;
+ if (cs->gic->nmi_support) {
+ /*
+ * If an NMI is active this takes precedence over anything else
+ * for priority purposes; the NMI bit is only in the AP1R0 bit.
+ * We return here the effective priority of the NMI, which is
+ * either 0x0 or 0x80. Callers will need to check NMI again for
+ * purposes of either setting the RPR register bits or for
+ * prioritization of NMI vs non-NMI.
+ */
+ if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
+ return 0;
+ }
+ if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
+ return (cs->gic->gicd_ctlr & GICD_CTLR_DS) ? 0 : 0x80;
+ }
+ }
+
for (i = 0; i < icc_num_aprs(cs); i++) {
uint32_t apr = cs->icc_apr[GICV3_G0][i] |
cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i];
@@ -898,12 +922,24 @@ static bool icc_hppi_can_preempt(GICv3CPUState *cs)
*/
int rprio;
uint32_t mask;
+ ARMCPU *cpu = ARM_CPU(cs->cpu);
+ CPUARMState *env = &cpu->env;
if (icc_no_enabled_hppi(cs)) {
return false;
}
- if (cs->hppi.prio >= cs->icc_pmr_el1) {
+ if (cs->hppi.nmi) {
+ if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
+ cs->hppi.grp == GICV3_G1NS) {
+ if (cs->icc_pmr_el1 < 0x80) {
+ return false;
+ }
+ if (arm_is_secure(env) && cs->icc_pmr_el1 == 0x80) {
+ return false;
+ }
+ }
+ } else if (cs->hppi.prio >= cs->icc_pmr_el1) {
/* Priority mask masks this interrupt */
return false;
}
@@ -923,6 +959,12 @@ static bool icc_hppi_can_preempt(GICv3CPUState *cs)
return true;
}
+ if (cs->hppi.nmi && (cs->hppi.prio & mask) == (rprio & mask)) {
+ if (!(cs->icc_apr[cs->hppi.grp][0] & ICC_AP1R_EL1_NMI)) {
+ return true;
+ }
+ }
+
return false;
}
@@ -1044,8 +1086,13 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
int aprbit = prio >> (8 - cs->prebits);
int regno = aprbit / 32;
int regbit = aprbit % 32;
+ bool nmi = cs->hppi.nmi;
- cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
+ if (nmi) {
+ cs->icc_apr[cs->hppi.grp][regno] |= ICC_AP1R_EL1_NMI;
+ } else {
+ cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
+ }
if (irq < GIC_INTERNAL) {
cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1);
@@ -1159,6 +1206,7 @@ static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
GICv3CPUState *cs = icc_cs_from_env(env);
+ int el = arm_current_el(env);
uint64_t intid;
if (icv_access(env, HCR_IMO)) {
@@ -1172,13 +1220,44 @@ static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
}
if (!gicv3_intid_is_special(intid)) {
- icc_activate_irq(cs, intid);
+ if (cs->hppi.nmi && env->cp15.sctlr_el[el] & SCTLR_NMI) {
+ intid = INTID_NMI;
+ } else {
+ icc_activate_irq(cs, intid);
+ }
}
trace_gicv3_icc_iar1_read(gicv3_redist_affid(cs), intid);
return intid;
}
+static uint64_t icc_nmiar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ GICv3CPUState *cs = icc_cs_from_env(env);
+ uint64_t intid;
+
+ if (icv_access(env, HCR_IMO)) {
+ return icv_nmiar1_read(env, ri);
+ }
+
+ if (!icc_hppi_can_preempt(cs)) {
+ intid = INTID_SPURIOUS;
+ } else {
+ intid = icc_hppir1_value(cs, env);
+ }
+
+ if (!gicv3_intid_is_special(intid)) {
+ if (!cs->hppi.nmi) {
+ intid = INTID_SPURIOUS;
+ } else {
+ icc_activate_irq(cs, intid);
+ }
+ }
+
+ trace_gicv3_icc_nmiar1_read(gicv3_redist_affid(cs), intid);
+ return intid;
+}
+
static void icc_drop_prio(GICv3CPUState *cs, int grp)
{
/* Drop the priority of the currently active interrupt in
@@ -1205,6 +1284,12 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp)
if (!*papr) {
continue;
}
+
+ if (i == 0 && cs->gic->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) {
+ *papr &= (~ICC_AP1R_EL1_NMI);
+ break;
+ }
+
/* Clear the lowest set bit */
*papr &= *papr - 1;
break;
@@ -1239,6 +1324,15 @@ static int icc_highest_active_group(GICv3CPUState *cs)
*/
int i;
+ if (cs->gic->nmi_support) {
+ if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
+ return GICV3_G1;
+ }
+ if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
+ return GICV3_G1NS;
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) {
int g0ctz = ctz32(cs->icc_apr[GICV3_G0][i]);
int g1ctz = ctz32(cs->icc_apr[GICV3_G1][i]);
@@ -1693,7 +1787,11 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
return;
}
- cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
+ if (cs->gic->nmi_support) {
+ cs->icc_apr[grp][regno] = value & (0xFFFFFFFFU | ICC_AP1R_EL1_NMI);
+ } else {
+ cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
+ }
gicv3_cpuif_update(cs);
}
@@ -1783,7 +1881,7 @@ static void icc_dir_write(CPUARMState *env, const ARMCPRegInfo *ri,
static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
GICv3CPUState *cs = icc_cs_from_env(env);
- int prio;
+ uint64_t prio;
if (icv_access(env, HCR_FMO | HCR_IMO)) {
return icv_rpr_read(env, ri);
@@ -1803,6 +1901,22 @@ static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
}
}
+ if (cs->gic->nmi_support) {
+ /* NMI info is reported in the high bits of RPR */
+ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env)) {
+ if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
+ prio |= ICC_RPR_EL1_NMI;
+ }
+ } else {
+ if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
+ prio |= ICC_RPR_EL1_NSNMI;
+ }
+ if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
+ prio |= ICC_RPR_EL1_NMI;
+ }
+ }
+ }
+
trace_gicv3_icc_rpr_read(gicv3_redist_affid(cs), prio);
return prio;
}
@@ -2482,6 +2596,15 @@ static const ARMCPRegInfo gicv3_cpuif_icc_apxr23_reginfo[] = {
},
};
+static const ARMCPRegInfo gicv3_cpuif_gicv3_nmi_reginfo[] = {
+ { .name = "ICC_NMIAR1_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 5,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL1_R, .accessfn = gicv3_irq_access,
+ .readfn = icc_nmiar1_read,
+ },
+};
+
static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
GICv3CPUState *cs = icc_cs_from_env(env);
@@ -2838,6 +2961,10 @@ void gicv3_init_cpuif(GICv3State *s)
*/
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
+ if (s->nmi_support) {
+ define_arm_cp_regs(cpu, gicv3_cpuif_gicv3_nmi_reginfo);
+ }
+
/*
* The CPU implementation specifies the number of supported
* bits of physical priority. For backwards compatibility
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 8d793243f4..81200eb90e 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -194,6 +194,10 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1)
#define ICC_CTLR_EL3_A3V (1U << 15)
#define ICC_CTLR_EL3_NDS (1U << 17)
+#define ICC_AP1R_EL1_NMI (1ULL << 63)
+#define ICC_RPR_EL1_NSNMI (1ULL << 62)
+#define ICC_RPR_EL1_NMI (1ULL << 63)
+
#define ICH_VMCR_EL2_VENG0_SHIFT 0
#define ICH_VMCR_EL2_VENG0 (1U << ICH_VMCR_EL2_VENG0_SHIFT)
#define ICH_VMCR_EL2_VENG1_SHIFT 1
@@ -511,6 +515,7 @@ FIELD(VTE, RDBASE, 42, RDBASE_PROCNUM_LENGTH)
/* Special interrupt IDs */
#define INTID_SECURE 1020
#define INTID_NONSECURE 1021
+#define INTID_NMI 1022
#define INTID_SPURIOUS 1023
/* Functions internal to the emulated GICv3 */
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 1ef29d0256..94030550d5 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -116,6 +116,7 @@ gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f
gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f 0x%x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x"
gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu 0x%x value 0x%" PRIx64
gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu 0x%x value 0x%" PRIx64
+gicv3_icc_nmiar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_NMIAR1 read cpu 0x%x value 0x%" PRIx64
gicv3_icc_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR%d write cpu 0x%x value 0x%" PRIx64
gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu 0x%x value 0x%" PRIx64
gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu 0x%x value 0x%" PRIx64
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 19/24] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (17 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 18/24] hw/intc/arm_gicv3: Add NMI handling CPU interface registers Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 20/24] hw/intc/arm_gicv3: Implement NMI interrupt priority Jinjie Ruan via
` (6 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
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 <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Enforce RES0 bit in NMI field when FEAT_GICv3_NMI is not implemented for
ICH_LR<n>_EL2.
- Add Reviewed-by.
v12:
- When NMI is 1, the virtual interrupt's priority is 0x0.
- Make the thisnmi logic more concisely in hppvi_index().
- Use is_nmi to simplify the code and check is_nmi before comparing vpmr.
- Remove redundant nmi_support check in ich_highest_active_virt_prio(),
hppvi_index(), icv_hppi_can_preempt(), icv_rpr_read() and icv_activate_irq().
- Also check sctlrx.NMI in icv_iar_read().
- Check icv_hppi_can_preempt() for icv_nmiar1_read().
- Check ICH_LR_EL2.NMI after check icv_hppi_can_preempt() as icv_iar_read()
do it in icv_nmiar1_read().
- Fix the comment style in icv_nmiar1_read().
- Correct thisnmi to bool in icv_eoir_write().
- Check thisnmi and nmi both true instead of identical in icv_eoir_write().
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<n>_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 | 105 +++++++++++++++++++++++++++++++++-----
hw/intc/gicv3_internal.h | 4 ++
hw/intc/trace-events | 1 +
3 files changed, 98 insertions(+), 12 deletions(-)
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index a5a1ef93ca..dff88c4283 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->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI) {
+ return 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 */
@@ -199,6 +204,7 @@ static int hppvi_index(GICv3CPUState *cs)
for (i = 0; i < cs->num_list_regs; i++) {
uint64_t lr = cs->ich_lr_el2[i];
+ bool thisnmi;
int thisprio;
if (ich_lr_state(lr) != ICH_LR_EL2_STATE_PENDING) {
@@ -217,10 +223,12 @@ static int hppvi_index(GICv3CPUState *cs)
}
}
+ thisnmi = lr & ICH_LR_EL2_NMI;
thisprio = ich_lr_prio(lr);
- if (thisprio < prio) {
+ if ((thisprio < prio) || ((thisprio == prio) && (thisnmi & (!nmi)))) {
prio = thisprio;
+ nmi = thisnmi;
idx = i;
}
}
@@ -289,6 +297,7 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
* equivalent of these checks.
*/
int grp;
+ bool is_nmi;
uint32_t mask, prio, rprio, vpmr;
if (!(cs->ich_hcr_el2 & ICH_HCR_EL2_EN)) {
@@ -301,10 +310,11 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
*/
prio = ich_lr_prio(lr);
+ is_nmi = lr & ICH_LR_EL2_NMI;
vpmr = extract64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VPMR_SHIFT,
ICH_VMCR_EL2_VPMR_LENGTH);
- if (prio >= vpmr) {
+ if (!is_nmi && prio >= vpmr) {
/* Priority mask masks this interrupt */
return false;
}
@@ -326,6 +336,11 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
return true;
}
+ if ((prio & mask) == (rprio & mask) && is_nmi &&
+ !(cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI)) {
+ return true;
+ }
+
return false;
}
@@ -550,7 +565,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 & 0xFFFFFFFFU;
+ if (cs->gic->nmi_support) {
+ cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
+ } else {
+ cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
+ }
gicv3_cpuif_virt_irq_fiq_update(cs);
return;
@@ -697,7 +716,11 @@ 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->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 +759,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 (nmi) {
+ cs->ich_apr[grp][regno] |= ICV_AP1R_EL1_NMI;
+ } else {
+ cs->ich_apr[grp][regno] |= (1 << regbit);
+ }
}
static void icv_activate_vlpi(GICv3CPUState *cs)
@@ -763,6 +792,7 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
int grp = ri->crm == 8 ? GICV3_G0 : GICV3_G1NS;
int idx = hppvi_index(cs);
uint64_t intid = INTID_SPURIOUS;
+ int el = arm_current_el(env);
if (idx == HPPVI_INDEX_VLPI) {
if (cs->hppvlpi.grp == grp && icv_hppvlpi_can_preempt(cs)) {
@@ -772,11 +802,16 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
} else if (idx >= 0) {
uint64_t lr = cs->ich_lr_el2[idx];
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
+ bool nmi = env->cp15.sctlr_el[el] & SCTLR_NMI && lr & ICH_LR_EL2_NMI;
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 (!nmi) {
+ icv_activate_irq(cs, idx, grp);
+ } else {
+ intid = INTID_NMI;
+ }
} else {
/* Interrupt goes from Pending to Invalid */
cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT;
@@ -797,8 +832,37 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
static uint64_t icv_nmiar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
- /* todo */
+ GICv3CPUState *cs = icc_cs_from_env(env);
+ int idx = hppvi_index(cs);
uint64_t intid = INTID_SPURIOUS;
+
+ if (idx >= 0 && idx != HPPVI_INDEX_VLPI) {
+ uint64_t lr = cs->ich_lr_el2[idx];
+ int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
+
+ if ((thisgrp == GICV3_G1NS) && icv_hppi_can_preempt(cs, lr)) {
+ intid = ich_lr_vintid(lr);
+ if (!gicv3_intid_is_special(intid)) {
+ if (lr & ICH_LR_EL2_NMI) {
+ icv_activate_irq(cs, idx, GICV3_G1NS);
+ } else {
+ intid = INTID_SPURIOUS;
+ }
+ } else {
+ /* Interrupt goes from Pending to Invalid */
+ cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT;
+ /*
+ * We will now return the (bogus) ID from the list register,
+ * as per the pseudocode.
+ */
+ }
+ }
+ }
+
+ trace_gicv3_icv_nmiar1_read(gicv3_redist_affid(cs), intid);
+
+ gicv3_cpuif_virt_update(cs);
+
return intid;
}
@@ -1423,7 +1487,7 @@ static void icv_increment_eoicount(GICv3CPUState *cs)
ICH_HCR_EL2_EOICOUNT_LENGTH, eoicount + 1);
}
-static int icv_drop_prio(GICv3CPUState *cs)
+static int icv_drop_prio(GICv3CPUState *cs, bool *nmi)
{
/* Drop the priority of the currently active virtual interrupt
* (favouring group 0 if there is a set active bit at
@@ -1445,6 +1509,12 @@ static int icv_drop_prio(GICv3CPUState *cs)
continue;
}
+ if (i == 0 && cs->gic->nmi_support && (*papr1 & ICV_AP1R_EL1_NMI)) {
+ *papr1 &= (~ICV_AP1R_EL1_NMI);
+ *nmi = true;
+ return 0xff;
+ }
+
/* We can't just use the bit-twiddling hack icc_drop_prio() does
* because we need to return the bit number we cleared so
* it can be compared against the list register's priority field.
@@ -1504,6 +1574,7 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
int irq = value & 0xffffff;
int grp = ri->crm == 8 ? GICV3_G0 : GICV3_G1NS;
int idx, dropprio;
+ bool nmi = false;
trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1,
gicv3_redist_affid(cs), value);
@@ -1516,8 +1587,8 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
* error checks" (because that lets us avoid scanning the AP
* registers twice).
*/
- dropprio = icv_drop_prio(cs);
- if (dropprio == 0xff) {
+ dropprio = icv_drop_prio(cs, &nmi);
+ if (dropprio == 0xff && !nmi) {
/* No active interrupt. It is CONSTRAINED UNPREDICTABLE
* whether the list registers are checked in this
* situation; we choose not to.
@@ -1539,8 +1610,9 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t lr = cs->ich_lr_el2[idx];
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp);
+ bool thisnmi = lr & ICH_LR_EL2_NMI;
- if (thisgrp == grp && lr_gprio == dropprio) {
+ if (thisgrp == grp && (lr_gprio == dropprio || (thisnmi & nmi))) {
if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) {
/*
* Priority drop and deactivate not split: deactivate irq now.
@@ -2626,7 +2698,11 @@ static void ich_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
trace_gicv3_ich_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
- cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
+ if (cs->gic->nmi_support) {
+ cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
+ } else {
+ cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
+ }
gicv3_cpuif_virt_irq_fiq_update(cs);
}
@@ -2743,6 +2819,11 @@ static void ich_lr_write(CPUARMState *env, const ARMCPRegInfo *ri,
8 - cs->vpribits, 0);
}
+ /* Enforce RES0 bit in NMI field when FEAT_GICv3_NMI is not implemented */
+ if (!cs->gic->nmi_support) {
+ value &= ~ICH_LR_EL2_NMI;
+ }
+
cs->ich_lr_el2[regno] = value;
gicv3_cpuif_virt_update(cs);
}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 81200eb90e..bc9f518fe8 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -246,6 +246,7 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1)
#define ICH_LR_EL2_PRIORITY_SHIFT 48
#define ICH_LR_EL2_PRIORITY_LENGTH 8
#define ICH_LR_EL2_PRIORITY_MASK (0xffULL << ICH_LR_EL2_PRIORITY_SHIFT)
+#define ICH_LR_EL2_NMI (1ULL << 59)
#define ICH_LR_EL2_GROUP (1ULL << 60)
#define ICH_LR_EL2_HW (1ULL << 61)
#define ICH_LR_EL2_STATE_SHIFT 62
@@ -277,6 +278,9 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1)
#define ICH_VTR_EL2_PREBITS_SHIFT 26
#define ICH_VTR_EL2_PRIBITS_SHIFT 29
+#define ICV_AP1R_EL1_NMI (1ULL << 63)
+#define ICV_RPR_EL1_NMI (1ULL << 63)
+
/* ITS Registers */
FIELD(GITS_BASER, SIZE, 0, 8)
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 94030550d5..47340b5bc1 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -152,6 +152,7 @@ gicv3_icv_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICV_RPR read cpu 0x%x valu
gicv3_icv_hppir_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_HPPIR%d read cpu 0x%x value 0x%" PRIx64
gicv3_icv_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICV_DIR write cpu 0x%x value 0x%" PRIx64
gicv3_icv_iar_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IAR%d read cpu 0x%x value 0x%" PRIx64
+gicv3_icv_nmiar1_read(uint32_t cpu, uint64_t val) "GICv3 ICV_NMIAR1 read cpu 0x%x value 0x%" PRIx64
gicv3_icv_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_EOIR%d write cpu 0x%x value 0x%" PRIx64
gicv3_cpuif_virt_update(uint32_t cpuid, int idx, int hppvlpi, int grp, int prio) "GICv3 CPU i/f 0x%x virt HPPI update LR index %d HPPVLPI %d grp %d prio %d"
gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting FIQ %d IRQ %d"
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 20/24] hw/intc/arm_gicv3: Implement NMI interrupt priority
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (18 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 19/24] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read() Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 21/24] hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update() Jinjie Ruan via
` (5 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
If GICD_CTLR_DS bit is zero and the NMI is non-secure, the NMI priority is
higher than 0x80, otherwise it is higher than 0x0. And save the interrupt
non-maskable property in hppi.nmi to deliver NMI exception. Since both GICR
and GICD can deliver NMI, it is both necessary to check whether the pending
irq is NMI in gicv3_redist_update_noirqset and gicv3_update_noirqset.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Swap the order of the irq and prio args in gicv3_get_priority() to make
input before output.
- Update the commit message.
v12:
- Fix the typo, "prioirty" -> "priority"
- Update the commit message, hppi.superprio -> hppi.nmi
super priority -> non-maskable property.
- Add Reviewed-by.
v10:
- has_superprio -> nmi.
- superpriority -> non-maskable property.
- gicr_isuperprio -> gicr_inmir0.
- superprio -> nmi.
v8:
- Add Reviewed-by.
v7:
- Reorder the irqbetter() code for clarity.
- Eliminate the has_superprio local variable for gicv3_get_priority().
- false -> cs->hpplpi.superprio in gicv3_redist_update_noirqset().
- 0x0 -> false in arm_gicv3_common_reset_hold().
- Clear superprio in several places for hppi, hpplpi and hppvlpi.
v6:
- Put the "extract superprio info" logic into gicv3_get_priority().
- Update the comment in irqbetter().
- Reset the cs->hppi.superprio to 0x0.
- Set hppi.superprio to false for LPI.
v4:
- Replace is_nmi with has_superprio to not a mix NMI and superpriority.
- Update the comment in irqbetter().
- Extract gicv3_get_priority() to avoid code repeat.
---
v3:
- Add missing brace
---
hw/intc/arm_gicv3.c | 67 +++++++++++++++++++++++++++++++++-----
hw/intc/arm_gicv3_common.c | 3 ++
hw/intc/arm_gicv3_redist.c | 3 ++
3 files changed, 64 insertions(+), 9 deletions(-)
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 0b8f79a122..58e18fff54 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -21,7 +21,7 @@
#include "hw/intc/arm_gicv3.h"
#include "gicv3_internal.h"
-static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
+static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio, bool nmi)
{
/* Return true if this IRQ at this priority should take
* precedence over the current recorded highest priority
@@ -30,14 +30,23 @@ static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
* is the same as this one (a property which the calling code
* relies on).
*/
- if (prio < cs->hppi.prio) {
- return true;
+ if (prio != cs->hppi.prio) {
+ return prio < cs->hppi.prio;
+ }
+
+ /*
+ * The same priority IRQ with non-maskable property should signal to
+ * the CPU as it have the priority higher than the labelled 0x80 or 0x00.
+ */
+ if (nmi != cs->hppi.nmi) {
+ return nmi;
}
+
/* If multiple pending interrupts have the same priority then it is an
* IMPDEF choice which of them to signal to the CPU. We choose to
* signal the one with the lowest interrupt number.
*/
- if (prio == cs->hppi.prio && irq <= cs->hppi.irq) {
+ if (irq <= cs->hppi.irq) {
return true;
}
return false;
@@ -129,6 +138,40 @@ static uint32_t gicr_int_pending(GICv3CPUState *cs)
return pend;
}
+static bool gicv3_get_priority(GICv3CPUState *cs, bool is_redist, int irq,
+ uint8_t *prio)
+{
+ uint32_t nmi = 0x0;
+
+ if (is_redist) {
+ nmi = extract32(cs->gicr_inmir0, irq, 1);
+ } else {
+ nmi = *gic_bmp_ptr32(cs->gic->nmi, irq);
+ nmi = nmi & (1 << (irq & 0x1f));
+ }
+
+ if (nmi) {
+ /* DS = 0 & Non-secure NMI */
+ if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
+ ((is_redist && extract32(cs->gicr_igroupr0, irq, 1)) ||
+ (!is_redist && gicv3_gicd_group_test(cs->gic, irq)))) {
+ *prio = 0x80;
+ } else {
+ *prio = 0x0;
+ }
+
+ return true;
+ }
+
+ if (is_redist) {
+ *prio = cs->gicr_ipriorityr[irq];
+ } else {
+ *prio = cs->gic->gicd_ipriority[irq];
+ }
+
+ return false;
+}
+
/* Update the interrupt status after state in a redistributor
* or CPU interface has changed, but don't tell the CPU i/f.
*/
@@ -141,6 +184,7 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
uint8_t prio;
int i;
uint32_t pend;
+ bool nmi = false;
/* Find out which redistributor interrupts are eligible to be
* signaled to the CPU interface.
@@ -152,10 +196,11 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
if (!(pend & (1 << i))) {
continue;
}
- prio = cs->gicr_ipriorityr[i];
- if (irqbetter(cs, i, prio)) {
+ nmi = gicv3_get_priority(cs, true, i, &prio);
+ if (irqbetter(cs, i, prio, nmi)) {
cs->hppi.irq = i;
cs->hppi.prio = prio;
+ cs->hppi.nmi = nmi;
seenbetter = true;
}
}
@@ -168,9 +213,10 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
(cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) &&
(cs->hpplpi.prio != 0xff)) {
- if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
+ if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio, cs->hpplpi.nmi)) {
cs->hppi.irq = cs->hpplpi.irq;
cs->hppi.prio = cs->hpplpi.prio;
+ cs->hppi.nmi = cs->hpplpi.nmi;
cs->hppi.grp = cs->hpplpi.grp;
seenbetter = true;
}
@@ -213,6 +259,7 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
int i;
uint8_t prio;
uint32_t pend = 0;
+ bool nmi = false;
assert(start >= GIC_INTERNAL);
assert(len > 0);
@@ -240,10 +287,11 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
*/
continue;
}
- prio = s->gicd_ipriority[i];
- if (irqbetter(cs, i, prio)) {
+ nmi = gicv3_get_priority(cs, false, i, &prio);
+ if (irqbetter(cs, i, prio, nmi)) {
cs->hppi.irq = i;
cs->hppi.prio = prio;
+ cs->hppi.nmi = nmi;
cs->seenbetter = true;
}
}
@@ -293,6 +341,7 @@ void gicv3_full_update_noirqset(GICv3State *s)
for (i = 0; i < s->num_cpu; i++) {
s->cpu[i].hppi.prio = 0xff;
+ s->cpu[i].hppi.nmi = false;
}
/* Note that we can guarantee that these functions will not
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 9810558b07..207f8417e1 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -536,8 +536,11 @@ static void arm_gicv3_common_reset_hold(Object *obj)
memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
cs->hppi.prio = 0xff;
+ cs->hppi.nmi = false;
cs->hpplpi.prio = 0xff;
+ cs->hpplpi.nmi = false;
cs->hppvlpi.prio = 0xff;
+ cs->hppvlpi.nmi = false;
/* State in the CPU interface must *not* be reset here, because it
* is part of the CPU's reset domain, not the GIC device's.
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index ed1f9d1e44..90b238fac0 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -120,6 +120,7 @@ static void update_for_one_lpi(GICv3CPUState *cs, int irq,
((prio == hpp->prio) && (irq <= hpp->irq))) {
hpp->irq = irq;
hpp->prio = prio;
+ hpp->nmi = false;
/* LPIs and vLPIs are always non-secure Grp1 interrupts */
hpp->grp = GICV3_G1NS;
}
@@ -156,6 +157,7 @@ static void update_for_all_lpis(GICv3CPUState *cs, uint64_t ptbase,
int i, bit;
hpp->prio = 0xff;
+ hpp->nmi = false;
for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
address_space_read(as, ptbase + i, MEMTXATTRS_UNSPECIFIED, &pend, 1);
@@ -241,6 +243,7 @@ static void gicv3_redist_update_vlpi_only(GICv3CPUState *cs)
if (!FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, VALID)) {
cs->hppvlpi.prio = 0xff;
+ cs->hppvlpi.nmi = false;
return;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 21/24] hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update()
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (19 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 20/24] hw/intc/arm_gicv3: Implement NMI interrupt priority Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 22/24] hw/intc/arm_gicv3: Report the VINMI interrupt Jinjie Ruan via
` (4 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
In CPU Interface, if the IRQ has the non-maskable property, report NMI to
the corresponding PE.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v12:
- Add Reviewed-by.
v10:
- superprio -> nmi.
- Update the commit message, superpriority -> non-maskable.
v6:
- Add Reviewed-by.
v4:
- Swap the ordering of the IFs.
v3:
- Remove handling nmi_is_irq flag.
---
hw/intc/arm_gicv3_cpuif.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index dff88c4283..60e2d9ec9c 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -1037,6 +1037,7 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
/* Tell the CPU about its highest priority pending interrupt */
int irqlevel = 0;
int fiqlevel = 0;
+ int nmilevel = 0;
ARMCPU *cpu = ARM_CPU(cs->cpu);
CPUARMState *env = &cpu->env;
@@ -1075,6 +1076,8 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
if (isfiq) {
fiqlevel = 1;
+ } else if (cs->hppi.nmi) {
+ nmilevel = 1;
} else {
irqlevel = 1;
}
@@ -1084,6 +1087,7 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
qemu_set_irq(cs->parent_fiq, fiqlevel);
qemu_set_irq(cs->parent_irq, irqlevel);
+ qemu_set_irq(cs->parent_nmi, nmilevel);
}
static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri)
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 22/24] hw/intc/arm_gicv3: Report the VINMI interrupt
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (20 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 21/24] hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update() Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 23/24] target/arm: Add FEAT_NMI to max Jinjie Ruan via
` (3 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
In vCPU Interface, if the vIRQ has the non-maskable property, report
vINMI to the corresponding vPE.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v12:
- Do not check nmi_support repetitively.
- Add Reviewed-by.
v10:
- Update the commit message, superpriority -> non-maskable.
v9:
- Update the commit subject and message, vNMI -> vINMI.
v6:
- Add Reviewed-by.
---
hw/intc/arm_gicv3_cpuif.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 60e2d9ec9c..0de7c41f96 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -480,6 +480,7 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
int idx;
int irqlevel = 0;
int fiqlevel = 0;
+ int nmilevel = 0;
idx = hppvi_index(cs);
trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx,
@@ -497,9 +498,17 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
uint64_t lr = cs->ich_lr_el2[idx];
if (icv_hppi_can_preempt(cs, lr)) {
- /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */
+ /*
+ * Virtual interrupts are simple: G0 are always FIQ, and G1 are
+ * IRQ or NMI which depends on the ICH_LR<n>_EL2.NMI to have
+ * non-maskable property.
+ */
if (lr & ICH_LR_EL2_GROUP) {
- irqlevel = 1;
+ if (lr & ICH_LR_EL2_NMI) {
+ nmilevel = 1;
+ } else {
+ irqlevel = 1;
+ }
} else {
fiqlevel = 1;
}
@@ -509,6 +518,7 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel);
qemu_set_irq(cs->parent_vfiq, fiqlevel);
qemu_set_irq(cs->parent_virq, irqlevel);
+ qemu_set_irq(cs->parent_vnmi, nmilevel);
}
static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 23/24] target/arm: Add FEAT_NMI to max
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (21 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 22/24] hw/intc/arm_gicv3: Report the VINMI interrupt Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-07 8:17 ` [PATCH v13 24/24] hw/arm/virt: Add FEAT_GICv3_NMI feature support in virt GIC Jinjie Ruan via
` (2 subsequent siblings)
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
Enable FEAT_NMI on the 'max' CPU.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
v12:
- Add Reviewed-by.
v3:
- Add Reviewed-by.
- Sorted to last.
---
docs/system/arm/emulation.rst | 1 +
target/arm/tcg/cpu64.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 2a7bbb82dc..a9ae7ede9f 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -64,6 +64,7 @@ the following architecture extensions:
- FEAT_MTE (Memory Tagging Extension)
- FEAT_MTE2 (Memory Tagging Extension)
- FEAT_MTE3 (MTE Asymmetric Fault Handling)
+- FEAT_NMI (Non-maskable Interrupt)
- FEAT_NV (Nested Virtualization)
- FEAT_NV2 (Enhanced nested virtualization support)
- FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm)
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 9f7a9f3d2c..62c4663512 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1175,6 +1175,7 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */
t = FIELD_DP64(t, ID_AA64PFR1, SME, 1); /* FEAT_SME */
t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */
+ t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1); /* FEAT_NMI */
cpu->isar.id_aa64pfr1 = t;
t = cpu->isar.id_aa64mmfr0;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v13 24/24] hw/arm/virt: Add FEAT_GICv3_NMI feature support in virt GIC
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (22 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 23/24] target/arm: Add FEAT_NMI to max Jinjie Ruan via
@ 2024-04-07 8:17 ` Jinjie Ruan via
2024-04-10 6:19 ` [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
2024-04-19 13:41 ` Peter Maydell
25 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-07 8:17 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Cc: ruanjinjie
FEAT_GICv3_NMI introduces GIC support for non-maskable interrupts (NMIs).
A PE that implements FEAT_NMI and FEAT_GICv3 also implements FEAT_GICv3_NMI.
A PE that does not implement FEAT_NMI, does not implement FEAT_GICv3_NMI.
So included support FEAT_GICv3_NMI feature as part of virt platform
GIC initialization if FEAT_NMI and FEAT_GICv3 supported.
And as Peter suggested, neither KVM nor hvf support FEAT_NMI yet, so add
tcg_enabled() to the condition. Defaulting QEMU to not trying to enable NMI
in the GIC device is the safe option. As and when those accelerators get NMI
support, we can add the handling to QEMU and update this code in the virt board.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
---
v13:
- Check tcg_enabled() for gicv3_nmi_present().
- Update the comment for gicv3_nmi_present().
- Update the commit message.
- Add Suggested-by.
v4:
- Add Reviewed-by.
v3:
- Adjust to be the last after add FEAT_NMI to max.
- Check whether support FEAT_NMI and FEAT_GICv3 for FEAT_GICv3_NMI.
---
hw/arm/virt.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index dca509d082..a8c9156b24 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -729,6 +729,18 @@ static void create_v2m(VirtMachineState *vms)
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
}
+/*
+ * A PE that implements FEAT_NMI and FEAT_GICv3 also implements FEAT_GICv3_NMI.
+ * A PE that does not implement FEAT_NMI, does not implement FEAT_GICv3_NMI.
+ */
+static bool gicv3_nmi_present(VirtMachineState *vms)
+{
+ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(0));
+
+ return tcg_enabled() && cpu_isar_feature(aa64_nmi, cpu) &&
+ (vms->gic_version != VIRT_GIC_VERSION_2);
+}
+
static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
{
MachineState *ms = MACHINE(vms);
@@ -802,6 +814,11 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
vms->virt);
}
}
+
+ if (gicv3_nmi_present(vms)) {
+ qdev_prop_set_bit(vms->gic, "has-nmi", true);
+ }
+
gicbusdev = SYS_BUS_DEVICE(vms->gic);
sysbus_realize_and_unref(gicbusdev, &error_fatal);
sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base);
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (23 preceding siblings ...)
2024-04-07 8:17 ` [PATCH v13 24/24] hw/arm/virt: Add FEAT_GICv3_NMI feature support in virt GIC Jinjie Ruan via
@ 2024-04-10 6:19 ` Jinjie Ruan via
2024-04-10 12:58 ` Peter Maydell
2024-04-19 13:41 ` Peter Maydell
25 siblings, 1 reply; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-10 6:19 UTC (permalink / raw)
To: peter.maydell, eduardo, marcel.apfelbaum, philmd, wangyanan55,
richard.henderson, qemu-devel, qemu-arm
Ping.
On 2024/4/7 16:17, Jinjie Ruan wrote:
> This patch set implements FEAT_NMI and FEAT_GICv3_NMI for ARMv8. These
> introduce support for a new category of interrupts in the architecture
> which we can use to provide NMI like functionality.
>
> There are two modes for using this FEAT_NMI. When PSTATE.ALLINT or
> PSTATE.SP & SCTLR_ELx.SCTLR_SPINTMASK is set, any entry to ELx causes all
> interrupts including those with superpriority to be masked on entry to ELn
> until the mask is explicitly removed by software or hardware. PSTATE.ALLINT
> can be managed by software using the new register control ALLINT.ALLINT.
> Independent controls are provided for this feature at each EL, usage at EL1
> should not disrupt EL2 or EL3.
>
> I have tested it with the following Linux patches which try to support
> FEAT_NMI in Linux kernel:
>
> https://lore.kernel.org/linux-arm-kernel/Y4sH5qX5bK9xfEBp@lpieralisi/T/#mb4ba4a2c045bf72c10c2202c1dd1b82d3240dc88
>
> In the test, SGI, PPI and SPI interrupts can all be set to have super priority
> to be converted to a hardware NMI interrupt. The SGI is tested with kernel
> IPI as NMI framework, softlockup, hardlockup and kgdb test cases, and the PPI
> interrupt is tested with "perf top" command with hardware NMI enabled, and
> the SPI interrupt is tested with a custom test module, in which NMI interrupts
> can be received and sent normally.
>
> And the Virtual NMI(VNMI) SGI, PPI and SPI interrupts has also been tested in
> nested QEMU Virtual Machine with host "virtualization=true". The SGI VNMI is
> tested by accessing GICR_INMIR0 and GICR_ISPENDR0 with devmem command, as well
> as hardlockup and kgdb testcases. The PPI VNMI is tested by accessing
> GICR_INMIR0 and GICR_ISPENDR0 with devmem command, as well as "perf top"
> command with hardware NMI enabled, which works well. The SPI VNMI is tested
> with a custom test module, in which SPI VNMI can be sent from the GIC and
> received normally.
>
> +-------------------------------------------------+
> | Distributor |
> +-------------------------------------------------+
> SPI | NMI | NMI
> \/ \/
> +--------+ +-------+
> | Redist | | Redist|
> +--------+ +-------+
> SGI | NMI PPI | NMI
> \/ \/
> +-------------+ +---------------+
> |CPU Interface| ... | CPU Interface |
> +-------------+ +---------------+
> | NMI | NMI
> \/ \/
> +-----+ +-----+
> | PE | | PE |
> +-----+ +-----+
>
> Changes in v13:
> - Handle PSTATE.ALLINT the same way as PSTATE.DAIF in the illegal_return
> exit path.
> - Adjust "hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU" to after
> "hw/intc/arm_gicv3: Add external IRQ lines for NMI" to fix the unexpected
> error with patchseries at this point.
> - Only connect NMI irq lines from GIC to CPU if vms->gic_version is not
> VIRT_GIC_VERSION_2 to fix the gic-version=2 unexpected error.
> - Enforce RES0 bit in NMI field when FEAT_GICv3_NMI is not implemented for
> ICH_LR<n>_EL2.
> - Swap the order of the "irq" and "prio" args in gicv3_get_priority() to make
> input before output.
> - Check tcg_enabled() for gicv3_nmi_present().
> - Update the comment for gicv3_nmi_present().
> - Update the commit message.
> - Add Reviewed-by.
> - Add Suggested-by.
>
> Changes in v12:
> - pPriority<63> = ICC_AP1R_EL1NS<63> if HaveNMIExt() and HaveEL(EL3) and
> (IsNonSecure(), fix the wrong writing.
> - Do not check nmi_support repetitively in icc_hppi_can_preempt(),
> and icc_activate_irq, ich_highest_active_virt_prio(), hppvi_index(),
> icv_hppi_can_preempt(), icv_rpr_read() and icv_activate_irq(),
> gicv3_cpuif_virt_irq_fiq_update().
> - Check hppi.nmi after check icc_hppi_can_preempt() for icc_iar1_read() and
> icc_nmiar1_read().
> - When NMI is 1, the virtual interrupt's priority is 0x0.
> - Make the thisnmi logic more concisely in hppvi_index().
> - Use is_nmi to simplify code and check is_nmi before comparing vpmr.
> - Also check sctlrx.NMI in icv_iar_read().
> - Check icv_hppi_can_preempt() for icv_nmiar1_read().
> - Check ICH_LR_EL2.NMI after check icv_hppi_can_preempt() as icv_iar_read()
> do it in icv_nmiar1_read().
> - Correct thisnmi to bool in icv_eoir_write().
> - Check thisnmi and nmi both true instead of identical in icv_eoir_write().
> - nmi_needed -> gicv3_cpu_nmi_needed, needed_nmi -> gicv3_nmi_needed.
> - Correct the comment style in arm_cpu_initfn() and icv_nmiar1_read().
> - Fix the typo, "prioirty" -> "priority".
> - Remove the redundant blank line.
> - Update the subject and commit message, hppi.superprio -> hppi.nmi,
> super priority -> non-maskable property.
> - Add Reviewed-by.
>
> Changes in v11:
> - Put vmstate_gicv3_cpu_nmi and vmstate_gicv3_gicd_nmi into existing list.
> - Remove the excess != 0.
> - Handle NMI priority in icc_highest_active_prio() and handle NMI RPR in
> icc_rpr_read() separately.
> - Only set NMI bit for a NMI and and ordinary priority bit for a non-NMI in
> icc_activate_irq().
> - Only clear APR bit for AP1R0 in icc_drop_prio().
> - Check special INTID_* in callers instead of passing two extra boolean args
> for ack functions.
> - Handle NMI in icc_hppi_can_preempt() and icc_highest_active_group().
> - Also check icc_hppi_can_preempt() for icc_nmiar1_read().
> - 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().
> - Add Reviewed-by.
>
> Changes in v10:
> - Correct the exception_target_el(env) to 2 in msr_set_allint_el1 helper,
> since it is a hypervisor trap from EL1 to EL2.
> - In arm_cpu_exec_interrupt(), if SCTLR_ELx.NMI is 0, NMI -> IRQ,
> VINMI -> VIRQ, VFNMI -> VFIQ.
> - Make arm_cpu_update_virq() and arm_cpu_update_vfiq() check that it is not a
> VINMI/VFNMI, so only set 1 bit in interrupt_request, not 2.
> - Adjust "hw/intc: Enable FEAT_GICv3_NMI Feature" to before "add irq
> non-maskable property".
> - superprio -> nmi, gicr_isuperprio -> gicr_inmir0, is_nmi -> nmi,
> is_hppi -> hppi, has_superprio -> nmi, superpriority -> non-maskable property.
> - Save NMI state in vmstate_gicv3_cpu and vmstate_gicv3.
> - Exchange the order of nmi and hppi parameters.
> - Handle APR and RPR NMI bits, rename ICH_AP1R_EL2_NMI to ICV_AP1R_EL1_NMI.
> - Set ICV_RPR_EL1.NMI according to the ICV_AP1R<n>_EL1.NMI in
> ich_highest_active_virt_prio()
> - Update the commit message.
>
> Changes in v9:
> - Move nmi_reginfo and related functions inside an existing ifdef
> TARGET_AARCH64 to solve the --target-list=aarch64-softmmu,arm-softmmu
> compilation problem.
> - Check 'isread' when writing to ALLINT.
> - Update the GPIOs passed in the arm_cpu_kvm_set_irq, and update the comment.
> - Definitely not merge VINMI and VFNMI into EXCP_VNMI.
> - ARM_CPU_VNMI -> ARM_CPU_VINMI, CPU_INTERRUPT_VNMI -> CPU_INTERRUPT_VINMI.
> - Update VINMI and VFNMI when writing HCR_EL2 or HCRX_EL2.
> - Update the commit subject and message, VNMI -> VINMI.
> - Handle CPSR_F and ISR_FS according to CPU_INTERRUPT_VFNMI instead of
> CPU_INTERRUPT_VFIQ and HCRX_EL2.VFNMI.
> - Not check SCTLR_NMI in arm_cpu_do_interrupt_aarch64().
> - Correct the INTID_NMI logic.
> - Declare cpu variable to reuse latter.
>
> Changes in v8:
> - Fix the rcu stall after sending a VNMI in qemu VM.
> - Fix an unexpected interrupt bug when sending VNMI by running qemu VM.
> - Test the VNMI interrupt.
> - Update the commit message.
> - Add Reviewed-by.
>
> Changes in v7:
> - env->cp15.hcrx_el2 -> arm_hcrx_el2_eff().
> - Reorder the irqbetter() code for clarity.
> - Eliminate the has_superprio local variable for gicv3_get_priority().
> - false -> cs->hpplpi.superprio in gicv3_redist_update_noirqset().
> - 0x0 -> false in arm_gicv3_common_reset_hold().
> - Clear superprio in several places for hppi, hpplpi and hppvlpi.
> - Add Reviewed-by.
>
> Changes in v6:
> - Fix DISAS_TOO_MANY to DISAS_UPDATE_EXIT for ALLINT MSR (immediate).
> - Verify that HCR_EL2.VF is set before checking VFNMI.
> - env->cp15.hcr_el2 -> arm_hcr_el2_eff().
> - env->cp15.hcrx_el2 -> arm_hcrx_el2_eff().
> - Not combine VFNMI with CPU_INTERRUPT_VNMI.
> - Implement icv_nmiar1_read().
> - Put the "extract superprio info" code into gicv3_get_priority().
> - Update the comment in irqbetter().
> - Reset the cs->hppi.superprio to 0x0.
> - Set hppi.superprio to false for LPI.
> - Add Reviewed-by.
>
> Changes in v5:
> - Remove the comment for ALLINT in cpu.h.
> - Merge allint_check() to msr_i_allint to clear the ALLINT MSR (immediate)
> implementation.
> - Rename msr_i_allint() to msr_set_allint_el1() to make it clearer.
> - Drop the & 1 in trans_MSR_i_ALLINT().
> - Add Reviewed-by.
>
> Changes in v4:
> - Handle VNMI within the CPU and the GIC.
> - Keep PSTATE.ALLINT in env->pstate but not env->allint.
> - Fix the ALLINT MSR (immediate) decodetree implementation.
> - Accept NMI unconditionally for arm_cpu_has_work() but add comment.
> - Improve nmi mask in arm_excp_unmasked().
> - Make the GICR_INMIR0 and GICD_INMIR implementation more clearer.
> - Improve ICC_NMIAR1_EL1 implementation
> - Extract gicv3_get_priority() to avoid priority code repetition.
> - Add Reviewed-by.
>
> Changes in v3:
> - Remove the FIQ NMI.
> - Adjust the patches Sequence.
> - Reomve the patch "Set pstate.ALLINT in arm_cpu_reset_hold".
> - Check whether support FEAT_NMI and FEAT_GICv3 for FEAT_GICv3_NMI.
> - With CPU_INTERRUPT_NMI, both CPSR_I and ISR_IS must be set.
> - Not include NMI logic when FEAT_NMI or SCTLR_ELx.NMI not enabled.
> - Refator nmi mask in arm_excp_unmasked().
> - Add VNMI definitions, add HCRX_VINMI and HCRX_VFNMI support in HCRX_EL2.
> - Add Reviewed-by and Acked-by.
> - Update the commit message.
>
> Changes in v2:
> - Break up the patches so that each one does only one thing.
> - Remove the command line option and just implement it in "max" cpu.
>
> Jinjie Ruan (24):
> target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI
> target/arm: Add PSTATE.ALLINT
> target/arm: Add support for FEAT_NMI, Non-maskable Interrupt
> target/arm: Implement ALLINT MSR (immediate)
> target/arm: Support MSR access to ALLINT
> target/arm: Add support for Non-maskable Interrupt
> target/arm: Add support for NMI in arm_phys_excp_target_el()
> target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI
> target/arm: Handle PSTATE.ALLINT on taking an exception
> hw/intc/arm_gicv3: Add external IRQ lines for NMI
> hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU
> target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64()
> hw/intc/arm_gicv3: Add has-nmi property to GICv3 device
> hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3
> hw/intc/arm_gicv3: Add irq non-maskable property
> hw/intc/arm_gicv3_redist: Implement GICR_INMIR0
> hw/intc/arm_gicv3: Implement GICD_INMIR
> hw/intc/arm_gicv3: Add NMI handling CPU interface registers
> hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
> hw/intc/arm_gicv3: Implement NMI interrupt priority
> hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update()
> hw/intc/arm_gicv3: Report the VINMI interrupt
> target/arm: Add FEAT_NMI to max
> hw/arm/virt: Add FEAT_GICv3_NMI feature support in virt GIC
>
> docs/system/arm/emulation.rst | 1 +
> hw/arm/virt.c | 27 ++-
> hw/intc/arm_gicv3.c | 67 +++++++-
> hw/intc/arm_gicv3_common.c | 48 ++++++
> hw/intc/arm_gicv3_cpuif.c | 258 +++++++++++++++++++++++++++--
> hw/intc/arm_gicv3_dist.c | 36 ++++
> hw/intc/arm_gicv3_kvm.c | 5 +
> hw/intc/arm_gicv3_redist.c | 22 +++
> hw/intc/gicv3_internal.h | 13 ++
> hw/intc/trace-events | 2 +
> include/hw/intc/arm_gic_common.h | 2 +
> include/hw/intc/arm_gicv3_common.h | 7 +
> target/arm/cpu-features.h | 5 +
> target/arm/cpu-qom.h | 5 +-
> target/arm/cpu.c | 147 ++++++++++++++--
> target/arm/cpu.h | 9 +
> target/arm/helper.c | 101 ++++++++++-
> target/arm/internals.h | 21 +++
> target/arm/tcg/a64.decode | 1 +
> target/arm/tcg/cpu64.c | 1 +
> target/arm/tcg/helper-a64.c | 16 +-
> target/arm/tcg/helper-a64.h | 1 +
> target/arm/tcg/translate-a64.c | 19 +++
> 23 files changed, 767 insertions(+), 47 deletions(-)
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI
2024-04-10 6:19 ` [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
@ 2024-04-10 12:58 ` Peter Maydell
2024-04-11 1:13 ` Jinjie Ruan via
0 siblings, 1 reply; 30+ messages in thread
From: Peter Maydell @ 2024-04-10 12:58 UTC (permalink / raw)
To: Jinjie Ruan
Cc: eduardo, marcel.apfelbaum, philmd, wangyanan55, richard.henderson,
qemu-devel, qemu-arm
On Wed, 10 Apr 2024 at 07:19, Jinjie Ruan via <qemu-arm@nongnu.org> wrote:
>
> Ping.
As I said in my reply on the previous version, we're in
freeze at the moment, so this patchset is not going anywhere
until 9.0 releases. I think it's in shape to apply after that.
thanks
-- PMM
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI
2024-04-10 12:58 ` Peter Maydell
@ 2024-04-11 1:13 ` Jinjie Ruan via
0 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-11 1:13 UTC (permalink / raw)
To: Peter Maydell
Cc: eduardo, marcel.apfelbaum, philmd, wangyanan55, richard.henderson,
qemu-devel, qemu-arm
On 2024/4/10 20:58, Peter Maydell wrote:
> On Wed, 10 Apr 2024 at 07:19, Jinjie Ruan via <qemu-arm@nongnu.org> wrote:
>>
>> Ping.
>
> As I said in my reply on the previous version, we're in
> freeze at the moment, so this patchset is not going anywhere
> until 9.0 releases. I think it's in shape to apply after that.
Thank you! I don't know if there's any other minor issues.
>
> thanks
> -- PMM
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI
2024-04-07 8:17 [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
` (24 preceding siblings ...)
2024-04-10 6:19 ` [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI Jinjie Ruan via
@ 2024-04-19 13:41 ` Peter Maydell
2024-04-22 2:25 ` Jinjie Ruan via
25 siblings, 1 reply; 30+ messages in thread
From: Peter Maydell @ 2024-04-19 13:41 UTC (permalink / raw)
To: Jinjie Ruan
Cc: eduardo, marcel.apfelbaum, philmd, wangyanan55, richard.henderson,
qemu-devel, qemu-arm
On Sun, 7 Apr 2024 at 09:19, Jinjie Ruan <ruanjinjie@huawei.com> wrote:
>
> This patch set implements FEAT_NMI and FEAT_GICv3_NMI for ARMv8. These
> introduce support for a new category of interrupts in the architecture
> which we can use to provide NMI like functionality.
I had one last loose end I wanted to tidy up, and I got round
to working through reading the spec about it today. This is
the question of what the "is NMI enabled?" test should be
in the code in arm_gicv3_cpuif.c.
The spec wording isn't always super clear, but there are several
things here:
* FEAT_NMI : the changes to the CPU proper which implement
superpriority for IRQ and FIQ, PSTATE.ALLINT, etc etc.
* FEAT_GICv3_NMI : the changes to the CPU interface for
GICv3 NMI handling. Any CPU with FEAT_NMI and FEAT_GICv3
must have this.
* NMI support in the IRI (Interrupt Routing Infrastructure,
i.e. all the bits of the GIC that aren't the cpuif; the
distributor and redistributors). Table 3-1 in the GIC spec
says that you can have an IRI without NMI support connected
to a CPU which does have NMI support. This is what the ID
register bit GICD_TYPER.NMI reports.
At the moment this patchset conflates FEAT_GICv3_NMI and
the NMI support in the IRI. The effect of this is that we
allow a machine model to create a CPU with FEAT_NMI but
without FEAT_GICv3_NMI in the cpuif, and we don't allow
a setup where the CPU and cpuif have NMI support but the
IRI does not. (This will actually happen with this patchset
with the sbsa-ref machine and -cpu max, because we haven't
(yet) made sbsa-ref enable NMI in the GIC device when the
CPU has NMI support.)
For a Linux guest this doesn't make much difference, because
Linux will only enable NMI support if it finds it in both
the IRI and the CPU, but I think it would be better to
get the enable-tests right as these can be awkward to change
after the fact in a backwards-compatible way.
I think this is easy to fix -- we can add a new bool field
GICv3CPUState::nmi_support which we initialize in
gicv3_init_cpuif() if the CPU has FEAT_NMI, and make the
checks in arm_gicv3_cpuif.c check cs->nmi_support instead
of cs->gic->nmi_support. That looks like this squashed into
patch 18:
diff --git a/include/hw/intc/arm_gicv3_common.h
b/include/hw/intc/arm_gicv3_common.h
index 88533749ebb..cd09bee3bc4 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -225,6 +225,13 @@ struct GICv3CPUState {
/* This is temporary working state, to avoid a malloc in gicv3_update() */
bool seenbetter;
+
+ /*
+ * Whether the CPU interface has NMI support (FEAT_GICv3_NMI). The
+ * CPU interface may support NMIs even when the GIC proper (what the
+ * spec calls the IRI; the redistributors and distributor) does not.
+ */
+ bool nmi_support;
};
/*
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 2457b7bca23..715909d0f7d 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -21,6 +21,7 @@
#include "hw/irq.h"
#include "cpu.h"
#include "target/arm/cpregs.h"
+#include "target/arm/cpu-features.h"
#include "sysemu/tcg.h"
#include "sysemu/qtest.h"
@@ -839,7 +840,7 @@ static int icc_highest_active_prio(GICv3CPUState *cs)
*/
int i;
- if (cs->gic->nmi_support) {
+ if (cs->nmi_support) {
/*
* If an NMI is active this takes precedence over anything else
* for priority purposes; the NMI bit is only in the AP1R0 bit.
@@ -1285,7 +1286,7 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp)
continue;
}
- if (i == 0 && cs->gic->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) {
+ if (i == 0 && cs->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) {
*papr &= (~ICC_AP1R_EL1_NMI);
break;
}
@@ -1324,7 +1325,7 @@ static int icc_highest_active_group(GICv3CPUState *cs)
*/
int i;
- if (cs->gic->nmi_support) {
+ if (cs->nmi_support) {
if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
return GICV3_G1;
}
@@ -1787,7 +1788,7 @@ static void icc_ap_write(CPUARMState *env, const
ARMCPRegInfo *ri,
return;
}
- if (cs->gic->nmi_support) {
+ if (cs->nmi_support) {
cs->icc_apr[grp][regno] = value & (0xFFFFFFFFU | ICC_AP1R_EL1_NMI);
} else {
cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
@@ -1901,7 +1902,7 @@ static uint64_t icc_rpr_read(CPUARMState *env,
const ARMCPRegInfo *ri)
}
}
- if (cs->gic->nmi_support) {
+ if (cs->nmi_support) {
/* NMI info is reported in the high bits of RPR */
if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env)) {
if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
@@ -2961,7 +2962,16 @@ void gicv3_init_cpuif(GICv3State *s)
*/
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
- if (s->nmi_support) {
+ /*
+ * If the CPU implements FEAT_NMI and FEAT_GICv3 it must also
+ * implement FEAT_GICv3_NMI, which is the CPU interface part
+ * of NMI support. This is distinct from whether the GIC proper
+ * (redistributors and distributor) have NMI support. In QEMU
+ * that is a property of the GIC device in s->nmi_support;
+ * cs->nmi_support indicates the CPU interface's support.
+ */
+ if (cpu_isar_feature(aa64_nmi, cpu)) {
+ cs->nmi_support = true;
define_arm_cp_regs(cpu, gicv3_cpuif_gicv3_nmi_reginfo);
}
plus this squashed into patch 19:
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 20a8e1f2fe4..b1f6c16ffef 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -566,7 +566,7 @@ static void icv_ap_write(CPUARMState *env, const
ARMCPRegInfo *ri,
trace_gicv3_icv_ap_write(ri->crm & 1, regno,
gicv3_redist_affid(cs), value);
- if (cs->gic->nmi_support) {
+ if (cs->nmi_support) {
cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
} else {
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
@@ -1510,7 +1510,7 @@ static int icv_drop_prio(GICv3CPUState *cs, bool *nmi)
continue;
}
- if (i == 0 && cs->gic->nmi_support && (*papr1 & ICV_AP1R_EL1_NMI)) {
+ if (i == 0 && cs->nmi_support && (*papr1 & ICV_AP1R_EL1_NMI)) {
*papr1 &= (~ICV_AP1R_EL1_NMI);
*nmi = true;
return 0xff;
@@ -2699,7 +2699,7 @@ static void ich_ap_write(CPUARMState *env, const
ARMCPRegInfo *ri,
trace_gicv3_ich_ap_write(ri->crm & 1, regno,
gicv3_redist_affid(cs), value);
- if (cs->gic->nmi_support) {
+ if (cs->nmi_support) {
cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
} else {
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
@@ -2821,7 +2821,7 @@ static void ich_lr_write(CPUARMState *env, const
ARMCPRegInfo *ri,
}
/* Enforce RES0 bit in NMI field when FEAT_GICv3_NMI is not implemented */
- if (!cs->gic->nmi_support) {
+ if (!cs->nmi_support) {
value &= ~ICH_LR_EL2_NMI;
}
The comments and commit message for patch 24 also need tweaking,
because they are written assuming that FEAT_GICv3_NMI means
"NMI support in the GIC proper", not "NMI support in the cpuif".
Since those changes are not too complicated, and I made them
locally anyway since I wanted to confirm that my plan was
workable, my proposal is that I will apply these fixes while
I take this series into target-arm.next for 9.1.
So I've applied this series to target-arm.next with the above
changes (preparatory to doing a pull request tail end of next
week once we release 9.0). Let me know if you'd prefer something
else.
thanks
-- PMM
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v13 00/24] target/arm: Implement FEAT_NMI and FEAT_GICv3_NMI
2024-04-19 13:41 ` Peter Maydell
@ 2024-04-22 2:25 ` Jinjie Ruan via
0 siblings, 0 replies; 30+ messages in thread
From: Jinjie Ruan via @ 2024-04-22 2:25 UTC (permalink / raw)
To: Peter Maydell
Cc: eduardo, marcel.apfelbaum, philmd, wangyanan55, richard.henderson,
qemu-devel, qemu-arm
On 2024/4/19 21:41, Peter Maydell wrote:
> On Sun, 7 Apr 2024 at 09:19, Jinjie Ruan <ruanjinjie@huawei.com> wrote:
>>
>> This patch set implements FEAT_NMI and FEAT_GICv3_NMI for ARMv8. These
>> introduce support for a new category of interrupts in the architecture
>> which we can use to provide NMI like functionality.
>
> I had one last loose end I wanted to tidy up, and I got round
> to working through reading the spec about it today. This is
> the question of what the "is NMI enabled?" test should be
> in the code in arm_gicv3_cpuif.c.
>
> The spec wording isn't always super clear, but there are several
> things here:
>
> * FEAT_NMI : the changes to the CPU proper which implement
> superpriority for IRQ and FIQ, PSTATE.ALLINT, etc etc.
> * FEAT_GICv3_NMI : the changes to the CPU interface for
> GICv3 NMI handling. Any CPU with FEAT_NMI and FEAT_GICv3
> must have this.
> * NMI support in the IRI (Interrupt Routing Infrastructure,
> i.e. all the bits of the GIC that aren't the cpuif; the
> distributor and redistributors). Table 3-1 in the GIC spec
> says that you can have an IRI without NMI support connected
> to a CPU which does have NMI support. This is what the ID
> register bit GICD_TYPER.NMI reports.
That is right. It seems reasonable for me.
>
> At the moment this patchset conflates FEAT_GICv3_NMI and
> the NMI support in the IRI. The effect of this is that we
> allow a machine model to create a CPU with FEAT_NMI but
> without FEAT_GICv3_NMI in the cpuif, and we don't allow
> a setup where the CPU and cpuif have NMI support but the
> IRI does not. (This will actually happen with this patchset
> with the sbsa-ref machine and -cpu max, because we haven't
> (yet) made sbsa-ref enable NMI in the GIC device when the
> CPU has NMI support.)
>
> For a Linux guest this doesn't make much difference, because
> Linux will only enable NMI support if it finds it in both
> the IRI and the CPU, but I think it would be better to
> get the enable-tests right as these can be awkward to change
> after the fact in a backwards-compatible way.
>
> I think this is easy to fix -- we can add a new bool field
> GICv3CPUState::nmi_support which we initialize in
> gicv3_init_cpuif() if the CPU has FEAT_NMI, and make the
> checks in arm_gicv3_cpuif.c check cs->nmi_support instead
> of cs->gic->nmi_support. That looks like this squashed into
> patch 18:
>
> diff --git a/include/hw/intc/arm_gicv3_common.h
> b/include/hw/intc/arm_gicv3_common.h
> index 88533749ebb..cd09bee3bc4 100644
> --- a/include/hw/intc/arm_gicv3_common.h
> +++ b/include/hw/intc/arm_gicv3_common.h
> @@ -225,6 +225,13 @@ struct GICv3CPUState {
>
> /* This is temporary working state, to avoid a malloc in gicv3_update() */
> bool seenbetter;
> +
> + /*
> + * Whether the CPU interface has NMI support (FEAT_GICv3_NMI). The
> + * CPU interface may support NMIs even when the GIC proper (what the
> + * spec calls the IRI; the redistributors and distributor) does not.
> + */
> + bool nmi_support;
> };
>
> /*
> diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
> index 2457b7bca23..715909d0f7d 100644
> --- a/hw/intc/arm_gicv3_cpuif.c
> +++ b/hw/intc/arm_gicv3_cpuif.c
> @@ -21,6 +21,7 @@
> #include "hw/irq.h"
> #include "cpu.h"
> #include "target/arm/cpregs.h"
> +#include "target/arm/cpu-features.h"
> #include "sysemu/tcg.h"
> #include "sysemu/qtest.h"
>
> @@ -839,7 +840,7 @@ static int icc_highest_active_prio(GICv3CPUState *cs)
> */
> int i;
>
> - if (cs->gic->nmi_support) {
> + if (cs->nmi_support) {
> /*
> * If an NMI is active this takes precedence over anything else
> * for priority purposes; the NMI bit is only in the AP1R0 bit.
> @@ -1285,7 +1286,7 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp)
> continue;
> }
>
> - if (i == 0 && cs->gic->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) {
> + if (i == 0 && cs->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) {
> *papr &= (~ICC_AP1R_EL1_NMI);
> break;
> }
> @@ -1324,7 +1325,7 @@ static int icc_highest_active_group(GICv3CPUState *cs)
> */
> int i;
>
> - if (cs->gic->nmi_support) {
> + if (cs->nmi_support) {
> if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
> return GICV3_G1;
> }
> @@ -1787,7 +1788,7 @@ static void icc_ap_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> return;
> }
>
> - if (cs->gic->nmi_support) {
> + if (cs->nmi_support) {
> cs->icc_apr[grp][regno] = value & (0xFFFFFFFFU | ICC_AP1R_EL1_NMI);
> } else {
> cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
> @@ -1901,7 +1902,7 @@ static uint64_t icc_rpr_read(CPUARMState *env,
> const ARMCPRegInfo *ri)
> }
> }
>
> - if (cs->gic->nmi_support) {
> + if (cs->nmi_support) {
> /* NMI info is reported in the high bits of RPR */
> if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env)) {
> if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
> @@ -2961,7 +2962,16 @@ void gicv3_init_cpuif(GICv3State *s)
> */
> define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
>
> - if (s->nmi_support) {
> + /*
> + * If the CPU implements FEAT_NMI and FEAT_GICv3 it must also
> + * implement FEAT_GICv3_NMI, which is the CPU interface part
> + * of NMI support. This is distinct from whether the GIC proper
> + * (redistributors and distributor) have NMI support. In QEMU
> + * that is a property of the GIC device in s->nmi_support;
> + * cs->nmi_support indicates the CPU interface's support.
> + */
> + if (cpu_isar_feature(aa64_nmi, cpu)) {
> + cs->nmi_support = true;
> define_arm_cp_regs(cpu, gicv3_cpuif_gicv3_nmi_reginfo);
> }
>
> plus this squashed into patch 19:
>
> diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
> index 20a8e1f2fe4..b1f6c16ffef 100644
> --- a/hw/intc/arm_gicv3_cpuif.c
> +++ b/hw/intc/arm_gicv3_cpuif.c
> @@ -566,7 +566,7 @@ static void icv_ap_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
>
> trace_gicv3_icv_ap_write(ri->crm & 1, regno,
> gicv3_redist_affid(cs), value);
>
> - if (cs->gic->nmi_support) {
> + if (cs->nmi_support) {
> cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
> } else {
> cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
> @@ -1510,7 +1510,7 @@ static int icv_drop_prio(GICv3CPUState *cs, bool *nmi)
> continue;
> }
>
> - if (i == 0 && cs->gic->nmi_support && (*papr1 & ICV_AP1R_EL1_NMI)) {
> + if (i == 0 && cs->nmi_support && (*papr1 & ICV_AP1R_EL1_NMI)) {
> *papr1 &= (~ICV_AP1R_EL1_NMI);
> *nmi = true;
> return 0xff;
> @@ -2699,7 +2699,7 @@ static void ich_ap_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
>
> trace_gicv3_ich_ap_write(ri->crm & 1, regno,
> gicv3_redist_affid(cs), value);
>
> - if (cs->gic->nmi_support) {
> + if (cs->nmi_support) {
> cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
> } else {
> cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
> @@ -2821,7 +2821,7 @@ static void ich_lr_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> }
>
> /* Enforce RES0 bit in NMI field when FEAT_GICv3_NMI is not implemented */
> - if (!cs->gic->nmi_support) {
> + if (!cs->nmi_support) {
> value &= ~ICH_LR_EL2_NMI;
> }
>
> The comments and commit message for patch 24 also need tweaking,
> because they are written assuming that FEAT_GICv3_NMI means
> "NMI support in the GIC proper", not "NMI support in the cpuif".
Yes, they're different, "FEAT_GICv3_NMI" is something beside PE, that is
the cpuif.
>
> Since those changes are not too complicated, and I made them
> locally anyway since I wanted to confirm that my plan was
> workable, my proposal is that I will apply these fixes while
> I take this series into target-arm.next for 9.1.
>
> So I've applied this series to target-arm.next with the above
> changes (preparatory to doing a pull request tail end of next
> week once we release 9.0). Let me know if you'd prefer something
> else.
>
Thank you! I think that is good.
> thanks
> -- PMM
^ permalink raw reply [flat|nested] 30+ messages in thread