diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index 4fb2a471a9..b654f91af9 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -72,6 +72,30 @@ void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0)); } + /* + * Sstc specification says the following about timer interrupt: + * "A supervisor timer interrupt becomes pending - as reflected in + * the STIP bit in the mip and sip registers - whenever time contains + * a value greater than or equal to stimecmp, treating the values + * as unsigned integers. Writes to stimecmp are guaranteed to be + * reflected in STIP eventually, but not necessarily immediately. + * The interrupt remains posted until stimecmp becomes greater + * than time - typically as a result of writing stimecmp." + * + * When timecmp = UINT64_MAX, the time CSR will eventually reach + * timecmp value but on next timer tick the time CSR will wrap-around + * and become zero which is less than UINT64_MAX. Now, the timer + * interrupt behaves like a level triggered interrupt so it will + * become 1 when time = timecmp = UINT64_MAX and next timer tick + * it will become 0 again because time = 0 < timecmp = UINT64_MAX. + * + * Based on above, we don't re-start the QEMU timer when timecmp + * equals UINT64_MAX. + */ + if (timecmp == UINT64_MAX) { + return; + } + /* otherwise, set up the future timer interrupt */ diff = timecmp - rtc_r; /* back to ns (note args switched in muldiv64) */