dev, arm: Add virtual timers to the generic timer model
[gem5.git] / src / dev / arm / generic_timer.cc
1 /*
2 * Copyright (c) 2013, 2015 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Gabrielli
38 * Andreas Sandberg
39 */
40
41 #include "dev/arm/generic_timer.hh"
42
43 #include "arch/arm/system.hh"
44 #include "debug/Timer.hh"
45 #include "dev/arm/base_gic.hh"
46 #include "params/GenericTimer.hh"
47
48 SystemCounter::SystemCounter()
49 : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
50 {
51 setFreq(0x01800000);
52 }
53
54 void
55 SystemCounter::setFreq(uint32_t freq)
56 {
57 if (_freq != 0) {
58 // Altering the frequency after boot shouldn't be done in practice.
59 warn_once("The frequency of the system counter has already been set");
60 }
61 _freq = freq;
62 _period = (1.0 / freq) * SimClock::Frequency;
63 _resetTick = curTick();
64 }
65
66 void
67 SystemCounter::serialize(std::ostream &os) const
68 {
69 SERIALIZE_SCALAR(_regCntkctl);
70 SERIALIZE_SCALAR(_freq);
71 SERIALIZE_SCALAR(_period);
72 SERIALIZE_SCALAR(_resetTick);
73 }
74
75 void
76 SystemCounter::unserialize(Checkpoint *cp,
77 const std::string &section)
78 {
79 // We didn't handle CNTKCTL in this class before, assume it's zero
80 // if it isn't present.
81 if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
82 _regCntkctl = 0;
83 UNSERIALIZE_SCALAR(_freq);
84 UNSERIALIZE_SCALAR(_period);
85 UNSERIALIZE_SCALAR(_resetTick);
86 }
87
88
89
90 ArchTimer::ArchTimer(const std::string &name,
91 SimObject &parent,
92 SystemCounter &sysctr,
93 const Interrupt &interrupt)
94 : _name(name), _parent(parent), _systemCounter(sysctr),
95 _interrupt(interrupt),
96 _control(0), _counterLimit(0), _offset(0),
97 _counterLimitReachedEvent(this)
98 {
99 }
100
101 void
102 ArchTimer::counterLimitReached()
103 {
104 _control.istatus = 1;
105
106 if (!_control.enable)
107 return;
108
109 DPRINTF(Timer, "Counter limit reached\n");
110 if (!_control.imask) {
111 DPRINTF(Timer, "Causing interrupt\n");
112 _interrupt.send();
113 }
114 }
115
116 void
117 ArchTimer::updateCounter()
118 {
119 if (_counterLimitReachedEvent.scheduled())
120 _parent.deschedule(_counterLimitReachedEvent);
121 if (value() >= _counterLimit) {
122 counterLimitReached();
123 } else {
124 const auto period(_systemCounter.period());
125 _control.istatus = 0;
126 _parent.schedule(_counterLimitReachedEvent,
127 curTick() + (_counterLimit - value()) * period);
128 }
129 }
130
131 void
132 ArchTimer::setCompareValue(uint64_t val)
133 {
134 _counterLimit = val;
135 updateCounter();
136 }
137
138 void
139 ArchTimer::setTimerValue(uint32_t val)
140 {
141 setCompareValue(value() + sext<32>(val));
142 }
143
144 void
145 ArchTimer::setControl(uint32_t val)
146 {
147 ArchTimerCtrl new_ctl = val;
148 if ((new_ctl.enable && !new_ctl.imask) &&
149 !(_control.enable && !_control.imask)) {
150 // Re-evalute the timer condition
151 if (_counterLimit >= value()) {
152 _control.istatus = 1;
153
154 DPRINTF(Timer, "Causing interrupt in control\n");
155 //_interrupt.send();
156 }
157 }
158 _control.enable = new_ctl.enable;
159 _control.imask = new_ctl.imask;
160 }
161
162 void
163 ArchTimer::setOffset(uint64_t val)
164 {
165 _offset = val;
166 updateCounter();
167 }
168
169 uint64_t
170 ArchTimer::value() const
171 {
172 return _systemCounter.value() - _offset;
173 }
174
175 void
176 ArchTimer::serialize(std::ostream &os) const
177 {
178 paramOut(os, "control_serial", _control);
179 SERIALIZE_SCALAR(_counterLimit);
180 SERIALIZE_SCALAR(_offset);
181
182 const bool event_scheduled(_counterLimitReachedEvent.scheduled());
183 SERIALIZE_SCALAR(event_scheduled);
184 if (event_scheduled) {
185 const Tick event_time(_counterLimitReachedEvent.when());
186 SERIALIZE_SCALAR(event_time);
187 }
188 }
189
190 void
191 ArchTimer::unserialize(Checkpoint *cp,
192 const std::string &section)
193 {
194 paramIn(cp, section, "control_serial", _control);
195 // We didn't serialize an offset before we added support for the
196 // virtual timer. Consider it optional to maintain backwards
197 // compatibility.
198 if (!UNSERIALIZE_OPT_SCALAR(_offset))
199 _offset = 0;
200 bool event_scheduled;
201 UNSERIALIZE_SCALAR(event_scheduled);
202 if (event_scheduled) {
203 Tick event_time;
204 UNSERIALIZE_SCALAR(event_time);
205 _parent.schedule(_counterLimitReachedEvent, event_time);
206 }
207 }
208
209 void
210 ArchTimer::Interrupt::send()
211 {
212 if (_ppi) {
213 _gic.sendPPInt(_irq, _cpu);
214 } else {
215 _gic.sendInt(_irq);
216 }
217 }
218
219
220 void
221 ArchTimer::Interrupt::clear()
222 {
223 if (_ppi) {
224 _gic.clearPPInt(_irq, _cpu);
225 } else {
226 _gic.clearInt(_irq);
227 }
228 }
229
230
231 GenericTimer::GenericTimer(GenericTimerParams *p)
232 : SimObject(p),
233 gic(p->gic),
234 irqPhys(p->int_phys),
235 irqVirt(p->int_virt)
236 {
237 dynamic_cast<ArmSystem &>(*p->system).setGenericTimer(this);
238 }
239
240 void
241 GenericTimer::serialize(std::ostream &os)
242 {
243 paramOut(os, "cpu_count", timers.size());
244
245 nameOut(os, csprintf("%s.sys_counter", name()));
246 systemCounter.serialize(os);
247
248 for (int i = 0; i < timers.size(); ++i) {
249 CoreTimers &core(getTimers(i));
250
251 nameOut(os, core.phys.name());
252 core.phys.serialize(os);
253
254 nameOut(os, core.virt.name());
255 core.virt.serialize(os);
256 }
257 }
258
259 void
260 GenericTimer::unserialize(Checkpoint *cp, const std::string &section)
261 {
262 systemCounter.unserialize(cp, csprintf("%s.sys_counter", section));
263
264 // Try to unserialize the CPU count. Old versions of the timer
265 // model assumed a 8 CPUs, so we fall back to that if the field
266 // isn't present.
267 static const unsigned OLD_CPU_MAX = 8;
268 unsigned cpu_count;
269 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
270 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
271 OLD_CPU_MAX);
272 cpu_count = OLD_CPU_MAX;
273 }
274
275 for (int i = 0; i < cpu_count; ++i) {
276 CoreTimers &core(getTimers(i));
277 // This should really be phys_timerN, but we are stuck with
278 // arch_timer for backwards compatibility.
279 core.phys.unserialize(cp, csprintf("%s.arch_timer%d", section, i));
280 core.virt.unserialize(cp, csprintf("%s.virt_timer%d", section, i));
281 }
282 }
283
284
285 GenericTimer::CoreTimers &
286 GenericTimer::getTimers(int cpu_id)
287 {
288 if (cpu_id >= timers.size())
289 createTimers(cpu_id + 1);
290
291 return *timers[cpu_id];
292 }
293
294 void
295 GenericTimer::createTimers(unsigned cpus)
296 {
297 assert(timers.size() < cpus);
298
299 const unsigned old_cpu_count(timers.size());
300 timers.resize(cpus);
301 for (unsigned i = old_cpu_count; i < cpus; ++i) {
302 timers[i].reset(
303 new CoreTimers(*this, i, irqPhys, irqVirt));
304 }
305 }
306
307
308 void
309 GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
310 {
311 CoreTimers &core(getTimers(cpu));
312
313 switch (reg) {
314 case MISCREG_CNTFRQ:
315 case MISCREG_CNTFRQ_EL0:
316 systemCounter.setFreq(val);
317 return;
318
319 case MISCREG_CNTKCTL:
320 case MISCREG_CNTKCTL_EL1:
321 systemCounter.setKernelControl(val);
322 return;
323
324 // Physical timer
325 case MISCREG_CNTP_CVAL:
326 case MISCREG_CNTP_CVAL_NS:
327 case MISCREG_CNTP_CVAL_EL0:
328 core.phys.setCompareValue(val);
329 return;
330
331 case MISCREG_CNTP_TVAL:
332 case MISCREG_CNTP_TVAL_NS:
333 case MISCREG_CNTP_TVAL_EL0:
334 core.phys.setTimerValue(val);
335 return;
336
337 case MISCREG_CNTP_CTL:
338 case MISCREG_CNTP_CTL_NS:
339 case MISCREG_CNTP_CTL_EL0:
340 core.phys.setControl(val);
341 return;
342
343 // Count registers
344 case MISCREG_CNTPCT:
345 case MISCREG_CNTPCT_EL0:
346 case MISCREG_CNTVCT:
347 case MISCREG_CNTVCT_EL0:
348 warn("Ignoring write to read only count register: %s\n",
349 miscRegName[reg]);
350 return;
351
352 // Virtual timer
353 case MISCREG_CNTVOFF:
354 case MISCREG_CNTVOFF_EL2:
355 core.virt.setOffset(val);
356 return;
357
358 case MISCREG_CNTV_CVAL:
359 case MISCREG_CNTV_CVAL_EL0:
360 core.virt.setCompareValue(val);
361 return;
362
363 case MISCREG_CNTV_TVAL:
364 case MISCREG_CNTV_TVAL_EL0:
365 core.virt.setTimerValue(val);
366 return;
367
368 case MISCREG_CNTV_CTL:
369 case MISCREG_CNTV_CTL_EL0:
370 core.virt.setControl(val);
371 return;
372
373 // PL1 phys. timer, secure
374 case MISCREG_CNTP_CTL_S:
375 case MISCREG_CNTPS_CVAL_EL1:
376 case MISCREG_CNTPS_TVAL_EL1:
377 case MISCREG_CNTPS_CTL_EL1:
378 /* FALLTHROUGH */
379
380 // PL2 phys. timer, non-secure
381 case MISCREG_CNTHCTL:
382 case MISCREG_CNTHCTL_EL2:
383 case MISCREG_CNTHP_CVAL:
384 case MISCREG_CNTHP_CVAL_EL2:
385 case MISCREG_CNTHP_TVAL:
386 case MISCREG_CNTHP_TVAL_EL2:
387 case MISCREG_CNTHP_CTL:
388 case MISCREG_CNTHP_CTL_EL2:
389 warn("Writing to unimplemented register: %s\n",
390 miscRegName[reg]);
391 return;
392
393 default:
394 warn("Writing to unknown register: %s\n", miscRegName[reg]);
395 return;
396 }
397 }
398
399
400 MiscReg
401 GenericTimer::readMiscReg(int reg, unsigned cpu)
402 {
403 CoreTimers &core(getTimers(cpu));
404
405 switch (reg) {
406 case MISCREG_CNTFRQ:
407 case MISCREG_CNTFRQ_EL0:
408 return systemCounter.freq();
409
410 case MISCREG_CNTKCTL:
411 case MISCREG_CNTKCTL_EL1:
412 return systemCounter.getKernelControl();
413
414 // Physical timer
415 case MISCREG_CNTP_CVAL:
416 case MISCREG_CNTP_CVAL_EL0:
417 return core.phys.compareValue();
418
419 case MISCREG_CNTP_TVAL:
420 case MISCREG_CNTP_TVAL_EL0:
421 return core.phys.timerValue();
422
423 case MISCREG_CNTP_CTL:
424 case MISCREG_CNTP_CTL_EL0:
425 case MISCREG_CNTP_CTL_NS:
426 return core.phys.control();
427
428 case MISCREG_CNTPCT:
429 case MISCREG_CNTPCT_EL0:
430 return core.phys.value();
431
432
433 // Virtual timer
434 case MISCREG_CNTVCT:
435 case MISCREG_CNTVCT_EL0:
436 return core.virt.value();
437
438 case MISCREG_CNTVOFF:
439 case MISCREG_CNTVOFF_EL2:
440 return core.virt.offset();
441
442 case MISCREG_CNTV_CVAL:
443 case MISCREG_CNTV_CVAL_EL0:
444 return core.virt.compareValue();
445
446 case MISCREG_CNTV_TVAL:
447 case MISCREG_CNTV_TVAL_EL0:
448 return core.virt.timerValue();
449
450 case MISCREG_CNTV_CTL:
451 case MISCREG_CNTV_CTL_EL0:
452 return core.virt.control();
453
454 // PL1 phys. timer, secure
455 case MISCREG_CNTP_CTL_S:
456 case MISCREG_CNTPS_CVAL_EL1:
457 case MISCREG_CNTPS_TVAL_EL1:
458 case MISCREG_CNTPS_CTL_EL1:
459 /* FALLTHROUGH */
460
461 // PL2 phys. timer, non-secure
462 case MISCREG_CNTHCTL:
463 case MISCREG_CNTHCTL_EL2:
464 case MISCREG_CNTHP_CVAL:
465 case MISCREG_CNTHP_CVAL_EL2:
466 case MISCREG_CNTHP_TVAL:
467 case MISCREG_CNTHP_TVAL_EL2:
468 case MISCREG_CNTHP_CTL:
469 case MISCREG_CNTHP_CTL_EL2:
470 warn("Reading from unimplemented register: %s\n",
471 miscRegName[reg]);
472 return 0;
473
474
475 default:
476 warn("Reading from unknown register: %s\n", miscRegName[reg]);
477 return 0;
478 }
479 }
480
481
482 GenericTimer *
483 GenericTimerParams::create()
484 {
485 return new GenericTimer(this);
486 }