All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq()
@ 2026-10-23  9:35 Harshit Mukhedkar
  2026-10-26  2:19 ` Alistair Francis
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Harshit Mukhedkar @ 2026-10-23  9:35 UTC (permalink / raw)
  To: qemu-riscv, qemu-devel
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, Harshit Mukhedkar,
	qemu-stable

pmu_timer_trigger_irq() reads the counter by passing
(target_ulong *)&curr_ctr_val to riscv_pmu_read_ctr(). On RV32 that
pointer is to a 32 bit type, so only half of the uint64_t gets written
and the rest is whatever was on the stack. The high word read from
riscv_pmu_read_ctr() is then ORed in on top of that, and the result is
compared against the software written counter to decide whether to raise
LCOFI. A stray bit in the garbage half can make that comparison wrong.

Read the low and high halves into their own target_ulong variables and
assemble the 64-bit value explicitly.

This was found while looking at #4724, whose reported mhpmcounterh
mismatch is fixed separately by 57b484e2d232.

Fixes: 74112400df65 ("target/riscv: More accurately model priv mode filtering.")
Cc: qemu-stable@nongnu.org
Signed-off-by: Harshit Mukhedkar <harshit007k@gmail.com>
---
 target/riscv/tcg/pmu.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c
index 1a4658319b..0165faf06b 100644
--- a/target/riscv/tcg/pmu.c
+++ b/target/riscv/tcg/pmu.c
@@ -355,7 +355,8 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
     CPURISCVState *env = &cpu->env;
     PMUCTRState *counter;
     int64_t irq_trigger_at;
-    uint64_t curr_ctr_val, curr_ctrh_val;
+    target_ulong ctr_lo = 0, ctr_hi = 0;
+    uint64_t curr_ctr_val;
     uint64_t ctr_val;
 
     if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
@@ -383,12 +384,19 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
         return;
     }
 
-    riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx);
-    ctr_val = counter->mhpmcounter_val;
+    /*
+     * riscv_pmu_read_ctr() stores a target_ulong, so on RV32 each call fills
+     * only 32 bits. Read each half into its own target_ulong and build the
+     * 64 bit value explicitly instead of passing a cast uint64_t pointer,
+     * which would leave the upper half uninitialised.
+     */
+    riscv_pmu_read_ctr(env, &ctr_lo, false, ctr_idx);
+    curr_ctr_val = ctr_lo;
     if (riscv_cpu_mxl(env) == MXL_RV32) {
-        riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx);
-        curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32);
+        riscv_pmu_read_ctr(env, &ctr_hi, true, ctr_idx);
+        curr_ctr_val |= (uint64_t)ctr_hi << 32;
     }
+    ctr_val = counter->mhpmcounter_val;
 
     /*
      * We can not accommodate for inhibited modes when setting up timer. Check
-- 
2.56.0



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

* Re: [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq()
  2026-10-23  9:35 [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq() Harshit Mukhedkar
@ 2026-10-26  2:19 ` Alistair Francis
  2026-10-26  2:27 ` Alistair Francis
  2026-10-28 11:59 ` Michael Tokarev
  2 siblings, 0 replies; 4+ messages in thread
From: Alistair Francis @ 2026-10-26  2:19 UTC (permalink / raw)
  To: harshit007k@gmail.com, qemu-riscv@nongnu.org,
	qemu-devel@nongnu.org
  Cc: qemu-stable@nongnu.org, palmer@dabbelt.com,
	daniel.barboza@oss.qualcomm.com, chao.liu@processmission.com,
	liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com

On Fri, 2026-10-23 at 15:05 +0530, Harshit Mukhedkar wrote:
> pmu_timer_trigger_irq() reads the counter by passing
> (target_ulong *)&curr_ctr_val to riscv_pmu_read_ctr(). On RV32 that
> pointer is to a 32 bit type, so only half of the uint64_t gets
> written
> and the rest is whatever was on the stack. The high word read from
> riscv_pmu_read_ctr() is then ORed in on top of that, and the result
> is
> compared against the software written counter to decide whether to
> raise
> LCOFI. A stray bit in the garbage half can make that comparison
> wrong.
> 
> Read the low and high halves into their own target_ulong variables
> and
> assemble the 64-bit value explicitly.
> 
> This was found while looking at #4724, whose reported mhpmcounterh
> mismatch is fixed separately by 57b484e2d232.
> 
> Fixes: 74112400df65 ("target/riscv: More accurately model priv mode
> filtering.")
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Harshit Mukhedkar <harshit007k@gmail.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/tcg/pmu.c | 18 +++++++++++++-----
>  1 file changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c
> index 1a4658319b..0165faf06b 100644
> --- a/target/riscv/tcg/pmu.c
> +++ b/target/riscv/tcg/pmu.c
> @@ -355,7 +355,8 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
>      CPURISCVState *env = &cpu->env;
>      PMUCTRState *counter;
>      int64_t irq_trigger_at;
> -    uint64_t curr_ctr_val, curr_ctrh_val;
> +    target_ulong ctr_lo = 0, ctr_hi = 0;
> +    uint64_t curr_ctr_val;
>      uint64_t ctr_val;
>  
>      if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
> @@ -383,12 +384,19 @@ static void pmu_timer_trigger_irq(RISCVCPU
> *cpu,
>          return;
>      }
>  
> -    riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false,
> ctr_idx);
> -    ctr_val = counter->mhpmcounter_val;
> +    /*
> +     * riscv_pmu_read_ctr() stores a target_ulong, so on RV32 each
> call fills
> +     * only 32 bits. Read each half into its own target_ulong and
> build the
> +     * 64 bit value explicitly instead of passing a cast uint64_t
> pointer,
> +     * which would leave the upper half uninitialised.
> +     */
> +    riscv_pmu_read_ctr(env, &ctr_lo, false, ctr_idx);
> +    curr_ctr_val = ctr_lo;
>      if (riscv_cpu_mxl(env) == MXL_RV32) {
> -        riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val,
> true, ctr_idx);
> -        curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32);
> +        riscv_pmu_read_ctr(env, &ctr_hi, true, ctr_idx);
> +        curr_ctr_val |= (uint64_t)ctr_hi << 32;
>      }
> +    ctr_val = counter->mhpmcounter_val;
>  
>      /*
>       * We can not accommodate for inhibited modes when setting up
> timer. Check

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

* Re: [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq()
  2026-10-23  9:35 [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq() Harshit Mukhedkar
  2026-10-26  2:19 ` Alistair Francis
@ 2026-10-26  2:27 ` Alistair Francis
  2026-10-28 11:59 ` Michael Tokarev
  2 siblings, 0 replies; 4+ messages in thread
From: Alistair Francis @ 2026-10-26  2:27 UTC (permalink / raw)
  To: harshit007k@gmail.com, qemu-riscv@nongnu.org,
	qemu-devel@nongnu.org
  Cc: qemu-stable@nongnu.org, palmer@dabbelt.com,
	daniel.barboza@oss.qualcomm.com, chao.liu@processmission.com,
	liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com

On Fri, 2026-10-23 at 15:05 +0530, Harshit Mukhedkar wrote:
> pmu_timer_trigger_irq() reads the counter by passing
> (target_ulong *)&curr_ctr_val to riscv_pmu_read_ctr(). On RV32 that
> pointer is to a 32 bit type, so only half of the uint64_t gets
> written
> and the rest is whatever was on the stack. The high word read from
> riscv_pmu_read_ctr() is then ORed in on top of that, and the result
> is
> compared against the software written counter to decide whether to
> raise
> LCOFI. A stray bit in the garbage half can make that comparison
> wrong.
> 
> Read the low and high halves into their own target_ulong variables
> and
> assemble the 64-bit value explicitly.
> 
> This was found while looking at #4724, whose reported mhpmcounterh
> mismatch is fixed separately by 57b484e2d232.
> 
> Fixes: 74112400df65 ("target/riscv: More accurately model priv mode
> filtering.")
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Harshit Mukhedkar <harshit007k@gmail.com>

Thanks!

Applied to riscv-to-apply.next

Alistair

> ---
>  target/riscv/tcg/pmu.c | 18 +++++++++++++-----
>  1 file changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c
> index 1a4658319b..0165faf06b 100644
> --- a/target/riscv/tcg/pmu.c
> +++ b/target/riscv/tcg/pmu.c
> @@ -355,7 +355,8 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
>      CPURISCVState *env = &cpu->env;
>      PMUCTRState *counter;
>      int64_t irq_trigger_at;
> -    uint64_t curr_ctr_val, curr_ctrh_val;
> +    target_ulong ctr_lo = 0, ctr_hi = 0;
> +    uint64_t curr_ctr_val;
>      uint64_t ctr_val;
>  
>      if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
> @@ -383,12 +384,19 @@ static void pmu_timer_trigger_irq(RISCVCPU
> *cpu,
>          return;
>      }
>  
> -    riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false,
> ctr_idx);
> -    ctr_val = counter->mhpmcounter_val;
> +    /*
> +     * riscv_pmu_read_ctr() stores a target_ulong, so on RV32 each
> call fills
> +     * only 32 bits. Read each half into its own target_ulong and
> build the
> +     * 64 bit value explicitly instead of passing a cast uint64_t
> pointer,
> +     * which would leave the upper half uninitialised.
> +     */
> +    riscv_pmu_read_ctr(env, &ctr_lo, false, ctr_idx);
> +    curr_ctr_val = ctr_lo;
>      if (riscv_cpu_mxl(env) == MXL_RV32) {
> -        riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val,
> true, ctr_idx);
> -        curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32);
> +        riscv_pmu_read_ctr(env, &ctr_hi, true, ctr_idx);
> +        curr_ctr_val |= (uint64_t)ctr_hi << 32;
>      }
> +    ctr_val = counter->mhpmcounter_val;
>  
>      /*
>       * We can not accommodate for inhibited modes when setting up
> timer. Check

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

* Re: [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq()
  2026-10-23  9:35 [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq() Harshit Mukhedkar
  2026-10-26  2:19 ` Alistair Francis
  2026-10-26  2:27 ` Alistair Francis
@ 2026-10-28 11:59 ` Michael Tokarev
  2 siblings, 0 replies; 4+ messages in thread
From: Michael Tokarev @ 2026-10-28 11:59 UTC (permalink / raw)
  To: Harshit Mukhedkar, qemu-riscv, qemu-devel
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, qemu-stable

On 10/23/26 12:35, Harshit Mukhedkar wrote:
> pmu_timer_trigger_irq() reads the counter by passing
> (target_ulong *)&curr_ctr_val to riscv_pmu_read_ctr(). On RV32 that
> pointer is to a 32 bit type, so only half of the uint64_t gets written
> and the rest is whatever was on the stack. The high word read from
> riscv_pmu_read_ctr() is then ORed in on top of that, and the result is
> compared against the software written counter to decide whether to raise
> LCOFI. A stray bit in the garbage half can make that comparison wrong.
> 
> Read the low and high halves into their own target_ulong variables and
> assemble the 64-bit value explicitly.
> 
> This was found while looking at #4724, whose reported mhpmcounterh
> mismatch is fixed separately by 57b484e2d232.
> 
> Fixes: 74112400df65 ("target/riscv: More accurately model priv mode filtering.")
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Harshit Mukhedkar <harshit007k@gmail.com>

This change has been marked for-stable.  However, just like a previous
change for RV32, I'm not applying it to 10.0.x branch, because it lacks
a few other commits in this area, and because RV32 is a very niche
platform to support in older stable releases.  Only 11.1.x gets it.

FWIW.

Thanks,

/mjt


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

end of thread, other threads:[~2026-10-28 11:59 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-23  9:35 [PATCH] target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq() Harshit Mukhedkar
2026-10-26  2:19 ` Alistair Francis
2026-10-26  2:27 ` Alistair Francis
2026-10-28 11:59 ` Michael Tokarev

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.