1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "qemu/osdep.h"
20#include "qemu/log.h"
21#include "cpu_bits.h"
22#include "time_helper.h"
23#include "hw/intc/riscv_aclint.h"
24
25static void riscv_vstimer_cb(void *opaque)
26{
27 RISCVCPU *cpu = opaque;
28 CPURISCVState *env = &cpu->env;
29 env->vstime_irq = 1;
30 riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1));
31}
32
33static void riscv_stimer_cb(void *opaque)
34{
35 RISCVCPU *cpu = opaque;
36 riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1));
37}
38
39
40
41
42
43void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
44 uint64_t timecmp, uint64_t delta,
45 uint32_t timer_irq)
46{
47 uint64_t diff, ns_diff, next;
48 CPURISCVState *env = &cpu->env;
49 RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg;
50 uint32_t timebase_freq = mtimer->timebase_freq;
51 uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
52
53 if (timecmp <= rtc_r) {
54
55
56
57
58 if (timer_irq == MIP_VSTIP) {
59 env->vstime_irq = 1;
60 }
61 riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1));
62 return;
63 }
64
65 if (timer_irq == MIP_VSTIP) {
66 env->vstime_irq = 0;
67 }
68
69 riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0));
70
71
72 diff = timecmp - rtc_r;
73
74 ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
75
76
77
78
79
80 if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
81 ns_diff > INT64_MAX) {
82 next = INT64_MAX;
83 } else {
84
85
86
87
88
89 next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
90
91
92
93
94 next = MIN(next, INT64_MAX);
95 }
96
97 timer_mod(timer, next);
98}
99
100void riscv_timer_init(RISCVCPU *cpu)
101{
102 CPURISCVState *env;
103
104 if (!cpu) {
105 return;
106 }
107
108 env = &cpu->env;
109 env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu);
110 env->stimecmp = 0;
111
112 env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu);
113 env->vstimecmp = 0;
114}
115