[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 07/33] hw/intc/sifive_clint: Fix muldiv64 overflow in sifive_clint
From: |
Alistair Francis |
Subject: |
[PULL 07/33] hw/intc/sifive_clint: Fix muldiv64 overflow in sifive_clint_write_timecmp() |
Date: |
Wed, 1 Sep 2021 12:09:32 +1000 |
From: David Hoppenbrouwers <david@salt-inc.org>
`muldiv64` would overflow in cases where the final 96-bit value does not
fit in a `uint64_t`. This would result in small values that cause an
interrupt to be triggered much sooner than intended.
The overflow can be detected in most cases by checking if the new value is
smaller than the previous value. If the final result is larger than
`diff` it is either correct or it doesn't matter as it is effectively
infinite anyways.
`next` is an `uint64_t` value, but `timer_mod` takes an `int64_t`. This
resulted in high values such as `UINT64_MAX` being converted to `-1`,
which caused an immediate timer interrupt.
By limiting `next` to `INT64_MAX` no overflow will happen while the
timer will still be effectively set to "infinitely" far in the future.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/493
Signed-off-by: David Hoppenbrouwers <david@salt-inc.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-id: 20210827152324.5201-1-david@salt-inc.org
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
hw/intc/sifive_clint.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
index 0f41e5ea1c..99c870ced2 100644
--- a/hw/intc/sifive_clint.c
+++ b/hw/intc/sifive_clint.c
@@ -59,8 +59,29 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu,
uint64_t value,
riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
diff = cpu->env.timecmp - rtc_r;
/* back to ns (note args switched in muldiv64) */
- next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
+ uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
+
+ /*
+ * check if ns_diff overflowed and check if the addition would potentially
+ * overflow
+ */
+ if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
+ ns_diff > INT64_MAX) {
+ next = INT64_MAX;
+ } else {
+ /*
+ * as it is very unlikely qemu_clock_get_ns will return a value
+ * greater than INT64_MAX, no additional check is needed for an
+ * unsigned integer overflow.
+ */
+ next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
+ /*
+ * if ns_diff is INT64_MAX next may still be outside the range
+ * of a signed integer.
+ */
+ next = MIN(next, INT64_MAX);
+ }
+
timer_mod(cpu->env.timer, next);
}
--
2.31.1
- [PULL 00/33] riscv-to-apply queue, Alistair Francis, 2021/08/31
- [PULL 01/33] hw/char: Add config for shakti uart, Alistair Francis, 2021/08/31
- [PULL 02/33] hw/riscv: virt: Move flash node to root, Alistair Francis, 2021/08/31
- [PULL 03/33] target/riscv: Correct a comment in riscv_csrrw(), Alistair Francis, 2021/08/31
- [PULL 04/33] target/riscv: Don't wrongly override isa version, Alistair Francis, 2021/08/31
- [PULL 05/33] target/riscv: Add User CSRs read-only check, Alistair Francis, 2021/08/31
- [PULL 07/33] hw/intc/sifive_clint: Fix muldiv64 overflow in sifive_clint_write_timecmp(),
Alistair Francis <=
- [PULL 06/33] hw/riscv/virt.c: Assemble plic_hart_config string with g_strjoinv(), Alistair Francis, 2021/08/31
- [PULL 08/33] hw/core/register: Add more 64-bit utilities, Alistair Francis, 2021/08/31
- [PULL 09/33] hw/registerfields: Use 64-bit bitfield for FIELD_DP64, Alistair Francis, 2021/08/31
- [PULL 10/33] target/riscv: Use tcg_constant_*, Alistair Francis, 2021/08/31
- [PULL 11/33] tests/tcg/riscv64: Add test for division, Alistair Francis, 2021/08/31
- [PULL 12/33] target/riscv: Clean up division helpers, Alistair Francis, 2021/08/31
- [PULL 15/33] target/riscv: Add DisasExtend to gen_arith*, Alistair Francis, 2021/08/31
- [PULL 13/33] target/riscv: Add DisasContext to gen_get_gpr, gen_set_gpr, Alistair Francis, 2021/08/31
- [PULL 16/33] target/riscv: Remove gen_arith_div*, Alistair Francis, 2021/08/31
- [PULL 17/33] target/riscv: Use gen_arith for mulh and mulhu, Alistair Francis, 2021/08/31