* [PULL 01/21] hw/arm/smmu-common: Remove the repeated ttb field
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 02/21] hw/gpio: npcm7xx: fixup out-of-bounds access Peter Maydell
` (20 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
From: JianChunfu <jansef.jian@hj-micro.com>
SMMUTransCfg->ttb is never used in QEMU, TT base address
can be accessed by SMMUTransCfg->tt[i]->ttb.
Signed-off-by: JianChunfu <jansef.jian@hj-micro.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Message-id: 20250221031034.69822-1-jansef.jian@hj-micro.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
include/hw/arm/smmu-common.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index d1a4a64551d..e5ad55bbae7 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -110,7 +110,6 @@ typedef struct SMMUTransCfg {
/* Used by stage-1 only. */
bool aa64; /* arch64 or aarch32 translation table */
bool record_faults; /* record fault events */
- uint64_t ttb; /* TT base address */
uint8_t oas; /* output address width */
uint8_t tbi; /* Top Byte Ignore */
int asid;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 02/21] hw/gpio: npcm7xx: fixup out-of-bounds access
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
2025-03-07 15:06 ` [PULL 01/21] hw/arm/smmu-common: Remove the repeated ttb field Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 03/21] tests/functional/test_arm_sx1: Check whether the serial console is working Peter Maydell
` (19 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
From: Patrick Venture <venture@google.com>
The reg isn't validated to be a possible register before
it's dereferenced for one case. The mmio space registered
for the gpio device is 4KiB but there aren't that many
registers in the struct.
Cc: qemu-stable@nongnu.org
Fixes: 526dbbe0874 ("hw/gpio: Add GPIO model for Nuvoton NPCM7xx")
Signed-off-by: Patrick Venture <venture@google.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20250226024603.493148-1-venture@google.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/gpio/npcm7xx_gpio.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c
index 23e67424c9f..2916056fae6 100644
--- a/hw/gpio/npcm7xx_gpio.c
+++ b/hw/gpio/npcm7xx_gpio.c
@@ -220,8 +220,6 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
return;
}
- diff = s->regs[reg] ^ value;
-
switch (reg) {
case NPCM7XX_GPIO_TLOCK1:
case NPCM7XX_GPIO_TLOCK2:
@@ -242,6 +240,7 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
case NPCM7XX_GPIO_PU:
case NPCM7XX_GPIO_PD:
case NPCM7XX_GPIO_IEM:
+ diff = s->regs[reg] ^ value;
s->regs[reg] = value;
npcm7xx_gpio_update_pins(s, diff);
break;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 03/21] tests/functional/test_arm_sx1: Check whether the serial console is working
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
2025-03-07 15:06 ` [PULL 01/21] hw/arm/smmu-common: Remove the repeated ttb field Peter Maydell
2025-03-07 15:06 ` [PULL 02/21] hw/gpio: npcm7xx: fixup out-of-bounds access Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 04/21] target/arm: Apply correct timer offset when calculating deadlines Peter Maydell
` (18 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
From: Thomas Huth <thuth@redhat.com>
The kernel that is used in the sx1 test prints the usual Linux log
onto the serial console, but this test currently ignores it. To
make sure that the serial device is working properly, let's check
for some strings in the output here.
While we're at it, also add the test to the corresponding section
in the MAINTAINERS file.
Signed-off-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20250226104833.1176253-1-thuth@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
MAINTAINERS | 1 +
tests/functional/test_arm_sx1.py | 7 ++++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 5df6020ed54..699cf59e0b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2010,6 +2010,7 @@ S: Maintained
F: hw/*/omap*
F: include/hw/arm/omap.h
F: docs/system/arm/sx1.rst
+F: tests/functional/test_arm_sx1.py
IPack
M: Alberto Garcia <berto@igalia.com>
diff --git a/tests/functional/test_arm_sx1.py b/tests/functional/test_arm_sx1.py
index 4dd1e1859fa..25800b388c9 100755
--- a/tests/functional/test_arm_sx1.py
+++ b/tests/functional/test_arm_sx1.py
@@ -43,7 +43,8 @@ def test_arm_sx1_initrd(self):
self.vm.add_args('-append', f'kunit.enable=0 rdinit=/sbin/init {self.CONSOLE_ARGS}')
self.vm.add_args('-no-reboot')
self.launch_kernel(zimage_path,
- initrd=initrd_path)
+ initrd=initrd_path,
+ wait_for='Boot successful')
self.vm.wait(timeout=120)
def test_arm_sx1_sd(self):
@@ -54,7 +55,7 @@ def test_arm_sx1_sd(self):
self.vm.add_args('-no-reboot')
self.vm.add_args('-snapshot')
self.vm.add_args('-drive', f'format=raw,if=sd,file={sd_fs_path}')
- self.launch_kernel(zimage_path)
+ self.launch_kernel(zimage_path, wait_for='Boot successful')
self.vm.wait(timeout=120)
def test_arm_sx1_flash(self):
@@ -65,7 +66,7 @@ def test_arm_sx1_flash(self):
self.vm.add_args('-no-reboot')
self.vm.add_args('-snapshot')
self.vm.add_args('-drive', f'format=raw,if=pflash,file={flash_path}')
- self.launch_kernel(zimage_path)
+ self.launch_kernel(zimage_path, wait_for='Boot successful')
self.vm.wait(timeout=120)
if __name__ == '__main__':
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 04/21] target/arm: Apply correct timer offset when calculating deadlines
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (2 preceding siblings ...)
2025-03-07 15:06 ` [PULL 03/21] tests/functional/test_arm_sx1: Check whether the serial console is working Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 05/21] target/arm: Don't apply CNTVOFF_EL2 for EL2_VIRT timer Peter Maydell
` (17 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
When we are calculating timer deadlines, the correct definition of
whether or not to apply an offset to the physical count is described
in the Arm ARM DDI4087 rev L.a section D12.2.4.1. This is different
from when the offset should be applied for a direct read of the
counter sysreg.
We got this right for the EL1 physical timer and for the EL1 virtual
timer, but got all the rest wrong: they should be using a zero offset
always.
Factor the offset calculation out into a function that has a comment
documenting exactly which offset it is calculating and which gets the
HYP, SEC, and HYPVIRT cases right.
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20250204125009.2281315-2-peter.maydell@linaro.org
---
target/arm/helper.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 71dead7241b..7f341d753cd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2460,6 +2460,32 @@ static uint64_t gt_phys_cnt_offset(CPUARMState *env)
return gt_phys_raw_cnt_offset(env);
}
+static uint64_t gt_indirect_access_timer_offset(CPUARMState *env, int timeridx)
+{
+ /*
+ * Return the timer offset to use for indirect accesses to the timer.
+ * This is the Offset value as defined in D12.2.4.1 "Operation of the
+ * CompareValue views of the timers".
+ *
+ * The condition here is not always the same as the condition for
+ * whether to apply an offset register when doing a direct read of
+ * the counter sysreg; those conditions are described in the
+ * access pseudocode for each counter register.
+ */
+ switch (timeridx) {
+ case GTIMER_PHYS:
+ return gt_phys_raw_cnt_offset(env);
+ case GTIMER_VIRT:
+ return env->cp15.cntvoff_el2;
+ case GTIMER_HYP:
+ case GTIMER_SEC:
+ case GTIMER_HYPVIRT:
+ return 0;
+ default:
+ g_assert_not_reached();
+ }
+}
+
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
{
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
@@ -2469,8 +2495,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
* Timer enabled: calculate and set current ISTATUS, irq, and
* reset timer to when ISTATUS next has to change
*/
- uint64_t offset = timeridx == GTIMER_VIRT ?
- cpu->env.cp15.cntvoff_el2 : gt_phys_raw_cnt_offset(&cpu->env);
+ uint64_t offset = gt_indirect_access_timer_offset(&cpu->env, timeridx);
uint64_t count = gt_get_countervalue(&cpu->env);
/* Note that this must be unsigned 64 bit arithmetic: */
int istatus = count - offset >= gt->cval;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 05/21] target/arm: Don't apply CNTVOFF_EL2 for EL2_VIRT timer
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (3 preceding siblings ...)
2025-03-07 15:06 ` [PULL 04/21] target/arm: Apply correct timer offset when calculating deadlines Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 06/21] target/arm: Make CNTPS_* UNDEF from Secure EL1 when Secure EL2 is enabled Peter Maydell
` (16 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
The CNTVOFF_EL2 offset register should only be applied for accessses
to CNTVCT_EL0 and for the EL1 virtual timer (CNTV_*). We were
incorrectly applying it for the EL2 virtual timer (CNTHV_*).
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20250204125009.2281315-3-peter.maydell@linaro.org
---
target/arm/helper.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7f341d753cd..5729b313f84 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2604,7 +2604,6 @@ static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
switch (timeridx) {
case GTIMER_VIRT:
- case GTIMER_HYPVIRT:
offset = gt_virt_cnt_offset(env);
break;
case GTIMER_PHYS:
@@ -2624,7 +2623,6 @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
switch (timeridx) {
case GTIMER_VIRT:
- case GTIMER_HYPVIRT:
offset = gt_virt_cnt_offset(env);
break;
case GTIMER_PHYS:
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 06/21] target/arm: Make CNTPS_* UNDEF from Secure EL1 when Secure EL2 is enabled
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (4 preceding siblings ...)
2025-03-07 15:06 ` [PULL 05/21] target/arm: Don't apply CNTVOFF_EL2 for EL2_VIRT timer Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 07/21] target/arm: Always apply CNTVOFF_EL2 for CNTV_TVAL_EL02 accesses Peter Maydell
` (15 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
When we added Secure EL2 support, we missed that this needs an update
to the access code for the EL3 physical timer registers. These are
supposed to UNDEF from Secure EL1 when Secure EL2 is enabled.
(Note for stable backporting: for backports to branches where
CP_ACCESS_UNDEFINED is not defined, the old name to use instead
is CP_ACCESS_TRAP_UNCATEGORIZED.)
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20250204125009.2281315-4-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 5729b313f84..5b6de446ace 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2387,6 +2387,9 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
if (!arm_is_secure(env)) {
return CP_ACCESS_UNDEFINED;
}
+ if (arm_is_el2_enabled(env)) {
+ return CP_ACCESS_UNDEFINED;
+ }
if (!(env->cp15.scr_el3 & SCR_ST)) {
return CP_ACCESS_TRAP_EL3;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 07/21] target/arm: Always apply CNTVOFF_EL2 for CNTV_TVAL_EL02 accesses
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (5 preceding siblings ...)
2025-03-07 15:06 ` [PULL 06/21] target/arm: Make CNTPS_* UNDEF from Secure EL1 when Secure EL2 is enabled Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 08/21] target/arm: Refactor handling of timer offset for direct register accesses Peter Maydell
` (14 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
Currently we handle CNTV_TVAL_EL02 by calling gt_tval_read() for the
EL1 virt timer. This is almost correct, but the underlying
CNTV_TVAL_EL0 register behaves slightly differently. CNTV_TVAL_EL02
always applies the CNTVOFF_EL2 offset; CNTV_TVAL_EL0 doesn't do so if
we're at EL2 and HCR_EL2.E2H is 1.
We were getting this wrong, because we ended up in
gt_virt_cnt_offset() and did the E2H check.
Factor out the tval read/write calculation from the selection of the
offset, so that we can special case gt_virt_tval_read() and
gt_virt_tval_write() to unconditionally pass CNTVOFF_EL2.
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20250204125009.2281315-5-peter.maydell@linaro.org
---
target/arm/helper.c | 36 +++++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5b6de446ace..acf77793c79 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2600,6 +2600,12 @@ static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
gt_recalc_timer(env_archcpu(env), timeridx);
}
+static uint64_t do_tval_read(CPUARMState *env, int timeridx, uint64_t offset)
+{
+ return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
+ (gt_get_countervalue(env) - offset));
+}
+
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx)
{
@@ -2614,8 +2620,16 @@ static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
break;
}
- return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
- (gt_get_countervalue(env) - offset));
+ return do_tval_read(env, timeridx, offset);
+}
+
+static void do_tval_write(CPUARMState *env, int timeridx, uint64_t value,
+ uint64_t offset)
+{
+ trace_arm_gt_tval_write(timeridx, value);
+ env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset +
+ sextract64(value, 0, 32);
+ gt_recalc_timer(env_archcpu(env), timeridx);
}
static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -2632,11 +2646,7 @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
offset = gt_phys_cnt_offset(env);
break;
}
-
- trace_arm_gt_tval_write(timeridx, value);
- env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset +
- sextract64(value, 0, 32);
- gt_recalc_timer(env_archcpu(env), timeridx);
+ do_tval_write(env, timeridx, value, offset);
}
static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -2768,13 +2778,21 @@ static void gt_virt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
static uint64_t gt_virt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
- return gt_tval_read(env, ri, GTIMER_VIRT);
+ /*
+ * This is CNTV_TVAL_EL02; unlike the underlying CNTV_TVAL_EL0
+ * we always apply CNTVOFF_EL2. Special case that here rather
+ * than going into the generic gt_tval_read() and then having
+ * to re-detect that it's this register.
+ * Note that the accessfn/perms mean we know we're at EL2 or EL3 here.
+ */
+ return do_tval_read(env, GTIMER_VIRT, env->cp15.cntvoff_el2);
}
static void gt_virt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
- gt_tval_write(env, ri, GTIMER_VIRT, value);
+ /* Similarly for writes to CNTV_TVAL_EL02 */
+ do_tval_write(env, GTIMER_VIRT, value, env->cp15.cntvoff_el2);
}
static void gt_virt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 08/21] target/arm: Refactor handling of timer offset for direct register accesses
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (6 preceding siblings ...)
2025-03-07 15:06 ` [PULL 07/21] target/arm: Always apply CNTVOFF_EL2 for CNTV_TVAL_EL02 accesses Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 09/21] target/arm: Implement SEL2 physical and virtual timers Peter Maydell
` (13 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
When reading or writing the timer registers, sometimes we need to
apply one of the timer offsets. Specifically, this happens for
direct reads of the counter registers CNTPCT_EL0 and CNTVCT_EL0 (and
their self-synchronized variants CNTVCTSS_EL0 and CNTPCTSS_EL0). It
also applies for direct reads and writes of the CNT*_TVAL_EL*
registers that provide the 32-bit downcounting view of each timer.
We currently do this with duplicated code in gt_tval_read() and
gt_tval_write() and a special-case in gt_virt_cnt_read() and
gt_cnt_read(). Refactor this so that we handle it all in a single
function gt_direct_access_timer_offset(), to parallel how we handle
the offset for indirect accesses.
The call in the WFIT helper previously to gt_virt_cnt_offset() is
now to gt_direct_access_timer_offset(); this is the correct
behaviour, but it's not immediately obvious that it shouldn't be
considered an indirect access, so we add an explanatory comment.
This commit should make no behavioural changes.
(Cc to stable because the following bugfix commit will
depend on this one.)
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20250204125009.2281315-6-peter.maydell@linaro.org
---
target/arm/internals.h | 5 +-
target/arm/helper.c | 103 +++++++++++++++++++------------------
target/arm/tcg/op_helper.c | 8 ++-
3 files changed, 62 insertions(+), 54 deletions(-)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index a6ff228f9fd..bb962389192 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1819,9 +1819,10 @@ int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type);
uint64_t gt_get_countervalue(CPUARMState *env);
/*
* Return the currently applicable offset between the system counter
- * and CNTVCT_EL0 (this will be either 0 or the value of CNTVOFF_EL2).
+ * and the counter for the specified timer, as used for direct register
+ * accesses.
*/
-uint64_t gt_virt_cnt_offset(CPUARMState *env);
+uint64_t gt_direct_access_timer_offset(CPUARMState *env, int timeridx);
/*
* Return mask of ARMMMUIdxBit values corresponding to an "invalidate
diff --git a/target/arm/helper.c b/target/arm/helper.c
index acf77793c79..54147d97611 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2455,14 +2455,6 @@ static uint64_t gt_phys_raw_cnt_offset(CPUARMState *env)
return 0;
}
-static uint64_t gt_phys_cnt_offset(CPUARMState *env)
-{
- if (arm_current_el(env) >= 2) {
- return 0;
- }
- return gt_phys_raw_cnt_offset(env);
-}
-
static uint64_t gt_indirect_access_timer_offset(CPUARMState *env, int timeridx)
{
/*
@@ -2489,6 +2481,52 @@ static uint64_t gt_indirect_access_timer_offset(CPUARMState *env, int timeridx)
}
}
+uint64_t gt_direct_access_timer_offset(CPUARMState *env, int timeridx)
+{
+ /*
+ * Return the timer offset to use for direct accesses to the
+ * counter registers CNTPCT and CNTVCT, and for direct accesses
+ * to the CNT*_TVAL registers.
+ *
+ * This isn't exactly the same as the indirect-access offset,
+ * because here we also care about what EL the register access
+ * is being made from.
+ *
+ * This corresponds to the access pseudocode for the registers.
+ */
+ uint64_t hcr;
+
+ switch (timeridx) {
+ case GTIMER_PHYS:
+ if (arm_current_el(env) >= 2) {
+ return 0;
+ }
+ return gt_phys_raw_cnt_offset(env);
+ case GTIMER_VIRT:
+ switch (arm_current_el(env)) {
+ case 2:
+ hcr = arm_hcr_el2_eff(env);
+ if (hcr & HCR_E2H) {
+ return 0;
+ }
+ break;
+ case 0:
+ hcr = arm_hcr_el2_eff(env);
+ if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
+ return 0;
+ }
+ break;
+ }
+ return env->cp15.cntvoff_el2;
+ case GTIMER_HYP:
+ case GTIMER_SEC:
+ case GTIMER_HYPVIRT:
+ return 0;
+ default:
+ g_assert_not_reached();
+ }
+}
+
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
{
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
@@ -2561,34 +2599,14 @@ static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
- return gt_get_countervalue(env) - gt_phys_cnt_offset(env);
-}
-
-uint64_t gt_virt_cnt_offset(CPUARMState *env)
-{
- uint64_t hcr;
-
- switch (arm_current_el(env)) {
- case 2:
- hcr = arm_hcr_el2_eff(env);
- if (hcr & HCR_E2H) {
- return 0;
- }
- break;
- case 0:
- hcr = arm_hcr_el2_eff(env);
- if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
- return 0;
- }
- break;
- }
-
- return env->cp15.cntvoff_el2;
+ uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_PHYS);
+ return gt_get_countervalue(env) - offset;
}
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
- return gt_get_countervalue(env) - gt_virt_cnt_offset(env);
+ uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
+ return gt_get_countervalue(env) - offset;
}
static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -2609,16 +2627,7 @@ static uint64_t do_tval_read(CPUARMState *env, int timeridx, uint64_t offset)
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx)
{
- uint64_t offset = 0;
-
- switch (timeridx) {
- case GTIMER_VIRT:
- offset = gt_virt_cnt_offset(env);
- break;
- case GTIMER_PHYS:
- offset = gt_phys_cnt_offset(env);
- break;
- }
+ uint64_t offset = gt_direct_access_timer_offset(env, timeridx);
return do_tval_read(env, timeridx, offset);
}
@@ -2636,16 +2645,8 @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx,
uint64_t value)
{
- uint64_t offset = 0;
+ uint64_t offset = gt_direct_access_timer_offset(env, timeridx);
- switch (timeridx) {
- case GTIMER_VIRT:
- offset = gt_virt_cnt_offset(env);
- break;
- case GTIMER_PHYS:
- offset = gt_phys_cnt_offset(env);
- break;
- }
do_tval_write(env, timeridx, value, offset);
}
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index 02c375d196d..30786fd1ff4 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -427,7 +427,13 @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
int target_el = check_wfx_trap(env, false, &excp);
/* The WFIT should time out when CNTVCT_EL0 >= the specified value. */
uint64_t cntval = gt_get_countervalue(env);
- uint64_t offset = gt_virt_cnt_offset(env);
+ /*
+ * We want the value that we would get if we read CNTVCT_EL0 from
+ * the current exception level, so the direct_access offset, not
+ * the indirect_access one. Compare the pseudocode LocalTimeoutEvent(),
+ * which calls VirtualCounterTimer().
+ */
+ uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
uint64_t cntvct = cntval - offset;
uint64_t nexttick;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 09/21] target/arm: Implement SEL2 physical and virtual timers
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (7 preceding siblings ...)
2025-03-07 15:06 ` [PULL 08/21] target/arm: Refactor handling of timer offset for direct register accesses Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 10/21] target/arm: Document the architectural names of our GTIMERs Peter Maydell
` (12 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
When FEAT_SEL2 was implemented the SEL2 timers were missed. This
shows up when building the latest Hafnium with SPMC_AT_EL=2. The
actual implementation utilises the same logic as the rest of the
timers so all we need to do is:
- define the timers and their access functions
- conditionally add the correct system registers
- create a new accessfn as the rules are subtly different to the
existing secure timer
Fixes: e9152ee91c (target/arm: add ARMv8.4-SEL2 system registers)
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20250204125009.2281315-7-peter.maydell@linaro.org
Cc: qemu-stable@nongnu.org
Cc: Andrei Homescu <ahomescu@google.com>
Cc: Arve Hjønnevåg <arve@google.com>
Cc: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
[PMM: CP_ACCESS_TRAP_UNCATEGORIZED -> CP_ACCESS_UNDEFINED;
offset logic now in gt_{indirect,direct}_access_timer_offset() ]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
include/hw/arm/bsa.h | 2 +
target/arm/cpu.h | 2 +
target/arm/gtimer.h | 4 +-
target/arm/cpu.c | 4 ++
target/arm/helper.c | 163 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 174 insertions(+), 1 deletion(-)
diff --git a/include/hw/arm/bsa.h b/include/hw/arm/bsa.h
index 8eaab603c03..13ed2d2ac19 100644
--- a/include/hw/arm/bsa.h
+++ b/include/hw/arm/bsa.h
@@ -22,6 +22,8 @@
#define QEMU_ARM_BSA_H
/* These are architectural INTID values */
+#define ARCH_TIMER_S_EL2_VIRT_IRQ 19
+#define ARCH_TIMER_S_EL2_IRQ 20
#define VIRTUAL_PMU_IRQ 23
#define ARCH_GIC_MAINT_IRQ 25
#define ARCH_TIMER_NS_EL2_IRQ 26
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 215845c7e25..8f52380c88c 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1171,6 +1171,8 @@ void arm_gt_vtimer_cb(void *opaque);
void arm_gt_htimer_cb(void *opaque);
void arm_gt_stimer_cb(void *opaque);
void arm_gt_hvtimer_cb(void *opaque);
+void arm_gt_sel2timer_cb(void *opaque);
+void arm_gt_sel2vtimer_cb(void *opaque);
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
void gt_rme_post_el_change(ARMCPU *cpu, void *opaque);
diff --git a/target/arm/gtimer.h b/target/arm/gtimer.h
index b992941bef1..0e89b8e58d0 100644
--- a/target/arm/gtimer.h
+++ b/target/arm/gtimer.h
@@ -15,7 +15,9 @@ enum {
GTIMER_HYP = 2,
GTIMER_SEC = 3,
GTIMER_HYPVIRT = 4,
-#define NUM_GTIMERS 5
+ GTIMER_S_EL2_PHYS = 5, /* CNTHPS_* ; only if FEAT_SEL2 */
+ GTIMER_S_EL2_VIRT = 6, /* CNTHVS_* ; only if FEAT_SEL2 */
+#define NUM_GTIMERS 7
};
#endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 948defa3f5d..cacbbc615a2 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2069,6 +2069,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
arm_gt_stimer_cb, cpu);
cpu->gt_timer[GTIMER_HYPVIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
arm_gt_hvtimer_cb, cpu);
+ cpu->gt_timer[GTIMER_S_EL2_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_sel2timer_cb, cpu);
+ cpu->gt_timer[GTIMER_S_EL2_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_sel2vtimer_cb, cpu);
}
#endif
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 54147d97611..407efe9427c 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2404,6 +2404,45 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
}
}
+static CPAccessResult gt_sel2timer_access(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /*
+ * The AArch64 register view of the secure EL2 timers are mostly
+ * accessible from EL3 and EL2 although can also be trapped to EL2
+ * from EL1 depending on nested virt config.
+ */
+ switch (arm_current_el(env)) {
+ case 0: /* UNDEFINED */
+ return CP_ACCESS_UNDEFINED;
+ case 1:
+ if (!arm_is_secure(env)) {
+ /* UNDEFINED */
+ return CP_ACCESS_UNDEFINED;
+ } else if (arm_hcr_el2_eff(env) & HCR_NV) {
+ /* Aarch64.SystemAccessTrap(EL2, 0x18) */
+ return CP_ACCESS_TRAP_EL2;
+ }
+ /* UNDEFINED */
+ return CP_ACCESS_UNDEFINED;
+ case 2:
+ if (!arm_is_secure(env)) {
+ /* UNDEFINED */
+ return CP_ACCESS_UNDEFINED;
+ }
+ return CP_ACCESS_OK;
+ case 3:
+ if (env->cp15.scr_el3 & SCR_EEL2) {
+ return CP_ACCESS_OK;
+ } else {
+ return CP_ACCESS_UNDEFINED;
+ }
+ default:
+ g_assert_not_reached();
+ }
+}
+
uint64_t gt_get_countervalue(CPUARMState *env)
{
ARMCPU *cpu = env_archcpu(env);
@@ -2475,6 +2514,8 @@ static uint64_t gt_indirect_access_timer_offset(CPUARMState *env, int timeridx)
case GTIMER_HYP:
case GTIMER_SEC:
case GTIMER_HYPVIRT:
+ case GTIMER_S_EL2_PHYS:
+ case GTIMER_S_EL2_VIRT:
return 0;
default:
g_assert_not_reached();
@@ -2521,6 +2562,8 @@ uint64_t gt_direct_access_timer_offset(CPUARMState *env, int timeridx)
case GTIMER_HYP:
case GTIMER_SEC:
case GTIMER_HYPVIRT:
+ case GTIMER_S_EL2_PHYS:
+ case GTIMER_S_EL2_VIRT:
return 0;
default:
g_assert_not_reached();
@@ -2953,6 +2996,62 @@ static void gt_sec_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
gt_ctl_write(env, ri, GTIMER_SEC, value);
}
+static void gt_sec_pel2_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ gt_timer_reset(env, ri, GTIMER_S_EL2_PHYS);
+}
+
+static void gt_sec_pel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_cval_write(env, ri, GTIMER_S_EL2_PHYS, value);
+}
+
+static uint64_t gt_sec_pel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return gt_tval_read(env, ri, GTIMER_S_EL2_PHYS);
+}
+
+static void gt_sec_pel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_tval_write(env, ri, GTIMER_S_EL2_PHYS, value);
+}
+
+static void gt_sec_pel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_ctl_write(env, ri, GTIMER_S_EL2_PHYS, value);
+}
+
+static void gt_sec_vel2_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ gt_timer_reset(env, ri, GTIMER_S_EL2_VIRT);
+}
+
+static void gt_sec_vel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_cval_write(env, ri, GTIMER_S_EL2_VIRT, value);
+}
+
+static uint64_t gt_sec_vel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return gt_tval_read(env, ri, GTIMER_S_EL2_VIRT);
+}
+
+static void gt_sec_vel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_tval_write(env, ri, GTIMER_S_EL2_VIRT, value);
+}
+
+static void gt_sec_vel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_ctl_write(env, ri, GTIMER_S_EL2_VIRT, value);
+}
+
static void gt_hv_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
gt_timer_reset(env, ri, GTIMER_HYPVIRT);
@@ -3009,6 +3108,20 @@ void arm_gt_stimer_cb(void *opaque)
gt_recalc_timer(cpu, GTIMER_SEC);
}
+void arm_gt_sel2timer_cb(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+
+ gt_recalc_timer(cpu, GTIMER_S_EL2_PHYS);
+}
+
+void arm_gt_sel2vtimer_cb(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+
+ gt_recalc_timer(cpu, GTIMER_S_EL2_VIRT);
+}
+
void arm_gt_hvtimer_cb(void *opaque)
{
ARMCPU *cpu = opaque;
@@ -5733,6 +5846,56 @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = {
.access = PL2_RW, .accessfn = sel2_access,
.nv2_redirect_offset = 0x48,
.fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) },
+#ifndef CONFIG_USER_ONLY
+ /* Secure EL2 Physical Timer */
+ { .name = "CNTHPS_TVAL_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 0,
+ .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL2_RW,
+ .accessfn = gt_sel2timer_access,
+ .readfn = gt_sec_pel2_tval_read,
+ .writefn = gt_sec_pel2_tval_write,
+ .resetfn = gt_sec_pel2_timer_reset,
+ },
+ { .name = "CNTHPS_CTL_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 1,
+ .type = ARM_CP_IO, .access = PL2_RW,
+ .accessfn = gt_sel2timer_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_PHYS].ctl),
+ .resetvalue = 0,
+ .writefn = gt_sec_pel2_ctl_write, .raw_writefn = raw_write,
+ },
+ { .name = "CNTHPS_CVAL_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 2,
+ .type = ARM_CP_IO, .access = PL2_RW,
+ .accessfn = gt_sel2timer_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_PHYS].cval),
+ .writefn = gt_sec_pel2_cval_write, .raw_writefn = raw_write,
+ },
+ /* Secure EL2 Virtual Timer */
+ { .name = "CNTHVS_TVAL_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 0,
+ .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL2_RW,
+ .accessfn = gt_sel2timer_access,
+ .readfn = gt_sec_vel2_tval_read,
+ .writefn = gt_sec_vel2_tval_write,
+ .resetfn = gt_sec_vel2_timer_reset,
+ },
+ { .name = "CNTHVS_CTL_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 1,
+ .type = ARM_CP_IO, .access = PL2_RW,
+ .accessfn = gt_sel2timer_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_VIRT].ctl),
+ .resetvalue = 0,
+ .writefn = gt_sec_vel2_ctl_write, .raw_writefn = raw_write,
+ },
+ { .name = "CNTHVS_CVAL_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 2,
+ .type = ARM_CP_IO, .access = PL2_RW,
+ .accessfn = gt_sel2timer_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_VIRT].cval),
+ .writefn = gt_sec_vel2_cval_write, .raw_writefn = raw_write,
+ },
+#endif
};
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 10/21] target/arm: Document the architectural names of our GTIMERs
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (8 preceding siblings ...)
2025-03-07 15:06 ` [PULL 09/21] target/arm: Implement SEL2 physical and virtual timers Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 11/21] hw/arm: enable secure EL2 timers for virt machine Peter Maydell
` (11 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
As we are about to add more physical and virtual timers let's make it
clear what each timer does.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20250204125009.2281315-8-peter.maydell@linaro.org
[PMM: Add timer register name prefix to each comment]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target/arm/gtimer.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/target/arm/gtimer.h b/target/arm/gtimer.h
index 0e89b8e58d0..d49c63cbf87 100644
--- a/target/arm/gtimer.h
+++ b/target/arm/gtimer.h
@@ -10,11 +10,11 @@
#define TARGET_ARM_GTIMER_H
enum {
- GTIMER_PHYS = 0,
- GTIMER_VIRT = 1,
- GTIMER_HYP = 2,
- GTIMER_SEC = 3,
- GTIMER_HYPVIRT = 4,
+ GTIMER_PHYS = 0, /* CNTP_* ; EL1 physical timer */
+ GTIMER_VIRT = 1, /* CNTV_* ; EL1 virtual timer */
+ GTIMER_HYP = 2, /* CNTHP_* ; EL2 physical timer */
+ GTIMER_SEC = 3, /* CNTPS_* ; EL3 physical timer */
+ GTIMER_HYPVIRT = 4, /* CNTHV_* ; EL2 virtual timer ; only if FEAT_VHE */
GTIMER_S_EL2_PHYS = 5, /* CNTHPS_* ; only if FEAT_SEL2 */
GTIMER_S_EL2_VIRT = 6, /* CNTHVS_* ; only if FEAT_SEL2 */
#define NUM_GTIMERS 7
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 11/21] hw/arm: enable secure EL2 timers for virt machine
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (9 preceding siblings ...)
2025-03-07 15:06 ` [PULL 10/21] target/arm: Document the architectural names of our GTIMERs Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:06 ` [PULL 12/21] hw/arm: enable secure EL2 timers for sbsa machine Peter Maydell
` (10 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20250204125009.2281315-9-peter.maydell@linaro.org
Cc: qemu-stable@nongnu.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 904c698b140..a96452f17a4 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -882,6 +882,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
[GTIMER_HYPVIRT] = ARCH_TIMER_NS_EL2_VIRT_IRQ,
+ [GTIMER_S_EL2_PHYS] = ARCH_TIMER_S_EL2_IRQ,
+ [GTIMER_S_EL2_VIRT] = ARCH_TIMER_S_EL2_VIRT_IRQ,
};
for (unsigned irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 12/21] hw/arm: enable secure EL2 timers for sbsa machine
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (10 preceding siblings ...)
2025-03-07 15:06 ` [PULL 11/21] hw/arm: enable secure EL2 timers for virt machine Peter Maydell
@ 2025-03-07 15:06 ` Peter Maydell
2025-03-07 15:07 ` [PULL 13/21] target/arm: Correct LDRD atomicity and fault behaviour Peter Maydell
` (9 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:06 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20250204125009.2281315-10-peter.maydell@linaro.org
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/sbsa-ref.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index e720de30641..aa09d7a0917 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -484,6 +484,8 @@ static void create_gic(SBSAMachineState *sms, MemoryRegion *mem)
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
[GTIMER_HYPVIRT] = ARCH_TIMER_NS_EL2_VIRT_IRQ,
+ [GTIMER_S_EL2_PHYS] = ARCH_TIMER_S_EL2_IRQ,
+ [GTIMER_S_EL2_VIRT] = ARCH_TIMER_S_EL2_VIRT_IRQ,
};
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 13/21] target/arm: Correct LDRD atomicity and fault behaviour
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (11 preceding siblings ...)
2025-03-07 15:06 ` [PULL 12/21] hw/arm: enable secure EL2 timers for sbsa machine Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 14/21] target/arm: Correct STRD atomicity Peter Maydell
` (8 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
Our LDRD implementation is wrong in two respects:
* if the address is 4-aligned and the load crosses a page boundary
and the second load faults and the first load was to the
base register (as in cases like "ldrd r2, r3, [r2]", then we
must not update the base register before taking the fault
* if the address is 8-aligned the access must be a 64-bit
single-copy atomic access, not two 32-bit accesses
Rewrite the handling of the loads in LDRD to use a single
tcg_gen_qemu_ld_i64() and split the result into the destination
registers. This allows us to get the atomicity requirements
right, and also implicitly means that we won't update the
base register too early for the page-crossing case.
Note that because we no longer increment 'addr' by 4 in the course of
performing the LDRD we must change the adjustment value we pass to
op_addr_ri_post() and op_addr_rr_post(): it no longer needs to
subtract 4 to get the correct value to use if doing base register
writeback.
STRD has the same problem with not getting the atomicity right;
we will deal with that in the following commit.
Cc: qemu-stable@nongnu.org
Reported-by: Stu Grossman <stu.grossman@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20250227142746.1698904-2-peter.maydell@linaro.org
---
target/arm/tcg/translate.c | 70 +++++++++++++++++++++++++-------------
1 file changed, 46 insertions(+), 24 deletions(-)
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index d8225b77c8c..93772da39a4 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -5003,10 +5003,49 @@ static bool op_store_rr(DisasContext *s, arg_ldst_rr *a,
return true;
}
+static void do_ldrd_load(DisasContext *s, TCGv_i32 addr, int rt, int rt2)
+{
+ /*
+ * LDRD is required to be an atomic 64-bit access if the
+ * address is 8-aligned, two atomic 32-bit accesses if
+ * it's only 4-aligned, and to give an alignment fault
+ * if it's not 4-aligned. This is MO_ALIGN_4 | MO_ATOM_SUBALIGN.
+ * Rt is always the word from the lower address, and Rt2 the
+ * data from the higher address, regardless of endianness.
+ * So (like gen_load_exclusive) we avoid gen_aa32_ld_i64()
+ * so we don't get its SCTLR_B check, and instead do a 64-bit access
+ * using MO_BE if appropriate and then split the two halves.
+ *
+ * For M-profile, and for A-profile before LPAE, the 64-bit
+ * atomicity is not required. We could model that using
+ * the looser MO_ATOM_IFALIGN_PAIR, but providing a higher
+ * level of atomicity than required is harmless (we would not
+ * currently generate better code for IFALIGN_PAIR here).
+ *
+ * This also gives us the correct behaviour of not updating
+ * rt if the load of rt2 faults; this is required for cases
+ * like "ldrd r2, r3, [r2]" where rt is also the base register.
+ */
+ int mem_idx = get_mem_index(s);
+ MemOp opc = MO_64 | MO_ALIGN_4 | MO_ATOM_SUBALIGN | s->be_data;
+ TCGv taddr = gen_aa32_addr(s, addr, opc);
+ TCGv_i64 t64 = tcg_temp_new_i64();
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ TCGv_i32 tmp2 = tcg_temp_new_i32();
+
+ tcg_gen_qemu_ld_i64(t64, taddr, mem_idx, opc);
+ if (s->be_data == MO_BE) {
+ tcg_gen_extr_i64_i32(tmp2, tmp, t64);
+ } else {
+ tcg_gen_extr_i64_i32(tmp, tmp2, t64);
+ }
+ store_reg(s, rt, tmp);
+ store_reg(s, rt2, tmp2);
+}
+
static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
{
- int mem_idx = get_mem_index(s);
- TCGv_i32 addr, tmp;
+ TCGv_i32 addr;
if (!ENABLE_ARCH_5TE) {
return false;
@@ -5017,18 +5056,10 @@ static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
}
addr = op_addr_rr_pre(s, a);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, a->rt, tmp);
-
- tcg_gen_addi_i32(addr, addr, 4);
-
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, a->rt + 1, tmp);
+ do_ldrd_load(s, addr, a->rt, a->rt + 1);
/* LDRD w/ base writeback is undefined if the registers overlap. */
- op_addr_rr_post(s, a, addr, -4);
+ op_addr_rr_post(s, a, addr, 0);
return true;
}
@@ -5152,23 +5183,14 @@ static bool op_store_ri(DisasContext *s, arg_ldst_ri *a,
static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
{
- int mem_idx = get_mem_index(s);
- TCGv_i32 addr, tmp;
+ TCGv_i32 addr;
addr = op_addr_ri_pre(s, a);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, a->rt, tmp);
-
- tcg_gen_addi_i32(addr, addr, 4);
-
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, rt2, tmp);
+ do_ldrd_load(s, addr, a->rt, rt2);
/* LDRD w/ base writeback is undefined if the registers overlap. */
- op_addr_ri_post(s, a, addr, -4);
+ op_addr_ri_post(s, a, addr, 0);
return true;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 14/21] target/arm: Correct STRD atomicity
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (12 preceding siblings ...)
2025-03-07 15:07 ` [PULL 13/21] target/arm: Correct LDRD atomicity and fault behaviour Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 15/21] target/arm: Drop unused address_offset from op_addr_{rr, ri}_post() Peter Maydell
` (7 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
Our STRD implementation doesn't correctly implement the requirement:
* if the address is 8-aligned the access must be a 64-bit
single-copy atomic access, not two 32-bit accesses
Rewrite the handling of STRD to use a single tcg_gen_qemu_st_i64()
of a value produced by concatenating the two 32 bit source registers.
This allows us to get the atomicity right.
As with the LDRD change, now that we don't update 'addr' in the
course of performing the store we need to adjust the offset
we pass to op_addr_ri_post() and op_addr_rr_post().
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20250227142746.1698904-3-peter.maydell@linaro.org
---
target/arm/tcg/translate.c | 59 +++++++++++++++++++++++++-------------
1 file changed, 39 insertions(+), 20 deletions(-)
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index 93772da39a4..404a254678a 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -5063,10 +5063,42 @@ static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
return true;
}
+static void do_strd_store(DisasContext *s, TCGv_i32 addr, int rt, int rt2)
+{
+ /*
+ * STRD is required to be an atomic 64-bit access if the
+ * address is 8-aligned, two atomic 32-bit accesses if
+ * it's only 4-aligned, and to give an alignment fault
+ * if it's not 4-aligned.
+ * Rt is always the word from the lower address, and Rt2 the
+ * data from the higher address, regardless of endianness.
+ * So (like gen_store_exclusive) we avoid gen_aa32_ld_i64()
+ * so we don't get its SCTLR_B check, and instead do a 64-bit access
+ * using MO_BE if appropriate, using a value constructed
+ * by putting the two halves together in the right order.
+ *
+ * As with LDRD, the 64-bit atomicity is not required for
+ * M-profile, or for A-profile before LPAE, and we provide
+ * the higher guarantee always for simplicity.
+ */
+ int mem_idx = get_mem_index(s);
+ MemOp opc = MO_64 | MO_ALIGN_4 | MO_ATOM_SUBALIGN | s->be_data;
+ TCGv taddr = gen_aa32_addr(s, addr, opc);
+ TCGv_i32 t1 = load_reg(s, rt);
+ TCGv_i32 t2 = load_reg(s, rt2);
+ TCGv_i64 t64 = tcg_temp_new_i64();
+
+ if (s->be_data == MO_BE) {
+ tcg_gen_concat_i32_i64(t64, t2, t1);
+ } else {
+ tcg_gen_concat_i32_i64(t64, t1, t2);
+ }
+ tcg_gen_qemu_st_i64(t64, taddr, mem_idx, opc);
+}
+
static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a)
{
- int mem_idx = get_mem_index(s);
- TCGv_i32 addr, tmp;
+ TCGv_i32 addr;
if (!ENABLE_ARCH_5TE) {
return false;
@@ -5077,15 +5109,9 @@ static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a)
}
addr = op_addr_rr_pre(s, a);
- tmp = load_reg(s, a->rt);
- gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
+ do_strd_store(s, addr, a->rt, a->rt + 1);
- tcg_gen_addi_i32(addr, addr, 4);
-
- tmp = load_reg(s, a->rt + 1);
- gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
-
- op_addr_rr_post(s, a, addr, -4);
+ op_addr_rr_post(s, a, addr, 0);
return true;
}
@@ -5213,20 +5239,13 @@ static bool trans_LDRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a)
static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
{
- int mem_idx = get_mem_index(s);
- TCGv_i32 addr, tmp;
+ TCGv_i32 addr;
addr = op_addr_ri_pre(s, a);
- tmp = load_reg(s, a->rt);
- gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
+ do_strd_store(s, addr, a->rt, rt2);
- tcg_gen_addi_i32(addr, addr, 4);
-
- tmp = load_reg(s, rt2);
- gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
-
- op_addr_ri_post(s, a, addr, -4);
+ op_addr_ri_post(s, a, addr, 0);
return true;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 15/21] target/arm: Drop unused address_offset from op_addr_{rr, ri}_post()
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (13 preceding siblings ...)
2025-03-07 15:07 ` [PULL 14/21] target/arm: Correct STRD atomicity Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 16/21] target/arm: Make dummy debug registers RAZ, not NOP Peter Maydell
` (6 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
All the callers of op_addr_rr_post() and op_addr_ri_post() now pass in
zero for the address_offset, so we can remove that 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>
Message-id: 20250227142746.1698904-4-peter.maydell@linaro.org
---
target/arm/tcg/translate.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index 404a254678a..d2800181388 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -4941,7 +4941,7 @@ static TCGv_i32 op_addr_rr_pre(DisasContext *s, arg_ldst_rr *a)
}
static void op_addr_rr_post(DisasContext *s, arg_ldst_rr *a,
- TCGv_i32 addr, int address_offset)
+ TCGv_i32 addr)
{
if (!a->p) {
TCGv_i32 ofs = load_reg(s, a->rm);
@@ -4954,7 +4954,6 @@ static void op_addr_rr_post(DisasContext *s, arg_ldst_rr *a,
} else if (!a->w) {
return;
}
- tcg_gen_addi_i32(addr, addr, address_offset);
store_reg(s, a->rn, addr);
}
@@ -4974,7 +4973,7 @@ static bool op_load_rr(DisasContext *s, arg_ldst_rr *a,
* Perform base writeback before the loaded value to
* ensure correct behavior with overlapping index registers.
*/
- op_addr_rr_post(s, a, addr, 0);
+ op_addr_rr_post(s, a, addr);
store_reg_from_load(s, a->rt, tmp);
return true;
}
@@ -4999,7 +4998,7 @@ static bool op_store_rr(DisasContext *s, arg_ldst_rr *a,
gen_aa32_st_i32(s, tmp, addr, mem_idx, mop);
disas_set_da_iss(s, mop, issinfo);
- op_addr_rr_post(s, a, addr, 0);
+ op_addr_rr_post(s, a, addr);
return true;
}
@@ -5059,7 +5058,7 @@ static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
do_ldrd_load(s, addr, a->rt, a->rt + 1);
/* LDRD w/ base writeback is undefined if the registers overlap. */
- op_addr_rr_post(s, a, addr, 0);
+ op_addr_rr_post(s, a, addr);
return true;
}
@@ -5111,7 +5110,7 @@ static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a)
do_strd_store(s, addr, a->rt, a->rt + 1);
- op_addr_rr_post(s, a, addr, 0);
+ op_addr_rr_post(s, a, addr);
return true;
}
@@ -5147,13 +5146,14 @@ static TCGv_i32 op_addr_ri_pre(DisasContext *s, arg_ldst_ri *a)
}
static void op_addr_ri_post(DisasContext *s, arg_ldst_ri *a,
- TCGv_i32 addr, int address_offset)
+ TCGv_i32 addr)
{
+ int address_offset = 0;
if (!a->p) {
if (a->u) {
- address_offset += a->imm;
+ address_offset = a->imm;
} else {
- address_offset -= a->imm;
+ address_offset = -a->imm;
}
} else if (!a->w) {
return;
@@ -5178,7 +5178,7 @@ static bool op_load_ri(DisasContext *s, arg_ldst_ri *a,
* Perform base writeback before the loaded value to
* ensure correct behavior with overlapping index registers.
*/
- op_addr_ri_post(s, a, addr, 0);
+ op_addr_ri_post(s, a, addr);
store_reg_from_load(s, a->rt, tmp);
return true;
}
@@ -5203,7 +5203,7 @@ static bool op_store_ri(DisasContext *s, arg_ldst_ri *a,
gen_aa32_st_i32(s, tmp, addr, mem_idx, mop);
disas_set_da_iss(s, mop, issinfo);
- op_addr_ri_post(s, a, addr, 0);
+ op_addr_ri_post(s, a, addr);
return true;
}
@@ -5216,7 +5216,7 @@ static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
do_ldrd_load(s, addr, a->rt, rt2);
/* LDRD w/ base writeback is undefined if the registers overlap. */
- op_addr_ri_post(s, a, addr, 0);
+ op_addr_ri_post(s, a, addr);
return true;
}
@@ -5245,7 +5245,7 @@ static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
do_strd_store(s, addr, a->rt, rt2);
- op_addr_ri_post(s, a, addr, 0);
+ op_addr_ri_post(s, a, addr);
return true;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 16/21] target/arm: Make dummy debug registers RAZ, not NOP
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (14 preceding siblings ...)
2025-03-07 15:07 ` [PULL 15/21] target/arm: Drop unused address_offset from op_addr_{rr, ri}_post() Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 17/21] util/qemu-timer.c: Don't warp timer from timerlist_rearm() Peter Maydell
` (5 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
In debug_helper.c we provide a few dummy versions of
debug registers:
* DBGVCR (AArch32 only): enable bits for vector-catch
debug events
* MDCCINT_EL1: interrupt enable bits for the DCC
debug communications channel
* DBGVCR32_EL2: the AArch64 accessor for the state in
DBGVCR
We implemented these only to stop Linux crashing on startup,
but we chose to implement them as ARM_CP_NOP. This worked
for Linux where it only cares about trying to write to these
registers, but is very confusing behaviour for anything that
wants to read the registers (perhaps for context state switches),
because the destination register will be left with whatever
random value it happened to have before the read.
Model these registers instead as RAZ.
Fixes: 5e8b12ffbb8c68 ("target-arm: Implement minimal DBGVCR, OSDLR_EL1, MDCCSR_EL0")
Fixes: 5dbdc4342f479d ("target-arm: Implement dummy MDCCINT_EL1")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2708
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20250228162424.1917269-1-peter.maydell@linaro.org
---
target/arm/debug_helper.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index 36bffde74e9..a9a619ba6b1 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -1037,7 +1037,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
{ .name = "DBGVCR",
.cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
.access = PL1_RW, .accessfn = access_tda,
- .type = ARM_CP_NOP },
+ .type = ARM_CP_CONST, .resetvalue = 0 },
/*
* Dummy MDCCINT_EL1, since we don't implement the Debug Communications
* Channel but Linux may try to access this register. The 32-bit
@@ -1046,7 +1046,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
{ .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0,
.access = PL1_RW, .accessfn = access_tdcc,
- .type = ARM_CP_NOP },
+ .type = ARM_CP_CONST, .resetvalue = 0 },
/*
* Dummy DBGCLAIM registers.
* "The architecture does not define any functionality for the CLAIM tag bits.",
@@ -1075,7 +1075,8 @@ static const ARMCPRegInfo debug_aa32_el1_reginfo[] = {
{ .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
.access = PL2_RW, .accessfn = access_dbgvcr32,
- .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
+ .type = ARM_CP_CONST | ARM_CP_EL3_NO_EL2_KEEP,
+ .resetvalue = 0 },
};
static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 17/21] util/qemu-timer.c: Don't warp timer from timerlist_rearm()
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (15 preceding siblings ...)
2025-03-07 15:07 ` [PULL 16/21] target/arm: Make dummy debug registers RAZ, not NOP Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 18/21] include/exec/memop.h: Expand comment for MO_ATOM_SUBALIGN Peter Maydell
` (4 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
Currently we call icount_start_warp_timer() from timerlist_rearm().
This produces incorrect behaviour, because timerlist_rearm() is
called, for instance, when a timer callback modifies its timer. We
cannot decide here to warp the timer forwards to the next timer
deadline merely because all_cpu_threads_idle() is true, because the
timer callback we were called from (or some other callback later in
the list of callbacks being invoked) may be about to raise a CPU
interrupt and move a CPU from idle to ready.
The only valid place to choose to warp the timer forward is from the
main loop, when we know we have no outstanding IO or timer callbacks
that might be about to wake up a CPU.
For Arm guests, this bug was mostly latent until the refactoring
commit f6fc36deef6abc ("target/arm/helper: Implement
CNTHCTL_EL2.CNT[VP]MASK"), which exposed it because it refactored a
timer callback so that it happened to call timer_mod() first and
raise the interrupt second, when it had previously raised the
interrupt first and called timer_mod() afterwards.
This call seems to have originally derived from the
pre-record-and-replay icount code, which (as of e.g. commit
db1a49726c3c in 2010) in this location did a call to
qemu_notify_event(), necessary to get the icount code in the vCPU
round-robin thread to stop and recalculate the icount deadline when a
timer was reprogrammed from the IO thread. In current QEMU,
everything is done on the vCPU thread when we are in icount mode, so
there's no need to try to notify another thread here.
I suspect that the other reason why this call was doing icount timer
warping is that it pre-dates commit efab87cf79077a from 2015, which
added a call to icount_start_warp_timer() to main_loop_wait(). Once
the call in timerlist_rearm() has been removed, if the timer
callbacks don't cause any CPU to be woken up then we will end up
calling icount_start_warp_timer() from main_loop_wait() when the rr
main loop code calls rr_wait_io_event().
Remove the incorrect call from timerlist_rearm().
Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2703
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20250210135804.3526943-1-peter.maydell@linaro.org
---
util/qemu-timer.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index 3243d2c515c..788466fe22f 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -409,10 +409,6 @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
static void timerlist_rearm(QEMUTimerList *timer_list)
{
- /* Interrupt execution to force deadline recalculation. */
- if (icount_enabled() && timer_list->clock->type == QEMU_CLOCK_VIRTUAL) {
- icount_start_warp_timer();
- }
timerlist_notify(timer_list);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 18/21] include/exec/memop.h: Expand comment for MO_ATOM_SUBALIGN
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (16 preceding siblings ...)
2025-03-07 15:07 ` [PULL 17/21] util/qemu-timer.c: Don't warp timer from timerlist_rearm() Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 19/21] hw/arm/smmu: Introduce smmu_configs_inv_sid_range() helper Peter Maydell
` (3 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
Expand the example in the comment documenting MO_ATOM_SUBALIGN,
to be clearer about the atomicity guarantees it represents.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20250228103222.1838913-1-peter.maydell@linaro.org
---
include/exec/memop.h | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/exec/memop.h b/include/exec/memop.h
index acdb40a9b3b..407a47d82c7 100644
--- a/include/exec/memop.h
+++ b/include/exec/memop.h
@@ -91,8 +91,12 @@ typedef enum MemOp {
* Depending on alignment, one or both will be single-copy atomic.
* This is the atomicity e.g. of Arm FEAT_LSE2 LDP.
* MO_ATOM_SUBALIGN: the operation is single-copy atomic by parts
- * by the alignment. E.g. if the address is 0 mod 4, then each
- * 4-byte subobject is single-copy atomic.
+ * by the alignment. E.g. if an 8-byte value is accessed at an
+ * address which is 0 mod 8, then the whole 8-byte access is
+ * single-copy atomic; otherwise, if it is accessed at 0 mod 4
+ * then each 4-byte subobject is single-copy atomic; otherwise
+ * if it is accessed at 0 mod 2 then the four 2-byte subobjects
+ * are single-copy atomic.
* This is the atomicity e.g. of IBM Power.
* MO_ATOM_NONE: the operation has no atomicity requirements.
*
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 19/21] hw/arm/smmu: Introduce smmu_configs_inv_sid_range() helper
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (17 preceding siblings ...)
2025-03-07 15:07 ` [PULL 18/21] include/exec/memop.h: Expand comment for MO_ATOM_SUBALIGN Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 20/21] target/rx: Set exception vector base to 0xffffff80 Peter Maydell
` (2 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
From: JianChunfu <jansef.jian@hj-micro.com>
Use a similar terminology smmu_hash_remove_by_sid_range() as the one
being used for other hash table matching functions since
smmuv3_invalidate_ste() name is not self explanatory, and introduce a
helper that invokes the g_hash_table_foreach_remove.
No functional change intended.
Signed-off-by: JianChunfu <jansef.jian@hj-micro.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Message-id: 20250228031438.3916-1-jansef.jian@hj-micro.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/smmu-internal.h | 5 -----
include/hw/arm/smmu-common.h | 6 ++++++
hw/arm/smmu-common.c | 21 +++++++++++++++++++++
hw/arm/smmuv3.c | 19 ++-----------------
hw/arm/trace-events | 3 ++-
5 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
index 843bebb185d..d143d296f34 100644
--- a/hw/arm/smmu-internal.h
+++ b/hw/arm/smmu-internal.h
@@ -141,9 +141,4 @@ typedef struct SMMUIOTLBPageInvInfo {
uint64_t mask;
} SMMUIOTLBPageInvInfo;
-typedef struct SMMUSIDRange {
- uint32_t start;
- uint32_t end;
-} SMMUSIDRange;
-
#endif
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index e5ad55bbae7..e5e2d09294d 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -142,6 +142,11 @@ typedef struct SMMUIOTLBKey {
uint8_t level;
} SMMUIOTLBKey;
+typedef struct SMMUSIDRange {
+ uint32_t start;
+ uint32_t end;
+} SMMUSIDRange;
+
struct SMMUState {
/* <private> */
SysBusDevice dev;
@@ -219,6 +224,7 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
uint8_t tg, uint64_t num_pages, uint8_t ttl);
void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
uint64_t num_pages, uint8_t ttl);
+void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
/* Unmap the range of all the notifiers registered to any IOMMU mr */
void smmu_inv_notifiers_all(SMMUState *s);
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 8c1b407b824..6e720e1b9a0 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -225,6 +225,27 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova);
}
+static gboolean
+smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
+{
+ SMMUDevice *sdev = (SMMUDevice *)key;
+ uint32_t sid = smmu_get_sid(sdev);
+ SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
+
+ if (sid < sid_range->start || sid > sid_range->end) {
+ return false;
+ }
+ trace_smmu_config_cache_inv(sid);
+ return true;
+}
+
+void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range)
+{
+ trace_smmu_configs_inv_sid_range(sid_range.start, sid_range.end);
+ g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range,
+ &sid_range);
+}
+
void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
uint8_t tg, uint64_t num_pages, uint8_t ttl)
{
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index b40acbe0245..1a96287ba9d 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -903,7 +903,7 @@ static void smmuv3_flush_config(SMMUDevice *sdev)
SMMUv3State *s = sdev->smmu;
SMMUState *bc = &s->smmu_state;
- trace_smmuv3_config_cache_inv(smmu_get_sid(sdev));
+ trace_smmu_config_cache_inv(smmu_get_sid(sdev));
g_hash_table_remove(bc->configs, sdev);
}
@@ -1277,20 +1277,6 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
}
}
-static gboolean
-smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data)
-{
- SMMUDevice *sdev = (SMMUDevice *)key;
- uint32_t sid = smmu_get_sid(sdev);
- SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
-
- if (sid < sid_range->start || sid > sid_range->end) {
- return false;
- }
- trace_smmuv3_config_cache_inv(sid);
- return true;
-}
-
static int smmuv3_cmdq_consume(SMMUv3State *s)
{
SMMUState *bs = ARM_SMMU(s);
@@ -1373,8 +1359,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
sid_range.end = sid_range.start + mask;
trace_smmuv3_cmdq_cfgi_ste_range(sid_range.start, sid_range.end);
- g_hash_table_foreach_remove(bs->configs, smmuv3_invalidate_ste,
- &sid_range);
+ smmu_configs_inv_sid_range(bs, sid_range);
break;
}
case SMMU_CMD_CFGI_CD:
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index f49cae1656e..f3386bd7ae1 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -22,6 +22,8 @@ smmu_iotlb_inv_asid_vmid(int asid, int vmid) "IOTLB invalidate asid=%d vmid=%d"
smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
smmu_iotlb_inv_vmid_s1(int vmid) "IOTLB invalidate vmid=%d"
smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
+smmu_configs_inv_sid_range(uint32_t start, uint32_t end) "Config cache INV SID range from 0x%x to 0x%x"
+smmu_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
smmu_iotlb_lookup_miss(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
@@ -59,7 +61,6 @@ smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
smmuv3_cmdq_tlbi_nsnh(void) ""
smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
-smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages, int stage) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" stage=%d"
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 20/21] target/rx: Set exception vector base to 0xffffff80
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (18 preceding siblings ...)
2025-03-07 15:07 ` [PULL 19/21] hw/arm/smmu: Introduce smmu_configs_inv_sid_range() helper Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-07 15:07 ` [PULL 21/21] target/rx: Remove TCG_CALL_NO_WG from helpers which write env Peter Maydell
2025-03-09 0:41 ` [PULL 00/21] target-arm queue Stefan Hajnoczi
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
From: Keith Packard <keithp@keithp.com>
The documentation says the vector is at 0xffffff80, instead of the
previous value of 0xffffffc0. That value must have been a bug because
the standard vector values (20, 21, 23, 25, 30) were all
past the end of the array.
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target/rx/helper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/rx/helper.c b/target/rx/helper.c
index 7f28e729891..e8aabf40ffb 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -88,7 +88,7 @@ void rx_cpu_do_interrupt(CPUState *cs)
cpu_stl_data(env, env->isp, env->pc);
if (vec < 0x100) {
- env->pc = cpu_ldl_data(env, 0xffffffc0 + vec * 4);
+ env->pc = cpu_ldl_data(env, 0xffffff80 + vec * 4);
} else {
env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PULL 21/21] target/rx: Remove TCG_CALL_NO_WG from helpers which write env
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (19 preceding siblings ...)
2025-03-07 15:07 ` [PULL 20/21] target/rx: Set exception vector base to 0xffffff80 Peter Maydell
@ 2025-03-07 15:07 ` Peter Maydell
2025-03-09 0:41 ` [PULL 00/21] target-arm queue Stefan Hajnoczi
21 siblings, 0 replies; 23+ messages in thread
From: Peter Maydell @ 2025-03-07 15:07 UTC (permalink / raw)
To: qemu-devel
From: Keith Packard <keithp@keithp.com>
Functions which modify TCG globals must not be marked TCG_CALL_NO_WG,
as that tells the optimizer that TCG global values already loaded in
machine registers are still valid, and so any changes which these
helpers make to the CPU state may be ignored.
The target/rx code chooses to put (among other things) all the PSW
bits and also ACC into globals, so the NO_WG flag on various
functions that touch the PSW or ACC is incorrect and must be removed.
This includes all the floating point helper functions, because
update_fpsw() will update PSW Z and S.
Signed-off-by: Keith Packard <keithp@keithp.com>
[PMM: Clarified commit message]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target/rx/helper.h | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/target/rx/helper.h b/target/rx/helper.h
index ebb47394744..8cc38b0cb71 100644
--- a/target/rx/helper.h
+++ b/target/rx/helper.h
@@ -4,27 +4,27 @@ DEF_HELPER_1(raise_privilege_violation, noreturn, env)
DEF_HELPER_1(wait, noreturn, env)
DEF_HELPER_2(rxint, noreturn, env, i32)
DEF_HELPER_1(rxbrk, noreturn, env)
-DEF_HELPER_FLAGS_3(fadd, TCG_CALL_NO_WG, f32, env, f32, f32)
-DEF_HELPER_FLAGS_3(fsub, TCG_CALL_NO_WG, f32, env, f32, f32)
-DEF_HELPER_FLAGS_3(fmul, TCG_CALL_NO_WG, f32, env, f32, f32)
-DEF_HELPER_FLAGS_3(fdiv, TCG_CALL_NO_WG, f32, env, f32, f32)
-DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_WG, void, env, f32, f32)
-DEF_HELPER_FLAGS_2(ftoi, TCG_CALL_NO_WG, i32, env, f32)
-DEF_HELPER_FLAGS_2(round, TCG_CALL_NO_WG, i32, env, f32)
-DEF_HELPER_FLAGS_2(itof, TCG_CALL_NO_WG, f32, env, i32)
+DEF_HELPER_3(fadd, f32, env, f32, f32)
+DEF_HELPER_3(fsub, f32, env, f32, f32)
+DEF_HELPER_3(fmul, f32, env, f32, f32)
+DEF_HELPER_3(fdiv, f32, env, f32, f32)
+DEF_HELPER_3(fcmp, void, env, f32, f32)
+DEF_HELPER_2(ftoi, i32, env, f32)
+DEF_HELPER_2(round, i32, env, f32)
+DEF_HELPER_2(itof, f32, env, i32)
DEF_HELPER_2(set_fpsw, void, env, i32)
-DEF_HELPER_FLAGS_2(racw, TCG_CALL_NO_WG, void, env, i32)
-DEF_HELPER_FLAGS_2(set_psw_rte, TCG_CALL_NO_WG, void, env, i32)
-DEF_HELPER_FLAGS_2(set_psw, TCG_CALL_NO_WG, void, env, i32)
+DEF_HELPER_2(racw, void, env, i32)
+DEF_HELPER_2(set_psw_rte, void, env, i32)
+DEF_HELPER_2(set_psw, void, env, i32)
DEF_HELPER_1(pack_psw, i32, env)
-DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32)
-DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32)
-DEF_HELPER_FLAGS_1(scmpu, TCG_CALL_NO_WG, void, env)
+DEF_HELPER_3(div, i32, env, i32, i32)
+DEF_HELPER_3(divu, i32, env, i32, i32)
+DEF_HELPER_1(scmpu, void, env)
DEF_HELPER_1(smovu, void, env)
DEF_HELPER_1(smovf, void, env)
DEF_HELPER_1(smovb, void, env)
DEF_HELPER_2(sstr, void, env, i32)
-DEF_HELPER_FLAGS_2(swhile, TCG_CALL_NO_WG, void, env, i32)
-DEF_HELPER_FLAGS_2(suntil, TCG_CALL_NO_WG, void, env, i32)
-DEF_HELPER_FLAGS_2(rmpa, TCG_CALL_NO_WG, void, env, i32)
+DEF_HELPER_2(swhile, void, env, i32)
+DEF_HELPER_2(suntil, void, env, i32)
+DEF_HELPER_2(rmpa, void, env, i32)
DEF_HELPER_1(satr, void, env)
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PULL 00/21] target-arm queue
2025-03-07 15:06 [PULL 00/21] target-arm queue Peter Maydell
` (20 preceding siblings ...)
2025-03-07 15:07 ` [PULL 21/21] target/rx: Remove TCG_CALL_NO_WG from helpers which write env Peter Maydell
@ 2025-03-09 0:41 ` Stefan Hajnoczi
21 siblings, 0 replies; 23+ messages in thread
From: Stefan Hajnoczi @ 2025-03-09 0:41 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/10.0 for any user-visible changes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread