dev, arm: Fix multi-core KVM race in the generic timer
[gem5.git] / src / dev / arm / generic_timer.cc
1 /*
2 * Copyright (c) 2013, 2015, 2017 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 "mem/packet_access.hh"
47 #include "params/GenericTimer.hh"
48 #include "params/GenericTimerMem.hh"
49
50 SystemCounter::SystemCounter()
51 : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
52 {
53 setFreq(0x01800000);
54 }
55
56 void
57 SystemCounter::setFreq(uint32_t freq)
58 {
59 if (_freq != 0) {
60 // Altering the frequency after boot shouldn't be done in practice.
61 warn_once("The frequency of the system counter has already been set");
62 }
63 _freq = freq;
64 _period = (1.0 / freq) * SimClock::Frequency;
65 _resetTick = curTick();
66 }
67
68 void
69 SystemCounter::serialize(CheckpointOut &cp) const
70 {
71 SERIALIZE_SCALAR(_regCntkctl);
72 SERIALIZE_SCALAR(_freq);
73 SERIALIZE_SCALAR(_period);
74 SERIALIZE_SCALAR(_resetTick);
75 }
76
77 void
78 SystemCounter::unserialize(CheckpointIn &cp)
79 {
80 // We didn't handle CNTKCTL in this class before, assume it's zero
81 // if it isn't present.
82 if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
83 _regCntkctl = 0;
84 UNSERIALIZE_SCALAR(_freq);
85 UNSERIALIZE_SCALAR(_period);
86 UNSERIALIZE_SCALAR(_resetTick);
87 }
88
89
90
91 ArchTimer::ArchTimer(const std::string &name,
92 SimObject &parent,
93 SystemCounter &sysctr,
94 const Interrupt &interrupt)
95 : _name(name), _parent(parent), _systemCounter(sysctr),
96 _interrupt(interrupt),
97 _control(0), _counterLimit(0), _offset(0),
98 _counterLimitReachedEvent(this)
99 {
100 }
101
102 void
103 ArchTimer::counterLimitReached()
104 {
105 _control.istatus = 1;
106
107 if (!_control.enable)
108 return;
109
110 DPRINTF(Timer, "Counter limit reached\n");
111 if (!_control.imask) {
112 DPRINTF(Timer, "Causing interrupt\n");
113 _interrupt.send();
114 }
115 }
116
117 void
118 ArchTimer::updateCounter()
119 {
120 if (_counterLimitReachedEvent.scheduled())
121 _parent.deschedule(_counterLimitReachedEvent);
122 if (value() >= _counterLimit) {
123 counterLimitReached();
124 } else {
125 const auto period(_systemCounter.period());
126 _control.istatus = 0;
127 _parent.schedule(_counterLimitReachedEvent,
128 curTick() + (_counterLimit - value()) * period);
129 }
130 }
131
132 void
133 ArchTimer::setCompareValue(uint64_t val)
134 {
135 _counterLimit = val;
136 updateCounter();
137 }
138
139 void
140 ArchTimer::setTimerValue(uint32_t val)
141 {
142 setCompareValue(value() + sext<32>(val));
143 }
144
145 void
146 ArchTimer::setControl(uint32_t val)
147 {
148 ArchTimerCtrl new_ctl = val;
149 if ((new_ctl.enable && !new_ctl.imask) &&
150 !(_control.enable && !_control.imask)) {
151 // Re-evalute the timer condition
152 if (_counterLimit >= value()) {
153 _control.istatus = 1;
154
155 DPRINTF(Timer, "Causing interrupt in control\n");
156 //_interrupt.send();
157 }
158 }
159 _control.enable = new_ctl.enable;
160 _control.imask = new_ctl.imask;
161 }
162
163 void
164 ArchTimer::setOffset(uint64_t val)
165 {
166 _offset = val;
167 updateCounter();
168 }
169
170 uint64_t
171 ArchTimer::value() const
172 {
173 return _systemCounter.value() - _offset;
174 }
175
176 void
177 ArchTimer::serialize(CheckpointOut &cp) const
178 {
179 paramOut(cp, "control_serial", _control);
180 SERIALIZE_SCALAR(_counterLimit);
181 SERIALIZE_SCALAR(_offset);
182
183 const bool event_scheduled(_counterLimitReachedEvent.scheduled());
184 SERIALIZE_SCALAR(event_scheduled);
185 if (event_scheduled) {
186 const Tick event_time(_counterLimitReachedEvent.when());
187 SERIALIZE_SCALAR(event_time);
188 }
189 }
190
191 void
192 ArchTimer::unserialize(CheckpointIn &cp)
193 {
194 paramIn(cp, "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 fatal_if(!p->system, "No system specified, can't instantiate timer.\n");
238 p->system->setGenericTimer(this);
239 }
240
241 void
242 GenericTimer::serialize(CheckpointOut &cp) const
243 {
244 paramOut(cp, "cpu_count", timers.size());
245
246 systemCounter.serializeSection(cp, "sys_counter");
247
248 for (int i = 0; i < timers.size(); ++i) {
249 const CoreTimers &core(*timers[i]);
250
251 // This should really be phys_timerN, but we are stuck with
252 // arch_timer for backwards compatibility.
253 core.phys.serializeSection(cp, csprintf("arch_timer%d", i));
254 core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
255 }
256 }
257
258 void
259 GenericTimer::unserialize(CheckpointIn &cp)
260 {
261 systemCounter.unserializeSection(cp, "sys_counter");
262
263 // Try to unserialize the CPU count. Old versions of the timer
264 // model assumed a 8 CPUs, so we fall back to that if the field
265 // isn't present.
266 static const unsigned OLD_CPU_MAX = 8;
267 unsigned cpu_count;
268 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
269 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
270 OLD_CPU_MAX);
271 cpu_count = OLD_CPU_MAX;
272 }
273
274 for (int i = 0; i < cpu_count; ++i) {
275 CoreTimers &core(getTimers(i));
276 // This should really be phys_timerN, but we are stuck with
277 // arch_timer for backwards compatibility.
278 core.phys.unserializeSection(cp, csprintf("arch_timer%d", i));
279 core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
280 }
281 }
282
283
284 GenericTimer::CoreTimers &
285 GenericTimer::getTimers(int cpu_id)
286 {
287 if (cpu_id >= timers.size())
288 createTimers(cpu_id + 1);
289
290 return *timers[cpu_id];
291 }
292
293 void
294 GenericTimer::createTimers(unsigned cpus)
295 {
296 assert(timers.size() < cpus);
297
298 const unsigned old_cpu_count(timers.size());
299 timers.resize(cpus);
300 for (unsigned i = old_cpu_count; i < cpus; ++i) {
301 timers[i].reset(
302 new CoreTimers(*this, i, irqPhys, irqVirt));
303 }
304 }
305
306
307 void
308 GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
309 {
310 // This method might have been called from another context if we
311 // are running in multi-core KVM. Migrate to the SimObject's event
312 // queue to prevent surprising race conditions.
313 EventQueue::ScopedMigration migrate(eventQueue());
314
315 CoreTimers &core(getTimers(cpu));
316
317 switch (reg) {
318 case MISCREG_CNTFRQ:
319 case MISCREG_CNTFRQ_EL0:
320 systemCounter.setFreq(val);
321 return;
322
323 case MISCREG_CNTKCTL:
324 case MISCREG_CNTKCTL_EL1:
325 systemCounter.setKernelControl(val);
326 return;
327
328 // Physical timer
329 case MISCREG_CNTP_CVAL:
330 case MISCREG_CNTP_CVAL_NS:
331 case MISCREG_CNTP_CVAL_EL0:
332 core.phys.setCompareValue(val);
333 return;
334
335 case MISCREG_CNTP_TVAL:
336 case MISCREG_CNTP_TVAL_NS:
337 case MISCREG_CNTP_TVAL_EL0:
338 core.phys.setTimerValue(val);
339 return;
340
341 case MISCREG_CNTP_CTL:
342 case MISCREG_CNTP_CTL_NS:
343 case MISCREG_CNTP_CTL_EL0:
344 core.phys.setControl(val);
345 return;
346
347 // Count registers
348 case MISCREG_CNTPCT:
349 case MISCREG_CNTPCT_EL0:
350 case MISCREG_CNTVCT:
351 case MISCREG_CNTVCT_EL0:
352 warn("Ignoring write to read only count register: %s\n",
353 miscRegName[reg]);
354 return;
355
356 // Virtual timer
357 case MISCREG_CNTVOFF:
358 case MISCREG_CNTVOFF_EL2:
359 core.virt.setOffset(val);
360 return;
361
362 case MISCREG_CNTV_CVAL:
363 case MISCREG_CNTV_CVAL_EL0:
364 core.virt.setCompareValue(val);
365 return;
366
367 case MISCREG_CNTV_TVAL:
368 case MISCREG_CNTV_TVAL_EL0:
369 core.virt.setTimerValue(val);
370 return;
371
372 case MISCREG_CNTV_CTL:
373 case MISCREG_CNTV_CTL_EL0:
374 core.virt.setControl(val);
375 return;
376
377 // PL1 phys. timer, secure
378 case MISCREG_CNTP_CTL_S:
379 case MISCREG_CNTPS_CVAL_EL1:
380 case MISCREG_CNTPS_TVAL_EL1:
381 case MISCREG_CNTPS_CTL_EL1:
382 /* FALLTHROUGH */
383
384 // PL2 phys. timer, non-secure
385 case MISCREG_CNTHCTL:
386 case MISCREG_CNTHCTL_EL2:
387 case MISCREG_CNTHP_CVAL:
388 case MISCREG_CNTHP_CVAL_EL2:
389 case MISCREG_CNTHP_TVAL:
390 case MISCREG_CNTHP_TVAL_EL2:
391 case MISCREG_CNTHP_CTL:
392 case MISCREG_CNTHP_CTL_EL2:
393 warn("Writing to unimplemented register: %s\n",
394 miscRegName[reg]);
395 return;
396
397 default:
398 warn("Writing to unknown register: %s\n", miscRegName[reg]);
399 return;
400 }
401 }
402
403
404 MiscReg
405 GenericTimer::readMiscReg(int reg, unsigned cpu)
406 {
407 // This method might have been called from another context if we
408 // are running in multi-core KVM. Migrate to the SimObject's event
409 // queue to prevent surprising race conditions.
410 EventQueue::ScopedMigration migrate(eventQueue());
411
412 CoreTimers &core(getTimers(cpu));
413
414 switch (reg) {
415 case MISCREG_CNTFRQ:
416 case MISCREG_CNTFRQ_EL0:
417 return systemCounter.freq();
418
419 case MISCREG_CNTKCTL:
420 case MISCREG_CNTKCTL_EL1:
421 return systemCounter.getKernelControl();
422
423 // Physical timer
424 case MISCREG_CNTP_CVAL:
425 case MISCREG_CNTP_CVAL_EL0:
426 return core.phys.compareValue();
427
428 case MISCREG_CNTP_TVAL:
429 case MISCREG_CNTP_TVAL_EL0:
430 return core.phys.timerValue();
431
432 case MISCREG_CNTP_CTL:
433 case MISCREG_CNTP_CTL_EL0:
434 case MISCREG_CNTP_CTL_NS:
435 return core.phys.control();
436
437 case MISCREG_CNTPCT:
438 case MISCREG_CNTPCT_EL0:
439 return core.phys.value();
440
441
442 // Virtual timer
443 case MISCREG_CNTVCT:
444 case MISCREG_CNTVCT_EL0:
445 return core.virt.value();
446
447 case MISCREG_CNTVOFF:
448 case MISCREG_CNTVOFF_EL2:
449 return core.virt.offset();
450
451 case MISCREG_CNTV_CVAL:
452 case MISCREG_CNTV_CVAL_EL0:
453 return core.virt.compareValue();
454
455 case MISCREG_CNTV_TVAL:
456 case MISCREG_CNTV_TVAL_EL0:
457 return core.virt.timerValue();
458
459 case MISCREG_CNTV_CTL:
460 case MISCREG_CNTV_CTL_EL0:
461 return core.virt.control();
462
463 // PL1 phys. timer, secure
464 case MISCREG_CNTP_CTL_S:
465 case MISCREG_CNTPS_CVAL_EL1:
466 case MISCREG_CNTPS_TVAL_EL1:
467 case MISCREG_CNTPS_CTL_EL1:
468 /* FALLTHROUGH */
469
470 // PL2 phys. timer, non-secure
471 case MISCREG_CNTHCTL:
472 case MISCREG_CNTHCTL_EL2:
473 case MISCREG_CNTHP_CVAL:
474 case MISCREG_CNTHP_CVAL_EL2:
475 case MISCREG_CNTHP_TVAL:
476 case MISCREG_CNTHP_TVAL_EL2:
477 case MISCREG_CNTHP_CTL:
478 case MISCREG_CNTHP_CTL_EL2:
479 warn("Reading from unimplemented register: %s\n",
480 miscRegName[reg]);
481 return 0;
482
483
484 default:
485 warn("Reading from unknown register: %s\n", miscRegName[reg]);
486 return 0;
487 }
488 }
489
490
491
492 GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
493 : PioDevice(p),
494 ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
495 timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
496 addrRanges{ctrlRange, timerRange},
497 systemCounter(),
498 physTimer(csprintf("%s.phys_timer0", name()),
499 *this, systemCounter,
500 ArchTimer::Interrupt(*p->gic, p->int_phys)),
501 virtTimer(csprintf("%s.virt_timer0", name()),
502 *this, systemCounter,
503 ArchTimer::Interrupt(*p->gic, p->int_virt))
504 {
505 }
506
507 void
508 GenericTimerMem::serialize(CheckpointOut &cp) const
509 {
510 paramOut(cp, "timer_count", 1);
511
512 systemCounter.serializeSection(cp, "sys_counter");
513
514 physTimer.serializeSection(cp, "phys_timer0");
515 virtTimer.serializeSection(cp, "virt_timer0");
516 }
517
518 void
519 GenericTimerMem::unserialize(CheckpointIn &cp)
520 {
521 systemCounter.unserializeSection(cp, "sys_counter");
522
523 unsigned timer_count;
524 UNSERIALIZE_SCALAR(timer_count);
525 // The timer count variable is just here for future versions where
526 // we support more than one set of timers.
527 if (timer_count != 1)
528 panic("Incompatible checkpoint: Only one set of timers supported");
529
530 physTimer.unserializeSection(cp, "phys_timer0");
531 virtTimer.unserializeSection(cp, "virt_timer0");
532 }
533
534 Tick
535 GenericTimerMem::read(PacketPtr pkt)
536 {
537 const unsigned size(pkt->getSize());
538 const Addr addr(pkt->getAddr());
539 uint64_t value;
540
541 pkt->makeResponse();
542 if (ctrlRange.contains(addr)) {
543 value = ctrlRead(addr - ctrlRange.start(), size);
544 } else if (timerRange.contains(addr)) {
545 value = timerRead(addr - timerRange.start(), size);
546 } else {
547 panic("Invalid address: 0x%x\n", addr);
548 }
549
550 DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
551
552 if (size == 8) {
553 pkt->set<uint64_t>(value);
554 } else if (size == 4) {
555 pkt->set<uint32_t>(value);
556 } else {
557 panic("Unexpected access size: %i\n", size);
558 }
559
560 return 0;
561 }
562
563 Tick
564 GenericTimerMem::write(PacketPtr pkt)
565 {
566 const unsigned size(pkt->getSize());
567 if (size != 8 && size != 4)
568 panic("Unexpected access size\n");
569
570 const Addr addr(pkt->getAddr());
571 const uint64_t value(size == 8 ?
572 pkt->get<uint64_t>() : pkt->get<uint32_t>());
573
574 DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
575 if (ctrlRange.contains(addr)) {
576 ctrlWrite(addr - ctrlRange.start(), size, value);
577 } else if (timerRange.contains(addr)) {
578 timerWrite(addr - timerRange.start(), size, value);
579 } else {
580 panic("Invalid address: 0x%x\n", addr);
581 }
582
583 pkt->makeResponse();
584 return 0;
585 }
586
587 uint64_t
588 GenericTimerMem::ctrlRead(Addr addr, size_t size) const
589 {
590 if (size == 4) {
591 switch (addr) {
592 case CTRL_CNTFRQ:
593 return systemCounter.freq();
594
595 case CTRL_CNTTIDR:
596 return 0x3; // Frame 0 implemented with virtual timers
597
598 case CTRL_CNTNSAR:
599 case CTRL_CNTACR_BASE:
600 warn("Reading from unimplemented control register (0x%x)\n", addr);
601 return 0;
602
603 case CTRL_CNTVOFF_LO_BASE:
604 return virtTimer.offset();
605
606 case CTRL_CNTVOFF_HI_BASE:
607 return virtTimer.offset() >> 32;
608
609 default:
610 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
611 return 0;
612 }
613 } else if (size == 8) {
614 switch (addr) {
615 case CTRL_CNTVOFF_LO_BASE:
616 return virtTimer.offset();
617
618 default:
619 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
620 return 0;
621 }
622 } else {
623 panic("Invalid access size: %i\n", size);
624 }
625 }
626
627 void
628 GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
629 {
630 if (size == 4) {
631 switch (addr) {
632 case CTRL_CNTFRQ:
633 case CTRL_CNTNSAR:
634 case CTRL_CNTTIDR:
635 case CTRL_CNTACR_BASE:
636 warn("Write to unimplemented control register (0x%x)\n", addr);
637 return;
638
639 case CTRL_CNTVOFF_LO_BASE:
640 virtTimer.setOffset(
641 insertBits(virtTimer.offset(), 31, 0, value));
642 return;
643
644 case CTRL_CNTVOFF_HI_BASE:
645 virtTimer.setOffset(
646 insertBits(virtTimer.offset(), 63, 32, value));
647 return;
648
649 default:
650 warn("Ignoring write to unexpected address (0x%x:%i)\n",
651 addr, size);
652 return;
653 }
654 } else if (size == 8) {
655 switch (addr) {
656 case CTRL_CNTVOFF_LO_BASE:
657 virtTimer.setOffset(value);
658 return;
659
660 default:
661 warn("Ignoring write to unexpected address (0x%x:%i)\n",
662 addr, size);
663 return;
664 }
665 } else {
666 panic("Invalid access size: %i\n", size);
667 }
668 }
669
670 uint64_t
671 GenericTimerMem::timerRead(Addr addr, size_t size) const
672 {
673 if (size == 4) {
674 switch (addr) {
675 case TIMER_CNTPCT_LO:
676 return physTimer.value();
677
678 case TIMER_CNTPCT_HI:
679 return physTimer.value() >> 32;
680
681 case TIMER_CNTVCT_LO:
682 return virtTimer.value();
683
684 case TIMER_CNTVCT_HI:
685 return virtTimer.value() >> 32;
686
687 case TIMER_CNTFRQ:
688 return systemCounter.freq();
689
690 case TIMER_CNTEL0ACR:
691 warn("Read from unimplemented timer register (0x%x)\n", addr);
692 return 0;
693
694 case CTRL_CNTVOFF_LO_BASE:
695 return virtTimer.offset();
696
697 case CTRL_CNTVOFF_HI_BASE:
698 return virtTimer.offset() >> 32;
699
700 case TIMER_CNTP_CVAL_LO:
701 return physTimer.compareValue();
702
703 case TIMER_CNTP_CVAL_HI:
704 return physTimer.compareValue() >> 32;
705
706 case TIMER_CNTP_TVAL:
707 return physTimer.timerValue();
708
709 case TIMER_CNTP_CTL:
710 return physTimer.control();
711
712 case TIMER_CNTV_CVAL_LO:
713 return virtTimer.compareValue();
714
715 case TIMER_CNTV_CVAL_HI:
716 return virtTimer.compareValue() >> 32;
717
718 case TIMER_CNTV_TVAL:
719 return virtTimer.timerValue();
720
721 case TIMER_CNTV_CTL:
722 return virtTimer.control();
723
724 default:
725 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
726 return 0;
727 }
728 } else if (size == 8) {
729 switch (addr) {
730 case TIMER_CNTPCT_LO:
731 return physTimer.value();
732
733 case TIMER_CNTVCT_LO:
734 return virtTimer.value();
735
736 case CTRL_CNTVOFF_LO_BASE:
737 return virtTimer.offset();
738
739 case TIMER_CNTP_CVAL_LO:
740 return physTimer.compareValue();
741
742 case TIMER_CNTV_CVAL_LO:
743 return virtTimer.compareValue();
744
745 default:
746 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
747 return 0;
748 }
749 } else {
750 panic("Invalid access size: %i\n", size);
751 }
752 }
753
754 void
755 GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
756 {
757 if (size == 4) {
758 switch (addr) {
759 case TIMER_CNTEL0ACR:
760 warn("Unimplemented timer register (0x%x)\n", addr);
761 return;
762
763 case TIMER_CNTP_CVAL_LO:
764 physTimer.setCompareValue(
765 insertBits(physTimer.compareValue(), 31, 0, value));
766 return;
767
768 case TIMER_CNTP_CVAL_HI:
769 physTimer.setCompareValue(
770 insertBits(physTimer.compareValue(), 63, 32, value));
771 return;
772
773 case TIMER_CNTP_TVAL:
774 physTimer.setTimerValue(value);
775 return;
776
777 case TIMER_CNTP_CTL:
778 physTimer.setControl(value);
779 return;
780
781 case TIMER_CNTV_CVAL_LO:
782 virtTimer.setCompareValue(
783 insertBits(virtTimer.compareValue(), 31, 0, value));
784 return;
785
786 case TIMER_CNTV_CVAL_HI:
787 virtTimer.setCompareValue(
788 insertBits(virtTimer.compareValue(), 63, 32, value));
789 return;
790
791 case TIMER_CNTV_TVAL:
792 virtTimer.setTimerValue(value);
793 return;
794
795 case TIMER_CNTV_CTL:
796 virtTimer.setControl(value);
797 return;
798
799 default:
800 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
801 return;
802 }
803 } else if (size == 8) {
804 switch (addr) {
805 case TIMER_CNTP_CVAL_LO:
806 return physTimer.setCompareValue(value);
807
808 case TIMER_CNTV_CVAL_LO:
809 return virtTimer.setCompareValue(value);
810
811 default:
812 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
813 return;
814 }
815 } else {
816 panic("Invalid access size: %i\n", size);
817 }
818 }
819
820 GenericTimer *
821 GenericTimerParams::create()
822 {
823 return new GenericTimer(this);
824 }
825
826 GenericTimerMem *
827 GenericTimerMemParams::create()
828 {
829 return new GenericTimerMem(this);
830 }