All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/37] target-arm queue
@ 2024-04-25 10:39 Peter Maydell
  2024-04-25 10:39 ` [PULL 01/37] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI Peter Maydell
                   ` (37 more replies)
  0 siblings, 38 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

Hi; here's the first arm pullreq for 9.1.

This includes the reset method function signature change, so it has
some chance of compile failures due to merge conflicts if some other
pullreq added a device reset method and that pullreq got applied
before this one.  If so, the changes needed to fix those up can be
created by running the spatch rune described in the commit message of
the "hw, target: Add ResetType argument to hold and exit phase
methods" commit.

thanks
-- PMM

The following changes since commit 5da72194df36535d773c8bdc951529ecd5e31707:

  Merge tag 'pull-tcg-20240424' of https://gitlab.com/rth7680/qemu into staging (2024-04-24 15:51:49 -0700)

are available in the Git repository at:

  https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20240425

for you to fetch changes up to 214652da123e3821657a64691ee556281e9f6238:

  tests/qtest: Add tests for the STM32L4x5 USART (2024-04-25 10:21:59 +0100)

----------------------------------------------------------------
target-arm queue:
 * Implement FEAT_NMI and NMI support in the GICv3
 * hw/dma: avoid apparent overflow in soc_dma_set_request
 * linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code
 * Add ResetType argument to Resettable hold and exit phase methods
 * Add RESET_TYPE_SNAPSHOT_LOAD ResetType
 * Implement STM32L4x5 USART

----------------------------------------------------------------
Anastasia Belova (1):
      hw/dma: avoid apparent overflow in soc_dma_set_request

Arnaud Minier (5):
      hw/char: Implement STM32L4x5 USART skeleton
      hw/char/stm32l4x5_usart: Enable serial read and write
      hw/char/stm32l4x5_usart: Add options for serial parameters setting
      hw/arm: Add the USART to the stm32l4x5 SoC
      tests/qtest: Add tests for the STM32L4x5 USART

Jinjie Ruan (22):
      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: 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: Enable NMI support in the GIC if the CPU has FEAT_NMI

Peter Maydell (9):
      hw/intc/arm_gicv3: Add NMI handling CPU interface registers
      hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
      linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code
      hw/misc: Don't special case RESET_TYPE_COLD in npcm7xx_clk, gcr
      allwinner-i2c, adm1272: Use device_cold_reset() for software-triggered reset
      scripts/coccinelle: New script to add ResetType to hold and exit phases
      hw, target: Add ResetType argument to hold and exit phase methods
      docs/devel/reset: Update to new API for hold and exit phase methods
      reset: Add RESET_TYPE_SNAPSHOT_LOAD

 MAINTAINERS                         |   1 +
 docs/devel/reset.rst                |  25 +-
 docs/system/arm/b-l475e-iot01a.rst  |   2 +-
 docs/system/arm/emulation.rst       |   1 +
 scripts/coccinelle/reset-type.cocci | 133 ++++++++
 hw/intc/gicv3_internal.h            |  13 +
 include/hw/arm/stm32l4x5_soc.h      |   7 +
 include/hw/char/stm32l4x5_usart.h   |  67 ++++
 include/hw/intc/arm_gic_common.h    |   2 +
 include/hw/intc/arm_gicv3_common.h  |  14 +
 include/hw/resettable.h             |   5 +-
 linux-user/flat.h                   |   5 +-
 target/arm/cpu-features.h           |   5 +
 target/arm/cpu-qom.h                |   5 +-
 target/arm/cpu.h                    |   9 +
 target/arm/internals.h              |  21 ++
 target/arm/tcg/helper-a64.h         |   1 +
 target/arm/tcg/a64.decode           |   1 +
 hw/adc/npcm7xx_adc.c                |   2 +-
 hw/arm/pxa2xx_pic.c                 |   2 +-
 hw/arm/smmu-common.c                |   2 +-
 hw/arm/smmuv3.c                     |   4 +-
 hw/arm/stellaris.c                  |  10 +-
 hw/arm/stm32l4x5_soc.c              |  83 ++++-
 hw/arm/virt.c                       |  29 +-
 hw/audio/asc.c                      |   2 +-
 hw/char/cadence_uart.c              |   2 +-
 hw/char/sifive_uart.c               |   2 +-
 hw/char/stm32l4x5_usart.c           | 637 ++++++++++++++++++++++++++++++++++++
 hw/core/cpu-common.c                |   2 +-
 hw/core/qdev.c                      |   4 +-
 hw/core/reset.c                     |  17 +-
 hw/core/resettable.c                |   8 +-
 hw/display/virtio-vga.c             |   4 +-
 hw/dma/soc_dma.c                    |   4 +-
 hw/gpio/npcm7xx_gpio.c              |   2 +-
 hw/gpio/pl061.c                     |   2 +-
 hw/gpio/stm32l4x5_gpio.c            |   2 +-
 hw/hyperv/vmbus.c                   |   2 +-
 hw/i2c/allwinner-i2c.c              |   5 +-
 hw/i2c/npcm7xx_smbus.c              |   2 +-
 hw/input/adb.c                      |   2 +-
 hw/input/ps2.c                      |  12 +-
 hw/intc/arm_gic_common.c            |   2 +-
 hw/intc/arm_gic_kvm.c               |   4 +-
 hw/intc/arm_gicv3.c                 |  67 +++-
 hw/intc/arm_gicv3_common.c          |  50 ++-
 hw/intc/arm_gicv3_cpuif.c           | 268 ++++++++++++++-
 hw/intc/arm_gicv3_dist.c            |  36 ++
 hw/intc/arm_gicv3_its.c             |   4 +-
 hw/intc/arm_gicv3_its_common.c      |   2 +-
 hw/intc/arm_gicv3_its_kvm.c         |   4 +-
 hw/intc/arm_gicv3_kvm.c             |   9 +-
 hw/intc/arm_gicv3_redist.c          |  22 ++
 hw/intc/xics.c                      |   2 +-
 hw/m68k/q800-glue.c                 |   2 +-
 hw/misc/djmemc.c                    |   2 +-
 hw/misc/iosb.c                      |   2 +-
 hw/misc/mac_via.c                   |   8 +-
 hw/misc/macio/cuda.c                |   4 +-
 hw/misc/macio/pmu.c                 |   4 +-
 hw/misc/mos6522.c                   |   2 +-
 hw/misc/npcm7xx_clk.c               |  13 +-
 hw/misc/npcm7xx_gcr.c               |  12 +-
 hw/misc/npcm7xx_mft.c               |   2 +-
 hw/misc/npcm7xx_pwm.c               |   2 +-
 hw/misc/stm32l4x5_exti.c            |   2 +-
 hw/misc/stm32l4x5_rcc.c             |  10 +-
 hw/misc/stm32l4x5_syscfg.c          |   2 +-
 hw/misc/xlnx-versal-cframe-reg.c    |   2 +-
 hw/misc/xlnx-versal-crl.c           |   2 +-
 hw/misc/xlnx-versal-pmc-iou-slcr.c  |   2 +-
 hw/misc/xlnx-versal-trng.c          |   2 +-
 hw/misc/xlnx-versal-xramc.c         |   2 +-
 hw/misc/xlnx-zynqmp-apu-ctrl.c      |   2 +-
 hw/misc/xlnx-zynqmp-crf.c           |   2 +-
 hw/misc/zynq_slcr.c                 |   4 +-
 hw/net/can/xlnx-zynqmp-can.c        |   2 +-
 hw/net/e1000.c                      |   2 +-
 hw/net/e1000e.c                     |   2 +-
 hw/net/igb.c                        |   2 +-
 hw/net/igbvf.c                      |   2 +-
 hw/nvram/xlnx-bbram.c               |   2 +-
 hw/nvram/xlnx-versal-efuse-ctrl.c   |   2 +-
 hw/nvram/xlnx-zynqmp-efuse.c        |   2 +-
 hw/pci-bridge/cxl_root_port.c       |   4 +-
 hw/pci-bridge/pcie_root_port.c      |   2 +-
 hw/pci-host/bonito.c                |   2 +-
 hw/pci-host/pnv_phb.c               |   4 +-
 hw/pci-host/pnv_phb3_msi.c          |   4 +-
 hw/pci/pci.c                        |   4 +-
 hw/rtc/mc146818rtc.c                |   2 +-
 hw/s390x/css-bridge.c               |   2 +-
 hw/sensor/adm1266.c                 |   2 +-
 hw/sensor/adm1272.c                 |   4 +-
 hw/sensor/isl_pmbus_vr.c            |  10 +-
 hw/sensor/max31785.c                |   2 +-
 hw/sensor/max34451.c                |   2 +-
 hw/ssi/npcm7xx_fiu.c                |   2 +-
 hw/timer/etraxfs_timer.c            |   2 +-
 hw/timer/npcm7xx_timer.c            |   2 +-
 hw/usb/hcd-dwc2.c                   |   8 +-
 hw/usb/xlnx-versal-usb2-ctrl-regs.c |   2 +-
 hw/virtio/virtio-pci.c              |   2 +-
 linux-user/flatload.c               | 293 +----------------
 target/arm/cpu.c                    | 151 ++++++++-
 target/arm/helper.c                 | 101 +++++-
 target/arm/tcg/cpu64.c              |   1 +
 target/arm/tcg/helper-a64.c         |  16 +-
 target/arm/tcg/translate-a64.c      |  19 ++
 target/avr/cpu.c                    |   4 +-
 target/cris/cpu.c                   |   4 +-
 target/hexagon/cpu.c                |   4 +-
 target/i386/cpu.c                   |   4 +-
 target/loongarch/cpu.c              |   4 +-
 target/m68k/cpu.c                   |   4 +-
 target/microblaze/cpu.c             |   4 +-
 target/mips/cpu.c                   |   4 +-
 target/openrisc/cpu.c               |   4 +-
 target/ppc/cpu_init.c               |   4 +-
 target/riscv/cpu.c                  |   4 +-
 target/rx/cpu.c                     |   4 +-
 target/sh4/cpu.c                    |   4 +-
 target/sparc/cpu.c                  |   4 +-
 target/tricore/cpu.c                |   4 +-
 target/xtensa/cpu.c                 |   4 +-
 tests/qtest/stm32l4x5_usart-test.c  | 315 ++++++++++++++++++
 hw/arm/Kconfig                      |   1 +
 hw/char/Kconfig                     |   3 +
 hw/char/meson.build                 |   1 +
 hw/char/trace-events                |  12 +
 hw/intc/trace-events                |   2 +
 tests/qtest/meson.build             |   4 +-
 133 files changed, 2239 insertions(+), 537 deletions(-)
 create mode 100644 scripts/coccinelle/reset-type.cocci
 create mode 100644 include/hw/char/stm32l4x5_usart.h
 create mode 100644 hw/char/stm32l4x5_usart.c
 create mode 100644 tests/qtest/stm32l4x5_usart-test.c


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PULL 01/37] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 02/37] target/arm: Add PSTATE.ALLINT Peter Maydell
                   ` (36 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-2-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 e5758d9fbc8..b300d0446d8 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 a620481d7cf..7a25ea65c9a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6187,13 +6187,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] 39+ messages in thread

* [PULL 02/37] target/arm: Add PSTATE.ALLINT
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
  2024-04-25 10:39 ` [PULL 01/37] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 03/37] target/arm: Add support for FEAT_NMI, Non-maskable Interrupt Peter Maydell
                   ` (35 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-3-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 bc0c84873ff..de740d223fa 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 ebaa7f00df3..29f3ef274ae 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] 39+ messages in thread

* [PULL 03/37] target/arm: Add support for FEAT_NMI, Non-maskable Interrupt
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
  2024-04-25 10:39 ` [PULL 01/37] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI Peter Maydell
  2024-04-25 10:39 ` [PULL 02/37] target/arm: Add PSTATE.ALLINT Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 04/37] target/arm: Implement ALLINT MSR (immediate) Peter Maydell
                   ` (34 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-4-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/internals.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index dd3da211a3f..516e0584bf5 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] 39+ messages in thread

* [PULL 04/37] target/arm: Implement ALLINT MSR (immediate)
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (2 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 03/37] target/arm: Add support for FEAT_NMI, Non-maskable Interrupt Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 05/37] target/arm: Support MSR access to ALLINT Peter Maydell
                   ` (33 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-5-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/helper-a64.h    |  1 +
 target/arm/tcg/a64.decode      |  1 +
 target/arm/tcg/helper-a64.c    | 12 ++++++++++++
 target/arm/tcg/translate-a64.c | 19 +++++++++++++++++++
 4 files changed, 33 insertions(+)

diff --git a/target/arm/tcg/helper-a64.h b/target/arm/tcg/helper-a64.h
index 575a5dab7dc..05181653999 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/a64.decode b/target/arm/tcg/a64.decode
index 8a20dce3c8f..0e7656fd158 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 29f3ef274ae..0ea8668ab4c 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/translate-a64.c b/target/arm/tcg/translate-a64.c
index 2666d527111..976094a5c80 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] 39+ messages in thread

* [PULL 05/37] target/arm: Support MSR access to ALLINT
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (3 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 04/37] target/arm: Implement ALLINT MSR (immediate) Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 06/37] target/arm: Add support for Non-maskable Interrupt Peter Maydell
                   ` (32 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-6-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7a25ea65c9a..b9443b1813a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7500,6 +7500,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)
@@ -9894,6 +9925,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] 39+ messages in thread

* [PULL 06/37] target/arm: Add support for Non-maskable Interrupt
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (4 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 05/37] target/arm: Support MSR access to ALLINT Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 07/37] target/arm: Add support for NMI in arm_phys_excp_target_el() Peter Maydell
                   ` (31 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-7-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu-qom.h   |   5 +-
 target/arm/cpu.h       |   6 ++
 target/arm/internals.h |  18 +++++
 target/arm/cpu.c       | 147 ++++++++++++++++++++++++++++++++++++++---
 target/arm/helper.c    |  33 +++++++--
 5 files changed, 193 insertions(+), 16 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 8e032691dbf..b497667d61e 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.h b/target/arm/cpu.h
index de740d223fa..08a6bc50de2 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/internals.h b/target/arm/internals.h
index 516e0584bf5..b53f5e8ff2a 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
  *
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index ab8d007a86c..d2dfd36fd45 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/helper.c b/target/arm/helper.c
index b9443b1813a..f61a65d8114 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6046,15 +6046,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)
@@ -6202,6 +6206,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,
@@ -6217,6 +6238,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,
@@ -10799,6 +10821,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)) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 07/37] target/arm: Add support for NMI in arm_phys_excp_target_el()
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (5 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 06/37] target/arm: Add support for Non-maskable Interrupt Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 08/37] target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI Peter Maydell
                   ` (30 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-8-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index f61a65d8114..4ee59b37059 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -10763,6 +10763,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] 39+ messages in thread

* [PULL 08/37] target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (6 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 07/37] target/arm: Add support for NMI in arm_phys_excp_target_el() Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 09/37] target/arm: Handle PSTATE.ALLINT on taking an exception Peter Maydell
                   ` (29 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-9-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 08a6bc50de2..97997dbd087 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 4ee59b37059..6b6d8a349a2 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] 39+ messages in thread

* [PULL 09/37] target/arm: Handle PSTATE.ALLINT on taking an exception
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (7 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 08/37] target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 10/37] hw/intc/arm_gicv3: Add external IRQ lines for NMI Peter Maydell
                   ` (28 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-10-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 6b6d8a349a2..5ff9e44649a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11733,6 +11733,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] 39+ messages in thread

* [PULL 10/37] hw/intc/arm_gicv3: Add external IRQ lines for NMI
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (8 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 09/37] target/arm: Handle PSTATE.ALLINT on taking an exception Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 11/37] hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU Peter Maydell
                   ` (27 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-11-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/intc/arm_gic_common.h   | 2 ++
 include/hw/intc/arm_gicv3_common.h | 2 ++
 hw/intc/arm_gicv3_common.c         | 6 ++++++
 3 files changed, 10 insertions(+)

diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
index 70803750081..97fea4102d3 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 4e2fb518e72..7324c7d983f 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 */
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index cb55c726810..c52f060026a 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);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 11/37] hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (9 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 10/37] hw/intc/arm_gicv3: Add external IRQ lines for NMI Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 12/37] target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64() Peter Maydell
                   ` (26 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-12-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 c9119ef3847..c4b03b09c27 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] 39+ messages in thread

* [PULL 12/37] target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64()
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (10 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 11/37] hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 13/37] hw/intc/arm_gicv3: Add has-nmi property to GICv3 device Peter Maydell
                   ` (25 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-13-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5ff9e44649a..6b224826fbb 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11653,10 +11653,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] 39+ messages in thread

* [PULL 13/37] hw/intc/arm_gicv3: Add has-nmi property to GICv3 device
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (11 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 12/37] target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64() Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 14/37] hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3 Peter Maydell
                   ` (24 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-14-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/gicv3_internal.h           | 1 +
 include/hw/intc/arm_gicv3_common.h | 1 +
 hw/intc/arm_gicv3_common.c         | 1 +
 hw/intc/arm_gicv3_dist.c           | 2 ++
 4 files changed, 5 insertions(+)

diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 29d5cdc1b69..8f4ebed2f42 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 7324c7d983f..4358c5319c1 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;
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index c52f060026a..2d2cea6858a 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 35e850685c0..22ddc0d6661 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;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 14/37] hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (12 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 13/37] hw/intc/arm_gicv3: Add has-nmi property to GICv3 device Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 15/37] hw/intc/arm_gicv3: Add irq non-maskable property Peter Maydell
                   ` (23 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-15-ruanjinjie@huawei.com
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-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 77eb37e1317..00a383079b9 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] 39+ messages in thread

* [PULL 15/37] hw/intc/arm_gicv3: Add irq non-maskable property
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (13 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 14/37] hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3 Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 16/37] hw/intc/arm_gicv3_redist: Implement GICR_INMIR0 Peter Maydell
                   ` (22 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-16-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/intc/arm_gicv3_common.h |  4 ++++
 hw/intc/arm_gicv3_common.c         | 38 ++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index 4358c5319c1..88533749ebb 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;
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 2d2cea6858a..9810558b076 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
     }
 };
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 16/37] hw/intc/arm_gicv3_redist: Implement GICR_INMIR0
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (14 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 15/37] hw/intc/arm_gicv3: Add irq non-maskable property Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 17/37] hw/intc/arm_gicv3: Implement GICD_INMIR Peter Maydell
                   ` (21 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-17-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/gicv3_internal.h   |  1 +
 hw/intc/arm_gicv3_redist.c | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 8f4ebed2f42..21697ecf391 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)
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 8153525849a..ed1f9d1e444 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;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 17/37] hw/intc/arm_gicv3: Implement GICD_INMIR
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (15 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 16/37] hw/intc/arm_gicv3_redist: Implement GICR_INMIR0 Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 18/37] hw/intc/arm_gicv3: Add NMI handling CPU interface registers Peter Maydell
                   ` (20 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-18-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/gicv3_internal.h |  2 ++
 hw/intc/arm_gicv3_dist.c | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 21697ecf391..8d793243f4e 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
 
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 22ddc0d6661..d8207acb22c 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;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 18/37] hw/intc/arm_gicv3: Add NMI handling CPU interface registers
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (16 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 17/37] hw/intc/arm_gicv3: Implement GICD_INMIR Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 19/37] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read() Peter Maydell
                   ` (19 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

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>
[PMM: Separate out whether cpuif supports NMI from whether the
 GIC proper (IRI) supports NMI]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240407081733.3231820-19-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/gicv3_internal.h           |   5 +
 include/hw/intc/arm_gicv3_common.h |   7 ++
 hw/intc/arm_gicv3_cpuif.c          | 147 ++++++++++++++++++++++++++++-
 hw/intc/trace-events               |   1 +
 4 files changed, 155 insertions(+), 5 deletions(-)

diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 8d793243f4e..81200eb90e3 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/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 67d8fd07b7f..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"
 
@@ -795,6 +796,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 +840,23 @@ static int icc_highest_active_prio(GICv3CPUState *cs)
      */
     int i;
 
+    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.
+         * 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 +923,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 +960,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 +1087,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 +1207,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 +1221,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 +1285,12 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp)
         if (!*papr) {
             continue;
         }
+
+        if (i == 0 && cs->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) {
+            *papr &= (~ICC_AP1R_EL1_NMI);
+            break;
+        }
+
         /* Clear the lowest set bit */
         *papr &= *papr - 1;
         break;
@@ -1239,6 +1325,15 @@ static int icc_highest_active_group(GICv3CPUState *cs)
      */
     int i;
 
+    if (cs->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 +1788,11 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
         return;
     }
 
-    cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
+    if (cs->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 +1882,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 +1902,22 @@ static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
         }
     }
 
+    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) {
+                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 +2597,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 +2962,19 @@ void gicv3_init_cpuif(GICv3State *s)
          */
         define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
 
+        /*
+         * 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);
+        }
+
         /*
          * The CPU implementation specifies the number of supported
          * bits of physical priority. For backwards compatibility
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 1ef29d0256a..94030550d5a 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] 39+ messages in thread

* [PULL 19/37] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read()
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (17 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 18/37] hw/intc/arm_gicv3: Add NMI handling CPU interface registers Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 20/37] hw/intc/arm_gicv3: Implement NMI interrupt priority Peter Maydell
                   ` (18 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

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>
[PMM: use cs->nmi_support instead of cs->gic->nmi_support]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240407081733.3231820-20-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/gicv3_internal.h  |   4 ++
 hw/intc/arm_gicv3_cpuif.c | 105 +++++++++++++++++++++++++++++++++-----
 hw/intc/trace-events      |   1 +
 3 files changed, 98 insertions(+), 12 deletions(-)

diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 81200eb90e3..bc9f518fe86 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/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 715909d0f7d..b1f6c16ffef 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -158,6 +158,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];
@@ -192,6 +196,7 @@ static int hppvi_index(GICv3CPUState *cs)
      * correct behaviour.
      */
     int prio = 0xff;
+    bool nmi = false;
 
     if (!(cs->ich_vmcr_el2 & (ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1))) {
         /* Both groups disabled, definitely nothing to do */
@@ -200,6 +205,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) {
@@ -218,10 +224,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;
         }
     }
@@ -290,6 +298,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)) {
@@ -302,10 +311,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;
     }
@@ -327,6 +337,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;
 }
 
@@ -551,7 +566,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->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;
@@ -698,7 +717,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;
@@ -737,13 +760,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)
@@ -764,6 +793,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)) {
@@ -773,11 +803,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;
@@ -798,8 +833,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;
 }
 
@@ -1424,7 +1488,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
@@ -1446,6 +1510,12 @@ static int icv_drop_prio(GICv3CPUState *cs)
             continue;
         }
 
+        if (i == 0 && cs->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.
@@ -1505,6 +1575,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);
@@ -1517,8 +1588,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.
@@ -1540,8 +1611,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.
@@ -2627,7 +2699,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->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);
 }
 
@@ -2744,6 +2820,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->nmi_support) {
+        value &= ~ICH_LR_EL2_NMI;
+    }
+
     cs->ich_lr_el2[regno] = value;
     gicv3_cpuif_virt_update(cs);
 }
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 94030550d5a..47340b5bc13 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] 39+ messages in thread

* [PULL 20/37] hw/intc/arm_gicv3: Implement NMI interrupt priority
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (18 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 19/37] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read() Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 21/37] hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update() Peter Maydell
                   ` (17 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-21-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 0b8f79a1227..58e18fff54f 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 9810558b076..207f8417e1f 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 ed1f9d1e444..90b238fac0b 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] 39+ messages in thread

* [PULL 21/37] hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update()
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (19 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 20/37] hw/intc/arm_gicv3: Implement NMI interrupt priority Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 22/37] hw/intc/arm_gicv3: Report the VINMI interrupt Peter Maydell
                   ` (16 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-22-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 b1f6c16ffef..2cf232d099c 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -1038,6 +1038,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;
 
@@ -1076,6 +1077,8 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
 
         if (isfiq) {
             fiqlevel = 1;
+        } else if (cs->hppi.nmi) {
+            nmilevel = 1;
         } else {
             irqlevel = 1;
         }
@@ -1085,6 +1088,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] 39+ messages in thread

* [PULL 22/37] hw/intc/arm_gicv3: Report the VINMI interrupt
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (20 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 21/37] hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update() Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 23/37] target/arm: Add FEAT_NMI to max Peter Maydell
                   ` (15 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-23-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 2cf232d099c..bdb13b00e98 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -481,6 +481,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,
@@ -498,9 +499,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;
             }
@@ -510,6 +519,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] 39+ messages in thread

* [PULL 23/37] target/arm: Add FEAT_NMI to max
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (21 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 22/37] hw/intc/arm_gicv3: Report the VINMI interrupt Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 24/37] hw/arm/virt: Enable NMI support in the GIC if the CPU has FEAT_NMI Peter Maydell
                   ` (14 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

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>
Message-id: 20240407081733.3231820-24-ruanjinjie@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 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 2a7bbb82dc4..a9ae7ede9fc 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 9f7a9f3d2cc..62c4663512b 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] 39+ messages in thread

* [PULL 24/37] hw/arm/virt: Enable NMI support in the GIC if the CPU has FEAT_NMI
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (22 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 23/37] target/arm: Add FEAT_NMI to max Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 25/37] hw/dma: avoid apparent overflow in soc_dma_set_request Peter Maydell
                   ` (13 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Jinjie Ruan <ruanjinjie@huawei.com>

If the CPU implements FEAT_NMI, then turn on the NMI support in the
GICv3 too.  It's permitted to have a configuration with FEAT_NMI in
the CPU (and thus NMI support in the CPU interfaces too) but no NMI
support in the distributor and redistributor, but this isn't a very
useful setup as it's close to having no NMI support at all.

We don't need to gate the enabling of NMI in the GIC behind a
machine version property, because none of our current CPUs
implement FEAT_NMI, and '-cpu max' is not something we maintain
migration compatibility across versions for. So we can always
enable the GIC NMI support when the CPU has it.

Neither hvf nor KVM support NMI in the GIC yet, so we don't enable
it unless we're using TCG.

Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20240407081733.3231820-25-ruanjinjie@huawei.com
[PMM: Update comment and commit message]
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/virt.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index c4b03b09c27..3c93c0c0a61 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -729,6 +729,20 @@ static void create_v2m(VirtMachineState *vms)
     vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
 }
 
+/*
+ * If the CPU has FEAT_NMI, then turn on the NMI support in the GICv3 too.
+ * It's permitted to have a configuration with NMI in the CPU (and thus the
+ * GICv3 CPU interface) but not in the distributor/redistributors, but it's
+ * not very useful.
+ */
+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 +816,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] 39+ messages in thread

* [PULL 25/37] hw/dma: avoid apparent overflow in soc_dma_set_request
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (23 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 24/37] hw/arm/virt: Enable NMI support in the GIC if the CPU has FEAT_NMI Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 26/37] linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code Peter Maydell
                   ` (12 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Anastasia Belova <abelova@astralinux.ru>

In soc_dma_set_request() we try to set a bit in a uint64_t, but we
do it with "1 << ch->num", which can't set any bits past 31;
any use for a channel number of 32 or more would fail due to
integer overflow.

This doesn't happen in practice for our current use of this code,
because the worst case is when we call soc_dma_init() with an
argument of 32 for the number of channels, and QEMU builds with
-fwrapv so the shift into the sign bit is well-defined. However,
it's obviously not the intended behaviour of the code.

Add casts to force the shift to be done as 64-bit arithmetic,
allowing up to 64 channels.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: afbb5194d4 ("Handle on-chip DMA controllers in one place, convert OMAP DMA to use it.")
Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
Message-id: 20240409115301.21829-1-abelova@astralinux.ru
[PMM: Edit commit message to clarify that this doesn't actually
 bite us in our current usage of this code.]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/soc_dma.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/dma/soc_dma.c b/hw/dma/soc_dma.c
index 3a430057f54..d5c52b804f8 100644
--- a/hw/dma/soc_dma.c
+++ b/hw/dma/soc_dma.c
@@ -209,9 +209,9 @@ void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
     dma->enabled_count += level - ch->enable;
 
     if (level)
-        dma->ch_enable_mask |= 1 << ch->num;
+        dma->ch_enable_mask |= (uint64_t)1 << ch->num;
     else
-        dma->ch_enable_mask &= ~(1 << ch->num);
+        dma->ch_enable_mask &= ~((uint64_t)1 << ch->num);
 
     if (level != ch->enable) {
         soc_dma_ch_freq_update(dma);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 26/37] linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (24 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 25/37] hw/dma: avoid apparent overflow in soc_dma_set_request Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 27/37] hw/misc: Don't special case RESET_TYPE_COLD in npcm7xx_clk, gcr Peter Maydell
                   ` (11 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

Ever since the bFLT format support was added in 2006, there has been
a chunk of code in the file guarded by CONFIG_BINFMT_SHARED_FLAT
which is supposedly for shared library support.  This is not enabled
and it's not possible to enable it, because if you do you'll run into
the "#error needs checking" in the calc_reloc() function.

Similarly, CONFIG_BINFMT_ZFLAT exists but can't be enabled because of
an "#error code needs checking" in load_flat_file().

This code is obviously unfinished and has never been used; nobody in
the intervening 18 years has complained about this or fixed it, so
just delete the dead code.  If anybody ever wants the feature they
can always pull it out of git, or (perhaps better) write it from
scratch based on the current Linux bFLT loader rather than the one of
18 years ago.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20240411115313.680433-1-peter.maydell@linaro.org
---
 linux-user/flat.h     |   5 +-
 linux-user/flatload.c | 293 ++----------------------------------------
 2 files changed, 11 insertions(+), 287 deletions(-)

diff --git a/linux-user/flat.h b/linux-user/flat.h
index ed518e2013b..e374b73e268 100644
--- a/linux-user/flat.h
+++ b/linux-user/flat.h
@@ -12,11 +12,8 @@
 
 #define	FLAT_VERSION			0x00000004L
 
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-#define	MAX_SHARED_LIBS			(4)
-#else
+/* QEMU doesn't support bflt shared libraries */
 #define	MAX_SHARED_LIBS			(1)
-#endif
 
 /*
  * To make everything easier to port and manage cross platform
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index 5b62aa0a2be..04d8138d12e 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -29,8 +29,6 @@
  *	JAN/99 -- coded full program relocation (gerg@snapgear.com)
  */
 
-/* ??? ZFLAT and shared library support is currently disabled.  */
-
 /****************************************************************************/
 
 #include "qemu/osdep.h"
@@ -64,10 +62,6 @@ struct lib_info {
     short loaded;		/* Has this library been loaded? */
 };
 
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-static int load_flat_shared_library(int id, struct lib_info *p);
-#endif
-
 struct linux_binprm;
 
 /****************************************************************************/
@@ -108,153 +102,6 @@ static int target_pread(int fd, abi_ulong ptr, abi_ulong len,
     unlock_user(buf, ptr, len);
     return ret;
 }
-/****************************************************************************/
-
-#ifdef CONFIG_BINFMT_ZFLAT
-
-#include <linux/zlib.h>
-
-#define LBUFSIZE	4000
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
-#define COMMENT      0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
-#define RESERVED     0xC0 /* bit 6,7:   reserved */
-
-static int decompress_exec(
-	struct linux_binprm *bprm,
-	unsigned long offset,
-	char *dst,
-	long len,
-	int fd)
-{
-	unsigned char *buf;
-	z_stream strm;
-	loff_t fpos;
-	int ret, retval;
-
-	DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
-
-	memset(&strm, 0, sizeof(strm));
-	strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
-	if (strm.workspace == NULL) {
-		DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
-		return -ENOMEM;
-	}
-	buf = kmalloc(LBUFSIZE, GFP_KERNEL);
-	if (buf == NULL) {
-		DBG_FLT("binfmt_flat: no memory for read buffer\n");
-		retval = -ENOMEM;
-		goto out_free;
-	}
-
-	/* Read in first chunk of data and parse gzip header. */
-	fpos = offset;
-	ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
-
-	strm.next_in = buf;
-	strm.avail_in = ret;
-	strm.total_in = 0;
-
-	retval = -ENOEXEC;
-
-	/* Check minimum size -- gzip header */
-	if (ret < 10) {
-		DBG_FLT("binfmt_flat: file too small?\n");
-		goto out_free_buf;
-	}
-
-	/* Check gzip magic number */
-	if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
-		DBG_FLT("binfmt_flat: unknown compression magic?\n");
-		goto out_free_buf;
-	}
-
-	/* Check gzip method */
-	if (buf[2] != 8) {
-		DBG_FLT("binfmt_flat: unknown compression method?\n");
-		goto out_free_buf;
-	}
-	/* Check gzip flags */
-	if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
-	    (buf[3] & RESERVED)) {
-		DBG_FLT("binfmt_flat: unknown flags?\n");
-		goto out_free_buf;
-	}
-
-	ret = 10;
-	if (buf[3] & EXTRA_FIELD) {
-		ret += 2 + buf[10] + (buf[11] << 8);
-		if (unlikely(LBUFSIZE == ret)) {
-			DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
-			goto out_free_buf;
-		}
-	}
-	if (buf[3] & ORIG_NAME) {
-		for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
-			;
-		if (unlikely(LBUFSIZE == ret)) {
-			DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
-			goto out_free_buf;
-		}
-	}
-	if (buf[3] & COMMENT) {
-		for (;  ret < LBUFSIZE && (buf[ret] != 0); ret++)
-			;
-		if (unlikely(LBUFSIZE == ret)) {
-			DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
-			goto out_free_buf;
-		}
-	}
-
-	strm.next_in += ret;
-	strm.avail_in -= ret;
-
-	strm.next_out = dst;
-	strm.avail_out = len;
-	strm.total_out = 0;
-
-	if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
-		DBG_FLT("binfmt_flat: zlib init failed?\n");
-		goto out_free_buf;
-	}
-
-	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
-		ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
-		if (ret <= 0)
-			break;
-                if (is_error(ret)) {
-			break;
-                }
-		len -= ret;
-
-		strm.next_in = buf;
-		strm.avail_in = ret;
-		strm.total_in = 0;
-	}
-
-	if (ret < 0) {
-		DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
-			ret, strm.msg);
-		goto out_zlib;
-	}
-
-	retval = 0;
-out_zlib:
-	zlib_inflateEnd(&strm);
-out_free_buf:
-	kfree(buf);
-out_free:
-	kfree(strm.workspace);
-out:
-	return retval;
-}
-
-#endif /* CONFIG_BINFMT_ZFLAT */
 
 /****************************************************************************/
 
@@ -268,40 +115,7 @@ calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
     abi_ulong text_len;
     abi_ulong start_code;
 
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-#error needs checking
-    if (r == 0)
-        id = curid;	/* Relocs of 0 are always self referring */
-    else {
-        id = (r >> 24) & 0xff;	/* Find ID for this reloc */
-        r &= 0x00ffffff;	/* Trim ID off here */
-    }
-    if (id >= MAX_SHARED_LIBS) {
-        fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
-                (unsigned) r, id);
-        goto failed;
-    }
-    if (curid != id) {
-        if (internalp) {
-            fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
-                    "in same module (%d != %d)\n",
-                    (unsigned) r, curid, id);
-            goto failed;
-        } else if (!p[id].loaded && is_error(load_flat_shared_library(id, p))) {
-            fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
-            goto failed;
-        }
-        /* Check versioning information (i.e. time stamps) */
-        if (p[id].build_date && p[curid].build_date
-            && p[curid].build_date < p[id].build_date) {
-            fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
-                    id, curid);
-            goto failed;
-        }
-    }
-#else
     id = 0;
-#endif
 
     start_brk = p[id].start_brk;
     start_data = p[id].start_data;
@@ -425,12 +239,10 @@ static int load_flat_file(struct linux_binprm * bprm,
     if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
         flags = FLAT_FLAG_RAM;
 
-#ifndef CONFIG_BINFMT_ZFLAT
     if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
-        fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
+        fprintf(stderr, "ZFLAT executables are not supported\n");
         return -ENOEXEC;
     }
-#endif
 
     /*
      * calculate the extra space we need to map in
@@ -483,17 +295,9 @@ static int load_flat_file(struct linux_binprm * bprm,
                         (int)(data_len + bss_len + stack_len), (int)datapos);
 
         fpos = ntohl(hdr->data_start);
-#ifdef CONFIG_BINFMT_ZFLAT
-        if (flags & FLAT_FLAG_GZDATA) {
-            result = decompress_exec(bprm, fpos, (char *) datapos,
-                                     data_len + (relocs * sizeof(abi_ulong)))
-        } else
-#endif
-        {
-            result = target_pread(bprm->src.fd, datapos,
-                                  data_len + (relocs * sizeof(abi_ulong)),
-                                  fpos);
-        }
+        result = target_pread(bprm->src.fd, datapos,
+                              data_len + (relocs * sizeof(abi_ulong)),
+                              fpos);
         if (result < 0) {
             fprintf(stderr, "Unable to read data+bss\n");
             return result;
@@ -515,38 +319,12 @@ static int load_flat_file(struct linux_binprm * bprm,
         datapos = realdatastart + indx_len;
         reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
 
-#ifdef CONFIG_BINFMT_ZFLAT
-#error code needs checking
-        /*
-         * load it all in and treat it like a RAM load from now on
-         */
-        if (flags & FLAT_FLAG_GZIP) {
-                result = decompress_exec(bprm, sizeof (struct flat_hdr),
-                                 (((char *) textpos) + sizeof (struct flat_hdr)),
-                                 (text_len + data_len + (relocs * sizeof(unsigned long))
-                                          - sizeof (struct flat_hdr)),
-                                 0);
-                memmove((void *) datapos, (void *) realdatastart,
-                                data_len + (relocs * sizeof(unsigned long)));
-        } else if (flags & FLAT_FLAG_GZDATA) {
-                fpos = 0;
-                result = bprm->file->f_op->read(bprm->file,
-                                (char *) textpos, text_len, &fpos);
-                if (!is_error(result)) {
-                        result = decompress_exec(bprm, text_len, (char *) datapos,
-                                         data_len + (relocs * sizeof(unsigned long)), 0);
-                }
-        }
-        else
-#endif
-        {
-            result = target_pread(bprm->src.fd, textpos,
-                                  text_len, 0);
-            if (result >= 0) {
-                result = target_pread(bprm->src.fd, datapos,
-                    data_len + (relocs * sizeof(abi_ulong)),
-                    ntohl(hdr->data_start));
-            }
+        result = target_pread(bprm->src.fd, textpos,
+                              text_len, 0);
+        if (result >= 0) {
+            result = target_pread(bprm->src.fd, datapos,
+                                  data_len + (relocs * sizeof(abi_ulong)),
+                                  ntohl(hdr->data_start));
         }
         if (result < 0) {
             fprintf(stderr, "Unable to read code+data+bss\n");
@@ -678,44 +456,6 @@ static int load_flat_file(struct linux_binprm * bprm,
 
 
 /****************************************************************************/
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-
-/*
- * Load a shared library into memory.  The library gets its own data
- * segment (including bss) but not argv/argc/environ.
- */
-
-static int load_flat_shared_library(int id, struct lib_info *libs)
-{
-	struct linux_binprm bprm;
-	int res;
-	char buf[16];
-
-	/* Create the file name */
-	sprintf(buf, "/lib/lib%d.so", id);
-
-	/* Open the file up */
-	bprm.filename = buf;
-	bprm.file = open_exec(bprm.filename);
-	res = PTR_ERR(bprm.file);
-	if (IS_ERR(bprm.file))
-		return res;
-
-	res = prepare_binprm(&bprm);
-
-        if (!is_error(res)) {
-		res = load_flat_file(&bprm, libs, id, NULL);
-        }
-	if (bprm.file) {
-		allow_write_access(bprm.file);
-		fput(bprm.file);
-		bprm.file = NULL;
-	}
-	return(res);
-}
-
-#endif /* CONFIG_BINFMT_SHARED_FLAT */
-
 int load_flt_binary(struct linux_binprm *bprm, struct image_info *info)
 {
     struct lib_info libinfo[MAX_SHARED_LIBS];
@@ -793,19 +533,6 @@ int load_flt_binary(struct linux_binprm *bprm, struct image_info *info)
      */
     start_addr = libinfo[0].entry;
 
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-#error here
-    for (i = MAX_SHARED_LIBS-1; i>0; i--) {
-            if (libinfo[i].loaded) {
-                    /* Push previous first to call address */
-                    --sp;
-                    if (put_user_ual(start_addr, sp))
-                        return -EFAULT;
-                    start_addr = libinfo[i].entry;
-            }
-    }
-#endif
-
     /* Stash our initial stack pointer into the mm structure */
     info->start_code = libinfo[0].start_code;
     info->end_code = libinfo[0].start_code + libinfo[0].text_len;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 27/37] hw/misc: Don't special case RESET_TYPE_COLD in npcm7xx_clk, gcr
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (25 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 26/37] linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 28/37] allwinner-i2c, adm1272: Use device_cold_reset() for software-triggered reset Peter Maydell
                   ` (10 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

The npcm7xx_clk and npcm7xx_gcr device reset methods look at
the ResetType argument and only handle RESET_TYPE_COLD,
producing a warning if another reset type is passed. This
is different from how every other three-phase-reset method
we have works, and makes it difficult to add new reset types.

A better pattern is "assume that any reset type you don't know
about should be handled like RESET_TYPE_COLD"; switch these
devices to do that. Then adding a new reset type will only
need to touch those devices where its behaviour really needs
to be different from the standard cold reset.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Luc Michel <luc.michel@amd.com>
Message-id: 20240412160809.1260625-2-peter.maydell@linaro.org
---
 hw/misc/npcm7xx_clk.c | 13 +++----------
 hw/misc/npcm7xx_gcr.c | 12 ++++--------
 2 files changed, 7 insertions(+), 18 deletions(-)

diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
index ac1622c38aa..2098c85ee01 100644
--- a/hw/misc/npcm7xx_clk.c
+++ b/hw/misc/npcm7xx_clk.c
@@ -873,20 +873,13 @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
 
     QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
 
-    switch (type) {
-    case RESET_TYPE_COLD:
-        memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
-        s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        npcm7xx_clk_update_all_clocks(s);
-        return;
-    }
-
+    memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
+    s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    npcm7xx_clk_update_all_clocks(s);
     /*
      * A small number of registers need to be reset on a core domain reset,
      * but no such reset type exists yet.
      */
-    qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.",
-                  __func__, type);
 }
 
 static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
index 9252f9d1488..c4c4e246d7e 100644
--- a/hw/misc/npcm7xx_gcr.c
+++ b/hw/misc/npcm7xx_gcr.c
@@ -159,14 +159,10 @@ static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
 
     QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
 
-    switch (type) {
-    case RESET_TYPE_COLD:
-        memcpy(s->regs, cold_reset_values, sizeof(s->regs));
-        s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
-        s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
-        s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
-        break;
-    }
+    memcpy(s->regs, cold_reset_values, sizeof(s->regs));
+    s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
+    s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
+    s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
 }
 
 static void npcm7xx_gcr_realize(DeviceState *dev, Error **errp)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 28/37] allwinner-i2c, adm1272: Use device_cold_reset() for software-triggered reset
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (26 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 27/37] hw/misc: Don't special case RESET_TYPE_COLD in npcm7xx_clk, gcr Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 29/37] scripts/coccinelle: New script to add ResetType to hold and exit phases Peter Maydell
                   ` (9 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

Rather than directly calling the device's implementation of its 'hold'
reset phase, call device_cold_reset(). This means we don't have to
adjust this callsite when we add another argument to the function
signature for the hold and exit reset methods.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Luc Michel <luc.michel@amd.com>
Message-id: 20240412160809.1260625-3-peter.maydell@linaro.org
---
 hw/i2c/allwinner-i2c.c | 3 +--
 hw/sensor/adm1272.c    | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c
index 8abcc39a5c2..96c20c86372 100644
--- a/hw/i2c/allwinner-i2c.c
+++ b/hw/i2c/allwinner-i2c.c
@@ -385,8 +385,7 @@ static void allwinner_i2c_write(void *opaque, hwaddr offset,
         break;
     case TWI_SRST_REG:
         if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) {
-            /* Perform reset */
-            allwinner_i2c_reset_hold(OBJECT(s));
+            device_cold_reset(DEVICE(s));
         }
         s->srst = value & TWI_SRST_MASK;
         break;
diff --git a/hw/sensor/adm1272.c b/hw/sensor/adm1272.c
index 1f7c8abb838..a19557ec9ea 100644
--- a/hw/sensor/adm1272.c
+++ b/hw/sensor/adm1272.c
@@ -386,7 +386,7 @@ static int adm1272_write_data(PMBusDevice *pmdev, const uint8_t *buf,
         break;
 
     case ADM1272_MFR_POWER_CYCLE:
-        adm1272_exit_reset((Object *)s);
+        device_cold_reset(DEVICE(s));
         break;
 
     case ADM1272_HYSTERESIS_LOW:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 29/37] scripts/coccinelle: New script to add ResetType to hold and exit phases
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (27 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 28/37] allwinner-i2c, adm1272: Use device_cold_reset() for software-triggered reset Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 30/37] hw, target: Add ResetType argument to hold and exit phase methods Peter Maydell
                   ` (8 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

We pass a ResetType argument to the Resettable class enter phase
method, but we don't pass it to hold and exit, even though the
callsites have it readily available.  This means that if a device
cared about the ResetType it would need to record it in the enter
phase method to use later on.  We should pass the type to all three
of the phase methods to avoid having to do that.

This coccinelle script adds the ResetType argument to the hold and
exit phases of the Resettable interface.

The first part of the script (rules holdfn_assigned, holdfn_defined,
exitfn_assigned, exitfn_defined) update implementations of the
interface within device models, both to change the signature of their
method implementations and to pass on the reset type when they invoke
reset on some other device.

The second part of the script is various special cases:
 * method callsites in resettable_phase_hold(), resettable_phase_exit()
   and device_phases_reset()
 * updating the typedefs for the methods
 * isl_pmbus_vr.c has some code where one device's reset method directly
   calls the implementation of a different device's method

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Luc Michel <luc.michel@amd.com>
Message-id: 20240412160809.1260625-4-peter.maydell@linaro.org
---
 scripts/coccinelle/reset-type.cocci | 133 ++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)
 create mode 100644 scripts/coccinelle/reset-type.cocci

diff --git a/scripts/coccinelle/reset-type.cocci b/scripts/coccinelle/reset-type.cocci
new file mode 100644
index 00000000000..14abdd7bd0c
--- /dev/null
+++ b/scripts/coccinelle/reset-type.cocci
@@ -0,0 +1,133 @@
+// Convert device code using three-phase reset to add a ResetType
+// argument to implementations of ResettableHoldPhase and
+// ResettableEnterPhase methods.
+//
+// Copyright Linaro Ltd 2024
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// for dir in include hw target; do \
+// spatch --macro-file scripts/cocci-macro-file.h \
+//        --sp-file scripts/coccinelle/reset-type.cocci \
+//        --keep-comments --smpl-spacing --in-place --include-headers \
+//        --dir $dir; done
+//
+// This coccinelle script aims to produce a complete change that needs
+// no human interaction, so as well as the generic "update device
+// implementations of the hold and exit phase methods" it includes
+// the special-case transformations needed for the core code and for
+// one device model that does something a bit nonstandard. Those
+// special cases are at the end of the file.
+
+// Look for where we use a function as a ResettableHoldPhase method,
+// either by directly assigning it to phases.hold or by calling
+// resettable_class_set_parent_phases, and remember the function name.
+@ holdfn_assigned @
+identifier enterfn, holdfn, exitfn;
+identifier rc;
+expression e;
+@@
+ResettableClass *rc;
+...
+(
+ rc->phases.hold = holdfn;
+|
+ resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
+)
+
+// Look for the definition of the function we found in holdfn_assigned,
+// and add the new argument. If the function calls a hold function
+// itself (probably chaining to the parent class reset) then add the
+// new argument there too.
+@ holdfn_defined @
+identifier holdfn_assigned.holdfn;
+typedef Object;
+identifier obj;
+expression parent;
+@@
+-holdfn(Object *obj)
++holdfn(Object *obj, ResetType type)
+{
+    <...
+-    parent.hold(obj)
++    parent.hold(obj, type)
+    ...>
+}
+
+// Similarly for ResettableExitPhase.
+@ exitfn_assigned @
+identifier enterfn, holdfn, exitfn;
+identifier rc;
+expression e;
+@@
+ResettableClass *rc;
+...
+(
+ rc->phases.exit = exitfn;
+|
+ resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
+)
+@ exitfn_defined @
+identifier exitfn_assigned.exitfn;
+typedef Object;
+identifier obj;
+expression parent;
+@@
+-exitfn(Object *obj)
++exitfn(Object *obj, ResetType type)
+{
+    <...
+-    parent.exit(obj)
++    parent.exit(obj, type)
+    ...>
+}
+
+// SPECIAL CASES ONLY BELOW HERE
+// We use a python scripted constraint on the position of the match
+// to ensure that they only match in a particular function. See
+// https://public-inbox.org/git/alpine.DEB.2.21.1808240652370.2344@hadrien/
+// which recommends this as the way to do "match only in this function".
+
+// Special case: isl_pmbus_vr.c has some reset methods calling others directly
+@ isl_pmbus_vr @
+identifier obj;
+@@
+- isl_pmbus_vr_exit_reset(obj);
++ isl_pmbus_vr_exit_reset(obj, type);
+
+// Special case: device_phases_reset() needs to pass RESET_TYPE_COLD
+@ device_phases_reset_hold @
+expression obj;
+identifier rc;
+identifier phase;
+position p : script:python() { p[0].current_element == "device_phases_reset" };
+@@
+- rc->phases.phase(obj)@p
++ rc->phases.phase(obj, RESET_TYPE_COLD)
+
+// Special case: in resettable_phase_hold() and resettable_phase_exit()
+// we need to pass through the ResetType argument to the method being called
+@ resettable_phase_hold @
+expression obj;
+identifier rc;
+position p : script:python() { p[0].current_element == "resettable_phase_hold" };
+@@
+- rc->phases.hold(obj)@p
++ rc->phases.hold(obj, type)
+@ resettable_phase_exit @
+expression obj;
+identifier rc;
+position p : script:python() { p[0].current_element == "resettable_phase_exit" };
+@@
+- rc->phases.exit(obj)@p
++ rc->phases.exit(obj, type)
+// Special case: the typedefs for the methods need to declare the new argument
+@ phase_typedef_hold @
+identifier obj;
+@@
+- typedef void (*ResettableHoldPhase)(Object *obj);
++ typedef void (*ResettableHoldPhase)(Object *obj, ResetType type);
+@ phase_typedef_exit @
+identifier obj;
+@@
+- typedef void (*ResettableExitPhase)(Object *obj);
++ typedef void (*ResettableExitPhase)(Object *obj, ResetType type);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 30/37] hw, target: Add ResetType argument to hold and exit phase methods
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (28 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 29/37] scripts/coccinelle: New script to add ResetType to hold and exit phases Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 31/37] docs/devel/reset: Update to new API for " Peter Maydell
                   ` (7 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

We pass a ResetType argument to the Resettable class enter
phase method, but we don't pass it to hold and exit, even though
the callsites have it readily available. This means that if
a device cared about the ResetType it would need to record it
in the enter phase method to use later on. Pass the type to
all three of the phase methods to avoid having to do that.

Commit created with

  for dir in hw target include; do \
      spatch --macro-file scripts/cocci-macro-file.h \
             --sp-file scripts/coccinelle/reset-type.cocci \
             --keep-comments --smpl-spacing --in-place \
             --include-headers --dir $dir; done

and no manual edits.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Luc Michel <luc.michel@amd.com>
Message-id: 20240412160809.1260625-5-peter.maydell@linaro.org
---
 include/hw/resettable.h             |  4 ++--
 hw/adc/npcm7xx_adc.c                |  2 +-
 hw/arm/pxa2xx_pic.c                 |  2 +-
 hw/arm/smmu-common.c                |  2 +-
 hw/arm/smmuv3.c                     |  4 ++--
 hw/arm/stellaris.c                  | 10 +++++-----
 hw/audio/asc.c                      |  2 +-
 hw/char/cadence_uart.c              |  2 +-
 hw/char/sifive_uart.c               |  2 +-
 hw/core/cpu-common.c                |  2 +-
 hw/core/qdev.c                      |  4 ++--
 hw/core/reset.c                     |  2 +-
 hw/core/resettable.c                |  4 ++--
 hw/display/virtio-vga.c             |  4 ++--
 hw/gpio/npcm7xx_gpio.c              |  2 +-
 hw/gpio/pl061.c                     |  2 +-
 hw/gpio/stm32l4x5_gpio.c            |  2 +-
 hw/hyperv/vmbus.c                   |  2 +-
 hw/i2c/allwinner-i2c.c              |  2 +-
 hw/i2c/npcm7xx_smbus.c              |  2 +-
 hw/input/adb.c                      |  2 +-
 hw/input/ps2.c                      | 12 ++++++------
 hw/intc/arm_gic_common.c            |  2 +-
 hw/intc/arm_gic_kvm.c               |  4 ++--
 hw/intc/arm_gicv3_common.c          |  2 +-
 hw/intc/arm_gicv3_its.c             |  4 ++--
 hw/intc/arm_gicv3_its_common.c      |  2 +-
 hw/intc/arm_gicv3_its_kvm.c         |  4 ++--
 hw/intc/arm_gicv3_kvm.c             |  4 ++--
 hw/intc/xics.c                      |  2 +-
 hw/m68k/q800-glue.c                 |  2 +-
 hw/misc/djmemc.c                    |  2 +-
 hw/misc/iosb.c                      |  2 +-
 hw/misc/mac_via.c                   |  8 ++++----
 hw/misc/macio/cuda.c                |  4 ++--
 hw/misc/macio/pmu.c                 |  4 ++--
 hw/misc/mos6522.c                   |  2 +-
 hw/misc/npcm7xx_mft.c               |  2 +-
 hw/misc/npcm7xx_pwm.c               |  2 +-
 hw/misc/stm32l4x5_exti.c            |  2 +-
 hw/misc/stm32l4x5_rcc.c             | 10 +++++-----
 hw/misc/stm32l4x5_syscfg.c          |  2 +-
 hw/misc/xlnx-versal-cframe-reg.c    |  2 +-
 hw/misc/xlnx-versal-crl.c           |  2 +-
 hw/misc/xlnx-versal-pmc-iou-slcr.c  |  2 +-
 hw/misc/xlnx-versal-trng.c          |  2 +-
 hw/misc/xlnx-versal-xramc.c         |  2 +-
 hw/misc/xlnx-zynqmp-apu-ctrl.c      |  2 +-
 hw/misc/xlnx-zynqmp-crf.c           |  2 +-
 hw/misc/zynq_slcr.c                 |  4 ++--
 hw/net/can/xlnx-zynqmp-can.c        |  2 +-
 hw/net/e1000.c                      |  2 +-
 hw/net/e1000e.c                     |  2 +-
 hw/net/igb.c                        |  2 +-
 hw/net/igbvf.c                      |  2 +-
 hw/nvram/xlnx-bbram.c               |  2 +-
 hw/nvram/xlnx-versal-efuse-ctrl.c   |  2 +-
 hw/nvram/xlnx-zynqmp-efuse.c        |  2 +-
 hw/pci-bridge/cxl_root_port.c       |  4 ++--
 hw/pci-bridge/pcie_root_port.c      |  2 +-
 hw/pci-host/bonito.c                |  2 +-
 hw/pci-host/pnv_phb.c               |  4 ++--
 hw/pci-host/pnv_phb3_msi.c          |  4 ++--
 hw/pci/pci.c                        |  4 ++--
 hw/rtc/mc146818rtc.c                |  2 +-
 hw/s390x/css-bridge.c               |  2 +-
 hw/sensor/adm1266.c                 |  2 +-
 hw/sensor/adm1272.c                 |  2 +-
 hw/sensor/isl_pmbus_vr.c            | 10 +++++-----
 hw/sensor/max31785.c                |  2 +-
 hw/sensor/max34451.c                |  2 +-
 hw/ssi/npcm7xx_fiu.c                |  2 +-
 hw/timer/etraxfs_timer.c            |  2 +-
 hw/timer/npcm7xx_timer.c            |  2 +-
 hw/usb/hcd-dwc2.c                   |  8 ++++----
 hw/usb/xlnx-versal-usb2-ctrl-regs.c |  2 +-
 hw/virtio/virtio-pci.c              |  2 +-
 target/arm/cpu.c                    |  4 ++--
 target/avr/cpu.c                    |  4 ++--
 target/cris/cpu.c                   |  4 ++--
 target/hexagon/cpu.c                |  4 ++--
 target/i386/cpu.c                   |  4 ++--
 target/loongarch/cpu.c              |  4 ++--
 target/m68k/cpu.c                   |  4 ++--
 target/microblaze/cpu.c             |  4 ++--
 target/mips/cpu.c                   |  4 ++--
 target/openrisc/cpu.c               |  4 ++--
 target/ppc/cpu_init.c               |  4 ++--
 target/riscv/cpu.c                  |  4 ++--
 target/rx/cpu.c                     |  4 ++--
 target/sh4/cpu.c                    |  4 ++--
 target/sparc/cpu.c                  |  4 ++--
 target/tricore/cpu.c                |  4 ++--
 target/xtensa/cpu.c                 |  4 ++--
 94 files changed, 150 insertions(+), 150 deletions(-)

diff --git a/include/hw/resettable.h b/include/hw/resettable.h
index bdcd1276b69..3161e471c9b 100644
--- a/include/hw/resettable.h
+++ b/include/hw/resettable.h
@@ -103,8 +103,8 @@ typedef enum ResetType {
  * the callback.
  */
 typedef void (*ResettableEnterPhase)(Object *obj, ResetType type);
-typedef void (*ResettableHoldPhase)(Object *obj);
-typedef void (*ResettableExitPhase)(Object *obj);
+typedef void (*ResettableHoldPhase)(Object *obj, ResetType type);
+typedef void (*ResettableExitPhase)(Object *obj, ResetType type);
 typedef ResettableState * (*ResettableGetState)(Object *obj);
 typedef void (*ResettableTrFunction)(Object *obj);
 typedef ResettableTrFunction (*ResettableGetTrFunction)(Object *obj);
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
index c6647eec6d7..de8469dae4f 100644
--- a/hw/adc/npcm7xx_adc.c
+++ b/hw/adc/npcm7xx_adc.c
@@ -218,7 +218,7 @@ static void npcm7xx_adc_enter_reset(Object *obj, ResetType type)
     npcm7xx_adc_reset(s);
 }
 
-static void npcm7xx_adc_hold_reset(Object *obj)
+static void npcm7xx_adc_hold_reset(Object *obj, ResetType type)
 {
     NPCM7xxADCState *s = NPCM7XX_ADC(obj);
 
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
index f54546cd4df..34c5555dba9 100644
--- a/hw/arm/pxa2xx_pic.c
+++ b/hw/arm/pxa2xx_pic.c
@@ -272,7 +272,7 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id)
     return 0;
 }
 
-static void pxa2xx_pic_reset_hold(Object *obj)
+static void pxa2xx_pic_reset_hold(Object *obj, ResetType type)
 {
     PXA2xxPICState *s = PXA2XX_PIC(obj);
 
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index c4b540656c1..1ce706bf94b 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -682,7 +682,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
     }
 }
 
-static void smmu_base_reset_hold(Object *obj)
+static void smmu_base_reset_hold(Object *obj, ResetType type)
 {
     SMMUState *s = ARM_SMMU(obj);
 
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 9eb56a70f39..2d1e0d55ec2 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1727,13 +1727,13 @@ static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev)
     }
 }
 
-static void smmu_reset_hold(Object *obj)
+static void smmu_reset_hold(Object *obj, ResetType type)
 {
     SMMUv3State *s = ARM_SMMUV3(obj);
     SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s);
 
     if (c->parent_phases.hold) {
-        c->parent_phases.hold(obj);
+        c->parent_phases.hold(obj, type);
     }
 
     smmuv3_init_regs(s);
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index a2f998bf9e2..376746251e6 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -394,7 +394,7 @@ static void stellaris_sys_reset_enter(Object *obj, ResetType type)
     s->dcgc[0] = 1;
 }
 
-static void stellaris_sys_reset_hold(Object *obj)
+static void stellaris_sys_reset_hold(Object *obj, ResetType type)
 {
     ssys_state *s = STELLARIS_SYS(obj);
 
@@ -402,7 +402,7 @@ static void stellaris_sys_reset_hold(Object *obj)
     ssys_calculate_system_clock(s, true);
 }
 
-static void stellaris_sys_reset_exit(Object *obj)
+static void stellaris_sys_reset_exit(Object *obj, ResetType type)
 {
 }
 
@@ -618,7 +618,7 @@ static void stellaris_i2c_reset_enter(Object *obj, ResetType type)
         i2c_end_transfer(s->bus);
 }
 
-static void stellaris_i2c_reset_hold(Object *obj)
+static void stellaris_i2c_reset_hold(Object *obj, ResetType type)
 {
     stellaris_i2c_state *s = STELLARIS_I2C(obj);
 
@@ -631,7 +631,7 @@ static void stellaris_i2c_reset_hold(Object *obj)
     s->mcr = 0;
 }
 
-static void stellaris_i2c_reset_exit(Object *obj)
+static void stellaris_i2c_reset_exit(Object *obj, ResetType type)
 {
     stellaris_i2c_state *s = STELLARIS_I2C(obj);
 
@@ -787,7 +787,7 @@ static void stellaris_adc_trigger(void *opaque, int irq, int level)
     }
 }
 
-static void stellaris_adc_reset_hold(Object *obj)
+static void stellaris_adc_reset_hold(Object *obj, ResetType type)
 {
     StellarisADCState *s = STELLARIS_ADC(obj);
     int n;
diff --git a/hw/audio/asc.c b/hw/audio/asc.c
index 87b56243262..805416372c2 100644
--- a/hw/audio/asc.c
+++ b/hw/audio/asc.c
@@ -610,7 +610,7 @@ static void asc_fifo_init(ASCFIFOState *fs, int index)
     g_free(name);
 }
 
-static void asc_reset_hold(Object *obj)
+static void asc_reset_hold(Object *obj, ResetType type)
 {
     ASCState *s = ASC(obj);
 
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index db31d7cc859..77d9a2a221f 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -525,7 +525,7 @@ static void cadence_uart_reset_init(Object *obj, ResetType type)
     s->r[R_TTRIG] = 0x00000020;
 }
 
-static void cadence_uart_reset_hold(Object *obj)
+static void cadence_uart_reset_hold(Object *obj, ResetType type)
 {
     CadenceUARTState *s = CADENCE_UART(obj);
 
diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c
index e8716c42523..7fc6787f690 100644
--- a/hw/char/sifive_uart.c
+++ b/hw/char/sifive_uart.c
@@ -214,7 +214,7 @@ static void sifive_uart_reset_enter(Object *obj, ResetType type)
     s->rx_fifo_len = 0;
 }
 
-static void sifive_uart_reset_hold(Object *obj)
+static void sifive_uart_reset_hold(Object *obj, ResetType type)
 {
     SiFiveUARTState *s = SIFIVE_UART(obj);
     qemu_irq_lower(s->irq);
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 4bd9c70a83f..a72d48d9e17 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -113,7 +113,7 @@ void cpu_reset(CPUState *cpu)
     trace_cpu_reset(cpu->cpu_index);
 }
 
-static void cpu_common_reset_hold(Object *obj)
+static void cpu_common_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cpu = CPU(obj);
     CPUClass *cc = CPU_GET_CLASS(cpu);
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 00efaf1bd10..f3a996f57de 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -760,10 +760,10 @@ static void device_phases_reset(DeviceState *dev)
         rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD);
     }
     if (rc->phases.hold) {
-        rc->phases.hold(OBJECT(dev));
+        rc->phases.hold(OBJECT(dev), RESET_TYPE_COLD);
     }
     if (rc->phases.exit) {
-        rc->phases.exit(OBJECT(dev));
+        rc->phases.exit(OBJECT(dev), RESET_TYPE_COLD);
     }
 }
 
diff --git a/hw/core/reset.c b/hw/core/reset.c
index d50da7e3041..f9fef45e050 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -73,7 +73,7 @@ static ResettableState *legacy_reset_get_state(Object *obj)
     return &lr->reset_state;
 }
 
-static void legacy_reset_hold(Object *obj)
+static void legacy_reset_hold(Object *obj, ResetType type)
 {
     LegacyReset *lr = LEGACY_RESET(obj);
 
diff --git a/hw/core/resettable.c b/hw/core/resettable.c
index c3df75c6ba8..bebf7f10b26 100644
--- a/hw/core/resettable.c
+++ b/hw/core/resettable.c
@@ -181,7 +181,7 @@ static void resettable_phase_hold(Object *obj, void *opaque, ResetType type)
             trace_resettable_transitional_function(obj, obj_typename);
             tr_func(obj);
         } else if (rc->phases.hold) {
-            rc->phases.hold(obj);
+            rc->phases.hold(obj, type);
         }
     }
     trace_resettable_phase_hold_end(obj, obj_typename, s->count);
@@ -204,7 +204,7 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type)
     if (--s->count == 0) {
         trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit);
         if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) {
-            rc->phases.exit(obj);
+            rc->phases.exit(obj, type);
         }
     }
     s->exit_phase_in_progress = false;
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 94d3353f540..276f315108b 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -180,14 +180,14 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     }
 }
 
-static void virtio_vga_base_reset_hold(Object *obj)
+static void virtio_vga_base_reset_hold(Object *obj, ResetType type)
 {
     VirtIOVGABaseClass *klass = VIRTIO_VGA_BASE_GET_CLASS(obj);
     VirtIOVGABase *vvga = VIRTIO_VGA_BASE(obj);
 
     /* reset virtio-gpu */
     if (klass->parent_phases.hold) {
-        klass->parent_phases.hold(obj);
+        klass->parent_phases.hold(obj, type);
     }
 
     /* reset vga */
diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c
index 6e70ac1f24b..ba19b9ebad3 100644
--- a/hw/gpio/npcm7xx_gpio.c
+++ b/hw/gpio/npcm7xx_gpio.c
@@ -352,7 +352,7 @@ static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type)
     s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc;
 }
 
-static void npcm7xx_gpio_hold_reset(Object *obj)
+static void npcm7xx_gpio_hold_reset(Object *obj, ResetType type)
 {
     NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
 
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index 86f23836553..d5838b8e98d 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -484,7 +484,7 @@ static void pl061_enter_reset(Object *obj, ResetType type)
     s->amsel = 0;
 }
 
-static void pl061_hold_reset(Object *obj)
+static void pl061_hold_reset(Object *obj, ResetType type)
 {
     PL061State *s = PL061(obj);
     int i, level;
diff --git a/hw/gpio/stm32l4x5_gpio.c b/hw/gpio/stm32l4x5_gpio.c
index 63b8763e9d3..71bf5fddb2a 100644
--- a/hw/gpio/stm32l4x5_gpio.c
+++ b/hw/gpio/stm32l4x5_gpio.c
@@ -70,7 +70,7 @@ static bool is_push_pull(Stm32l4x5GpioState *s, unsigned pin)
     return extract32(s->otyper, pin, 1) == 0;
 }
 
-static void stm32l4x5_gpio_reset_hold(Object *obj)
+static void stm32l4x5_gpio_reset_hold(Object *obj, ResetType type)
 {
     Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
 
diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
index f33afeeea27..490d805d298 100644
--- a/hw/hyperv/vmbus.c
+++ b/hw/hyperv/vmbus.c
@@ -2453,7 +2453,7 @@ static void vmbus_unrealize(BusState *bus)
     qemu_mutex_destroy(&vmbus->rx_queue_lock);
 }
 
-static void vmbus_reset_hold(Object *obj)
+static void vmbus_reset_hold(Object *obj, ResetType type)
 {
     vmbus_deinit(VMBUS(obj));
 }
diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c
index 96c20c86372..16f1d6d40e7 100644
--- a/hw/i2c/allwinner-i2c.c
+++ b/hw/i2c/allwinner-i2c.c
@@ -170,7 +170,7 @@ static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s)
     return s->cntr & TWI_CNTR_INT_EN;
 }
 
-static void allwinner_i2c_reset_hold(Object *obj)
+static void allwinner_i2c_reset_hold(Object *obj, ResetType type)
 {
     AWI2CState *s = AW_I2C(obj);
 
diff --git a/hw/i2c/npcm7xx_smbus.c b/hw/i2c/npcm7xx_smbus.c
index 0ea3083bb6e..22d68fc67dd 100644
--- a/hw/i2c/npcm7xx_smbus.c
+++ b/hw/i2c/npcm7xx_smbus.c
@@ -1022,7 +1022,7 @@ static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
     s->rx_cur = 0;
 }
 
-static void npcm7xx_smbus_hold_reset(Object *obj)
+static void npcm7xx_smbus_hold_reset(Object *obj, ResetType type)
 {
     NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
 
diff --git a/hw/input/adb.c b/hw/input/adb.c
index 98f39b4281a..aff7130fd0f 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -231,7 +231,7 @@ static const VMStateDescription vmstate_adb_bus = {
     }
 };
 
-static void adb_bus_reset_hold(Object *obj)
+static void adb_bus_reset_hold(Object *obj, ResetType type)
 {
     ADBBusState *adb_bus = ADB_BUS(obj);
 
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 00b695a0b97..d6f834443dd 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -1007,7 +1007,7 @@ void ps2_write_mouse(PS2MouseState *s, int val)
     }
 }
 
-static void ps2_reset_hold(Object *obj)
+static void ps2_reset_hold(Object *obj, ResetType type)
 {
     PS2State *s = PS2_DEVICE(obj);
 
@@ -1015,7 +1015,7 @@ static void ps2_reset_hold(Object *obj)
     ps2_reset_queue(s);
 }
 
-static void ps2_reset_exit(Object *obj)
+static void ps2_reset_exit(Object *obj, ResetType type)
 {
     PS2State *s = PS2_DEVICE(obj);
 
@@ -1048,7 +1048,7 @@ static void ps2_common_post_load(PS2State *s)
     q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1;
 }
 
-static void ps2_kbd_reset_hold(Object *obj)
+static void ps2_kbd_reset_hold(Object *obj, ResetType type)
 {
     PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
     PS2KbdState *s = PS2_KBD_DEVICE(obj);
@@ -1056,7 +1056,7 @@ static void ps2_kbd_reset_hold(Object *obj)
     trace_ps2_kbd_reset(s);
 
     if (ps2dc->parent_phases.hold) {
-        ps2dc->parent_phases.hold(obj);
+        ps2dc->parent_phases.hold(obj, type);
     }
 
     s->scan_enabled = 1;
@@ -1065,7 +1065,7 @@ static void ps2_kbd_reset_hold(Object *obj)
     s->modifiers = 0;
 }
 
-static void ps2_mouse_reset_hold(Object *obj)
+static void ps2_mouse_reset_hold(Object *obj, ResetType type)
 {
     PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
     PS2MouseState *s = PS2_MOUSE_DEVICE(obj);
@@ -1073,7 +1073,7 @@ static void ps2_mouse_reset_hold(Object *obj)
     trace_ps2_mouse_reset(s);
 
     if (ps2dc->parent_phases.hold) {
-        ps2dc->parent_phases.hold(obj);
+        ps2dc->parent_phases.hold(obj, type);
     }
 
     s->mouse_status = 0;
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
index 94c173cb071..53fb2c4e2d3 100644
--- a/hw/intc/arm_gic_common.c
+++ b/hw/intc/arm_gic_common.c
@@ -263,7 +263,7 @@ static inline void arm_gic_common_reset_irq_state(GICState *s, int cidx,
     }
 }
 
-static void arm_gic_common_reset_hold(Object *obj)
+static void arm_gic_common_reset_hold(Object *obj, ResetType type)
 {
     GICState *s = ARM_GIC_COMMON(obj);
     int i, j;
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index e0d9e512a37..53defee7d59 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -473,13 +473,13 @@ static void kvm_arm_gic_get(GICState *s)
     }
 }
 
-static void kvm_arm_gic_reset_hold(Object *obj)
+static void kvm_arm_gic_reset_hold(Object *obj, ResetType type)
 {
     GICState *s = ARM_GIC_COMMON(obj);
     KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
 
     if (kgc->parent_phases.hold) {
-        kgc->parent_phases.hold(obj);
+        kgc->parent_phases.hold(obj, type);
     }
 
     if (kvm_arm_gic_can_save_restore(s)) {
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 207f8417e1f..bd50a1b0795 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -495,7 +495,7 @@ static void arm_gicv3_finalize(Object *obj)
     g_free(s->redist_region_count);
 }
 
-static void arm_gicv3_common_reset_hold(Object *obj)
+static void arm_gicv3_common_reset_hold(Object *obj, ResetType type)
 {
     GICv3State *s = ARM_GICV3_COMMON(obj);
     int i;
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index 52e9aca9c65..bf31158470e 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -1950,13 +1950,13 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
     }
 }
 
-static void gicv3_its_reset_hold(Object *obj)
+static void gicv3_its_reset_hold(Object *obj, ResetType type)
 {
     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
     GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
 
     if (c->parent_phases.hold) {
-        c->parent_phases.hold(obj);
+        c->parent_phases.hold(obj, type);
     }
 
     /* Quiescent bit reset to 1 */
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
index 331d6b93cc1..0b97362cd21 100644
--- a/hw/intc/arm_gicv3_its_common.c
+++ b/hw/intc/arm_gicv3_its_common.c
@@ -123,7 +123,7 @@ void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
     msi_nonbroken = true;
 }
 
-static void gicv3_its_common_reset_hold(Object *obj)
+static void gicv3_its_common_reset_hold(Object *obj, ResetType type)
 {
     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
 
diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
index 3befc960db2..35539c099fc 100644
--- a/hw/intc/arm_gicv3_its_kvm.c
+++ b/hw/intc/arm_gicv3_its_kvm.c
@@ -197,14 +197,14 @@ static void kvm_arm_its_post_load(GICv3ITSState *s)
                       GITS_CTLR, &s->ctlr, true, &error_abort);
 }
 
-static void kvm_arm_its_reset_hold(Object *obj)
+static void kvm_arm_its_reset_hold(Object *obj, ResetType type)
 {
     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
     KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s);
     int i;
 
     if (c->parent_phases.hold) {
-        c->parent_phases.hold(obj);
+        c->parent_phases.hold(obj, type);
     }
 
     if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 00a383079b9..9ea6b8e2189 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -703,7 +703,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
     c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
 }
 
-static void kvm_arm_gicv3_reset_hold(Object *obj)
+static void kvm_arm_gicv3_reset_hold(Object *obj, ResetType type)
 {
     GICv3State *s = ARM_GICV3_COMMON(obj);
     KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
@@ -711,7 +711,7 @@ static void kvm_arm_gicv3_reset_hold(Object *obj)
     DPRINTF("Reset\n");
 
     if (kgc->parent_phases.hold) {
-        kgc->parent_phases.hold(obj);
+        kgc->parent_phases.hold(obj, type);
     }
 
     if (s->migration_blocker) {
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 700abfa7a62..9b3b7abaea2 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -579,7 +579,7 @@ static void ics_reset_irq(ICSIRQState *irq)
     irq->saved_priority = 0xff;
 }
 
-static void ics_reset_hold(Object *obj)
+static void ics_reset_hold(Object *obj, ResetType type)
 {
     ICSState *ics = ICS(obj);
     g_autofree uint8_t *flags = g_malloc(ics->nr_irqs);
diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c
index b5a7713863f..e2ae7c32011 100644
--- a/hw/m68k/q800-glue.c
+++ b/hw/m68k/q800-glue.c
@@ -175,7 +175,7 @@ static void glue_nmi_release(void *opaque)
     GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0);
 }
 
-static void glue_reset_hold(Object *obj)
+static void glue_reset_hold(Object *obj, ResetType type)
 {
     GLUEState *s = GLUE(obj);
 
diff --git a/hw/misc/djmemc.c b/hw/misc/djmemc.c
index 9b69656c3a8..96d5efb5e3a 100644
--- a/hw/misc/djmemc.c
+++ b/hw/misc/djmemc.c
@@ -96,7 +96,7 @@ static void djmemc_init(Object *obj)
     sysbus_init_mmio(sbd, &s->mem_regs);
 }
 
-static void djmemc_reset_hold(Object *obj)
+static void djmemc_reset_hold(Object *obj, ResetType type)
 {
     DJMEMCState *s = DJMEMC(obj);
 
diff --git a/hw/misc/iosb.c b/hw/misc/iosb.c
index e20305e8013..31927eaedb4 100644
--- a/hw/misc/iosb.c
+++ b/hw/misc/iosb.c
@@ -81,7 +81,7 @@ static const MemoryRegionOps iosb_mmio_ops = {
     .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static void iosb_reset_hold(Object *obj)
+static void iosb_reset_hold(Object *obj, ResetType type)
 {
     IOSBState *s = IOSB(obj);
 
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index db6142b5f41..652395b84fc 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -1203,7 +1203,7 @@ static int via1_post_load(void *opaque, int version_id)
 }
 
 /* VIA 1 */
-static void mos6522_q800_via1_reset_hold(Object *obj)
+static void mos6522_q800_via1_reset_hold(Object *obj, ResetType type)
 {
     MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(obj);
     MOS6522State *ms = MOS6522(v1s);
@@ -1211,7 +1211,7 @@ static void mos6522_q800_via1_reset_hold(Object *obj)
     ADBBusState *adb_bus = &v1s->adb_bus;
 
     if (mdc->parent_phases.hold) {
-        mdc->parent_phases.hold(obj);
+        mdc->parent_phases.hold(obj, type);
     }
 
     ms->timers[0].frequency = VIA_TIMER_FREQ;
@@ -1359,13 +1359,13 @@ static void mos6522_q800_via2_portB_write(MOS6522State *s)
     }
 }
 
-static void mos6522_q800_via2_reset_hold(Object *obj)
+static void mos6522_q800_via2_reset_hold(Object *obj, ResetType type)
 {
     MOS6522State *ms = MOS6522(obj);
     MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
 
     if (mdc->parent_phases.hold) {
-        mdc->parent_phases.hold(obj);
+        mdc->parent_phases.hold(obj, type);
     }
 
     ms->timers[0].frequency = VIA_TIMER_FREQ;
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index 41934e2cf8e..beab0ffb13f 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -586,13 +586,13 @@ static void mos6522_cuda_portB_write(MOS6522State *s)
     cuda_update(cs);
 }
 
-static void mos6522_cuda_reset_hold(Object *obj)
+static void mos6522_cuda_reset_hold(Object *obj, ResetType type)
 {
     MOS6522State *ms = MOS6522(obj);
     MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
 
     if (mdc->parent_phases.hold) {
-        mdc->parent_phases.hold(obj);
+        mdc->parent_phases.hold(obj, type);
     }
 
     ms->timers[0].frequency = CUDA_TIMER_FREQ;
diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c
index e40c51bf529..238da58eade 100644
--- a/hw/misc/macio/pmu.c
+++ b/hw/misc/macio/pmu.c
@@ -792,7 +792,7 @@ static void mos6522_pmu_portB_write(MOS6522State *s)
     pmu_update(ps);
 }
 
-static void mos6522_pmu_reset_hold(Object *obj)
+static void mos6522_pmu_reset_hold(Object *obj, ResetType type)
 {
     MOS6522State *ms = MOS6522(obj);
     MOS6522PMUState *mps = container_of(ms, MOS6522PMUState, parent_obj);
@@ -800,7 +800,7 @@ static void mos6522_pmu_reset_hold(Object *obj)
     MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
 
     if (mdc->parent_phases.hold) {
-        mdc->parent_phases.hold(obj);
+        mdc->parent_phases.hold(obj, type);
     }
 
     ms->timers[0].frequency = VIA_TIMER_FREQ;
diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c
index e3fe87c20ca..515f62e687d 100644
--- a/hw/misc/mos6522.c
+++ b/hw/misc/mos6522.c
@@ -642,7 +642,7 @@ const VMStateDescription vmstate_mos6522 = {
     }
 };
 
-static void mos6522_reset_hold(Object *obj)
+static void mos6522_reset_hold(Object *obj, ResetType type)
 {
     MOS6522State *s = MOS6522(obj);
 
diff --git a/hw/misc/npcm7xx_mft.c b/hw/misc/npcm7xx_mft.c
index 9a848584e18..9fcc69fe5c5 100644
--- a/hw/misc/npcm7xx_mft.c
+++ b/hw/misc/npcm7xx_mft.c
@@ -467,7 +467,7 @@ static void npcm7xx_mft_enter_reset(Object *obj, ResetType type)
     npcm7xx_mft_reset(s);
 }
 
-static void npcm7xx_mft_hold_reset(Object *obj)
+static void npcm7xx_mft_hold_reset(Object *obj, ResetType type)
 {
     NPCM7xxMFTState *s = NPCM7XX_MFT(obj);
 
diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
index fca2dd2e5af..f7f77e30a22 100644
--- a/hw/misc/npcm7xx_pwm.c
+++ b/hw/misc/npcm7xx_pwm.c
@@ -468,7 +468,7 @@ static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
     s->piir = 0x00000000;
 }
 
-static void npcm7xx_pwm_hold_reset(Object *obj)
+static void npcm7xx_pwm_hold_reset(Object *obj, ResetType type)
 {
     NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
     int i;
diff --git a/hw/misc/stm32l4x5_exti.c b/hw/misc/stm32l4x5_exti.c
index 9fd859160d4..a090dbd366f 100644
--- a/hw/misc/stm32l4x5_exti.c
+++ b/hw/misc/stm32l4x5_exti.c
@@ -77,7 +77,7 @@ static unsigned configurable_mask(unsigned bank)
      return valid_mask(bank) & ~exti_romask[bank];
 }
 
-static void stm32l4x5_exti_reset_hold(Object *obj)
+static void stm32l4x5_exti_reset_hold(Object *obj, ResetType type)
 {
     Stm32l4x5ExtiState *s = STM32L4X5_EXTI(obj);
 
diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c
index ed2dbd9dc3f..417bd5e85f6 100644
--- a/hw/misc/stm32l4x5_rcc.c
+++ b/hw/misc/stm32l4x5_rcc.c
@@ -113,13 +113,13 @@ static void clock_mux_reset_enter(Object *obj, ResetType type)
     set_clock_mux_init_info(s, s->id);
 }
 
-static void clock_mux_reset_hold(Object *obj)
+static void clock_mux_reset_hold(Object *obj, ResetType type)
 {
     RccClockMuxState *s = RCC_CLOCK_MUX(obj);
     clock_mux_update(s, true);
 }
 
-static void clock_mux_reset_exit(Object *obj)
+static void clock_mux_reset_exit(Object *obj, ResetType type)
 {
     RccClockMuxState *s = RCC_CLOCK_MUX(obj);
     clock_mux_update(s, false);
@@ -263,13 +263,13 @@ static void pll_reset_enter(Object *obj, ResetType type)
     set_pll_init_info(s, s->id);
 }
 
-static void pll_reset_hold(Object *obj)
+static void pll_reset_hold(Object *obj, ResetType type)
 {
     RccPllState *s = RCC_PLL(obj);
     pll_update(s, true);
 }
 
-static void pll_reset_exit(Object *obj)
+static void pll_reset_exit(Object *obj, ResetType type)
 {
     RccPllState *s = RCC_PLL(obj);
     pll_update(s, false);
@@ -907,7 +907,7 @@ static void rcc_update_csr(Stm32l4x5RccState *s)
     rcc_update_irq(s);
 }
 
-static void stm32l4x5_rcc_reset_hold(Object *obj)
+static void stm32l4x5_rcc_reset_hold(Object *obj, ResetType type)
 {
     Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
     s->cr = 0x00000063;
diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
index 3dafc00b49d..a5a1ce26804 100644
--- a/hw/misc/stm32l4x5_syscfg.c
+++ b/hw/misc/stm32l4x5_syscfg.c
@@ -65,7 +65,7 @@
 
 #define NUM_LINES_PER_EXTICR_REG 4
 
-static void stm32l4x5_syscfg_hold_reset(Object *obj)
+static void stm32l4x5_syscfg_hold_reset(Object *obj, ResetType type)
 {
     Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj);
 
diff --git a/hw/misc/xlnx-versal-cframe-reg.c b/hw/misc/xlnx-versal-cframe-reg.c
index a6ab287b019..3fc838bd54b 100644
--- a/hw/misc/xlnx-versal-cframe-reg.c
+++ b/hw/misc/xlnx-versal-cframe-reg.c
@@ -542,7 +542,7 @@ static void cframe_reg_reset_enter(Object *obj, ResetType type)
     }
 }
 
-static void cframe_reg_reset_hold(Object *obj)
+static void cframe_reg_reset_hold(Object *obj, ResetType type)
 {
     XlnxVersalCFrameReg *s = XLNX_VERSAL_CFRAME_REG(obj);
 
diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c
index 1f1762ef163..f143900d5b4 100644
--- a/hw/misc/xlnx-versal-crl.c
+++ b/hw/misc/xlnx-versal-crl.c
@@ -311,7 +311,7 @@ static void crl_reset_enter(Object *obj, ResetType type)
     }
 }
 
-static void crl_reset_hold(Object *obj)
+static void crl_reset_hold(Object *obj, ResetType type)
 {
     XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
 
diff --git a/hw/misc/xlnx-versal-pmc-iou-slcr.c b/hw/misc/xlnx-versal-pmc-iou-slcr.c
index 60e13a78ab8..e469c04d763 100644
--- a/hw/misc/xlnx-versal-pmc-iou-slcr.c
+++ b/hw/misc/xlnx-versal-pmc-iou-slcr.c
@@ -1350,7 +1350,7 @@ static void xlnx_versal_pmc_iou_slcr_reset_init(Object *obj, ResetType type)
     }
 }
 
-static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj)
+static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj, ResetType type)
 {
     XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
 
diff --git a/hw/misc/xlnx-versal-trng.c b/hw/misc/xlnx-versal-trng.c
index 6495188dc74..51eb7600414 100644
--- a/hw/misc/xlnx-versal-trng.c
+++ b/hw/misc/xlnx-versal-trng.c
@@ -632,7 +632,7 @@ static void trng_unrealize(DeviceState *dev)
     s->prng = NULL;
 }
 
-static void trng_reset_hold(Object *obj)
+static void trng_reset_hold(Object *obj, ResetType type)
 {
     trng_reset(XLNX_VERSAL_TRNG(obj));
 }
diff --git a/hw/misc/xlnx-versal-xramc.c b/hw/misc/xlnx-versal-xramc.c
index a5f78c190eb..ad839ce7e9f 100644
--- a/hw/misc/xlnx-versal-xramc.c
+++ b/hw/misc/xlnx-versal-xramc.c
@@ -137,7 +137,7 @@ static void xram_ctrl_reset_enter(Object *obj, ResetType type)
     ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size);
 }
 
-static void xram_ctrl_reset_hold(Object *obj)
+static void xram_ctrl_reset_hold(Object *obj, ResetType type)
 {
     XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj);
 
diff --git a/hw/misc/xlnx-zynqmp-apu-ctrl.c b/hw/misc/xlnx-zynqmp-apu-ctrl.c
index 1d441b41dfe..87e4a140679 100644
--- a/hw/misc/xlnx-zynqmp-apu-ctrl.c
+++ b/hw/misc/xlnx-zynqmp-apu-ctrl.c
@@ -150,7 +150,7 @@ static void zynqmp_apu_reset_enter(Object *obj, ResetType type)
     s->cpu_in_wfi = 0;
 }
 
-static void zynqmp_apu_reset_hold(Object *obj)
+static void zynqmp_apu_reset_hold(Object *obj, ResetType type)
 {
     XlnxZynqMPAPUCtrl *s = XLNX_ZYNQMP_APU_CTRL(obj);
 
diff --git a/hw/misc/xlnx-zynqmp-crf.c b/hw/misc/xlnx-zynqmp-crf.c
index a83efb44e31..e5aba56f691 100644
--- a/hw/misc/xlnx-zynqmp-crf.c
+++ b/hw/misc/xlnx-zynqmp-crf.c
@@ -191,7 +191,7 @@ static void crf_reset_enter(Object *obj, ResetType type)
     }
 }
 
-static void crf_reset_hold(Object *obj)
+static void crf_reset_hold(Object *obj, ResetType type)
 {
     XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
     ir_update_irq(s);
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
index d2ac2e77f26..3412ff099ea 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -416,7 +416,7 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type)
     s->regs[R_DDRIOB + 12] = 0x00000021;
 }
 
-static void zynq_slcr_reset_hold(Object *obj)
+static void zynq_slcr_reset_hold(Object *obj, ResetType type)
 {
     ZynqSLCRState *s = ZYNQ_SLCR(obj);
 
@@ -425,7 +425,7 @@ static void zynq_slcr_reset_hold(Object *obj)
     zynq_slcr_propagate_clocks(s);
 }
 
-static void zynq_slcr_reset_exit(Object *obj)
+static void zynq_slcr_reset_exit(Object *obj, ResetType type)
 {
     ZynqSLCRState *s = ZYNQ_SLCR(obj);
 
diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c
index ca0ce4e8bbf..58f1432bb35 100644
--- a/hw/net/can/xlnx-zynqmp-can.c
+++ b/hw/net/can/xlnx-zynqmp-can.c
@@ -1006,7 +1006,7 @@ static void xlnx_zynqmp_can_reset_init(Object *obj, ResetType type)
     ptimer_transaction_commit(s->can_timer);
 }
 
-static void xlnx_zynqmp_can_reset_hold(Object *obj)
+static void xlnx_zynqmp_can_reset_hold(Object *obj, ResetType type)
 {
     XlnxZynqMPCANState *s = XLNX_ZYNQMP_CAN(obj);
     unsigned int i;
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 43f3a4a7011..5012b964640 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -373,7 +373,7 @@ static bool e1000_vet_init_need(void *opaque)
     return chkflag(VET);
 }
 
-static void e1000_reset_hold(Object *obj)
+static void e1000_reset_hold(Object *obj, ResetType type)
 {
     E1000State *d = E1000(obj);
     E1000BaseClass *edc = E1000_GET_CLASS(d);
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index 7c6f6029518..edc101eaf68 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -513,7 +513,7 @@ static void e1000e_pci_uninit(PCIDevice *pci_dev)
     msi_uninit(pci_dev);
 }
 
-static void e1000e_qdev_reset_hold(Object *obj)
+static void e1000e_qdev_reset_hold(Object *obj, ResetType type)
 {
     E1000EState *s = E1000E(obj);
 
diff --git a/hw/net/igb.c b/hw/net/igb.c
index 9b37523d6df..1ef6170465f 100644
--- a/hw/net/igb.c
+++ b/hw/net/igb.c
@@ -486,7 +486,7 @@ static void igb_pci_uninit(PCIDevice *pci_dev)
     msi_uninit(pci_dev);
 }
 
-static void igb_qdev_reset_hold(Object *obj)
+static void igb_qdev_reset_hold(Object *obj, ResetType type)
 {
     IGBState *s = IGB(obj);
 
diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c
index 94a4e885f20..21a97d4d61d 100644
--- a/hw/net/igbvf.c
+++ b/hw/net/igbvf.c
@@ -282,7 +282,7 @@ static void igbvf_pci_realize(PCIDevice *dev, Error **errp)
     pcie_ari_init(dev, 0x150);
 }
 
-static void igbvf_qdev_reset_hold(Object *obj)
+static void igbvf_qdev_reset_hold(Object *obj, ResetType type)
 {
     PCIDevice *vf = PCI_DEVICE(obj);
 
diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c
index 0a71a005c69..09575a77d77 100644
--- a/hw/nvram/xlnx-bbram.c
+++ b/hw/nvram/xlnx-bbram.c
@@ -417,7 +417,7 @@ static RegisterAccessInfo bbram_ctrl_regs_info[] = {
     }
 };
 
-static void bbram_ctrl_reset_hold(Object *obj)
+static void bbram_ctrl_reset_hold(Object *obj, ResetType type)
 {
     XlnxBBRam *s = XLNX_BBRAM(obj);
     unsigned int i;
diff --git a/hw/nvram/xlnx-versal-efuse-ctrl.c b/hw/nvram/xlnx-versal-efuse-ctrl.c
index e4b9e11a3dd..def6fe3302b 100644
--- a/hw/nvram/xlnx-versal-efuse-ctrl.c
+++ b/hw/nvram/xlnx-versal-efuse-ctrl.c
@@ -658,7 +658,7 @@ static void efuse_ctrl_register_reset(RegisterInfo *reg)
     register_reset(reg);
 }
 
-static void efuse_ctrl_reset_hold(Object *obj)
+static void efuse_ctrl_reset_hold(Object *obj, ResetType type)
 {
     XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj);
     unsigned int i;
diff --git a/hw/nvram/xlnx-zynqmp-efuse.c b/hw/nvram/xlnx-zynqmp-efuse.c
index ec98456e5d1..2d465f0fc6a 100644
--- a/hw/nvram/xlnx-zynqmp-efuse.c
+++ b/hw/nvram/xlnx-zynqmp-efuse.c
@@ -770,7 +770,7 @@ static void zynqmp_efuse_register_reset(RegisterInfo *reg)
     register_reset(reg);
 }
 
-static void zynqmp_efuse_reset_hold(Object *obj)
+static void zynqmp_efuse_reset_hold(Object *obj, ResetType type)
 {
     XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj);
     unsigned int i;
diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index 8a30da602cc..2dd10239bd2 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -186,13 +186,13 @@ static void cxl_rp_realize(DeviceState *dev, Error **errp)
                      component_bar);
 }
 
-static void cxl_rp_reset_hold(Object *obj)
+static void cxl_rp_reset_hold(Object *obj, ResetType type)
 {
     PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj);
     CXLRootPort *crp = CXL_ROOT_PORT(obj);
 
     if (rpc->parent_phases.hold) {
-        rpc->parent_phases.hold(obj);
+        rpc->parent_phases.hold(obj, type);
     }
 
     latch_registers(crp);
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index efd96bf1741..09a34786bc6 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -43,7 +43,7 @@ static void rp_write_config(PCIDevice *d, uint32_t address,
     pcie_aer_root_write_config(d, address, val, len, root_cmd);
 }
 
-static void rp_reset_hold(Object *obj)
+static void rp_reset_hold(Object *obj, ResetType type)
 {
     PCIDevice *d = PCI_DEVICE(obj);
     DeviceState *qdev = DEVICE(obj);
diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c
index 1f0c4353484..1516d0074dd 100644
--- a/hw/pci-host/bonito.c
+++ b/hw/pci-host/bonito.c
@@ -590,7 +590,7 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num)
     }
 }
 
-static void bonito_reset_hold(Object *obj)
+static void bonito_reset_hold(Object *obj, ResetType type)
 {
     PCIBonitoState *s = PCI_BONITO(obj);
     uint32_t val = 0;
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index 157c00782ce..d4c118d4436 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -208,7 +208,7 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
     dc->user_creatable = true;
 }
 
-static void pnv_phb_root_port_reset_hold(Object *obj)
+static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
 {
     PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj);
     PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(obj);
@@ -216,7 +216,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj)
     uint8_t *conf = d->config;
 
     if (rpc->parent_phases.hold) {
-        rpc->parent_phases.hold(obj);
+        rpc->parent_phases.hold(obj, type);
     }
 
     if (phb_rp->version == 3) {
diff --git a/hw/pci-host/pnv_phb3_msi.c b/hw/pci-host/pnv_phb3_msi.c
index dc8d8637f26..a6d827f903f 100644
--- a/hw/pci-host/pnv_phb3_msi.c
+++ b/hw/pci-host/pnv_phb3_msi.c
@@ -228,13 +228,13 @@ static void phb3_msi_resend(ICSState *ics)
     }
 }
 
-static void phb3_msi_reset_hold(Object *obj)
+static void phb3_msi_reset_hold(Object *obj, ResetType type)
 {
     Phb3MsiState *msi = PHB3_MSI(obj);
     ICSStateClass *icsc = ICS_GET_CLASS(obj);
 
     if (icsc->parent_phases.hold) {
-        icsc->parent_phases.hold(obj);
+        icsc->parent_phases.hold(obj, type);
     }
 
     memset(msi->rba, 0, sizeof(msi->rba));
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e7a39cb203a..324c1302d25 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -64,7 +64,7 @@ bool pci_available = true;
 
 static char *pcibus_get_dev_path(DeviceState *dev);
 static char *pcibus_get_fw_dev_path(DeviceState *dev);
-static void pcibus_reset_hold(Object *obj);
+static void pcibus_reset_hold(Object *obj, ResetType type);
 static bool pcie_has_upstream_port(PCIDevice *dev);
 
 static Property pci_props[] = {
@@ -427,7 +427,7 @@ void pci_device_reset(PCIDevice *dev)
  * Called via bus_cold_reset on RST# assert, after the devices
  * have been reset device_cold_reset-ed already.
  */
-static void pcibus_reset_hold(Object *obj)
+static void pcibus_reset_hold(Object *obj, ResetType type)
 {
     PCIBus *bus = PCI_BUS(obj);
     int i;
diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index f4c18692325..3379f92748b 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -998,7 +998,7 @@ static void rtc_reset_enter(Object *obj, ResetType type)
     }
 }
 
-static void rtc_reset_hold(Object *obj)
+static void rtc_reset_hold(Object *obj, ResetType type)
 {
     MC146818RtcState *s = MC146818_RTC(obj);
 
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 34639f21435..8657ff7bf48 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev,
     qdev_unrealize(dev);
 }
 
-static void virtual_css_bus_reset_hold(Object *obj)
+static void virtual_css_bus_reset_hold(Object *obj, ResetType type)
 {
     /* This should actually be modelled via the generic css */
     css_reset();
diff --git a/hw/sensor/adm1266.c b/hw/sensor/adm1266.c
index 5454b73a639..25b87a72961 100644
--- a/hw/sensor/adm1266.c
+++ b/hw/sensor/adm1266.c
@@ -76,7 +76,7 @@ static const uint8_t adm1266_ic_device_id[] = {0x03, 0x41, 0x12, 0x66};
 static const uint8_t adm1266_ic_device_rev[] = {0x08, 0x01, 0x08, 0x07, 0x0,
                                                 0x0, 0x07, 0x41, 0x30};
 
-static void adm1266_exit_reset(Object *obj)
+static void adm1266_exit_reset(Object *obj, ResetType type)
 {
     ADM1266State *s = ADM1266(obj);
     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
diff --git a/hw/sensor/adm1272.c b/hw/sensor/adm1272.c
index a19557ec9ea..3fc1e5d0ad9 100644
--- a/hw/sensor/adm1272.c
+++ b/hw/sensor/adm1272.c
@@ -185,7 +185,7 @@ static uint32_t adm1272_direct_to_watts(uint16_t value)
     return pmbus_direct_mode2data(c, value);
 }
 
-static void adm1272_exit_reset(Object *obj)
+static void adm1272_exit_reset(Object *obj, ResetType type)
 {
     ADM1272State *s = ADM1272(obj);
     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
diff --git a/hw/sensor/isl_pmbus_vr.c b/hw/sensor/isl_pmbus_vr.c
index e51269f6b83..304a66ea8b0 100644
--- a/hw/sensor/isl_pmbus_vr.c
+++ b/hw/sensor/isl_pmbus_vr.c
@@ -63,7 +63,7 @@ static void isl_pmbus_vr_set(Object *obj, Visitor *v, const char *name,
     pmbus_check_limits(pmdev);
 }
 
-static void isl_pmbus_vr_exit_reset(Object *obj)
+static void isl_pmbus_vr_exit_reset(Object *obj, ResetType type)
 {
     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
 
@@ -102,11 +102,11 @@ static void isl_pmbus_vr_exit_reset(Object *obj)
 }
 
 /* The raa228000 uses different direct mode coefficients from most isl devices */
-static void raa228000_exit_reset(Object *obj)
+static void raa228000_exit_reset(Object *obj, ResetType type)
 {
     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
 
-    isl_pmbus_vr_exit_reset(obj);
+    isl_pmbus_vr_exit_reset(obj, type);
 
     pmdev->pages[0].read_iout = 0;
     pmdev->pages[0].read_pout = 0;
@@ -119,13 +119,13 @@ static void raa228000_exit_reset(Object *obj)
     pmdev->pages[0].read_temperature_3 = 0;
 }
 
-static void isl69259_exit_reset(Object *obj)
+static void isl69259_exit_reset(Object *obj, ResetType type)
 {
     ISLState *s = ISL69260(obj);
     static const uint8_t ic_device_id[] = {0x04, 0x00, 0x81, 0xD2, 0x49, 0x3c};
     g_assert(sizeof(ic_device_id) <= sizeof(s->ic_device_id));
 
-    isl_pmbus_vr_exit_reset(obj);
+    isl_pmbus_vr_exit_reset(obj, type);
 
     s->ic_device_id_len = sizeof(ic_device_id);
     memcpy(s->ic_device_id, ic_device_id, sizeof(ic_device_id));
diff --git a/hw/sensor/max31785.c b/hw/sensor/max31785.c
index 916ed4d457b..3577a7c2180 100644
--- a/hw/sensor/max31785.c
+++ b/hw/sensor/max31785.c
@@ -444,7 +444,7 @@ static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf,
     return 0;
 }
 
-static void max31785_exit_reset(Object *obj)
+static void max31785_exit_reset(Object *obj, ResetType type)
 {
     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
     MAX31785State *s = MAX31785(obj);
diff --git a/hw/sensor/max34451.c b/hw/sensor/max34451.c
index 031ae53f594..93b53f3db2f 100644
--- a/hw/sensor/max34451.c
+++ b/hw/sensor/max34451.c
@@ -608,7 +608,7 @@ static inline void *memset_word(void *s, uint16_t c, size_t n)
     return s;
 }
 
-static void max34451_exit_reset(Object *obj)
+static void max34451_exit_reset(Object *obj, ResetType type)
 {
     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
     MAX34451State *s = MAX34451(obj);
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
index 81dd972ee8c..119c38c4156 100644
--- a/hw/ssi/npcm7xx_fiu.c
+++ b/hw/ssi/npcm7xx_fiu.c
@@ -483,7 +483,7 @@ static void npcm7xx_fiu_enter_reset(Object *obj, ResetType type)
     s->regs[NPCM7XX_FIU_CFG] = 0x0000000b;
 }
 
-static void npcm7xx_fiu_hold_reset(Object *obj)
+static void npcm7xx_fiu_hold_reset(Object *obj, ResetType type)
 {
     NPCM7xxFIUState *s = NPCM7XX_FIU(obj);
     int i;
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
index da7c946af52..dd6d96b0a10 100644
--- a/hw/timer/etraxfs_timer.c
+++ b/hw/timer/etraxfs_timer.c
@@ -357,7 +357,7 @@ static void etraxfs_timer_reset_enter(Object *obj, ResetType type)
     t->rw_intr_mask = 0;
 }
 
-static void etraxfs_timer_reset_hold(Object *obj)
+static void etraxfs_timer_reset_hold(Object *obj, ResetType type)
 {
     ETRAXTimerState *t = ETRAX_TIMER(obj);
 
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
index 779c6049fab..c55ba022353 100644
--- a/hw/timer/npcm7xx_timer.c
+++ b/hw/timer/npcm7xx_timer.c
@@ -592,7 +592,7 @@ static void npcm7xx_watchdog_timer_expired(void *opaque)
     }
 }
 
-static void npcm7xx_timer_hold_reset(Object *obj)
+static void npcm7xx_timer_hold_reset(Object *obj, ResetType type)
 {
     NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
     int i;
diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c
index 222eef82a55..8cac9c0a062 100644
--- a/hw/usb/hcd-dwc2.c
+++ b/hw/usb/hcd-dwc2.c
@@ -1305,7 +1305,7 @@ static void dwc2_reset_enter(Object *obj, ResetType type)
     }
 }
 
-static void dwc2_reset_hold(Object *obj)
+static void dwc2_reset_hold(Object *obj, ResetType type)
 {
     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
     DWC2State *s = DWC2_USB(obj);
@@ -1313,13 +1313,13 @@ static void dwc2_reset_hold(Object *obj)
     trace_usb_dwc2_reset_hold();
 
     if (c->parent_phases.hold) {
-        c->parent_phases.hold(obj);
+        c->parent_phases.hold(obj, type);
     }
 
     dwc2_update_irq(s);
 }
 
-static void dwc2_reset_exit(Object *obj)
+static void dwc2_reset_exit(Object *obj, ResetType type)
 {
     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
     DWC2State *s = DWC2_USB(obj);
@@ -1327,7 +1327,7 @@ static void dwc2_reset_exit(Object *obj)
     trace_usb_dwc2_reset_exit();
 
     if (c->parent_phases.exit) {
-        c->parent_phases.exit(obj);
+        c->parent_phases.exit(obj, type);
     }
 
     s->hprt0 = HPRT0_PWR;
diff --git a/hw/usb/xlnx-versal-usb2-ctrl-regs.c b/hw/usb/xlnx-versal-usb2-ctrl-regs.c
index 6fc453817ea..66c793a6021 100644
--- a/hw/usb/xlnx-versal-usb2-ctrl-regs.c
+++ b/hw/usb/xlnx-versal-usb2-ctrl-regs.c
@@ -153,7 +153,7 @@ static void usb2_ctrl_regs_reset_init(Object *obj, ResetType type)
     }
 }
 
-static void usb2_ctrl_regs_reset_hold(Object *obj)
+static void usb2_ctrl_regs_reset_hold(Object *obj, ResetType type)
 {
     VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj);
 
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index cb159fd0785..b1d02f4b3de 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -2292,7 +2292,7 @@ static void virtio_pci_reset(DeviceState *qdev)
     }
 }
 
-static void virtio_pci_bus_reset_hold(Object *obj)
+static void virtio_pci_bus_reset_hold(Object *obj, ResetType type)
 {
     PCIDevice *dev = PCI_DEVICE(obj);
     DeviceState *qdev = DEVICE(obj);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d2dfd36fd45..a152def2413 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -220,7 +220,7 @@ static void cp_reg_check_reset(gpointer key, gpointer value,  gpointer opaque)
     assert(oldvalue == newvalue);
 }
 
-static void arm_cpu_reset_hold(Object *obj)
+static void arm_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     ARMCPU *cpu = ARM_CPU(cs);
@@ -228,7 +228,7 @@ static void arm_cpu_reset_hold(Object *obj)
     CPUARMState *env = &cpu->env;
 
     if (acc->parent_phases.hold) {
-        acc->parent_phases.hold(obj);
+        acc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPUARMState, end_reset_fields));
diff --git a/target/avr/cpu.c b/target/avr/cpu.c
index 45ee1b5f89e..71ce62a4c25 100644
--- a/target/avr/cpu.c
+++ b/target/avr/cpu.c
@@ -66,7 +66,7 @@ static void avr_restore_state_to_opc(CPUState *cs,
     cpu_env(cs)->pc_w = data[0];
 }
 
-static void avr_cpu_reset_hold(Object *obj)
+static void avr_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     AVRCPU *cpu = AVR_CPU(cs);
@@ -74,7 +74,7 @@ static void avr_cpu_reset_hold(Object *obj)
     CPUAVRState *env = &cpu->env;
 
     if (mcc->parent_phases.hold) {
-        mcc->parent_phases.hold(obj);
+        mcc->parent_phases.hold(obj, type);
     }
 
     env->pc_w = 0;
diff --git a/target/cris/cpu.c b/target/cris/cpu.c
index eb4bddcb7e7..535ec39c730 100644
--- a/target/cris/cpu.c
+++ b/target/cris/cpu.c
@@ -61,7 +61,7 @@ static int cris_cpu_mmu_index(CPUState *cs, bool ifetch)
     return !!(cpu_env(cs)->pregs[PR_CCS] & U_FLAG);
 }
 
-static void cris_cpu_reset_hold(Object *obj)
+static void cris_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj);
@@ -69,7 +69,7 @@ static void cris_cpu_reset_hold(Object *obj)
     uint32_t vr;
 
     if (ccc->parent_phases.hold) {
-        ccc->parent_phases.hold(obj);
+        ccc->parent_phases.hold(obj, type);
     }
 
     vr = env->pregs[PR_VR];
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 3a716b9be3c..a56bb4b075c 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -273,14 +273,14 @@ static void hexagon_restore_state_to_opc(CPUState *cs,
     cpu_env(cs)->gpr[HEX_REG_PC] = data[0];
 }
 
-static void hexagon_cpu_reset_hold(Object *obj)
+static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(obj);
     CPUHexagonState *env = cpu_env(cs);
 
     if (mcc->parent_phases.hold) {
-        mcc->parent_phases.hold(obj);
+        mcc->parent_phases.hold(obj, type);
     }
 
     set_default_nan_mode(1, &env->fp_status);
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index fd6af0d7632..fa1ea3735d2 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6830,7 +6830,7 @@ static void x86_cpu_set_sgxlepubkeyhash(CPUX86State *env)
 #endif
 }
 
-static void x86_cpu_reset_hold(Object *obj)
+static void x86_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     X86CPU *cpu = X86_CPU(cs);
@@ -6841,7 +6841,7 @@ static void x86_cpu_reset_hold(Object *obj)
     int i;
 
     if (xcc->parent_phases.hold) {
-        xcc->parent_phases.hold(obj);
+        xcc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPUX86State, end_reset_fields));
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 203a349055c..bac84dca7af 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -495,14 +495,14 @@ static void loongarch_max_initfn(Object *obj)
     loongarch_la464_initfn(obj);
 }
 
-static void loongarch_cpu_reset_hold(Object *obj)
+static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(obj);
     CPULoongArchState *env = cpu_env(cs);
 
     if (lacc->parent_phases.hold) {
-        lacc->parent_phases.hold(obj);
+        lacc->parent_phases.hold(obj, type);
     }
 
     env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index df49ff1880c..efd6bbded86 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -71,7 +71,7 @@ static void m68k_unset_feature(CPUM68KState *env, int feature)
     env->features &= ~BIT_ULL(feature);
 }
 
-static void m68k_cpu_reset_hold(Object *obj)
+static void m68k_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     M68kCPUClass *mcc = M68K_CPU_GET_CLASS(obj);
@@ -80,7 +80,7 @@ static void m68k_cpu_reset_hold(Object *obj)
     int i;
 
     if (mcc->parent_phases.hold) {
-        mcc->parent_phases.hold(obj);
+        mcc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPUM68KState, end_reset_fields));
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 96c2b71f7f7..f8dc3173fc0 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -181,7 +181,7 @@ static void microblaze_cpu_set_irq(void *opaque, int irq, int level)
 }
 #endif
 
-static void mb_cpu_reset_hold(Object *obj)
+static void mb_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
@@ -189,7 +189,7 @@ static void mb_cpu_reset_hold(Object *obj)
     CPUMBState *env = &cpu->env;
 
     if (mcc->parent_phases.hold) {
-        mcc->parent_phases.hold(obj);
+        mcc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPUMBState, end_reset_fields));
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 8d8f690a535..bbe01d07dd8 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -185,7 +185,7 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc)
 
 #include "cpu-defs.c.inc"
 
-static void mips_cpu_reset_hold(Object *obj)
+static void mips_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     MIPSCPU *cpu = MIPS_CPU(cs);
@@ -193,7 +193,7 @@ static void mips_cpu_reset_hold(Object *obj)
     CPUMIPSState *env = &cpu->env;
 
     if (mcc->parent_phases.hold) {
-        mcc->parent_phases.hold(obj);
+        mcc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPUMIPSState, end_reset_fields));
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index 33c45dbf04e..d711035cf59 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -85,14 +85,14 @@ static void openrisc_disas_set_info(CPUState *cpu, disassemble_info *info)
     info->print_insn = print_insn_or1k;
 }
 
-static void openrisc_cpu_reset_hold(Object *obj)
+static void openrisc_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
     OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(obj);
 
     if (occ->parent_phases.hold) {
-        occ->parent_phases.hold(obj);
+        occ->parent_phases.hold(obj, type);
     }
 
     memset(&cpu->env, 0, offsetof(CPUOpenRISCState, end_reset_fields));
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 6241de62ce8..6d82f24c875 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7136,7 +7136,7 @@ static int ppc_cpu_mmu_index(CPUState *cs, bool ifetch)
     return ppc_env_mmu_index(cpu_env(cs), ifetch);
 }
 
-static void ppc_cpu_reset_hold(Object *obj)
+static void ppc_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -7146,7 +7146,7 @@ static void ppc_cpu_reset_hold(Object *obj)
     int i;
 
     if (pcc->parent_phases.hold) {
-        pcc->parent_phases.hold(obj);
+        pcc->parent_phases.hold(obj, type);
     }
 
     msr = (target_ulong)0;
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 36e3e5fdaf5..eb1a2e7d6d9 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -918,7 +918,7 @@ static int riscv_cpu_mmu_index(CPUState *cs, bool ifetch)
     return riscv_env_mmu_index(cpu_env(cs), ifetch);
 }
 
-static void riscv_cpu_reset_hold(Object *obj)
+static void riscv_cpu_reset_hold(Object *obj, ResetType type)
 {
 #ifndef CONFIG_USER_ONLY
     uint8_t iprio;
@@ -930,7 +930,7 @@ static void riscv_cpu_reset_hold(Object *obj)
     CPURISCVState *env = &cpu->env;
 
     if (mcc->parent_phases.hold) {
-        mcc->parent_phases.hold(obj);
+        mcc->parent_phases.hold(obj, type);
     }
 #ifndef CONFIG_USER_ONLY
     env->misa_mxl = mcc->misa_mxl_max;
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
index da673a595d4..e3dfb097225 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -69,7 +69,7 @@ static int riscv_cpu_mmu_index(CPUState *cs, bool ifunc)
     return 0;
 }
 
-static void rx_cpu_reset_hold(Object *obj)
+static void rx_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     RXCPUClass *rcc = RX_CPU_GET_CLASS(obj);
@@ -77,7 +77,7 @@ static void rx_cpu_reset_hold(Object *obj)
     uint32_t *resetvec;
 
     if (rcc->parent_phases.hold) {
-        rcc->parent_phases.hold(obj);
+        rcc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPURXState, end_reset_fields));
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index 4f5a4a3d985..43e35ec2ca7 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -103,14 +103,14 @@ static int sh4_cpu_mmu_index(CPUState *cs, bool ifetch)
     }
 }
 
-static void superh_cpu_reset_hold(Object *obj)
+static void superh_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(obj);
     CPUSH4State *env = cpu_env(cs);
 
     if (scc->parent_phases.hold) {
-        scc->parent_phases.hold(obj);
+        scc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPUSH4State, end_reset_fields));
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index e820f50acf6..485d416925b 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -29,14 +29,14 @@
 
 //#define DEBUG_FEATURES
 
-static void sparc_cpu_reset_hold(Object *obj)
+static void sparc_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(obj);
     CPUSPARCState *env = cpu_env(cs);
 
     if (scc->parent_phases.hold) {
-        scc->parent_phases.hold(obj);
+        scc->parent_phases.hold(obj, type);
     }
 
     memset(env, 0, offsetof(CPUSPARCState, end_reset_fields));
diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c
index a9af73aeb58..8f9b72c3a04 100644
--- a/target/tricore/cpu.c
+++ b/target/tricore/cpu.c
@@ -58,13 +58,13 @@ static void tricore_restore_state_to_opc(CPUState *cs,
     cpu_env(cs)->PC = data[0];
 }
 
-static void tricore_cpu_reset_hold(Object *obj)
+static void tricore_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     TriCoreCPUClass *tcc = TRICORE_CPU_GET_CLASS(obj);
 
     if (tcc->parent_phases.hold) {
-        tcc->parent_phases.hold(obj);
+        tcc->parent_phases.hold(obj, type);
     }
 
     cpu_state_reset(cpu_env(cs));
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index 875cf843c93..de907cfeb1b 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -93,7 +93,7 @@ bool xtensa_abi_call0(void)
 }
 #endif
 
-static void xtensa_cpu_reset_hold(Object *obj)
+static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
     XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj);
@@ -102,7 +102,7 @@ static void xtensa_cpu_reset_hold(Object *obj)
                                       XTENSA_OPTION_DFP_COPROCESSOR);
 
     if (xcc->parent_phases.hold) {
-        xcc->parent_phases.hold(obj);
+        xcc->parent_phases.hold(obj, type);
     }
 
     env->pc = env->config->exception_vector[EXC_RESET0 + env->static_vectors];
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 31/37] docs/devel/reset: Update to new API for hold and exit phase methods
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (29 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 30/37] hw, target: Add ResetType argument to hold and exit phase methods Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 32/37] reset: Add RESET_TYPE_SNAPSHOT_LOAD Peter Maydell
                   ` (6 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

Update the reset documentation's example code to match the new API
for the hold and exit phase method APIs where they take a ResetType
argument.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Luc Michel <luc.michel@amd.com>
Message-id: 20240412160809.1260625-6-peter.maydell@linaro.org
---
 docs/devel/reset.rst | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst
index 2ea85e7779b..49baa1ea271 100644
--- a/docs/devel/reset.rst
+++ b/docs/devel/reset.rst
@@ -150,25 +150,25 @@ in reset.
         mydev->var = 0;
     }
 
-    static void mydev_reset_hold(Object *obj)
+    static void mydev_reset_hold(Object *obj, ResetType type)
     {
         MyDevClass *myclass = MYDEV_GET_CLASS(obj);
         MyDevState *mydev = MYDEV(obj);
         /* call parent class hold phase */
         if (myclass->parent_phases.hold) {
-            myclass->parent_phases.hold(obj);
+            myclass->parent_phases.hold(obj, type);
         }
         /* set an IO */
         qemu_set_irq(mydev->irq, 1);
     }
 
-    static void mydev_reset_exit(Object *obj)
+    static void mydev_reset_exit(Object *obj, ResetType type)
     {
         MyDevClass *myclass = MYDEV_GET_CLASS(obj);
         MyDevState *mydev = MYDEV(obj);
         /* call parent class exit phase */
         if (myclass->parent_phases.exit) {
-            myclass->parent_phases.exit(obj);
+            myclass->parent_phases.exit(obj, type);
         }
         /* clear an IO */
         qemu_set_irq(mydev->irq, 0);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 32/37] reset: Add RESET_TYPE_SNAPSHOT_LOAD
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (30 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 31/37] docs/devel/reset: Update to new API for " Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 33/37] hw/char: Implement STM32L4x5 USART skeleton Peter Maydell
                   ` (5 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

Some devices and machines need to handle the reset before a vmsave
snapshot is loaded differently -- the main user is the handling of
RNG seed information, which does not want to put a new RNG seed into
a ROM blob when we are doing a snapshot load.

Currently this kind of reset handling is supported only for:
 * TYPE_MACHINE reset methods, which take a ShutdownCause argument
 * reset functions registered with qemu_register_reset_nosnapshotload

To allow a three-phase-reset device to also distinguish "snapshot
load" reset from the normal kind, add a new ResetType
RESET_TYPE_SNAPSHOT_LOAD. All our existing reset methods ignore
the reset type, so we don't need to update any device code.

Add the enum type, and make qemu_devices_reset() use the
right reset type for the ShutdownCause it is passed. This
allows us to get rid of the device_reset_reason global we
were using to implement qemu_register_reset_nosnapshotload().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Luc Michel <luc.michel@amd.com>
Message-id: 20240412160809.1260625-7-peter.maydell@linaro.org
---
 docs/devel/reset.rst    | 17 ++++++++++++++---
 include/hw/resettable.h |  1 +
 hw/core/reset.c         | 15 ++++-----------
 hw/core/resettable.c    |  4 ----
 4 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst
index 49baa1ea271..9746a4e8a0b 100644
--- a/docs/devel/reset.rst
+++ b/docs/devel/reset.rst
@@ -27,9 +27,7 @@ instantly reset an object, without keeping it in reset state, just call
 ``resettable_reset()``. These functions take two parameters: a pointer to the
 object to reset and a reset type.
 
-Several types of reset will be supported. For now only cold reset is defined;
-others may be added later. The Resettable interface handles reset types with an
-enum:
+The Resettable interface handles reset types with an enum ``ResetType``:
 
 ``RESET_TYPE_COLD``
   Cold reset is supported by every resettable object. In QEMU, it means we reset
@@ -37,6 +35,19 @@ enum:
   from what is a real hardware cold reset. It differs from other resets (like
   warm or bus resets) which may keep certain parts untouched.
 
+``RESET_TYPE_SNAPSHOT_LOAD``
+  This is called for a reset which is being done to put the system into a
+  clean state prior to loading a snapshot. (This corresponds to a reset
+  with ``SHUTDOWN_CAUSE_SNAPSHOT_LOAD``.) Almost all devices should treat
+  this the same as ``RESET_TYPE_COLD``. The main exception is devices which
+  have some non-deterministic state they want to reinitialize to a different
+  value on each cold reset, such as RNG seed information, and which they
+  must not reinitialize on a snapshot-load reset.
+
+Devices which implement reset methods must treat any unknown ``ResetType``
+as equivalent to ``RESET_TYPE_COLD``; this will reduce the amount of
+existing code we need to change if we add more types in future.
+
 Calling ``resettable_reset()`` is equivalent to calling
 ``resettable_assert_reset()`` then ``resettable_release_reset()``. It is
 possible to interleave multiple calls to these three functions. There may
diff --git a/include/hw/resettable.h b/include/hw/resettable.h
index 3161e471c9b..7e249deb8b5 100644
--- a/include/hw/resettable.h
+++ b/include/hw/resettable.h
@@ -35,6 +35,7 @@ typedef struct ResettableState ResettableState;
  */
 typedef enum ResetType {
     RESET_TYPE_COLD,
+    RESET_TYPE_SNAPSHOT_LOAD,
 } ResetType;
 
 /*
diff --git a/hw/core/reset.c b/hw/core/reset.c
index f9fef45e050..58dfc8db3dc 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -43,13 +43,6 @@ static ResettableContainer *get_root_reset_container(void)
     return root_reset_container;
 }
 
-/*
- * Reason why the currently in-progress qemu_devices_reset() was called.
- * If we made at least SHUTDOWN_CAUSE_SNAPSHOT_LOAD have a corresponding
- * ResetType we could perhaps avoid the need for this global.
- */
-static ShutdownCause device_reset_reason;
-
 /*
  * This is an Object which implements Resettable simply to call the
  * callback function in the hold phase.
@@ -77,8 +70,7 @@ static void legacy_reset_hold(Object *obj, ResetType type)
 {
     LegacyReset *lr = LEGACY_RESET(obj);
 
-    if (device_reset_reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD &&
-        lr->skip_on_snapshot_load) {
+    if (type == RESET_TYPE_SNAPSHOT_LOAD && lr->skip_on_snapshot_load) {
         return;
     }
     lr->func(lr->opaque);
@@ -180,8 +172,9 @@ void qemu_unregister_resettable(Object *obj)
 
 void qemu_devices_reset(ShutdownCause reason)
 {
-    device_reset_reason = reason;
+    ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ?
+        RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD;
 
     /* Reset the simulation */
-    resettable_reset(OBJECT(get_root_reset_container()), RESET_TYPE_COLD);
+    resettable_reset(OBJECT(get_root_reset_container()), type);
 }
diff --git a/hw/core/resettable.c b/hw/core/resettable.c
index bebf7f10b26..6dd3e3dc487 100644
--- a/hw/core/resettable.c
+++ b/hw/core/resettable.c
@@ -48,8 +48,6 @@ void resettable_reset(Object *obj, ResetType type)
 
 void resettable_assert_reset(Object *obj, ResetType type)
 {
-    /* TODO: change this assert when adding support for other reset types */
-    assert(type == RESET_TYPE_COLD);
     trace_resettable_reset_assert_begin(obj, type);
     assert(!enter_phase_in_progress);
 
@@ -64,8 +62,6 @@ void resettable_assert_reset(Object *obj, ResetType type)
 
 void resettable_release_reset(Object *obj, ResetType type)
 {
-    /* TODO: change this assert when adding support for other reset types */
-    assert(type == RESET_TYPE_COLD);
     trace_resettable_reset_release_begin(obj, type);
     assert(!enter_phase_in_progress);
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 33/37] hw/char: Implement STM32L4x5 USART skeleton
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (31 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 32/37] reset: Add RESET_TYPE_SNAPSHOT_LOAD Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 34/37] hw/char/stm32l4x5_usart: Enable serial read and write Peter Maydell
                   ` (4 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Arnaud Minier <arnaud.minier@telecom-paris.fr>

Add the basic infrastructure (register read/write, type...)
to implement the STM32L4x5 USART.

Also create different types for the USART, UART and LPUART
of the STM32L4x5 to deduplicate code and enable the
implementation of different behaviors depending on the type.

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240329174402.60382-2-arnaud.minier@telecom-paris.fr
[PMM: update to new reset hold method signature;
 fixed a few checkpatch nits]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 MAINTAINERS                       |   1 +
 include/hw/char/stm32l4x5_usart.h |  66 +++++
 hw/char/stm32l4x5_usart.c         | 396 ++++++++++++++++++++++++++++++
 hw/char/Kconfig                   |   3 +
 hw/char/meson.build               |   1 +
 hw/char/trace-events              |   4 +
 6 files changed, 471 insertions(+)
 create mode 100644 include/hw/char/stm32l4x5_usart.h
 create mode 100644 hw/char/stm32l4x5_usart.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 8bb32f4a7e9..d5a51812422 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1115,6 +1115,7 @@ M: Inès Varhol <ines.varhol@telecom-paris.fr>
 L: qemu-arm@nongnu.org
 S: Maintained
 F: hw/arm/stm32l4x5_soc.c
+F: hw/char/stm32l4x5_usart.c
 F: hw/misc/stm32l4x5_exti.c
 F: hw/misc/stm32l4x5_syscfg.c
 F: hw/misc/stm32l4x5_rcc.c
diff --git a/include/hw/char/stm32l4x5_usart.h b/include/hw/char/stm32l4x5_usart.h
new file mode 100644
index 00000000000..8d38a85a6e6
--- /dev/null
+++ b/include/hw/char/stm32l4x5_usart.h
@@ -0,0 +1,66 @@
+/*
+ * STM32L4X5 USART (Universal Synchronous Asynchronous Receiver Transmitter)
+ *
+ * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * The STM32L4X5 USART is heavily inspired by the stm32f2xx_usart
+ * by Alistair Francis.
+ * The reference used is the STMicroElectronics RM0351 Reference manual
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
+ */
+
+#ifndef HW_STM32L4X5_USART_H
+#define HW_STM32L4X5_USART_H
+
+#include "hw/sysbus.h"
+#include "chardev/char-fe.h"
+#include "qom/object.h"
+
+#define TYPE_STM32L4X5_USART_BASE "stm32l4x5-usart-base"
+#define TYPE_STM32L4X5_USART "stm32l4x5-usart"
+#define TYPE_STM32L4X5_UART "stm32l4x5-uart"
+#define TYPE_STM32L4X5_LPUART "stm32l4x5-lpuart"
+OBJECT_DECLARE_TYPE(Stm32l4x5UsartBaseState, Stm32l4x5UsartBaseClass,
+                    STM32L4X5_USART_BASE)
+
+typedef enum {
+    STM32L4x5_USART,
+    STM32L4x5_UART,
+    STM32L4x5_LPUART,
+} Stm32l4x5UsartType;
+
+struct Stm32l4x5UsartBaseState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion mmio;
+
+    uint32_t cr1;
+    uint32_t cr2;
+    uint32_t cr3;
+    uint32_t brr;
+    uint32_t gtpr;
+    uint32_t rtor;
+    /* rqr is write-only */
+    uint32_t isr;
+    /* icr is a clear register */
+    uint32_t rdr;
+    uint32_t tdr;
+
+    Clock *clk;
+    CharBackend chr;
+    qemu_irq irq;
+};
+
+struct Stm32l4x5UsartBaseClass {
+    SysBusDeviceClass parent_class;
+
+    Stm32l4x5UsartType type;
+};
+
+#endif /* HW_STM32L4X5_USART_H */
diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
new file mode 100644
index 00000000000..62957ec3e59
--- /dev/null
+++ b/hw/char/stm32l4x5_usart.c
@@ -0,0 +1,396 @@
+/*
+ * STM32L4X5 USART (Universal Synchronous Asynchronous Receiver Transmitter)
+ *
+ * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * The STM32L4X5 USART is heavily inspired by the stm32f2xx_usart
+ * by Alistair Francis.
+ * The reference used is the STMicroElectronics RM0351 Reference manual
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "chardev/char-fe.h"
+#include "chardev/char-serial.h"
+#include "migration/vmstate.h"
+#include "hw/char/stm32l4x5_usart.h"
+#include "hw/clock.h"
+#include "hw/irq.h"
+#include "hw/qdev-clock.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/registerfields.h"
+#include "trace.h"
+
+
+REG32(CR1, 0x00)
+    FIELD(CR1, M1, 28, 1)    /* Word length (part 2, see M0) */
+    FIELD(CR1, EOBIE, 27, 1) /* End of Block interrupt enable */
+    FIELD(CR1, RTOIE, 26, 1) /* Receiver timeout interrupt enable */
+    FIELD(CR1, DEAT, 21, 5)  /* Driver Enable assertion time */
+    FIELD(CR1, DEDT, 16, 5)  /* Driver Enable de-assertion time */
+    FIELD(CR1, OVER8, 15, 1) /* Oversampling mode */
+    FIELD(CR1, CMIE, 14, 1)  /* Character match interrupt enable */
+    FIELD(CR1, MME, 13, 1)   /* Mute mode enable */
+    FIELD(CR1, M0, 12, 1)    /* Word length (part 1, see M1) */
+    FIELD(CR1, WAKE, 11, 1)  /* Receiver wakeup method */
+    FIELD(CR1, PCE, 10, 1)   /* Parity control enable */
+    FIELD(CR1, PS, 9, 1)     /* Parity selection */
+    FIELD(CR1, PEIE, 8, 1)   /* PE interrupt enable */
+    FIELD(CR1, TXEIE, 7, 1)  /* TXE interrupt enable */
+    FIELD(CR1, TCIE, 6, 1)   /* Transmission complete interrupt enable */
+    FIELD(CR1, RXNEIE, 5, 1) /* RXNE interrupt enable */
+    FIELD(CR1, IDLEIE, 4, 1) /* IDLE interrupt enable */
+    FIELD(CR1, TE, 3, 1)     /* Transmitter enable */
+    FIELD(CR1, RE, 2, 1)     /* Receiver enable */
+    FIELD(CR1, UESM, 1, 1)   /* USART enable in Stop mode */
+    FIELD(CR1, UE, 0, 1)     /* USART enable */
+REG32(CR2, 0x04)
+    FIELD(CR2, ADD_1, 28, 4)    /* ADD[7:4] */
+    FIELD(CR2, ADD_0, 24, 1)    /* ADD[3:0] */
+    FIELD(CR2, RTOEN, 23, 1)    /* Receiver timeout enable */
+    FIELD(CR2, ABRMOD, 21, 2)   /* Auto baud rate mode */
+    FIELD(CR2, ABREN, 20, 1)    /* Auto baud rate enable */
+    FIELD(CR2, MSBFIRST, 19, 1) /* Most significant bit first */
+    FIELD(CR2, DATAINV, 18, 1)  /* Binary data inversion */
+    FIELD(CR2, TXINV, 17, 1)    /* TX pin active level inversion */
+    FIELD(CR2, RXINV, 16, 1)    /* RX pin active level inversion */
+    FIELD(CR2, SWAP, 15, 1)     /* Swap RX/TX pins */
+    FIELD(CR2, LINEN, 14, 1)    /* LIN mode enable */
+    FIELD(CR2, STOP, 12, 2)     /* STOP bits */
+    FIELD(CR2, CLKEN, 11, 1)    /* Clock enable */
+    FIELD(CR2, CPOL, 10, 1)     /* Clock polarity */
+    FIELD(CR2, CPHA, 9, 1)      /* Clock phase */
+    FIELD(CR2, LBCL, 8, 1)      /* Last bit clock pulse */
+    FIELD(CR2, LBDIE, 6, 1)     /* LIN break detection interrupt enable */
+    FIELD(CR2, LBDL, 5, 1)      /* LIN break detection length */
+    FIELD(CR2, ADDM7, 4, 1)     /* 7-bit / 4-bit Address Detection */
+
+REG32(CR3, 0x08)
+    /* TCBGTIE only on STM32L496xx/4A6xx devices */
+    FIELD(CR3, UCESM, 23, 1)   /* USART Clock Enable in Stop Mode */
+    FIELD(CR3, WUFIE, 22, 1)   /* Wakeup from Stop mode interrupt enable */
+    FIELD(CR3, WUS, 20, 2)     /* Wakeup from Stop mode interrupt flag selection */
+    FIELD(CR3, SCARCNT, 17, 3) /* Smartcard auto-retry count */
+    FIELD(CR3, DEP, 15, 1)     /* Driver enable polarity selection */
+    FIELD(CR3, DEM, 14, 1)     /* Driver enable mode */
+    FIELD(CR3, DDRE, 13, 1)    /* DMA Disable on Reception Error */
+    FIELD(CR3, OVRDIS, 12, 1)  /* Overrun Disable */
+    FIELD(CR3, ONEBIT, 11, 1)  /* One sample bit method enable */
+    FIELD(CR3, CTSIE, 10, 1)   /* CTS interrupt enable */
+    FIELD(CR3, CTSE, 9, 1)     /* CTS enable */
+    FIELD(CR3, RTSE, 8, 1)     /* RTS enable */
+    FIELD(CR3, DMAT, 7, 1)     /* DMA enable transmitter */
+    FIELD(CR3, DMAR, 6, 1)     /* DMA enable receiver */
+    FIELD(CR3, SCEN, 5, 1)     /* Smartcard mode enable */
+    FIELD(CR3, NACK, 4, 1)     /* Smartcard NACK enable */
+    FIELD(CR3, HDSEL, 3, 1)    /* Half-duplex selection */
+    FIELD(CR3, IRLP, 2, 1)     /* IrDA low-power */
+    FIELD(CR3, IREN, 1, 1)     /* IrDA mode enable */
+    FIELD(CR3, EIE, 0, 1)      /* Error interrupt enable */
+REG32(BRR, 0x0C)
+    FIELD(BRR, BRR, 0, 16)
+REG32(GTPR, 0x10)
+    FIELD(GTPR, GT, 8, 8)  /* Guard time value */
+    FIELD(GTPR, PSC, 0, 8) /* Prescaler value */
+REG32(RTOR, 0x14)
+    FIELD(RTOR, BLEN, 24, 8) /* Block Length */
+    FIELD(RTOR, RTO, 0, 24)  /* Receiver timeout value */
+REG32(RQR, 0x18)
+    FIELD(RQR, TXFRQ, 4, 1)  /* Transmit data flush request */
+    FIELD(RQR, RXFRQ, 3, 1)  /* Receive data flush request */
+    FIELD(RQR, MMRQ, 2, 1)   /* Mute mode request */
+    FIELD(RQR, SBKRQ, 1, 1)  /* Send break request */
+    FIELD(RQR, ABBRRQ, 0, 1) /* Auto baud rate request */
+REG32(ISR, 0x1C)
+    /* TCBGT only for STM32L475xx/476xx/486xx devices */
+    FIELD(ISR, REACK, 22, 1) /* Receive enable acknowledge flag */
+    FIELD(ISR, TEACK, 21, 1) /* Transmit enable acknowledge flag */
+    FIELD(ISR, WUF, 20, 1)   /* Wakeup from Stop mode flag */
+    FIELD(ISR, RWU, 19, 1)   /* Receiver wakeup from Mute mode */
+    FIELD(ISR, SBKF, 18, 1)  /* Send break flag */
+    FIELD(ISR, CMF, 17, 1)   /* Character match flag */
+    FIELD(ISR, BUSY, 16, 1)  /* Busy flag */
+    FIELD(ISR, ABRF, 15, 1)  /* Auto Baud rate flag */
+    FIELD(ISR, ABRE, 14, 1)  /* Auto Baud rate error */
+    FIELD(ISR, EOBF, 12, 1)  /* End of block flag */
+    FIELD(ISR, RTOF, 11, 1)  /* Receiver timeout */
+    FIELD(ISR, CTS, 10, 1)   /* CTS flag */
+    FIELD(ISR, CTSIF, 9, 1)  /* CTS interrupt flag */
+    FIELD(ISR, LBDF, 8, 1)   /* LIN break detection flag */
+    FIELD(ISR, TXE, 7, 1)    /* Transmit data register empty */
+    FIELD(ISR, TC, 6, 1)     /* Transmission complete */
+    FIELD(ISR, RXNE, 5, 1)   /* Read data register not empty */
+    FIELD(ISR, IDLE, 4, 1)   /* Idle line detected */
+    FIELD(ISR, ORE, 3, 1)    /* Overrun error */
+    FIELD(ISR, NF, 2, 1)     /* START bit Noise detection flag */
+    FIELD(ISR, FE, 1, 1)     /* Framing Error */
+    FIELD(ISR, PE, 0, 1)     /* Parity Error */
+REG32(ICR, 0x20)
+    FIELD(ICR, WUCF, 20, 1)   /* Wakeup from Stop mode clear flag */
+    FIELD(ICR, CMCF, 17, 1)   /* Character match clear flag */
+    FIELD(ICR, EOBCF, 12, 1)  /* End of block clear flag */
+    FIELD(ICR, RTOCF, 11, 1)  /* Receiver timeout clear flag */
+    FIELD(ICR, CTSCF, 9, 1)   /* CTS clear flag */
+    FIELD(ICR, LBDCF, 8, 1)   /* LIN break detection clear flag */
+    /* TCBGTCF only on STM32L496xx/4A6xx devices */
+    FIELD(ICR, TCCF, 6, 1)    /* Transmission complete clear flag */
+    FIELD(ICR, IDLECF, 4, 1)  /* Idle line detected clear flag */
+    FIELD(ICR, ORECF, 3, 1)   /* Overrun error clear flag */
+    FIELD(ICR, NCF, 2, 1)     /* Noise detected clear flag */
+    FIELD(ICR, FECF, 1, 1)    /* Framing error clear flag */
+    FIELD(ICR, PECF, 0, 1)    /* Parity error clear flag */
+REG32(RDR, 0x24)
+    FIELD(RDR, RDR, 0, 9)
+REG32(TDR, 0x28)
+    FIELD(TDR, TDR, 0, 9)
+
+static void stm32l4x5_usart_base_reset_hold(Object *obj, ResetType type)
+{
+    Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
+
+    s->cr1 = 0x00000000;
+    s->cr2 = 0x00000000;
+    s->cr3 = 0x00000000;
+    s->brr = 0x00000000;
+    s->gtpr = 0x00000000;
+    s->rtor = 0x00000000;
+    s->isr = 0x020000C0;
+    s->rdr = 0x00000000;
+    s->tdr = 0x00000000;
+}
+
+static uint64_t stm32l4x5_usart_base_read(void *opaque, hwaddr addr,
+                                     unsigned int size)
+{
+    Stm32l4x5UsartBaseState *s = opaque;
+    uint64_t retvalue = 0;
+
+    switch (addr) {
+    case A_CR1:
+        retvalue = s->cr1;
+        break;
+    case A_CR2:
+        retvalue = s->cr2;
+        break;
+    case A_CR3:
+        retvalue = s->cr3;
+        break;
+    case A_BRR:
+        retvalue = FIELD_EX32(s->brr, BRR, BRR);
+        break;
+    case A_GTPR:
+        retvalue = s->gtpr;
+        break;
+    case A_RTOR:
+        retvalue = s->rtor;
+        break;
+    case A_RQR:
+        /* RQR is a write only register */
+        retvalue = 0x00000000;
+        break;
+    case A_ISR:
+        retvalue = s->isr;
+        break;
+    case A_ICR:
+        /* ICR is a clear register */
+        retvalue = 0x00000000;
+        break;
+    case A_RDR:
+        retvalue = FIELD_EX32(s->rdr, RDR, RDR);
+        /* Reset RXNE flag */
+        s->isr &= ~R_ISR_RXNE_MASK;
+        break;
+    case A_TDR:
+        retvalue = FIELD_EX32(s->tdr, TDR, TDR);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+        break;
+    }
+
+    trace_stm32l4x5_usart_read(addr, retvalue);
+
+    return retvalue;
+}
+
+static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
+                                  uint64_t val64, unsigned int size)
+{
+    Stm32l4x5UsartBaseState *s = opaque;
+    const uint32_t value = val64;
+
+    trace_stm32l4x5_usart_write(addr, value);
+
+    switch (addr) {
+    case A_CR1:
+        s->cr1 = value;
+        return;
+    case A_CR2:
+        s->cr2 = value;
+        return;
+    case A_CR3:
+        s->cr3 = value;
+        return;
+    case A_BRR:
+        s->brr = value;
+        return;
+    case A_GTPR:
+        s->gtpr = value;
+        return;
+    case A_RTOR:
+        s->rtor = value;
+        return;
+    case A_RQR:
+        return;
+    case A_ISR:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: ISR is read only !\n", __func__);
+        return;
+    case A_ICR:
+        /* Clear the status flags */
+        s->isr &= ~value;
+        return;
+    case A_RDR:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: RDR is read only !\n", __func__);
+        return;
+    case A_TDR:
+        s->tdr = value;
+        return;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+    }
+}
+
+static const MemoryRegionOps stm32l4x5_usart_base_ops = {
+    .read = stm32l4x5_usart_base_read,
+    .write = stm32l4x5_usart_base_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .max_access_size = 4,
+        .min_access_size = 4,
+        .unaligned = false
+    },
+    .impl = {
+        .max_access_size = 4,
+        .min_access_size = 4,
+        .unaligned = false
+    },
+};
+
+static Property stm32l4x5_usart_base_properties[] = {
+    DEFINE_PROP_CHR("chardev", Stm32l4x5UsartBaseState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32l4x5_usart_base_init(Object *obj)
+{
+    Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+    memory_region_init_io(&s->mmio, obj, &stm32l4x5_usart_base_ops, s,
+                          TYPE_STM32L4X5_USART_BASE, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+    s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
+}
+
+static const VMStateDescription vmstate_stm32l4x5_usart_base = {
+    .name = TYPE_STM32L4X5_USART_BASE,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cr1, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(cr2, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(cr3, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(brr, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(gtpr, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(rtor, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(isr, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(rdr, Stm32l4x5UsartBaseState),
+        VMSTATE_UINT32(tdr, Stm32l4x5UsartBaseState),
+        VMSTATE_CLOCK(clk, Stm32l4x5UsartBaseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static void stm32l4x5_usart_base_realize(DeviceState *dev, Error **errp)
+{
+    ERRP_GUARD();
+    Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(dev);
+    if (!clock_has_source(s->clk)) {
+        error_setg(errp, "USART clock must be wired up by SoC code");
+        return;
+    }
+}
+
+static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+    rc->phases.hold = stm32l4x5_usart_base_reset_hold;
+    device_class_set_props(dc, stm32l4x5_usart_base_properties);
+    dc->realize = stm32l4x5_usart_base_realize;
+    dc->vmsd = &vmstate_stm32l4x5_usart_base;
+}
+
+static void stm32l4x5_usart_class_init(ObjectClass *oc, void *data)
+{
+    Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
+
+    subc->type = STM32L4x5_USART;
+}
+
+static void stm32l4x5_uart_class_init(ObjectClass *oc, void *data)
+{
+    Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
+
+    subc->type = STM32L4x5_UART;
+}
+
+static void stm32l4x5_lpuart_class_init(ObjectClass *oc, void *data)
+{
+    Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
+
+    subc->type = STM32L4x5_LPUART;
+}
+
+static const TypeInfo stm32l4x5_usart_types[] = {
+    {
+        .name           = TYPE_STM32L4X5_USART_BASE,
+        .parent         = TYPE_SYS_BUS_DEVICE,
+        .instance_size  = sizeof(Stm32l4x5UsartBaseState),
+        .instance_init  = stm32l4x5_usart_base_init,
+        .class_init     = stm32l4x5_usart_base_class_init,
+        .abstract       = true,
+    }, {
+        .name           = TYPE_STM32L4X5_USART,
+        .parent         = TYPE_STM32L4X5_USART_BASE,
+        .class_init     = stm32l4x5_usart_class_init,
+    }, {
+        .name           = TYPE_STM32L4X5_UART,
+        .parent         = TYPE_STM32L4X5_USART_BASE,
+        .class_init     = stm32l4x5_uart_class_init,
+    }, {
+        .name           = TYPE_STM32L4X5_LPUART,
+        .parent         = TYPE_STM32L4X5_USART_BASE,
+        .class_init     = stm32l4x5_lpuart_class_init,
+    }
+};
+
+DEFINE_TYPES(stm32l4x5_usart_types)
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 6b6cf2fc1df..4fd74ea8788 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -41,6 +41,9 @@ config VIRTIO_SERIAL
 config STM32F2XX_USART
     bool
 
+config STM32L4X5_USART
+    bool
+
 config CMSDK_APB_UART
     bool
 
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 006d20f1e25..e5b13b69580 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -31,6 +31,7 @@ system_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
 system_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c'))
 system_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
 system_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
+system_ss.add(when: 'CONFIG_STM32L4X5_USART', if_true: files('stm32l4x5_usart.c'))
 system_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
 system_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
 system_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c'))
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 7a398c82a57..689bed9e025 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -106,6 +106,10 @@ cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
 sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64
 sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64
 
+# stm32l4x5_usart.c
+stm32l4x5_usart_read(uint64_t addr, uint32_t data) "USART: Read <0x%" PRIx64 "> -> 0x%" PRIx32 ""
+stm32l4x5_usart_write(uint64_t addr, uint32_t data) "USART: Write <0x%" PRIx64 "> <- 0x%" PRIx32 ""
+
 # xen_console.c
 xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int port, unsigned int limit) "idx %u ring_ref %u port %u limit %u"
 xen_console_disconnect(unsigned int idx) "idx %u"
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 34/37] hw/char/stm32l4x5_usart: Enable serial read and write
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (32 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 33/37] hw/char: Implement STM32L4x5 USART skeleton Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 35/37] hw/char/stm32l4x5_usart: Add options for serial parameters setting Peter Maydell
                   ` (3 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Arnaud Minier <arnaud.minier@telecom-paris.fr>

Implement the ability to read and write characters to the
usart using the serial port.

The character transmission is based on the
cmsdk-apb-uart implementation.

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240329174402.60382-3-arnaud.minier@telecom-paris.fr
[PMM: fixed a few checkpatch nits]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/char/stm32l4x5_usart.h |   1 +
 hw/char/stm32l4x5_usart.c         | 143 ++++++++++++++++++++++++++++++
 hw/char/trace-events              |   7 ++
 3 files changed, 151 insertions(+)

diff --git a/include/hw/char/stm32l4x5_usart.h b/include/hw/char/stm32l4x5_usart.h
index 8d38a85a6e6..dd3866682a3 100644
--- a/include/hw/char/stm32l4x5_usart.h
+++ b/include/hw/char/stm32l4x5_usart.h
@@ -55,6 +55,7 @@ struct Stm32l4x5UsartBaseState {
     Clock *clk;
     CharBackend chr;
     qemu_irq irq;
+    guint watch_tag;
 };
 
 struct Stm32l4x5UsartBaseClass {
diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
index 62957ec3e59..755fc0bb5a3 100644
--- a/hw/char/stm32l4x5_usart.c
+++ b/hw/char/stm32l4x5_usart.c
@@ -154,6 +154,123 @@ REG32(RDR, 0x24)
 REG32(TDR, 0x28)
     FIELD(TDR, TDR, 0, 9)
 
+static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
+{
+    if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK))        ||
+        ((s->isr & R_ISR_CMF_MASK) && (s->cr1 & R_CR1_CMIE_MASK))         ||
+        ((s->isr & R_ISR_ABRF_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK))      ||
+        ((s->isr & R_ISR_EOBF_MASK) && (s->cr1 & R_CR1_EOBIE_MASK))       ||
+        ((s->isr & R_ISR_RTOF_MASK) && (s->cr1 & R_CR1_RTOIE_MASK))       ||
+        ((s->isr & R_ISR_CTSIF_MASK) && (s->cr3 & R_CR3_CTSIE_MASK))      ||
+        ((s->isr & R_ISR_LBDF_MASK) && (s->cr2 & R_CR2_LBDIE_MASK))       ||
+        ((s->isr & R_ISR_TXE_MASK) && (s->cr1 & R_CR1_TXEIE_MASK))        ||
+        ((s->isr & R_ISR_TC_MASK) && (s->cr1 & R_CR1_TCIE_MASK))          ||
+        ((s->isr & R_ISR_RXNE_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK))      ||
+        ((s->isr & R_ISR_IDLE_MASK) && (s->cr1 & R_CR1_IDLEIE_MASK))      ||
+        ((s->isr & R_ISR_ORE_MASK) &&
+            ((s->cr1 & R_CR1_RXNEIE_MASK) || (s->cr3 & R_CR3_EIE_MASK)))  ||
+        /* TODO: Handle NF ? */
+        ((s->isr & R_ISR_FE_MASK) && (s->cr3 & R_CR3_EIE_MASK))           ||
+        ((s->isr & R_ISR_PE_MASK) && (s->cr1 & R_CR1_PEIE_MASK))) {
+        qemu_irq_raise(s->irq);
+        trace_stm32l4x5_usart_irq_raised(s->isr);
+    } else {
+        qemu_irq_lower(s->irq);
+        trace_stm32l4x5_usart_irq_lowered();
+    }
+}
+
+static int stm32l4x5_usart_base_can_receive(void *opaque)
+{
+    Stm32l4x5UsartBaseState *s = opaque;
+
+    if (!(s->isr & R_ISR_RXNE_MASK)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void stm32l4x5_usart_base_receive(void *opaque, const uint8_t *buf,
+                                         int size)
+{
+    Stm32l4x5UsartBaseState *s = opaque;
+
+    if (!((s->cr1 & R_CR1_UE_MASK) && (s->cr1 & R_CR1_RE_MASK))) {
+        trace_stm32l4x5_usart_receiver_not_enabled(
+            FIELD_EX32(s->cr1, CR1, UE), FIELD_EX32(s->cr1, CR1, RE));
+        return;
+    }
+
+    /* Check if overrun detection is enabled and if there is an overrun */
+    if (!(s->cr3 & R_CR3_OVRDIS_MASK) && (s->isr & R_ISR_RXNE_MASK)) {
+        /*
+         * A character has been received while
+         * the previous has not been read = Overrun.
+         */
+        s->isr |= R_ISR_ORE_MASK;
+        trace_stm32l4x5_usart_overrun_detected(s->rdr, *buf);
+    } else {
+        /* No overrun */
+        s->rdr = *buf;
+        s->isr |= R_ISR_RXNE_MASK;
+        trace_stm32l4x5_usart_rx(s->rdr);
+    }
+
+    stm32l4x5_update_irq(s);
+}
+
+/*
+ * Try to send tx data, and arrange to be called back later if
+ * we can't (ie the char backend is busy/blocking).
+ */
+static gboolean usart_transmit(void *do_not_use, GIOCondition cond,
+                               void *opaque)
+{
+    Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(opaque);
+    int ret;
+    /* TODO: Handle 9 bits transmission */
+    uint8_t ch = s->tdr;
+
+    s->watch_tag = 0;
+
+    if (!(s->cr1 & R_CR1_TE_MASK) || (s->isr & R_ISR_TXE_MASK)) {
+        return G_SOURCE_REMOVE;
+    }
+
+    ret = qemu_chr_fe_write(&s->chr, &ch, 1);
+    if (ret <= 0) {
+        s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+                                             usart_transmit, s);
+        if (!s->watch_tag) {
+            /*
+             * Most common reason to be here is "no chardev backend":
+             * just insta-drain the buffer, so the serial output
+             * goes into a void, rather than blocking the guest.
+             */
+            goto buffer_drained;
+        }
+        /* Transmit pending */
+        trace_stm32l4x5_usart_tx_pending();
+        return G_SOURCE_REMOVE;
+    }
+
+buffer_drained:
+    /* Character successfully sent */
+    trace_stm32l4x5_usart_tx(ch);
+    s->isr |= R_ISR_TC_MASK | R_ISR_TXE_MASK;
+    stm32l4x5_update_irq(s);
+    return G_SOURCE_REMOVE;
+}
+
+static void usart_cancel_transmit(Stm32l4x5UsartBaseState *s)
+{
+    if (s->watch_tag) {
+        g_source_remove(s->watch_tag);
+        s->watch_tag = 0;
+    }
+}
+
 static void stm32l4x5_usart_base_reset_hold(Object *obj, ResetType type)
 {
     Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
@@ -167,6 +284,22 @@ static void stm32l4x5_usart_base_reset_hold(Object *obj, ResetType type)
     s->isr = 0x020000C0;
     s->rdr = 0x00000000;
     s->tdr = 0x00000000;
+
+    usart_cancel_transmit(s);
+    stm32l4x5_update_irq(s);
+}
+
+static void usart_update_rqr(Stm32l4x5UsartBaseState *s, uint32_t value)
+{
+    /* TXFRQ */
+    /* Reset RXNE flag */
+    if (value & R_RQR_RXFRQ_MASK) {
+        s->isr &= ~R_ISR_RXNE_MASK;
+    }
+    /* MMRQ */
+    /* SBKRQ */
+    /* ABRRQ */
+    stm32l4x5_update_irq(s);
 }
 
 static uint64_t stm32l4x5_usart_base_read(void *opaque, hwaddr addr,
@@ -209,6 +342,7 @@ static uint64_t stm32l4x5_usart_base_read(void *opaque, hwaddr addr,
         retvalue = FIELD_EX32(s->rdr, RDR, RDR);
         /* Reset RXNE flag */
         s->isr &= ~R_ISR_RXNE_MASK;
+        stm32l4x5_update_irq(s);
         break;
     case A_TDR:
         retvalue = FIELD_EX32(s->tdr, TDR, TDR);
@@ -235,6 +369,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
     switch (addr) {
     case A_CR1:
         s->cr1 = value;
+        stm32l4x5_update_irq(s);
         return;
     case A_CR2:
         s->cr2 = value;
@@ -252,6 +387,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
         s->rtor = value;
         return;
     case A_RQR:
+        usart_update_rqr(s, value);
         return;
     case A_ISR:
         qemu_log_mask(LOG_GUEST_ERROR,
@@ -260,6 +396,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
     case A_ICR:
         /* Clear the status flags */
         s->isr &= ~value;
+        stm32l4x5_update_irq(s);
         return;
     case A_RDR:
         qemu_log_mask(LOG_GUEST_ERROR,
@@ -267,6 +404,8 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
         return;
     case A_TDR:
         s->tdr = value;
+        s->isr &= ~R_ISR_TXE_MASK;
+        usart_transmit(NULL, G_IO_OUT, s);
         return;
     default:
         qemu_log_mask(LOG_GUEST_ERROR,
@@ -336,6 +475,10 @@ static void stm32l4x5_usart_base_realize(DeviceState *dev, Error **errp)
         error_setg(errp, "USART clock must be wired up by SoC code");
         return;
     }
+
+    qemu_chr_fe_set_handlers(&s->chr, stm32l4x5_usart_base_can_receive,
+                             stm32l4x5_usart_base_receive, NULL, NULL,
+                             s, NULL, true);
 }
 
 static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 689bed9e025..f22f0ee2bc5 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -109,6 +109,13 @@ sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %
 # stm32l4x5_usart.c
 stm32l4x5_usart_read(uint64_t addr, uint32_t data) "USART: Read <0x%" PRIx64 "> -> 0x%" PRIx32 ""
 stm32l4x5_usart_write(uint64_t addr, uint32_t data) "USART: Write <0x%" PRIx64 "> <- 0x%" PRIx32 ""
+stm32l4x5_usart_rx(uint8_t c) "USART: got character 0x%x from backend"
+stm32l4x5_usart_tx(uint8_t c) "USART: character 0x%x sent to backend"
+stm32l4x5_usart_tx_pending(void) "USART: character send to backend pending"
+stm32l4x5_usart_irq_raised(uint32_t reg) "USART: IRQ raised: 0x%08"PRIx32
+stm32l4x5_usart_irq_lowered(void) "USART: IRQ lowered"
+stm32l4x5_usart_overrun_detected(uint8_t current, uint8_t received) "USART: Overrun detected, RDR='0x%x', received 0x%x"
+stm32l4x5_usart_receiver_not_enabled(uint8_t ue_bit, uint8_t re_bit) "USART: Receiver not enabled, UE=0x%x, RE=0x%x"
 
 # xen_console.c
 xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int port, unsigned int limit) "idx %u ring_ref %u port %u limit %u"
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 35/37] hw/char/stm32l4x5_usart: Add options for serial parameters setting
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (33 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 34/37] hw/char/stm32l4x5_usart: Enable serial read and write Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 36/37] hw/arm: Add the USART to the stm32l4x5 SoC Peter Maydell
                   ` (2 subsequent siblings)
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Arnaud Minier <arnaud.minier@telecom-paris.fr>

Add a function to change the settings of the
serial connection.

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240329174402.60382-4-arnaud.minier@telecom-paris.fr
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/char/stm32l4x5_usart.c | 98 +++++++++++++++++++++++++++++++++++++++
 hw/char/trace-events      |  1 +
 2 files changed, 99 insertions(+)

diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
index 755fc0bb5a3..2627aab8324 100644
--- a/hw/char/stm32l4x5_usart.c
+++ b/hw/char/stm32l4x5_usart.c
@@ -271,6 +271,92 @@ static void usart_cancel_transmit(Stm32l4x5UsartBaseState *s)
     }
 }
 
+static void stm32l4x5_update_params(Stm32l4x5UsartBaseState *s)
+{
+    int speed, parity, data_bits, stop_bits;
+    uint32_t value, usart_div;
+    QEMUSerialSetParams ssp;
+
+    /* Select the parity type */
+    if (s->cr1 & R_CR1_PCE_MASK) {
+        if (s->cr1 & R_CR1_PS_MASK) {
+            parity = 'O';
+        } else {
+            parity = 'E';
+        }
+    } else {
+        parity = 'N';
+    }
+
+    /* Select the number of stop bits */
+    switch (FIELD_EX32(s->cr2, CR2, STOP)) {
+    case 0:
+        stop_bits = 1;
+        break;
+    case 2:
+        stop_bits = 2;
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP,
+            "UNIMPLEMENTED: fractionnal stop bits; CR2[13:12] = %u",
+            FIELD_EX32(s->cr2, CR2, STOP));
+        return;
+    }
+
+    /* Select the length of the word */
+    switch ((FIELD_EX32(s->cr1, CR1, M1) << 1) | FIELD_EX32(s->cr1, CR1, M0)) {
+    case 0:
+        data_bits = 8;
+        break;
+    case 1:
+        data_bits = 9;
+        break;
+    case 2:
+        data_bits = 7;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "UNDEFINED: invalid word length, CR1.M = 0b11");
+        return;
+    }
+
+    /* Select the baud rate */
+    value = FIELD_EX32(s->brr, BRR, BRR);
+    if (value < 16) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "UNDEFINED: BRR less than 16: %u", value);
+        return;
+    }
+
+    if (FIELD_EX32(s->cr1, CR1, OVER8) == 0) {
+        /*
+         * Oversampling by 16
+         * BRR = USARTDIV
+         */
+        usart_div = value;
+    } else {
+        /*
+         * Oversampling by 8
+         * - BRR[2:0] = USARTDIV[3:0] shifted 1 bit to the right.
+         * - BRR[3] must be kept cleared.
+         * - BRR[15:4] = USARTDIV[15:4]
+         * - The frequency is multiplied by 2
+         */
+        usart_div = ((value & 0xFFF0) | ((value & 0x0007) << 1)) / 2;
+    }
+
+    speed = clock_get_hz(s->clk) / usart_div;
+
+    ssp.speed     = speed;
+    ssp.parity    = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+
+    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+
+    trace_stm32l4x5_usart_update_params(speed, parity, data_bits, stop_bits);
+}
+
 static void stm32l4x5_usart_base_reset_hold(Object *obj, ResetType type)
 {
     Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
@@ -369,16 +455,19 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
     switch (addr) {
     case A_CR1:
         s->cr1 = value;
+        stm32l4x5_update_params(s);
         stm32l4x5_update_irq(s);
         return;
     case A_CR2:
         s->cr2 = value;
+        stm32l4x5_update_params(s);
         return;
     case A_CR3:
         s->cr3 = value;
         return;
     case A_BRR:
         s->brr = value;
+        stm32l4x5_update_params(s);
         return;
     case A_GTPR:
         s->gtpr = value;
@@ -447,10 +536,19 @@ static void stm32l4x5_usart_base_init(Object *obj)
     s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
 }
 
+static int stm32l4x5_usart_base_post_load(void *opaque, int version_id)
+{
+    Stm32l4x5UsartBaseState *s = (Stm32l4x5UsartBaseState *)opaque;
+
+    stm32l4x5_update_params(s);
+    return 0;
+}
+
 static const VMStateDescription vmstate_stm32l4x5_usart_base = {
     .name = TYPE_STM32L4X5_USART_BASE,
     .version_id = 1,
     .minimum_version_id = 1,
+    .post_load = stm32l4x5_usart_base_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32(cr1, Stm32l4x5UsartBaseState),
         VMSTATE_UINT32(cr2, Stm32l4x5UsartBaseState),
diff --git a/hw/char/trace-events b/hw/char/trace-events
index f22f0ee2bc5..8875758076c 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -116,6 +116,7 @@ stm32l4x5_usart_irq_raised(uint32_t reg) "USART: IRQ raised: 0x%08"PRIx32
 stm32l4x5_usart_irq_lowered(void) "USART: IRQ lowered"
 stm32l4x5_usart_overrun_detected(uint8_t current, uint8_t received) "USART: Overrun detected, RDR='0x%x', received 0x%x"
 stm32l4x5_usart_receiver_not_enabled(uint8_t ue_bit, uint8_t re_bit) "USART: Receiver not enabled, UE=0x%x, RE=0x%x"
+stm32l4x5_usart_update_params(int speed, uint8_t parity, int data, int stop) "USART: speed: %d, parity: %c, data bits: %d, stop bits: %d"
 
 # xen_console.c
 xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int port, unsigned int limit) "idx %u ring_ref %u port %u limit %u"
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 36/37] hw/arm: Add the USART to the stm32l4x5 SoC
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (34 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 35/37] hw/char/stm32l4x5_usart: Add options for serial parameters setting Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 10:39 ` [PULL 37/37] tests/qtest: Add tests for the STM32L4x5 USART Peter Maydell
  2024-04-25 16:45 ` [PULL 00/37] target-arm queue Richard Henderson
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Arnaud Minier <arnaud.minier@telecom-paris.fr>

Add the USART to the SoC and connect it to the other implemented devices.

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240329174402.60382-5-arnaud.minier@telecom-paris.fr
[PMM: fixed a few checkpatch nits]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 docs/system/arm/b-l475e-iot01a.rst |  2 +-
 include/hw/arm/stm32l4x5_soc.h     |  7 +++
 hw/arm/stm32l4x5_soc.c             | 83 +++++++++++++++++++++++++++---
 hw/arm/Kconfig                     |  1 +
 4 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/docs/system/arm/b-l475e-iot01a.rst b/docs/system/arm/b-l475e-iot01a.rst
index 0afef8e4f45..a76c9976c50 100644
--- a/docs/system/arm/b-l475e-iot01a.rst
+++ b/docs/system/arm/b-l475e-iot01a.rst
@@ -19,13 +19,13 @@ Currently B-L475E-IOT01A machine's only supports the following devices:
 - STM32L4x5 SYSCFG (System configuration controller)
 - STM32L4x5 RCC (Reset and clock control)
 - STM32L4x5 GPIOs (General-purpose I/Os)
+- STM32L4x5 USARTs, UARTs and LPUART (Serial ports)
 
 Missing devices
 """""""""""""""
 
 The B-L475E-IOT01A does *not* support the following devices:
 
-- Serial ports (UART)
 - Analog to Digital Converter (ADC)
 - SPI controller
 - Timer controller (TIMER)
diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h
index ee5f3624055..c243fb0e7f9 100644
--- a/include/hw/arm/stm32l4x5_soc.h
+++ b/include/hw/arm/stm32l4x5_soc.h
@@ -31,6 +31,7 @@
 #include "hw/misc/stm32l4x5_exti.h"
 #include "hw/misc/stm32l4x5_rcc.h"
 #include "hw/gpio/stm32l4x5_gpio.h"
+#include "hw/char/stm32l4x5_usart.h"
 #include "qom/object.h"
 
 #define TYPE_STM32L4X5_SOC "stm32l4x5-soc"
@@ -41,6 +42,9 @@ OBJECT_DECLARE_TYPE(Stm32l4x5SocState, Stm32l4x5SocClass, STM32L4X5_SOC)
 
 #define NUM_EXTI_OR_GATES 4
 
+#define STM_NUM_USARTS 3
+#define STM_NUM_UARTS 2
+
 struct Stm32l4x5SocState {
     SysBusDevice parent_obj;
 
@@ -51,6 +55,9 @@ struct Stm32l4x5SocState {
     Stm32l4x5SyscfgState syscfg;
     Stm32l4x5RccState rcc;
     Stm32l4x5GpioState gpio[NUM_GPIOS];
+    Stm32l4x5UsartBaseState usart[STM_NUM_USARTS];
+    Stm32l4x5UsartBaseState uart[STM_NUM_UARTS];
+    Stm32l4x5UsartBaseState lpuart;
 
     MemoryRegion sram1;
     MemoryRegion sram2;
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
index 40e294f838f..39924822f3d 100644
--- a/hw/arm/stm32l4x5_soc.c
+++ b/hw/arm/stm32l4x5_soc.c
@@ -28,6 +28,7 @@
 #include "sysemu/sysemu.h"
 #include "hw/or-irq.h"
 #include "hw/arm/stm32l4x5_soc.h"
+#include "hw/char/stm32l4x5_usart.h"
 #include "hw/gpio/stm32l4x5_gpio.h"
 #include "hw/qdev-clock.h"
 #include "hw/misc/unimp.h"
@@ -116,6 +117,22 @@ static const struct {
     { 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 },
 };
 
+static const hwaddr usart_addr[] = {
+    0x40013800, /* "USART1", 0x400 */
+    0x40004400, /* "USART2", 0x400 */
+    0x40004800, /* "USART3", 0x400 */
+};
+static const hwaddr uart_addr[] = {
+    0x40004C00, /* "UART4" , 0x400 */
+    0x40005000  /* "UART5" , 0x400 */
+};
+
+#define LPUART_BASE_ADDRESS 0x40008000
+
+static const int usart_irq[] = { 37, 38, 39 };
+static const int uart_irq[] = { 52, 53 };
+#define LPUART_IRQ 70
+
 static void stm32l4x5_soc_initfn(Object *obj)
 {
     Stm32l4x5SocState *s = STM32L4X5_SOC(obj);
@@ -132,6 +149,18 @@ static void stm32l4x5_soc_initfn(Object *obj)
         g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i);
         object_initialize_child(obj, name, &s->gpio[i], TYPE_STM32L4X5_GPIO);
     }
+
+    for (int i = 0; i < STM_NUM_USARTS; i++) {
+        object_initialize_child(obj, "usart[*]", &s->usart[i],
+                                TYPE_STM32L4X5_USART);
+    }
+
+    for (int i = 0; i < STM_NUM_UARTS; i++) {
+        object_initialize_child(obj, "uart[*]", &s->uart[i],
+                                TYPE_STM32L4X5_UART);
+    }
+    object_initialize_child(obj, "lpuart1", &s->lpuart,
+                            TYPE_STM32L4X5_LPUART);
 }
 
 static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -279,6 +308,54 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
     sysbus_mmio_map(busdev, 0, RCC_BASE_ADDRESS);
     sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, RCC_IRQ));
 
+    /* USART devices */
+    for (int i = 0; i < STM_NUM_USARTS; i++) {
+        g_autofree char *name = g_strdup_printf("usart%d-out", i + 1);
+        dev = DEVICE(&(s->usart[i]));
+        qdev_prop_set_chr(dev, "chardev", serial_hd(i));
+        qdev_connect_clock_in(dev, "clk",
+            qdev_get_clock_out(DEVICE(&(s->rcc)), name));
+        busdev = SYS_BUS_DEVICE(dev);
+        if (!sysbus_realize(busdev, errp)) {
+            return;
+        }
+        sysbus_mmio_map(busdev, 0, usart_addr[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i]));
+    }
+
+    /*
+     * TODO: Connect the USARTs, UARTs and LPUART to the EXTI once the EXTI
+     * can handle other gpio-in than the gpios. (e.g. Direct Lines for the
+     * usarts)
+     */
+
+    /* UART devices */
+    for (int i = 0; i < STM_NUM_UARTS; i++) {
+        g_autofree char *name = g_strdup_printf("uart%d-out", STM_NUM_USARTS + i + 1);
+        dev = DEVICE(&(s->uart[i]));
+        qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + i));
+        qdev_connect_clock_in(dev, "clk",
+            qdev_get_clock_out(DEVICE(&(s->rcc)), name));
+        busdev = SYS_BUS_DEVICE(dev);
+        if (!sysbus_realize(busdev, errp)) {
+            return;
+        }
+        sysbus_mmio_map(busdev, 0, uart_addr[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, uart_irq[i]));
+    }
+
+    /* LPUART device*/
+    dev = DEVICE(&(s->lpuart));
+    qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + STM_NUM_UARTS));
+    qdev_connect_clock_in(dev, "clk",
+        qdev_get_clock_out(DEVICE(&(s->rcc)), "lpuart1-out"));
+    busdev = SYS_BUS_DEVICE(dev);
+    if (!sysbus_realize(busdev, errp)) {
+        return;
+    }
+    sysbus_mmio_map(busdev, 0, LPUART_BASE_ADDRESS);
+    sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, LPUART_IRQ));
+
     /* APB1 BUS */
     create_unimplemented_device("TIM2",      0x40000000, 0x400);
     create_unimplemented_device("TIM3",      0x40000400, 0x400);
@@ -294,10 +371,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
     create_unimplemented_device("SPI2",      0x40003800, 0x400);
     create_unimplemented_device("SPI3",      0x40003C00, 0x400);
     /* RESERVED:    0x40004000, 0x400 */
-    create_unimplemented_device("USART2",    0x40004400, 0x400);
-    create_unimplemented_device("USART3",    0x40004800, 0x400);
-    create_unimplemented_device("UART4",     0x40004C00, 0x400);
-    create_unimplemented_device("UART5",     0x40005000, 0x400);
     create_unimplemented_device("I2C1",      0x40005400, 0x400);
     create_unimplemented_device("I2C2",      0x40005800, 0x400);
     create_unimplemented_device("I2C3",      0x40005C00, 0x400);
@@ -308,7 +381,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
     create_unimplemented_device("DAC1",      0x40007400, 0x400);
     create_unimplemented_device("OPAMP",     0x40007800, 0x400);
     create_unimplemented_device("LPTIM1",    0x40007C00, 0x400);
-    create_unimplemented_device("LPUART1",   0x40008000, 0x400);
     /* RESERVED:    0x40008400, 0x400 */
     create_unimplemented_device("SWPMI1",    0x40008800, 0x400);
     /* RESERVED:    0x40008C00, 0x800 */
@@ -325,7 +397,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
     create_unimplemented_device("TIM1",      0x40012C00, 0x400);
     create_unimplemented_device("SPI1",      0x40013000, 0x400);
     create_unimplemented_device("TIM8",      0x40013400, 0x400);
-    create_unimplemented_device("USART1",    0x40013800, 0x400);
     /* RESERVED:    0x40013C00, 0x400 */
     create_unimplemented_device("TIM15",     0x40014000, 0x400);
     create_unimplemented_device("TIM16",     0x40014400, 0x400);
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 893a7bff66b..098d0433753 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -477,6 +477,7 @@ config STM32L4X5_SOC
     select STM32L4X5_SYSCFG
     select STM32L4X5_RCC
     select STM32L4X5_GPIO
+    select STM32L4X5_USART
 
 config XLNX_ZYNQMP_ARM
     bool
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PULL 37/37] tests/qtest: Add tests for the STM32L4x5 USART
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (35 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 36/37] hw/arm: Add the USART to the stm32l4x5 SoC Peter Maydell
@ 2024-04-25 10:39 ` Peter Maydell
  2024-04-25 16:45 ` [PULL 00/37] target-arm queue Richard Henderson
  37 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2024-04-25 10:39 UTC (permalink / raw)
  To: qemu-devel

From: Arnaud Minier <arnaud.minier@telecom-paris.fr>

Test:
- read/write from/to the usart registers
- send/receive a character/string over the serial port

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20240329174402.60382-6-arnaud.minier@telecom-paris.fr
[PMM: fix checkpatch nits, remove commented out code]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/qtest/stm32l4x5_usart-test.c | 315 +++++++++++++++++++++++++++++
 tests/qtest/meson.build            |   4 +-
 2 files changed, 318 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/stm32l4x5_usart-test.c

diff --git a/tests/qtest/stm32l4x5_usart-test.c b/tests/qtest/stm32l4x5_usart-test.c
new file mode 100644
index 00000000000..89025182331
--- /dev/null
+++ b/tests/qtest/stm32l4x5_usart-test.c
@@ -0,0 +1,315 @@
+/*
+ * QTest testcase for STML4X5_USART
+ *
+ * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "hw/misc/stm32l4x5_rcc_internals.h"
+#include "hw/registerfields.h"
+
+#define RCC_BASE_ADDR 0x40021000
+/* Use USART 1 ADDR, assume the others work the same */
+#define USART1_BASE_ADDR 0x40013800
+
+/* See stm32l4x5_usart for definitions */
+REG32(CR1, 0x00)
+    FIELD(CR1, M1, 28, 1)
+    FIELD(CR1, OVER8, 15, 1)
+    FIELD(CR1, M0, 12, 1)
+    FIELD(CR1, PCE, 10, 1)
+    FIELD(CR1, TXEIE, 7, 1)
+    FIELD(CR1, RXNEIE, 5, 1)
+    FIELD(CR1, TE, 3, 1)
+    FIELD(CR1, RE, 2, 1)
+    FIELD(CR1, UE, 0, 1)
+REG32(CR2, 0x04)
+REG32(CR3, 0x08)
+    FIELD(CR3, OVRDIS, 12, 1)
+REG32(BRR, 0x0C)
+REG32(GTPR, 0x10)
+REG32(RTOR, 0x14)
+REG32(RQR, 0x18)
+REG32(ISR, 0x1C)
+    FIELD(ISR, TXE, 7, 1)
+    FIELD(ISR, RXNE, 5, 1)
+    FIELD(ISR, ORE, 3, 1)
+REG32(ICR, 0x20)
+REG32(RDR, 0x24)
+REG32(TDR, 0x28)
+
+#define NVIC_ISPR1 0XE000E204
+#define NVIC_ICPR1 0xE000E284
+#define USART1_IRQ 37
+
+static bool check_nvic_pending(QTestState *qts, unsigned int n)
+{
+    /* No USART interrupts are less than 32 */
+    assert(n > 32);
+    n -= 32;
+    return qtest_readl(qts, NVIC_ISPR1) & (1 << n);
+}
+
+static bool clear_nvic_pending(QTestState *qts, unsigned int n)
+{
+    /* No USART interrupts are less than 32 */
+    assert(n > 32);
+    n -= 32;
+    qtest_writel(qts, NVIC_ICPR1, (1 << n));
+    return true;
+}
+
+/*
+ * Wait indefinitely for the flag to be updated.
+ * If this is run on a slow CI runner,
+ * the meson harness will timeout after 10 minutes for us.
+ */
+static bool usart_wait_for_flag(QTestState *qts, uint32_t event_addr,
+                                uint32_t flag)
+{
+    while (true) {
+        if ((qtest_readl(qts, event_addr) & flag)) {
+            return true;
+        }
+        g_usleep(1000);
+    }
+
+    return false;
+}
+
+static void usart_receive_string(QTestState *qts, int sock_fd, const char *in,
+                                 char *out)
+{
+    int i, in_len = strlen(in);
+
+    g_assert_true(send(sock_fd, in, in_len, 0) == in_len);
+    for (i = 0; i < in_len; i++) {
+        g_assert_true(usart_wait_for_flag(qts,
+            USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK));
+        out[i] = qtest_readl(qts, USART1_BASE_ADDR + A_RDR);
+    }
+    out[i] = '\0';
+}
+
+static void usart_send_string(QTestState *qts, const char *in)
+{
+    int i, in_len = strlen(in);
+
+    for (i = 0; i < in_len; i++) {
+        qtest_writel(qts, USART1_BASE_ADDR + A_TDR, in[i]);
+        g_assert_true(usart_wait_for_flag(qts,
+            USART1_BASE_ADDR + A_ISR, R_ISR_TXE_MASK));
+    }
+}
+
+/* Init the RCC clocks to run at 80 MHz */
+static void init_clocks(QTestState *qts)
+{
+    uint32_t value;
+
+    /* MSIRANGE can be set only when MSI is OFF or READY */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_CR), R_CR_MSION_MASK);
+
+    /* Clocking from MSI, in case MSI was not the default source */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0);
+
+    /*
+     * Update PLL and set MSI as the source clock.
+     * PLLM = 1 --> 000
+     * PLLN = 40 --> 40
+     * PPLLR = 2 --> 00
+     * PLLDIV = unused, PLLP = unused (SAI3), PLLQ = unused (48M1)
+     * SRC = MSI --> 01
+     */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_PLLCFGR), R_PLLCFGR_PLLREN_MASK |
+            (40 << R_PLLCFGR_PLLN_SHIFT) |
+            (0b01 << R_PLLCFGR_PLLSRC_SHIFT));
+
+    /* PLL activation */
+
+    value = qtest_readl(qts, (RCC_BASE_ADDR + A_CR));
+    qtest_writel(qts, (RCC_BASE_ADDR + A_CR), value | R_CR_PLLON_MASK);
+
+    /* RCC_CFGR is OK by defaut */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0);
+
+    /* CCIPR : no periph clock by default */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0);
+
+    /* Switches on the PLL clock source */
+    value = qtest_readl(qts, (RCC_BASE_ADDR + A_CFGR));
+    qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), (value & ~R_CFGR_SW_MASK) |
+        (0b11 << R_CFGR_SW_SHIFT));
+
+    /* Enable SYSCFG clock enabled */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR), R_APB2ENR_SYSCFGEN_MASK);
+
+    /* Enable the IO port B clock (See p.252) */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_AHB2ENR), R_AHB2ENR_GPIOBEN_MASK);
+
+    /* Enable the clock for USART1 (cf p.259) */
+    /* We rewrite SYSCFGEN to not disable it */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR),
+                 R_APB2ENR_SYSCFGEN_MASK | R_APB2ENR_USART1EN_MASK);
+
+    /* TODO: Enable usart via gpio */
+
+    /* Set PCLK as the clock for USART1(cf p.272) i.e. reset both bits */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0);
+
+    /* Reset USART1 (see p.249) */
+    qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 1 << 14);
+    qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 0);
+}
+
+static void init_uart(QTestState *qts)
+{
+    uint32_t cr1;
+
+    init_clocks(qts);
+
+    /*
+     * For 115200 bauds, see p.1349.
+     * The clock has a frequency of 80Mhz,
+     * for 115200, we have to put a divider of 695 = 0x2B7.
+     */
+    qtest_writel(qts, (USART1_BASE_ADDR + A_BRR), 0x2B7);
+
+    /*
+     * Set the oversampling by 16,
+     * disable the parity control and
+     * set the word length to 8. (cf p.1377)
+     */
+    cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
+    cr1 &= ~(R_CR1_M1_MASK | R_CR1_M0_MASK | R_CR1_OVER8_MASK | R_CR1_PCE_MASK);
+    qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), cr1);
+
+    /* Enable the transmitter, the receiver and the USART. */
+    qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
+        R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
+}
+
+static void test_write_read(void)
+{
+    QTestState *qts = qtest_init("-M b-l475e-iot01a");
+
+    /* Test that we can write and retrieve a value from the device */
+    qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 0xFFFFFFFF);
+    const uint32_t tdr = qtest_readl(qts, USART1_BASE_ADDR + A_TDR);
+    g_assert_cmpuint(tdr, ==, 0x000001FF);
+}
+
+static void test_receive_char(void)
+{
+    int sock_fd;
+    uint32_t cr1;
+    QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
+
+    init_uart(qts);
+
+    /* Try without initializing IRQ */
+    g_assert_true(send(sock_fd, "a", 1, 0) == 1);
+    usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK);
+    g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'a');
+    g_assert_false(check_nvic_pending(qts, USART1_IRQ));
+
+    /* Now with the IRQ */
+    cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
+    cr1 |= R_CR1_RXNEIE_MASK;
+    qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1);
+    g_assert_true(send(sock_fd, "b", 1, 0) == 1);
+    usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK);
+    g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'b');
+    g_assert_true(check_nvic_pending(qts, USART1_IRQ));
+    clear_nvic_pending(qts, USART1_IRQ);
+
+    close(sock_fd);
+
+    qtest_quit(qts);
+}
+
+static void test_send_char(void)
+{
+    int sock_fd;
+    char s[1];
+    uint32_t cr1;
+    QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
+
+    init_uart(qts);
+
+    /* Try without initializing IRQ */
+    qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'c');
+    g_assert_true(recv(sock_fd, s, 1, 0) == 1);
+    g_assert_cmphex(s[0], ==, 'c');
+    g_assert_false(check_nvic_pending(qts, USART1_IRQ));
+
+    /* Now with the IRQ */
+    cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
+    cr1 |= R_CR1_TXEIE_MASK;
+    qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1);
+    qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'd');
+    g_assert_true(recv(sock_fd, s, 1, 0) == 1);
+    g_assert_cmphex(s[0], ==, 'd');
+    g_assert_true(check_nvic_pending(qts, USART1_IRQ));
+    clear_nvic_pending(qts, USART1_IRQ);
+
+    close(sock_fd);
+
+    qtest_quit(qts);
+}
+
+static void test_receive_str(void)
+{
+    int sock_fd;
+    char s[10];
+    QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
+
+    init_uart(qts);
+
+    usart_receive_string(qts, sock_fd, "hello", s);
+    g_assert_true(memcmp(s, "hello", 5) == 0);
+
+    close(sock_fd);
+
+    qtest_quit(qts);
+}
+
+static void test_send_str(void)
+{
+    int sock_fd;
+    char s[10];
+    QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
+
+    init_uart(qts);
+
+    usart_send_string(qts, "world");
+    g_assert_true(recv(sock_fd, s, 10, 0) == 5);
+    g_assert_true(memcmp(s, "world", 5) == 0);
+
+    close(sock_fd);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    g_test_set_nonfatal_assertions();
+
+    qtest_add_func("stm32l4x5/usart/write_read", test_write_read);
+    qtest_add_func("stm32l4x5/usart/receive_char", test_receive_char);
+    qtest_add_func("stm32l4x5/usart/send_char", test_send_char);
+    qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str);
+    qtest_add_func("stm32l4x5/usart/send_str", test_send_str);
+    ret = g_test_run();
+
+    return ret;
+}
+
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 36c5c13a7bb..b128fa5a4bd 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -7,6 +7,7 @@ slow_qtests = {
   'npcm7xx_pwm-test': 300,
   'npcm7xx_watchdog_timer-test': 120,
   'qom-test' : 900,
+  'stm32l4x5_usart-test' : 600,
   'test-hmp' : 240,
   'pxe-test': 610,
   'prom-env-test': 360,
@@ -205,7 +206,8 @@ qtests_stm32l4x5 = \
   ['stm32l4x5_exti-test',
    'stm32l4x5_syscfg-test',
    'stm32l4x5_rcc-test',
-   'stm32l4x5_gpio-test']
+   'stm32l4x5_gpio-test',
+   'stm32l4x5_usart-test']
 
 qtests_arm = \
   (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PULL 00/37] target-arm queue
  2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
                   ` (36 preceding siblings ...)
  2024-04-25 10:39 ` [PULL 37/37] tests/qtest: Add tests for the STM32L4x5 USART Peter Maydell
@ 2024-04-25 16:45 ` Richard Henderson
  37 siblings, 0 replies; 39+ messages in thread
From: Richard Henderson @ 2024-04-25 16:45 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel

On 4/25/24 03:39, Peter Maydell wrote:
> Hi; here's the first arm pullreq for 9.1.
> 
> This includes the reset method function signature change, so it has
> some chance of compile failures due to merge conflicts if some other
> pullreq added a device reset method and that pullreq got applied
> before this one.  If so, the changes needed to fix those up can be
> created by running the spatch rune described in the commit message of
> the "hw, target: Add ResetType argument to hold and exit phase
> methods" commit.
> 
> thanks
> -- PMM
> 
> The following changes since commit 5da72194df36535d773c8bdc951529ecd5e31707:
> 
>    Merge tag 'pull-tcg-20240424' ofhttps://gitlab.com/rth7680/qemu  into staging (2024-04-24 15:51:49 -0700)
> 
> are available in the Git repository at:
> 
>    https://git.linaro.org/people/pmaydell/qemu-arm.git  tags/pull-target-arm-20240425
> 
> for you to fetch changes up to 214652da123e3821657a64691ee556281e9f6238:
> 
>    tests/qtest: Add tests for the STM32L4x5 USART (2024-04-25 10:21:59 +0100)
> 
> ----------------------------------------------------------------
> target-arm queue:
>   * Implement FEAT_NMI and NMI support in the GICv3
>   * hw/dma: avoid apparent overflow in soc_dma_set_request
>   * linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code
>   * Add ResetType argument to Resettable hold and exit phase methods
>   * Add RESET_TYPE_SNAPSHOT_LOAD ResetType
>   * Implement STM32L4x5 USART

Applied, thanks.  Please update https://wiki.qemu.org/ChangeLog/9.1 as appropriate.


r~



^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2024-04-25 16:46 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-25 10:39 [PULL 00/37] target-arm queue Peter Maydell
2024-04-25 10:39 ` [PULL 01/37] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NMI Peter Maydell
2024-04-25 10:39 ` [PULL 02/37] target/arm: Add PSTATE.ALLINT Peter Maydell
2024-04-25 10:39 ` [PULL 03/37] target/arm: Add support for FEAT_NMI, Non-maskable Interrupt Peter Maydell
2024-04-25 10:39 ` [PULL 04/37] target/arm: Implement ALLINT MSR (immediate) Peter Maydell
2024-04-25 10:39 ` [PULL 05/37] target/arm: Support MSR access to ALLINT Peter Maydell
2024-04-25 10:39 ` [PULL 06/37] target/arm: Add support for Non-maskable Interrupt Peter Maydell
2024-04-25 10:39 ` [PULL 07/37] target/arm: Add support for NMI in arm_phys_excp_target_el() Peter Maydell
2024-04-25 10:39 ` [PULL 08/37] target/arm: Handle IS/FS in ISR_EL1 for NMI, VINMI and VFNMI Peter Maydell
2024-04-25 10:39 ` [PULL 09/37] target/arm: Handle PSTATE.ALLINT on taking an exception Peter Maydell
2024-04-25 10:39 ` [PULL 10/37] hw/intc/arm_gicv3: Add external IRQ lines for NMI Peter Maydell
2024-04-25 10:39 ` [PULL 11/37] hw/arm/virt: Wire NMI and VINMI irq lines from GIC to CPU Peter Maydell
2024-04-25 10:39 ` [PULL 12/37] target/arm: Handle NMI in arm_cpu_do_interrupt_aarch64() Peter Maydell
2024-04-25 10:39 ` [PULL 13/37] hw/intc/arm_gicv3: Add has-nmi property to GICv3 device Peter Maydell
2024-04-25 10:39 ` [PULL 14/37] hw/intc/arm_gicv3_kvm: Not set has-nmi=true for the KVM GICv3 Peter Maydell
2024-04-25 10:39 ` [PULL 15/37] hw/intc/arm_gicv3: Add irq non-maskable property Peter Maydell
2024-04-25 10:39 ` [PULL 16/37] hw/intc/arm_gicv3_redist: Implement GICR_INMIR0 Peter Maydell
2024-04-25 10:39 ` [PULL 17/37] hw/intc/arm_gicv3: Implement GICD_INMIR Peter Maydell
2024-04-25 10:39 ` [PULL 18/37] hw/intc/arm_gicv3: Add NMI handling CPU interface registers Peter Maydell
2024-04-25 10:39 ` [PULL 19/37] hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read() Peter Maydell
2024-04-25 10:39 ` [PULL 20/37] hw/intc/arm_gicv3: Implement NMI interrupt priority Peter Maydell
2024-04-25 10:39 ` [PULL 21/37] hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update() Peter Maydell
2024-04-25 10:39 ` [PULL 22/37] hw/intc/arm_gicv3: Report the VINMI interrupt Peter Maydell
2024-04-25 10:39 ` [PULL 23/37] target/arm: Add FEAT_NMI to max Peter Maydell
2024-04-25 10:39 ` [PULL 24/37] hw/arm/virt: Enable NMI support in the GIC if the CPU has FEAT_NMI Peter Maydell
2024-04-25 10:39 ` [PULL 25/37] hw/dma: avoid apparent overflow in soc_dma_set_request Peter Maydell
2024-04-25 10:39 ` [PULL 26/37] linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code Peter Maydell
2024-04-25 10:39 ` [PULL 27/37] hw/misc: Don't special case RESET_TYPE_COLD in npcm7xx_clk, gcr Peter Maydell
2024-04-25 10:39 ` [PULL 28/37] allwinner-i2c, adm1272: Use device_cold_reset() for software-triggered reset Peter Maydell
2024-04-25 10:39 ` [PULL 29/37] scripts/coccinelle: New script to add ResetType to hold and exit phases Peter Maydell
2024-04-25 10:39 ` [PULL 30/37] hw, target: Add ResetType argument to hold and exit phase methods Peter Maydell
2024-04-25 10:39 ` [PULL 31/37] docs/devel/reset: Update to new API for " Peter Maydell
2024-04-25 10:39 ` [PULL 32/37] reset: Add RESET_TYPE_SNAPSHOT_LOAD Peter Maydell
2024-04-25 10:39 ` [PULL 33/37] hw/char: Implement STM32L4x5 USART skeleton Peter Maydell
2024-04-25 10:39 ` [PULL 34/37] hw/char/stm32l4x5_usart: Enable serial read and write Peter Maydell
2024-04-25 10:39 ` [PULL 35/37] hw/char/stm32l4x5_usart: Add options for serial parameters setting Peter Maydell
2024-04-25 10:39 ` [PULL 36/37] hw/arm: Add the USART to the stm32l4x5 SoC Peter Maydell
2024-04-25 10:39 ` [PULL 37/37] tests/qtest: Add tests for the STM32L4x5 USART Peter Maydell
2024-04-25 16:45 ` [PULL 00/37] target-arm queue Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.