1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "qemu/osdep.h"
28#include "hw/sysbus.h"
29#include "hw/register.h"
30#include "qemu/bitops.h"
31#include "qapi/error.h"
32#include "qemu/log.h"
33#include "qemu/timer.h"
34#include "migration/vmstate.h"
35#include "hw/qdev-properties.h"
36#include "hw/irq.h"
37
38#ifndef ARM_GEN_TIMER_ERR_DEBUG
39#define ARM_GEN_TIMER_ERR_DEBUG 0
40#endif
41
42#define TYPE_ARM_GEN_TIMER "arm.generic-timer"
43
44#define ARM_GEN_TIMER(obj) \
45 OBJECT_CHECK(ARMGenTimer, (obj), TYPE_ARM_GEN_TIMER)
46
47REG32(COUNTER_CONTROL_REGISTER, 0x0)
48 FIELD(COUNTER_CONTROL_REGISTER, EN, 1, 1)
49 FIELD(COUNTER_CONTROL_REGISTER, HDBG, 0, 1)
50REG32(COUNTER_STATUS_REGISTER, 0x4)
51 FIELD(COUNTER_STATUS_REGISTER, DBGH, 1, 1)
52REG32(CURRENT_COUNTER_VALUE_LOWER_REGISTER, 0x8)
53REG32(CURRENT_COUNTER_VALUE_UPPER_REGISTER, 0xc)
54REG32(BASE_FREQUENCY_ID_REGISTER, 0x20)
55
56#define R_MAX (R_BASE_FREQUENCY_ID_REGISTER + 1)
57
58typedef struct ARMGenTimer {
59 SysBusDevice parent_obj;
60 MemoryRegion iomem;
61
62 bool enabled;
63 uint64_t tick_offset;
64
65 uint32_t regs[R_MAX];
66 RegisterInfo regs_info[R_MAX];
67} ARMGenTimer;
68
69static void counter_control_postw(RegisterInfo *reg, uint64_t val64)
70{
71 ARMGenTimer *s = ARM_GEN_TIMER(reg->opaque);
72 bool new_status = extract32(s->regs[R_COUNTER_CONTROL_REGISTER],
73 R_COUNTER_CONTROL_REGISTER_EN_SHIFT,
74 R_COUNTER_CONTROL_REGISTER_EN_LENGTH);
75 uint64_t current_ticks;
76
77 current_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL),
78 NANOSECONDS_PER_SECOND, 1000000);
79
80 if ((s->enabled && !new_status) ||
81 (!s->enabled && new_status)) {
82
83 s->tick_offset = current_ticks - s->tick_offset;
84 }
85
86 s->enabled = new_status;
87}
88
89static uint64_t couter_low_value_postr(RegisterInfo *reg, uint64_t val64)
90{
91 ARMGenTimer *s = ARM_GEN_TIMER(reg->opaque);
92 uint64_t current_ticks, total_ticks;
93 uint32_t low_ticks;
94
95 if (s->enabled) {
96 current_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL),
97 NANOSECONDS_PER_SECOND, 1000000);
98 total_ticks = current_ticks - s->tick_offset;
99 low_ticks = (uint32_t) total_ticks;
100 } else {
101
102 low_ticks = (uint32_t) s->tick_offset;
103 }
104
105 return low_ticks;
106}
107
108static uint64_t couter_high_value_postr(RegisterInfo *reg, uint64_t val64)
109{
110 ARMGenTimer *s = ARM_GEN_TIMER(reg->opaque);
111 uint64_t current_ticks, total_ticks;
112 uint32_t high_ticks;
113
114 if (s->enabled) {
115 current_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL),
116 NANOSECONDS_PER_SECOND, 1000000);
117 total_ticks = current_ticks - s->tick_offset;
118 high_ticks = (uint32_t) (total_ticks >> 32);
119 } else {
120
121 high_ticks = (uint32_t) (s->tick_offset >> 32);
122 }
123
124 return high_ticks;
125}
126
127
128static RegisterAccessInfo arm_gen_timer_regs_info[] = {
129 { .name = "COUNTER_CONTROL_REGISTER",
130 .addr = A_COUNTER_CONTROL_REGISTER,
131 .rsvd = 0xfffffffc,
132 .post_write = counter_control_postw,
133 },{ .name = "COUNTER_STATUS_REGISTER",
134 .addr = A_COUNTER_STATUS_REGISTER,
135 .rsvd = 0xfffffffd, .ro = 0x2,
136 },{ .name = "CURRENT_COUNTER_VALUE_LOWER_REGISTER",
137 .addr = A_CURRENT_COUNTER_VALUE_LOWER_REGISTER,
138 .post_read = couter_low_value_postr,
139 },{ .name = "CURRENT_COUNTER_VALUE_UPPER_REGISTER",
140 .addr = A_CURRENT_COUNTER_VALUE_UPPER_REGISTER,
141 .post_read = couter_high_value_postr,
142 },{ .name = "BASE_FREQUENCY_ID_REGISTER",
143 .addr = A_BASE_FREQUENCY_ID_REGISTER,
144 }
145};
146
147static void arm_gen_timer_reset(DeviceState *dev)
148{
149 ARMGenTimer *s = ARM_GEN_TIMER(dev);
150 unsigned int i;
151
152 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
153 register_reset(&s->regs_info[i]);
154 }
155
156 s->tick_offset = 0;
157 s->enabled = false;
158}
159
160static MemTxResult arm_gen_timer_access(MemoryTransaction *tr)
161{
162 MemTxAttrs attr = tr->attr;
163 void *opaque = tr->opaque;
164 hwaddr addr = tr->addr;
165 unsigned size = tr->size;
166 uint64_t value = tr->data.u64;;
167 bool is_write = tr->rw;
168
169 if (is_write && !attr.secure) {
170
171 qemu_log_mask(LOG_GUEST_ERROR,
172 "Non secure writes to the system timestamp generator " \
173 "are invalid\n");
174 return MEMTX_ERROR;
175 }
176
177 if (is_write) {
178 register_write_memory(opaque, addr, value, size);
179 } else {
180 tr->data.u64 = register_read_memory(opaque, addr, size);
181 }
182
183 return MEMTX_OK;
184}
185
186static const MemoryRegionOps arm_gen_timer_ops = {
187 .access = arm_gen_timer_access,
188 .endianness = DEVICE_LITTLE_ENDIAN,
189 .valid = {
190 .min_access_size = 4,
191 .max_access_size = 4,
192 },
193};
194
195static void arm_gen_timer_init(Object *obj)
196{
197 ARMGenTimer *s = ARM_GEN_TIMER(obj);
198 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
199 RegisterInfoArray *reg_array;
200
201 memory_region_init(&s->iomem, obj, TYPE_ARM_GEN_TIMER,
202 R_MAX * 4);
203 reg_array =
204 register_init_block32(DEVICE(obj), arm_gen_timer_regs_info,
205 ARRAY_SIZE(arm_gen_timer_regs_info),
206 s->regs_info, s->regs,
207 &arm_gen_timer_ops,
208 ARM_GEN_TIMER_ERR_DEBUG,
209 R_MAX * 4);
210 memory_region_add_subregion(&s->iomem,
211 0x0,
212 ®_array->mem);
213 sysbus_init_mmio(sbd, &s->iomem);
214}
215
216static const VMStateDescription vmstate_arm_gen_timer = {
217 .name = TYPE_ARM_GEN_TIMER,
218 .version_id = 1,
219 .minimum_version_id = 1,
220 .fields = (VMStateField[]) {
221 VMSTATE_UINT32_ARRAY(regs, ARMGenTimer, R_MAX),
222 VMSTATE_END_OF_LIST(),
223 }
224};
225
226static void arm_gen_timer_class_init(ObjectClass *klass, void *data)
227{
228 DeviceClass *dc = DEVICE_CLASS(klass);
229
230 dc->reset = arm_gen_timer_reset;
231 dc->vmsd = &vmstate_arm_gen_timer;
232}
233
234static const TypeInfo arm_gen_timer_info = {
235 .name = TYPE_ARM_GEN_TIMER,
236 .parent = TYPE_SYS_BUS_DEVICE,
237 .instance_size = sizeof(ARMGenTimer),
238 .class_init = arm_gen_timer_class_init,
239 .instance_init = arm_gen_timer_init,
240};
241
242static void arm_gen_timer_register_types(void)
243{
244 type_register_static(&arm_gen_timer_info);
245}
246
247type_init(arm_gen_timer_register_types)
248