gem5 v24.0.0.0
Loading...
Searching...
No Matches
generic_timer.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013, 2015, 2017-2018,2020,2022 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
39
40#include <cmath>
41#include <string_view>
42
43#include "arch/arm/page_size.hh"
44#include "arch/arm/system.hh"
45#include "arch/arm/utility.hh"
46#include "base/logging.hh"
47#include "base/trace.hh"
48#include "config/kvm_isa.hh"
49#include "config/use_kvm.hh"
50#include "cpu/base.hh"
51#include "cpu/kvm/vm.hh"
52#include "debug/Timer.hh"
53#include "dev/arm/base_gic.hh"
54#include "mem/packet_access.hh"
55#include "params/GenericTimer.hh"
56#include "params/GenericTimerFrame.hh"
57#include "params/GenericTimerMem.hh"
58#include "params/SystemCounter.hh"
59#include "sim/core.hh"
60#include "sim/cur_tick.hh"
61
62namespace gem5
63{
64
65using namespace ArmISA;
66
67SystemCounter::SystemCounter(const SystemCounterParams &p)
68 : SimObject(p),
69 _enabled(true),
70 _value(0),
71 _increment(1),
72 _freqTable(p.freqs),
73 _activeFreqEntry(0),
74 _updateTick(0),
75 _freqUpdateEvent([this]{ freqUpdateCallback(); }, name()),
76 _nextFreqEntry(0)
77{
78 fatal_if(_freqTable.empty(), "SystemCounter::SystemCounter: Base "
79 "frequency not provided\n");
80 // Store the table end marker as a 32-bit zero word
81 _freqTable.push_back(0);
83 "SystemCounter::SystemCounter: Architecture states a maximum of 1004 "
84 "frequency table entries, limit surpassed\n");
85 // Set the active frequency to be the base
86 _freq = _freqTable.front();
88}
89
90void
92{
93 fatal_if(!sys_cnt, "SystemCounter::validateCounterRef: No valid system "
94 "counter, can't instantiate system timers\n");
95}
96
97void
99{
100 DPRINTF(Timer, "SystemCounter::enable: Counter enabled\n");
101 _enabled = true;
102 updateTick();
103}
104
105void
107{
108 DPRINTF(Timer, "SystemCounter::disable: Counter disabled\n");
109 updateValue();
110 _enabled = false;
111}
112
113uint64_t
115{
116 if (_enabled)
117 updateValue();
118 return _value;
119}
120
121void
123{
124 uint64_t new_value =
126 if (new_value > _value) {
127 _value = new_value;
128 updateTick();
129 }
130}
131
132void
133SystemCounter::setValue(uint64_t new_value)
134{
135 if (_enabled)
136 warn("Explicit value set with counter enabled, UNKNOWNN result\n");
137 _value = new_value;
138 updateTick();
140}
141
142Tick
143SystemCounter::whenValue(uint64_t cur_val, uint64_t target_val) const
144{
145 Tick when = curTick();
146 if (target_val > cur_val) {
147 uint64_t num_cycles =
148 std::ceil((target_val - cur_val) / ((double) _increment));
149 // Take into account current cycle remaining ticks
150 Tick rem_ticks = _period - (curTick() % _period);
151 if (rem_ticks < _period) {
152 when += rem_ticks;
153 num_cycles -= 1;
154 }
155 when += num_cycles * _period;
156 }
157 return when;
158}
159
160Tick
161SystemCounter::whenValue(uint64_t target_val)
162{
163 return whenValue(value(), target_val);
164}
165
166void
171
172void
174{
175 if (new_freq_entry < _freqTable.size()) {
176 auto &new_freq = _freqTable[new_freq_entry];
177 if (new_freq != _freq) {
178 _nextFreqEntry = new_freq_entry;
179 // Wait until the value for which the lowest frequency increment
180 // is a exact divisor. This covers both high to low and low to
181 // high transitions
182 uint64_t new_incr = _freqTable[0] / new_freq;
183 uint64_t target_val = value();
184 target_val += target_val % std::max(_increment, new_incr);
185 reschedule(_freqUpdateEvent, whenValue(target_val), true);
186 }
187 }
188}
189
190void
192{
193 DPRINTF(Timer, "SystemCounter::freqUpdateCallback: Changing counter "
194 "frequency\n");
195 if (_enabled)
196 updateValue();
202}
203
204void
206{
207 _listeners.push_back(listener);
208}
209
210void
212{
213 for (auto &listener : _listeners)
214 listener->notify();
215}
216
217void
219{
220 DPRINTF(Timer, "SystemCounter::serialize: Serializing\n");
228 bool pending_freq_update = _freqUpdateEvent.scheduled();
229 SERIALIZE_SCALAR(pending_freq_update);
230 if (pending_freq_update) {
231 Tick when_freq_update = _freqUpdateEvent.when();
232 SERIALIZE_SCALAR(when_freq_update);
233 }
235}
236
237void
239{
240 DPRINTF(Timer, "SystemCounter::unserialize: Unserializing\n");
248 bool pending_freq_update;
249 UNSERIALIZE_SCALAR(pending_freq_update);
250 if (pending_freq_update) {
251 Tick when_freq_update;
252 UNSERIALIZE_SCALAR(when_freq_update);
253 reschedule(_freqUpdateEvent, when_freq_update, true);
254 }
256
258}
259
260ArchTimer::ArchTimer(const std::string &name,
261 SimObject &parent,
262 SystemCounter &sysctr,
263 ArmInterruptPin *interrupt)
264 : _name(name), _parent(parent), _systemCounter(sysctr),
265 _interrupt(interrupt),
266 _control(0), _counterLimit(0), _offset(0),
267 _counterLimitReachedEvent([this]{ counterLimitReached(); }, name)
268{
269 _systemCounter.registerListener(this);
270}
271
272void
274{
275 if (!_control.enable)
276 return;
277
278 DPRINTF(Timer, "Counter limit reached\n");
279 _control.istatus = 1;
280 if (!_control.imask) {
281 if (scheduleEvents()) {
282 DPRINTF(Timer, "Causing interrupt\n");
283 _interrupt->raise();
284 } else {
285 DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n");
286 }
287 }
288}
289
290void
292{
295 if (value() >= _counterLimit) {
297 } else {
298 // Clear the interurpt when timers conditions are not met
299 if (_interrupt->active()) {
300 DPRINTF(Timer, "Clearing interrupt\n");
301 _interrupt->clear();
302 }
303
304 _control.istatus = 0;
305
306 if (scheduleEvents()) {
309 }
310 }
311}
312
313void
319
320void
325
326void
328{
329 ArchTimerCtrl old_ctl = _control, new_ctl = val;
330 _control.enable = new_ctl.enable;
331 _control.imask = new_ctl.imask;
332 _control.istatus = old_ctl.istatus;
333 // Timer unmasked or enabled
334 if ((old_ctl.imask && !new_ctl.imask) ||
335 (!old_ctl.enable && new_ctl.enable))
337 // Timer masked or disabled
338 else if ((!old_ctl.imask && new_ctl.imask) ||
339 (old_ctl.enable && !new_ctl.enable)) {
340
341 if (_interrupt->active()) {
342 DPRINTF(Timer, "Clearing interrupt\n");
343 // We are clearing the interrupt but we are not
344 // setting istatus to 0 as we are doing
345 // in the updateCounter.
346 // istatus signals that Timer conditions are met.
347 // It shouldn't depend on masking.
348 // if enable is zero. istatus is unknown.
349 _interrupt->clear();
350 }
351 }
352}
353
354void
356{
357 _offset = val;
359}
360
361uint64_t
363{
364 return _systemCounter.value() - _offset;
365}
366
367void
372
373void
380
381void
383{
384 paramIn(cp, "control_serial", _control);
385 // We didn't serialize an offset before we added support for the
386 // virtual timer. Consider it optional to maintain backwards
387 // compatibility.
389 _offset = 0;
390
391 // We no longer schedule an event here because we may enter KVM
392 // emulation. The event creation is delayed until drainResume().
393}
394
403
404void
409
410bool
412{
413 if constexpr (USE_KVM &&
414 std::string_view(KVM_ISA) == std::string_view("arm")) {
415 auto *vm = system.getKvmVM();
416 return !vm || !vm->validEnvironment();
417 } else {
418 return true;
419 }
420}
421
422GenericTimer::GenericTimer(const GenericTimerParams &p)
423 : SimObject(p),
424 systemCounter(*p.counter),
425 system(*p.system)
426{
428 fatal_if(!p.system, "GenericTimer::GenericTimer: No system specified, "
429 "can't instantiate architected timers\n");
431}
432
433void
435{
436 paramOut(cp, "cpu_count", timers.size());
437
438 for (int i = 0; i < timers.size(); ++i) {
439 const CoreTimers &core(*timers[i]);
440 core.serializeSection(cp, csprintf("pe_implementation%d", i));
441 }
442}
443
444void
446{
447 // Try to unserialize the CPU count. Old versions of the timer
448 // model assumed a 8 CPUs, so we fall back to that if the field
449 // isn't present.
450 static const unsigned OLD_CPU_MAX = 8;
451 unsigned cpu_count;
452 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
453 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
454 OLD_CPU_MAX);
455 cpu_count = OLD_CPU_MAX;
456 }
457
458 // We cannot assert for equality here because CPU timers are dynamically
459 // created on the first miscreg access. Therefore, if we take the checkpoint
460 // before any timer registers have been accessed, the number of counters
461 // is actually smaller than the total number of CPUs.
462 if (cpu_count > system.threads.size()) {
463 fatal("The simulated system has been initialized with %d CPUs, "
464 "but the Generic Timer checkpoint expects %d CPUs. Consider "
465 "restoring the checkpoint specifying %d CPUs.",
466 system.threads.size(), cpu_count, cpu_count);
467 }
468
469 for (int i = 0; i < cpu_count; ++i) {
470 CoreTimers &core(getTimers(i));
471 core.unserializeSection(cp, csprintf("pe_implementation%d", i));
472 }
473}
474
477{
478 if (cpu_id >= timers.size())
479 createTimers(cpu_id + 1);
480
481 return *timers[cpu_id];
482}
483
484void
486{
487 assert(timers.size() < cpus);
488 auto &p = params();
489
490 const unsigned old_cpu_count(timers.size());
491 timers.resize(cpus);
492 for (unsigned i = old_cpu_count; i < cpus; ++i) {
493
495
496 timers[i].reset(
497 new CoreTimers(*this, system, i,
498 p.int_el3_phys->get(tc),
499 p.int_el1_phys->get(tc),
500 p.int_el1_virt->get(tc),
501 p.int_el2_ns_phys->get(tc),
502 p.int_el2_ns_virt->get(tc),
503 p.int_el2_s_phys->get(tc),
504 p.int_el2_s_virt->get(tc)));
505 }
506}
507
508void
510 ArchTimer *timer, RegVal old_cnt_ctl, RegVal cnt_ctl)
511{
512 uint64_t evnten = bits(cnt_ctl, 2);
513 uint64_t old_evnten = bits(old_cnt_ctl, 2);
514 uint8_t old_trans_to = ev_stream->transitionTo;
515 uint8_t old_trans_bit = ev_stream->transitionBit;
516 ev_stream->transitionTo = !bits(cnt_ctl, 3);
517 ev_stream->transitionBit = bits(cnt_ctl, 7, 4);
518 // Reschedule the Event Stream if enabled and any change in
519 // configuration
520 if (evnten && ((old_evnten != evnten) ||
521 (old_trans_to != ev_stream->transitionTo) ||
522 (old_trans_bit != ev_stream->transitionBit))) {
523
524 Tick when = timer->whenValue(
525 ev_stream->eventTargetValue(timer->value()));
526 reschedule(ev_stream->event, when, true);
527 } else if (old_evnten && !evnten) {
528 // Event Stream generation disabled
529 if (ev_stream->event.scheduled())
530 deschedule(ev_stream->event);
531 }
532}
533
534void
536{
537 CoreTimers &core(getTimers(cpu));
538
539 switch (reg) {
540 case MISCREG_CNTFRQ:
542 core.cntfrq = val;
543 warn_if(core.cntfrq != systemCounter.freq(), "CNTFRQ configured freq "
544 "does not match the system counter freq\n");
545 return;
546 case MISCREG_CNTKCTL:
548 {
549 RegVal old_cnt_ctl = core.cntkctl;
550 core.cntkctl = val;
551
552 ArchTimer *timer = &core.virtEL1;
553 CoreTimers::EventStream *ev_stream = &core.virtEvStream;
554
555 handleStream(ev_stream, timer, old_cnt_ctl, val);
556 return;
557 }
558 case MISCREG_CNTHCTL:
560 {
561 RegVal old_cnt_ctl = core.cnthctl;
562 core.cnthctl = val;
563
564 ArchTimer *timer = &core.physEL1;
565 CoreTimers::EventStream *ev_stream = &core.physEvStream;
566
567 handleStream(ev_stream, timer, old_cnt_ctl, val);
568 return;
569 }
570 // EL1 physical timer
574 return;
575
579 return;
580
583 core.physEL1.setControl(val);
584 return;
585
586 // Count registers
587 case MISCREG_CNTPCT:
589 case MISCREG_CNTVCT:
591 warn("Ignoring write to read only count register: %s\n",
593 return;
594
595 // EL1 virtual timer
596 case MISCREG_CNTVOFF:
598 core.virtEL1.setOffset(val);
599 return;
600
604 return;
605
609 return;
610
611 case MISCREG_CNTV_CTL:
613 core.virtEL1.setControl(val);
614 return;
615
616 // EL3 physical timer
619 core.physEL3.setControl(val);
620 return;
621
625 return;
626
630 return;
631
632 // EL2 Non-secure physical timer
636 return;
637
641 return;
642
646 return;
647
648 // EL2 Non-secure virtual timer
651 return;
652
655 return;
656
659 return;
660
661 // EL2 Secure physical timer
663 core.physSEL2.setControl(val);
664 return;
665
668 return;
669
672 return;
673
674 // EL2 Secure virtual timer
676 core.virtSEL2.setControl(val);
677 return;
678
681 return;
682
685 return;
686
687 default:
688 warn("Writing to unknown register: %s\n", miscRegName[reg]);
689 return;
690 }
691}
692
693
694RegVal
696{
697 CoreTimers &core(getTimers(cpu));
698
699 switch (reg) {
700 case MISCREG_CNTFRQ:
702 return core.cntfrq;
703 case MISCREG_CNTKCTL:
705 return core.cntkctl & 0x00000000ffffffff;
706 case MISCREG_CNTHCTL:
708 return core.cnthctl & 0x00000000ffffffff;
709 // EL1 physical timer
712 return core.physEL1.compareValue();
713
716 return core.physEL1.timerValue();
717
720 return core.physEL1.control();
721
722 case MISCREG_CNTPCT:
724 return core.physEL1.value();
725
726
727 // EL1 virtual timer
728 case MISCREG_CNTVCT:
730 return core.virtEL1.value();
731
732 case MISCREG_CNTVOFF:
734 return core.virtEL1.offset();
735
738 return core.virtEL1.compareValue();
739
742 return core.virtEL1.timerValue();
743
744 case MISCREG_CNTV_CTL:
746 return core.virtEL1.control();
747
748 // EL3 physical timer
751 return core.physEL3.control();
752
755 return core.physEL3.compareValue();
756
759 return core.physEL3.timerValue();
760
761 // EL2 Non-secure physical timer
764 return core.physNsEL2.control();
765
768 return core.physNsEL2.compareValue();
769
772 return core.physNsEL2.timerValue();
773
774 // EL2 Non-secure virtual timer
776 return core.virtNsEL2.control();
777
779 return core.virtNsEL2.compareValue();
780
782 return core.virtNsEL2.timerValue();
783
784 // EL2 Secure physical timer
786 return core.physSEL2.control();
787
789 return core.physSEL2.compareValue();
790
792 return core.physSEL2.timerValue();
793
794 // EL2 Secure virtual timer
796 return core.virtSEL2.control();
797
799 return core.virtSEL2.compareValue();
800
802 return core.virtSEL2.timerValue();
803
804 default:
805 warn("Reading from unknown register: %s\n", miscRegName[reg]);
806 return 0;
807 }
808}
809
811 ArmSystem &system, unsigned cpu,
812 ArmInterruptPin *irq_el3_phys, ArmInterruptPin *irq_el1_phys,
813 ArmInterruptPin *irq_el1_virt, ArmInterruptPin *irq_el2_ns_phys,
814 ArmInterruptPin *irq_el2_ns_virt, ArmInterruptPin *irq_el2_s_phys,
815 ArmInterruptPin *irq_el2_s_virt)
816 : parent(_parent),
817 cntfrq(parent.params().cntfrq),
818 cntkctl(0), cnthctl(0),
819 threadContext(system.threads[cpu]),
820 irqPhysEL3(irq_el3_phys),
821 irqPhysEL1(irq_el1_phys),
822 irqVirtEL1(irq_el1_virt),
823 irqPhysNsEL2(irq_el2_ns_phys),
824 irqVirtNsEL2(irq_el2_ns_virt),
825 irqPhysSEL2(irq_el2_s_phys),
826 irqVirtSEL2(irq_el2_s_virt),
827 physEL3(csprintf("%s.el3_phys_timer%d", parent.name(), cpu),
828 system, parent, parent.systemCounter,
829 irq_el3_phys),
830 physEL1(csprintf("%s.el1_phys_timer%d", parent.name(), cpu),
831 system, parent, parent.systemCounter,
832 irq_el1_phys),
833 virtEL1(csprintf("%s.el1_virt_timer%d", parent.name(), cpu),
834 system, parent, parent.systemCounter,
835 irq_el1_virt),
836 physNsEL2(csprintf("%s.el2_ns_phys_timer%d", parent.name(), cpu),
837 system, parent, parent.systemCounter,
838 irq_el2_ns_phys),
839 virtNsEL2(csprintf("%s.el2_ns_virt_timer%d", parent.name(), cpu),
840 system, parent, parent.systemCounter,
841 irq_el2_ns_virt),
842 physSEL2(csprintf("%s.el2_s_phys_timer%d", parent.name(), cpu),
843 system, parent, parent.systemCounter,
844 irq_el2_s_phys),
845 virtSEL2(csprintf("%s.el2_s_virt_timer%d", parent.name(), cpu),
846 system, parent, parent.systemCounter,
847 irq_el2_s_virt),
848 physEvStream{
850 csprintf("%s.phys_event_gen%d", parent.name(), cpu)), 0, 0
851 },
852 virtEvStream{
853 EventFunctionWrapper([this]{ virtEventStreamCallback(); },
854 csprintf("%s.virt_event_gen%d", parent.name(), cpu)), 0, 0
855 }
856{
857}
858
859void
865
866void
868{
869 eventStreamCallback();
870 schedNextEvent(virtEvStream, virtEL1);
871}
872
873void
875{
876 sendEvent(threadContext);
877 threadContext->getCpuPtr()->wakeup(threadContext->threadId());
878}
879
880void
882 ArchTimer &timer)
883{
884 parent.reschedule(ev_stream.event, timer.whenValue(
885 ev_stream.eventTargetValue(timer.value())), true);
886}
887
888void
890{
891 schedNextEvent(virtEvStream, virtEL1);
892 schedNextEvent(physEvStream, physEL1);
893}
894
895void
897{
898 SERIALIZE_SCALAR(cntfrq);
899 SERIALIZE_SCALAR(cntkctl);
900 SERIALIZE_SCALAR(cnthctl);
901
902 const bool phys_ev_scheduled = physEvStream.event.scheduled();
903 SERIALIZE_SCALAR(phys_ev_scheduled);
904 if (phys_ev_scheduled) {
905 const Tick phys_ev_when = physEvStream.event.when();
906 SERIALIZE_SCALAR(phys_ev_when);
907 }
908 SERIALIZE_SCALAR(physEvStream.transitionTo);
909 SERIALIZE_SCALAR(physEvStream.transitionBit);
910
911 const bool virt_ev_scheduled = virtEvStream.event.scheduled();
912 SERIALIZE_SCALAR(virt_ev_scheduled);
913 if (virt_ev_scheduled) {
914 const Tick virt_ev_when = virtEvStream.event.when();
915 SERIALIZE_SCALAR(virt_ev_when);
916 }
917 SERIALIZE_SCALAR(virtEvStream.transitionTo);
918 SERIALIZE_SCALAR(virtEvStream.transitionBit);
919
920 physEL3.serializeSection(cp, "phys_el3_timer");
921 physEL1.serializeSection(cp, "phys_el1_timer");
922 virtEL1.serializeSection(cp, "virt_el1_timer");
923 physNsEL2.serializeSection(cp, "phys_ns_el2_timer");
924 virtNsEL2.serializeSection(cp, "virt_ns_el2_timer");
925 physSEL2.serializeSection(cp, "phys_s_el2_timer");
926 virtSEL2.serializeSection(cp, "virt_s_el2_timer");
927}
928
929void
931{
932 UNSERIALIZE_SCALAR(cntfrq);
933 UNSERIALIZE_SCALAR(cntkctl);
934 UNSERIALIZE_SCALAR(cnthctl);
935
936 bool phys_ev_scheduled;
937 UNSERIALIZE_SCALAR(phys_ev_scheduled);
938 if (phys_ev_scheduled) {
939 Tick phys_ev_when;
940 UNSERIALIZE_SCALAR(phys_ev_when);
941 parent.reschedule(physEvStream.event, phys_ev_when, true);
942 }
943 UNSERIALIZE_SCALAR(physEvStream.transitionTo);
944 UNSERIALIZE_SCALAR(physEvStream.transitionBit);
945
946 bool virt_ev_scheduled;
947 UNSERIALIZE_SCALAR(virt_ev_scheduled);
948 if (virt_ev_scheduled) {
949 Tick virt_ev_when;
950 UNSERIALIZE_SCALAR(virt_ev_when);
951 parent.reschedule(virtEvStream.event, virt_ev_when, true);
952 }
953 UNSERIALIZE_SCALAR(virtEvStream.transitionTo);
954 UNSERIALIZE_SCALAR(virtEvStream.transitionBit);
955
956 physEL3.unserializeSection(cp, "phys_el3_timer");
957 physEL1.unserializeSection(cp, "phys_el1_timer");
958 virtEL1.unserializeSection(cp, "virt_el1_timer");
959 physNsEL2.unserializeSection(cp, "phys_ns_el2_timer");
960 virtNsEL2.unserializeSection(cp, "virt_ns_el2_timer");
961 physSEL2.unserializeSection(cp, "phys_s_el2_timer");
962 virtSEL2.unserializeSection(cp, "virt_s_el2_timer");
963}
964
965void
967{
968 DPRINTF(Timer, "Setting %s := 0x%x\n", miscRegName[reg], val);
969 parent.setMiscReg(reg, cpu, val);
970}
971
972RegVal
974{
975 RegVal value = parent.readMiscReg(reg, cpu);
976 DPRINTF(Timer, "Reading %s as 0x%x\n", miscRegName[reg], value);
977 return value;
978}
979
980GenericTimerFrame::GenericTimerFrame(const GenericTimerFrameParams &p)
981 : PioDevice(p),
982 timerRange(RangeSize(p.cnt_base, ArmSystem::PageBytes)),
983 addrRanges({timerRange}),
984 systemCounter(*p.counter),
985 physTimer(csprintf("%s.phys_timer", name()),
986 *this, systemCounter, p.int_phys->get()),
987 virtTimer(csprintf("%s.virt_timer", name()),
988 *this, systemCounter,
989 p.int_virt->get()),
990 accessBits(0x3f),
991 system(*dynamic_cast<ArmSystem *>(sys))
992{
994 // Expose optional CNTEL0Base register frame
995 if (p.cnt_el0_base != MaxAddr) {
996 timerEl0Range = RangeSize(p.cnt_el0_base, ArmSystem::PageBytes);
997 accessBitsEl0 = 0x303;
998 addrRanges.push_back(timerEl0Range);
999 }
1000 for (auto &range : addrRanges)
1001 GenericTimerMem::validateFrameRange(range);
1002}
1003
1004void
1006{
1007 SERIALIZE_SCALAR(accessBits);
1008 if (hasEl0View())
1009 SERIALIZE_SCALAR(accessBitsEl0);
1011
1012 physTimer.serializeSection(cp, "phys_timer");
1013 virtTimer.serializeSection(cp, "virt_timer");
1014}
1015
1016void
1018{
1019 UNSERIALIZE_SCALAR(accessBits);
1020 if (hasEl0View())
1021 UNSERIALIZE_SCALAR(accessBitsEl0);
1023
1024 physTimer.unserializeSection(cp, "phys_timer");
1025 virtTimer.unserializeSection(cp, "virt_timer");
1026}
1027
1028uint64_t
1030{
1031 return virtTimer.offset();
1032}
1033
1034void
1036{
1037 virtTimer.setOffset(new_offset);
1038}
1039
1040bool
1042{
1043 return timerEl0Range.valid();
1044}
1045
1046uint8_t
1048{
1049 return accessBits;
1050}
1051
1052void
1054{
1055 accessBits = data & 0x3f;
1056}
1057
1058bool
1063
1064void
1069
1070bool
1072{
1073 return accessBits.rvoff;
1074}
1075
1078{
1079 return addrRanges;
1080}
1081
1082Tick
1084{
1085 const Addr addr = pkt->getAddr();
1086 const size_t size = pkt->getSize();
1087 const bool is_sec = pkt->isSecure();
1088 panic_if(size != 4 && size != 8,
1089 "GenericTimerFrame::read: Invalid size %i\n", size);
1090
1091 bool to_el0 = false;
1092 uint64_t resp = 0;
1093 Addr offset = 0;
1094 if (timerRange.contains(addr)) {
1096 } else if (hasEl0View() && timerEl0Range.contains(addr)) {
1098 to_el0 = true;
1099 } else {
1100 panic("GenericTimerFrame::read: Invalid address: 0x%x\n", addr);
1101 }
1102
1103 resp = timerRead(offset, size, is_sec, to_el0);
1104
1105 DPRINTF(Timer, "GenericTimerFrame::read: 0x%x<-0x%x(%i) [S = %u]\n", resp,
1106 addr, size, is_sec);
1107
1108 pkt->setUintX(resp, ByteOrder::little);
1109 pkt->makeResponse();
1110 return 0;
1111}
1112
1113Tick
1115{
1116 const Addr addr = pkt->getAddr();
1117 const size_t size = pkt->getSize();
1118 const bool is_sec = pkt->isSecure();
1119 panic_if(size != 4 && size != 8,
1120 "GenericTimerFrame::write: Invalid size %i\n", size);
1121
1122 bool to_el0 = false;
1123 const uint64_t data = pkt->getUintX(ByteOrder::little);
1124 Addr offset = 0;
1125 if (timerRange.contains(addr)) {
1127 } else if (hasEl0View() && timerEl0Range.contains(addr)) {
1129 to_el0 = true;
1130 } else {
1131 panic("GenericTimerFrame::write: Invalid address: 0x%x\n", addr);
1132 }
1133
1134 timerWrite(offset, size, data, is_sec, to_el0);
1135
1136 DPRINTF(Timer, "GenericTimerFrame::write: 0x%x->0x%x(%i) [S = %u]\n", data,
1137 addr, size, is_sec);
1138
1139 pkt->makeResponse();
1140 return 0;
1141}
1142
1143uint64_t
1144GenericTimerFrame::timerRead(Addr addr, size_t size, bool is_sec,
1145 bool to_el0) const
1146{
1149 return 0;
1150
1151 switch (addr) {
1152 case TIMER_CNTPCT_LO:
1153 if (!accessBits.rpct || (to_el0 && !accessBitsEl0.pcten))
1154 return 0;
1155 else
1156 return physTimer.value();
1157
1158 case TIMER_CNTPCT_HI:
1159 if (!accessBits.rpct || (to_el0 && !accessBitsEl0.pcten))
1160 return 0;
1161 else
1162 return physTimer.value() >> 32;
1163
1164 case TIMER_CNTFRQ:
1165 if ((!accessBits.rfrq) ||
1166 (to_el0 && (!accessBitsEl0.pcten && !accessBitsEl0.vcten)))
1167 return 0;
1168 else
1169 return systemCounter.freq();
1170
1171 case TIMER_CNTEL0ACR:
1172 if (!hasEl0View() || to_el0)
1173 return 0;
1174 else
1175 return accessBitsEl0;
1176
1177 case TIMER_CNTP_CVAL_LO:
1178 if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1179 return 0;
1180 else
1181 return physTimer.compareValue();
1182
1183 case TIMER_CNTP_CVAL_HI:
1184 if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1185 return 0;
1186 else
1187 return physTimer.compareValue() >> 32;
1188
1189 case TIMER_CNTP_TVAL:
1190 if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1191 return 0;
1192 else
1193 return physTimer.timerValue();
1194 case TIMER_CNTP_CTL:
1195 if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1196 return 0;
1197 else
1198 return physTimer.control();
1199
1200 case TIMER_CNTVCT_LO:
1201 if (!accessBits.rvct || (to_el0 && !accessBitsEl0.vcten))
1202 return 0;
1203 else
1204 return virtTimer.value();
1205
1206 case TIMER_CNTVCT_HI:
1207 if (!accessBits.rvct || (to_el0 && !accessBitsEl0.vcten))
1208 return 0;
1209 else
1210 return virtTimer.value() >> 32;
1211
1212 case TIMER_CNTVOFF_LO:
1213 if (!accessBits.rvoff || (to_el0))
1214 return 0;
1215 else
1216 return virtTimer.offset();
1217
1218 case TIMER_CNTVOFF_HI:
1219 if (!accessBits.rvoff || (to_el0))
1220 return 0;
1221 else
1222 return virtTimer.offset() >> 32;
1223
1224 case TIMER_CNTV_CVAL_LO:
1225 if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1226 return 0;
1227 else
1228 return virtTimer.compareValue();
1229
1230 case TIMER_CNTV_CVAL_HI:
1231 if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1232 return 0;
1233 else
1234 return virtTimer.compareValue() >> 32;
1235
1236 case TIMER_CNTV_TVAL:
1237 if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1238 return 0;
1239 else
1240 return virtTimer.timerValue();
1241
1242 case TIMER_CNTV_CTL:
1243 if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1244 return 0;
1245 else
1246 return virtTimer.control();
1247
1248 default:
1249 warn("GenericTimerFrame::timerRead: Unexpected address (0x%x:%i), "
1250 "assuming RAZ\n", addr, size);
1251 return 0;
1252 }
1253}
1254
1255void
1257 bool is_sec, bool to_el0)
1258{
1261 return;
1262
1263 switch (addr) {
1265 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTPCT]\n",
1266 addr);
1267 return;
1268
1269 case TIMER_CNTFRQ:
1270 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTFRQ]\n",
1271 addr);
1272 return;
1273
1274 case TIMER_CNTEL0ACR:
1275 if (!hasEl0View() || to_el0)
1276 return;
1277
1278 insertBits(accessBitsEl0, 9, 8, data);
1279 insertBits(accessBitsEl0, 1, 0, data);
1280 return;
1281
1282 case TIMER_CNTP_CVAL_LO:
1283 if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1284 return;
1285 data = size == 4 ? insertBits(physTimer.compareValue(),
1286 31, 0, data) : data;
1288 return;
1289
1290 case TIMER_CNTP_CVAL_HI:
1291 if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1292 return;
1295 return;
1296
1297 case TIMER_CNTP_TVAL:
1298 if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1299 return;
1301 return;
1302
1303 case TIMER_CNTP_CTL:
1304 if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1305 return;
1307 return;
1308
1310 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVCT]\n",
1311 addr);
1312 return;
1314 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVOFF]\n",
1315 addr);
1316 return;
1317
1318 case TIMER_CNTV_CVAL_LO:
1319 if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1320 return;
1321 data = size == 4 ? insertBits(virtTimer.compareValue(),
1322 31, 0, data) : data;
1324 return;
1325
1326 case TIMER_CNTV_CVAL_HI:
1327 if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1328 return;
1331 return;
1332
1333 case TIMER_CNTV_TVAL:
1334 if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1335 return;
1337 return;
1338
1339 case TIMER_CNTV_CTL:
1340 if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1341 return;
1343 return;
1344
1345 default:
1346 warn("GenericTimerFrame::timerWrite: Unexpected address (0x%x:%i), "
1347 "assuming WI\n", addr, size);
1348 }
1349}
1350
1351GenericTimerMem::GenericTimerMem(const GenericTimerMemParams &p)
1352 : PioDevice(p),
1353 counterCtrlRange(RangeSize(p.cnt_control_base, ArmSystem::PageBytes)),
1354 counterStatusRange(RangeSize(p.cnt_read_base, ArmSystem::PageBytes)),
1355 timerCtrlRange(RangeSize(p.cnt_ctl_base, ArmSystem::PageBytes)),
1356 cnttidr(0x0),
1357 addrRanges{counterCtrlRange, counterStatusRange, timerCtrlRange},
1358 systemCounter(*p.counter),
1359 frames(p.frames),
1360 system(*dynamic_cast<ArmSystem *>(sys))
1361{
1363 for (auto &range : addrRanges)
1366 "GenericTimerMem::GenericTimerMem: Architecture states a maximum of "
1367 "8 memory-mapped timer frames, limit surpassed\n");
1368 // Initialize CNTTIDR with each frame's features
1369 for (int i = 0; i < frames.size(); i++) {
1370 uint32_t features = 0x1;
1371 features |= 0x2;
1372 if (frames[i]->hasEl0View())
1373 features |= 0x4;
1374 features <<= i * 4;
1375 replaceBits(cnttidr, (i + 1) * 4 - 1, i * 4, features);
1376 }
1377}
1378
1379void
1381{
1383 "GenericTimerMem::validateFrameRange: Architecture states each "
1384 "register frame should be in a separate memory page, specified "
1385 "range base address [0x%x] is not compliant\n");
1386}
1387
1388bool
1390{
1391 return !sys.has(ArmExtension::SECURITY) || is_sec;
1392}
1393
1396{
1397 return addrRanges;
1398}
1399
1400Tick
1402{
1403 const Addr addr = pkt->getAddr();
1404 const size_t size = pkt->getSize();
1405 const bool is_sec = pkt->isSecure();
1406 panic_if(size != 4 && size != 8,
1407 "GenericTimerMem::read: Invalid size %i\n", size);
1408
1409 uint64_t resp = 0;
1411 resp = counterCtrlRead(addr - counterCtrlRange.start(), size, is_sec);
1414 else if (timerCtrlRange.contains(addr))
1415 resp = timerCtrlRead(addr - timerCtrlRange.start(), size, is_sec);
1416 else
1417 panic("GenericTimerMem::read: Invalid address: 0x%x\n", addr);
1418
1419 DPRINTF(Timer, "GenericTimerMem::read: 0x%x<-0x%x(%i) [S = %u]\n", resp,
1420 addr, size, is_sec);
1421
1422 pkt->setUintX(resp, ByteOrder::little);
1423 pkt->makeResponse();
1424 return 0;
1425}
1426
1427Tick
1429{
1430 const Addr addr = pkt->getAddr();
1431 const size_t size = pkt->getSize();
1432 const bool is_sec = pkt->isSecure();
1433 panic_if(size != 4 && size != 8,
1434 "GenericTimerMem::write: Invalid size %i\n", size);
1435
1436 const uint64_t data = pkt->getUintX(ByteOrder::little);
1438 counterCtrlWrite(addr - counterCtrlRange.start(), size, data, is_sec);
1441 else if (timerCtrlRange.contains(addr))
1442 timerCtrlWrite(addr - timerCtrlRange.start(), size, data, is_sec);
1443 else
1444 panic("GenericTimerMem::write: Invalid address: 0x%x\n", addr);
1445
1446 DPRINTF(Timer, "GenericTimerMem::write: 0x%x->0x%x(%i) [S = %u]\n", data,
1447 addr, size, is_sec);
1448
1449 pkt->makeResponse();
1450 return 0;
1451}
1452
1453uint64_t
1454GenericTimerMem::counterCtrlRead(Addr addr, size_t size, bool is_sec) const
1455{
1457 return 0;
1458 switch (addr) {
1459 case COUNTER_CTRL_CNTCR:
1460 {
1461 CNTCR cntcr = 0;
1462 cntcr.en = systemCounter.enabled();
1463 cntcr.fcreq = systemCounter.activeFreqEntry();
1464 return cntcr;
1465 }
1466 case COUNTER_CTRL_CNTSR:
1467 {
1468 CNTSR cntsr = 0;
1469 cntsr.fcack = systemCounter.activeFreqEntry();
1470 return cntsr;
1471 }
1473 case COUNTER_CTRL_CNTCV_HI: return systemCounter.value() >> 32;
1474 case COUNTER_CTRL_CNTSCR: return 0;
1475 case COUNTER_CTRL_CNTID: return 0;
1476 default:
1477 {
1478 auto &freq_table = systemCounter.freqTable();
1479 for (int i = 0; i < (freq_table.size() - 1); i++) {
1480 Addr offset = COUNTER_CTRL_CNTFID + (i * 0x4);
1481 if (addr == offset)
1482 return freq_table[i];
1483 }
1484 warn("GenericTimerMem::counterCtrlRead: Unexpected address "
1485 "(0x%x:%i), assuming RAZ\n", addr, size);
1486 return 0;
1487 }
1488 }
1489}
1490
1491void
1493 bool is_sec)
1494{
1496 return;
1497
1498 switch (addr) {
1499 case COUNTER_CTRL_CNTCR:
1500 {
1501 CNTCR val = data;
1502 if (!systemCounter.enabled() && val.en)
1504 else if (systemCounter.enabled() && !val.en)
1506
1507 if (val.hdbg)
1508 warn("GenericTimerMem::counterCtrlWrite: Halt-on-debug is not "
1509 "supported\n");
1510 if (val.scen)
1511 warn("GenericTimerMem::counterCtrlWrite: Counter Scaling is not "
1512 "supported\n");
1513 if (val.fcreq != systemCounter.activeFreqEntry())
1515 return;
1516 }
1517
1518 case COUNTER_CTRL_CNTSR:
1519 warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTSR]\n",
1520 addr);
1521 return;
1522
1524 data = size == 4 ? insertBits(systemCounter.value(), 31, 0, data)
1525 : data;
1527 return;
1528
1530 data = insertBits(systemCounter.value(), 63, 32, data);
1532 return;
1533
1535 return;
1536
1537 case COUNTER_CTRL_CNTID:
1538 warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTID]\n",
1539 addr);
1540 return;
1541
1542 default:
1543 {
1544 auto &freq_table = systemCounter.freqTable();
1545 for (int i = 0; i < (freq_table.size() - 1); i++) {
1546 Addr offset = COUNTER_CTRL_CNTFID + (i * 0x4);
1547 if (addr == offset) {
1548 freq_table[i] = data;
1549 // This is changing the currently selected frequency
1550 if (i == systemCounter.activeFreqEntry()) {
1551 // We've changed the frequency in the table entry,
1552 // however the counter will still work with the
1553 // current one until transition is completed
1555 }
1556 return;
1557 }
1558 }
1559 warn("GenericTimerMem::counterCtrlWrite: Unexpected address "
1560 "(0x%x:%i), assuming WI\n", addr, size);
1561 }
1562 }
1563}
1564
1565uint64_t
1567{
1568 switch (addr) {
1570 case COUNTER_STATUS_CNTCV_HI: return systemCounter.value() >> 32;
1571 default:
1572 warn("GenericTimerMem::counterStatusRead: Unexpected address "
1573 "(0x%x:%i), assuming RAZ\n", addr, size);
1574 return 0;
1575 }
1576}
1577
1578void
1580{
1581 switch (addr) {
1583 warn("GenericTimerMem::counterStatusWrite: RO reg (0x%x) [CNTCV]\n",
1584 addr);
1585 return;
1586 default:
1587 warn("GenericTimerMem::counterStatusWrite: Unexpected address "
1588 "(0x%x:%i), assuming WI\n", addr, size);
1589 }
1590}
1591
1592uint64_t
1593GenericTimerMem::timerCtrlRead(Addr addr, size_t size, bool is_sec) const
1594{
1595 switch (addr) {
1596 case TIMER_CTRL_CNTFRQ:
1597 if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return 0;
1598 return systemCounter.freq();
1599 case TIMER_CTRL_CNTNSAR:
1600 {
1601 if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return 0;
1602 uint32_t cntnsar = 0x0;
1603 for (int i = 0; i < frames.size(); i++) {
1604 if (frames[i]->hasNonSecureAccess())
1605 cntnsar |= 0x1 << i;
1606 }
1607 return cntnsar;
1608 }
1609 case TIMER_CTRL_CNTTIDR: return cnttidr;
1610 default:
1611 for (int i = 0; i < frames.size(); i++) {
1612 Addr cntacr_off = TIMER_CTRL_CNTACR + (i * 0x4);
1613 Addr cntvoff_lo_off = TIMER_CTRL_CNTVOFF_LO + (i * 0x4);
1614 Addr cntvoff_hi_off = TIMER_CTRL_CNTVOFF_HI + (i * 0x4);
1615 // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1616 // normal world
1617 bool hit = addr == cntacr_off || addr == cntvoff_lo_off ||
1618 addr == cntvoff_hi_off;
1619 bool has_access =
1621 frames[i]->hasNonSecureAccess();
1622 if (hit && !has_access) return 0;
1623 if (addr == cntacr_off)
1624 return frames[i]->getAccessBits();
1625 if (addr == cntvoff_lo_off || addr == cntvoff_hi_off) {
1626 return addr == cntvoff_lo_off ? frames[i]->getVirtOffset()
1627 : frames[i]->getVirtOffset() >> 32;
1628 }
1629 }
1630 warn("GenericTimerMem::timerCtrlRead: Unexpected address (0x%x:%i), "
1631 "assuming RAZ\n", addr, size);
1632 return 0;
1633 }
1634}
1635
1636void
1638 bool is_sec)
1639{
1640 switch (addr) {
1641 case TIMER_CTRL_CNTFRQ:
1642 if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return;
1644 "GenericTimerMem::timerCtrlWrite: CNTFRQ configured freq "
1645 "does not match the counter freq, ignoring\n");
1646 return;
1647 case TIMER_CTRL_CNTNSAR:
1648 if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return;
1649 for (int i = 0; i < frames.size(); i++) {
1650 // Check if the CNTNSAR.NS bit is set for this frame
1651 if (data & (0x1 << i))
1652 frames[i]->setNonSecureAccess();
1653 }
1654 return;
1655 case TIMER_CTRL_CNTTIDR:
1656 warn("GenericTimerMem::timerCtrlWrite: RO reg (0x%x) [CNTTIDR]\n",
1657 addr);
1658 return;
1659 default:
1660 for (int i = 0; i < frames.size(); i++) {
1661 Addr cntacr_off = TIMER_CTRL_CNTACR + (i * 0x4);
1662 Addr cntvoff_lo_off = TIMER_CTRL_CNTVOFF_LO + (i * 0x4);
1663 Addr cntvoff_hi_off = TIMER_CTRL_CNTVOFF_HI + (i * 0x4);
1664 // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1665 // normal world
1666 bool hit = addr == cntacr_off || addr == cntvoff_lo_off ||
1667 addr == cntvoff_hi_off;
1668 bool has_access =
1670 frames[i]->hasNonSecureAccess();
1671 if (hit && !has_access) return;
1672 if (addr == cntacr_off) {
1673 frames[i]->setAccessBits(data);
1674 return;
1675 }
1676 if (addr == cntvoff_lo_off || addr == cntvoff_hi_off) {
1677 if (addr == cntvoff_lo_off)
1678 data = size == 4 ? insertBits(frames[i]->getVirtOffset(),
1679 31, 0, data) : data;
1680 else
1681 data = insertBits(frames[i]->getVirtOffset(),
1682 63, 32, data);
1683 frames[i]->setVirtOffset(data);
1684 return;
1685 }
1686 }
1687 warn("GenericTimerMem::timerCtrlWrite: Unexpected address "
1688 "(0x%x:%i), assuming WI\n", addr, size);
1689 }
1690}
1691
1692} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
Base class for ARM GIC implementations.
const char data[]
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition addr_range.hh:82
bool scheduleEvents() override
Per-CPU architected timer.
EventFunctionWrapper _counterLimitReachedEvent
void setTimerValue(uint32_t val)
Sets the TimerValue view of the timer.
uint32_t timerValue() const
Returns the TimerValue view of the timer.
virtual bool scheduleEvents()
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
EndBitUnion(ArchTimerCtrl) const std SimObject & _parent
Name of this timer.
void drainResume() override
Resume execution after a successful drain.
uint64_t compareValue() const
Returns the CompareValue view of the timer.
uint64_t _offset
Offset relative to the physical timer (CNTVOFF)
void notify(void) override
Called from the SystemCounter when a change in counting speed occurred Events should be rescheduled p...
void setCompareValue(uint64_t val)
Sets the CompareValue view of the timer.
ArchTimer(const std::string &name, SimObject &parent, SystemCounter &sysctr, ArmInterruptPin *interrupt)
ArchTimerCtrl _control
Value of the control register ({CNTP/CNTHP/CNTV}_CTL).
void setOffset(uint64_t val)
void serialize(CheckpointOut &cp) const override
Serialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
uint64_t value() const
Returns the value of the counter which this timer relies on.
void setControl(uint32_t val)
uint32_t control() const
Sets the control register.
void updateCounter()
Timer settings or the offset has changed, re-evaluate trigger condition and raise interrupt if necess...
SystemCounter & _systemCounter
void counterLimitReached()
Called when the upcounter reaches the programmed value.
uint64_t offset() const
ArmInterruptPin *const _interrupt
uint64_t _counterLimit
Programmed limit value for the upcounter ({CNTP/CNTHP/CNTV}_CVAL).
Tick whenValue(uint64_t target_val)
Generic representation of an Arm interrupt pin.
Definition base_gic.hh:200
virtual void clear()=0
Clear a signalled interrupt.
virtual void raise()=0
Signal an interrupt.
bool active() const
True if interrupt pin is active, false otherwise.
Definition base_gic.hh:219
void setGenericTimer(GenericTimer *generic_timer)
Sets the pointer to the Generic Timer.
Definition system.hh:162
static constexpr Addr PageBytes
Definition system.hh:146
GenericTimerFrame(const GenericTimerFrameParams &p)
static const Addr TIMER_CNTP_CTL
void serialize(CheckpointOut &cp) const override
Serialize an object.
static const Addr TIMER_CNTV_TVAL
bool nonSecureAccess
Reports whether non-secure accesses are allowed to this frame.
uint64_t timerRead(Addr addr, size_t size, bool is_sec, bool to_el0) const
CNTBase/CNTEL0Base (Memory-mapped timer frame)
bool hasEl0View() const
Indicates if this frame implements a second EL0 view.
static const Addr TIMER_CNTP_CVAL_HI
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
static const Addr TIMER_CNTV_CVAL_LO
static const Addr TIMER_CNTVCT_LO
uint8_t getAccessBits() const
Returns the access bits for this frame.
static const Addr TIMER_CNTFRQ
SystemCounter & systemCounter
System counter reference.
bool hasNonSecureAccess() const
Indicates if non-secure accesses are allowed to this frame.
ArchTimer physTimer
Physical and virtual timers.
static const Addr TIMER_CNTP_CVAL_LO
void setAccessBits(uint8_t data)
Updates the access bits after a write to CNTCTLBase.CNTACR.
static const Addr TIMER_CNTV_CVAL_HI
void setVirtOffset(uint64_t new_offset)
Sets the virtual offset for this frame's virtual timer after a write to CNTVOFF.
const AddrRange timerRange
AddrRangeList getAddrRanges() const override
Every PIO device is obliged to provide an implementation that returns the address ranges the device r...
static const Addr TIMER_CNTP_TVAL
static const Addr TIMER_CNTVOFF_HI
static const Addr TIMER_CNTVCT_HI
AddrRangeList addrRanges
All MMIO ranges GenericTimerFrame responds to.
bool hasReadableVoff() const
Indicates if CNTVOFF is readable for this frame.
static const Addr TIMER_CNTPCT_LO
static const Addr TIMER_CNTVOFF_LO
static const Addr TIMER_CNTPCT_HI
uint64_t getVirtOffset() const
Returns the virtual offset for this frame if a virtual timer is implemented.
static const Addr TIMER_CNTEL0ACR
void setNonSecureAccess()
Allows non-secure accesses after an enabling write to CNTCTLBase.CNTNSAR.
static const Addr TIMER_CNTV_CTL
void timerWrite(Addr addr, size_t size, uint64_t data, bool is_sec, bool to_el0)
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
RegVal readMiscReg(int misc_reg) override
Read a system register belonging to this device.
void setMiscReg(int misc_reg, RegVal val) override
Write to a system register belonging to this device.
void counterCtrlWrite(Addr addr, size_t size, uint64_t data, bool is_sec)
static const Addr COUNTER_CTRL_CNTID
uint64_t counterCtrlRead(Addr addr, size_t size, bool is_sec) const
CNTControlBase (System counter control frame)
const AddrRange timerCtrlRange
static const Addr TIMER_CTRL_CNTTIDR
static const Addr COUNTER_CTRL_CNTCV_HI
static const Addr COUNTER_CTRL_CNTFID
GenericTimerMem(const GenericTimerMemParams &p)
static const Addr COUNTER_CTRL_CNTCV_LO
void counterStatusWrite(Addr addr, size_t size, uint64_t data)
std::vector< GenericTimerFrame * > frames
Timer frame references.
static const Addr TIMER_CTRL_CNTFRQ
static const Addr COUNTER_STATUS_CNTCV_HI
static const Addr COUNTER_CTRL_CNTSCR
const AddrRange counterStatusRange
static const Addr TIMER_CTRL_CNTACR
uint64_t timerCtrlRead(Addr addr, size_t size, bool is_sec) const
CNTCTLBase (Memory-mapped timer global control frame)
const AddrRange counterCtrlRange
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
static const Addr TIMER_CTRL_CNTVOFF_LO
static void validateFrameRange(const AddrRange &range)
Validates a Generic Timer register frame address range.
uint64_t counterStatusRead(Addr addr, size_t size) const
CNTReadBase (System counter status frame)
static const Addr COUNTER_STATUS_CNTCV_LO
AddrRangeList getAddrRanges() const override
Every PIO device is obliged to provide an implementation that returns the address ranges the device r...
void timerCtrlWrite(Addr addr, size_t size, uint64_t data, bool is_sec)
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
uint32_t cnttidr
ID register for reporting features of implemented timer frames.
static const Addr COUNTER_CTRL_CNTSR
SystemCounter & systemCounter
System counter reference.
const AddrRangeList addrRanges
All MMIO ranges GenericTimerMem responds to.
static constexpr size_t MAX_TIMER_FRAMES
Maximum architectural number of memory-mapped timer frames.
static const Addr TIMER_CTRL_CNTNSAR
static bool validateAccessPerm(ArmSystem &sys, bool is_sec)
Validates an MMIO access permissions.
static const Addr TIMER_CTRL_CNTVOFF_HI
void notify(void) override
Called from the SystemCounter when a change in counting speed occurred Events should be rescheduled p...
void serialize(CheckpointOut &cp) const override
Serialize an object.
void schedNextEvent(EventStream &ev_stream, ArchTimer &timer)
uint32_t cntfrq
System counter frequency as visible from this core.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
CoreTimers(GenericTimer &_parent, ArmSystem &system, unsigned cpu, ArmInterruptPin *irq_el3_phys, ArmInterruptPin *irq_el1_phys, ArmInterruptPin *irq_el1_virt, ArmInterruptPin *irq_el2_ns_phys, ArmInterruptPin *irq_el2_ns_virt, ArmInterruptPin *irq_el2_s_phys, ArmInterruptPin *irq_el2_s_virt)
ArmISA::CNTHCTL cnthctl
Hypervisor control register.
ArmISA::CNTKCTL cntkctl
Kernel control register.
std::vector< std::unique_ptr< CoreTimers > > timers
Per-CPU physical architected timers.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void setMiscReg(int misc_reg, unsigned cpu, RegVal val)
CoreTimers & getTimers(int cpu_id)
RegVal readMiscReg(int misc_reg, unsigned cpu)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void createTimers(unsigned cpus)
SystemCounter & systemCounter
System counter reference.
void handleStream(CoreTimers::EventStream *ev_stream, ArchTimer *timer, RegVal old_cnt_ctl, RegVal cnt_ctl)
ArmSystem & system
ARM system containing this timer.
GenericTimer(const Params &p)
bool validEnvironment() const
Verify gem5 configuration will support KVM emulation.
Definition vm.cc:555
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
bool isSecure() const
Definition packet.hh:836
Addr getAddr() const
Definition packet.hh:807
void setUintX(uint64_t w, ByteOrder endian)
Set the value in the word w after truncating it to the length of the packet and then byteswapping it ...
Definition packet.cc:361
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition packet.hh:1062
unsigned getSize() const
Definition packet.hh:817
uint64_t getUintX(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness and zero-extended to 64 bits.
Definition packet.cc:352
This device is the base class which all devices senstive to an address range inherit from.
Definition io_device.hh:103
Abstract superclass for simulation objects.
Abstract class for elements whose events depend on the counting speed of the System Counter.
Global system counter.
void updateValue(void)
Updates the counter value.
uint32_t _freq
Counter frequency (as specified by CNTFRQ).
std::vector< uint32_t > _freqTable
Frequency modes table with all possible frequencies for the counter.
bool enabled() const
Indicates if the counter is enabled.
std::vector< SystemCounterListener * > _listeners
Listeners to changes in counting speed.
void setValue(uint64_t new_value)
Sets the value explicitly from writes to CNTCR.CNTCV.
Tick _period
Cached copy of the counter period (inverse of the frequency).
Tick whenValue(uint64_t target_val)
Returns the tick at which a certain counter value is reached.
SystemCounter(const SystemCounterParams &p)
EventFunctionWrapper _freqUpdateEvent
Frequency update event handling.
size_t activeFreqEntry() const
Returns the currently active frequency table entry.
static constexpr size_t MAX_FREQ_ENTRIES
Maximum architectural number of frequency table entries.
static void validateCounterRef(SystemCounter *sys_cnt)
Validates a System Counter reference.
void updateTick(void)
Updates the update tick, normalizes to the lower cycle start tick.
uint64_t value()
Updates and returns the counter value.
void disable()
Disables the counter after a CNTCR.EN == 0.
void notifyListeners(void) const
Notifies counting speed changes to listeners.
void serialize(CheckpointOut &cp) const override
Serialize an object.
std::vector< uint32_t > & freqTable()
Returns a reference to the frequency modes table.
void enable()
Enables the counter after a CNTCR.EN == 1.
uint64_t _value
Counter value (as specified in CNTCV).
uint32_t freq() const
Returns the counter frequency.
void freqUpdateCallback()
Callback for the frequency update.
Tick _updateTick
Counter cycle start Tick when the counter status affecting its value has been updated.
uint64_t _increment
Value increment in each counter cycle.
size_t _activeFreqEntry
Currently selected entry in the table, its contents should match _freq.
void registerListener(SystemCounterListener *listener)
Called from System Counter Listeners to register.
void freqUpdateSchedule(size_t new_freq_entry)
Schedules a counter frequency update after a CNTCR.FCREQ == 1 This complies with frequency transition...
void unserialize(CheckpointIn &cp) override
Unserialize an object.
bool _enabled
Indicates if the counter is enabled.
int size() const
Definition system.hh:210
KvmVM * getKvmVM() const
Get a pointer to the Kernel Virtual Machine (KVM) SimObject, if present.
Definition system.hh:333
Threads threads
Definition system.hh:310
ThreadContext is the external interface to all thread state for anything outside of the CPU.
This module implements the global system counter and the local per-CPU architected timers as specifie...
AddrRange RangeSize(Addr start, Addr size)
bool valid() const
Determine if the range is valid.
bool contains(const Addr &a) const
Determine if the range contains an address.
Addr start() const
Get the start address of the range.
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition bitfield.hh:79
constexpr T insertBits(T val, unsigned first, unsigned last, B bit_val)
Returns val with bits first to last set to the LSBs of bit_val.
Definition bitfield.hh:185
constexpr uint64_t sext(uint64_t val)
Sign-extend an N-bit value to 64 bits.
Definition bitfield.hh:129
constexpr void replaceBits(T &val, unsigned first, unsigned last, B bit_val)
A convenience function to replace bits first to last of val with bit_val in place.
Definition bitfield.hh:216
DrainState
Object drain/handover states.
Definition drain.hh:75
@ Drained
Buffers drained, ready for serialization/handover.
void deschedule(Event &event)
Definition eventq.hh:1021
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
void reschedule(Event &event, Tick when, bool always=false)
Definition eventq.hh:1030
Tick when() const
Get the time that the event is scheduled.
Definition eventq.hh:501
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:236
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#define UNSERIALIZE_CONTAINER(member)
Definition serialize.hh:634
#define UNSERIALIZE_OPT_SCALAR(scalar)
Definition serialize.hh:582
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition serialize.cc:74
#define SERIALIZE_CONTAINER(member)
Definition serialize.hh:626
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition serialize.cc:81
const Params & params() const
#define warn(...)
Definition logging.hh:256
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition logging.hh:283
Bitfield< 7 > i
Definition misc_types.hh:67
void sendEvent(ThreadContext *tc)
Send an event (SEV) to a specific PE if there isn't already a pending event.
Definition utility.cc:65
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 0 > vm
@ MISCREG_CNTV_CTL_EL0
Definition misc.hh:819
@ MISCREG_CNTP_CTL_EL0
Definition misc.hh:816
@ MISCREG_CNTFRQ
Definition misc.hh:419
@ MISCREG_CNTV_TVAL
Definition misc.hh:433
@ MISCREG_CNTPS_TVAL_EL1
Definition misc.hh:832
@ MISCREG_CNTV_CVAL
Definition misc.hh:432
@ MISCREG_CNTVCT
Definition misc.hh:421
@ MISCREG_CNTPCT_EL0
Definition misc.hh:814
@ MISCREG_CNTHV_CTL_EL2
Definition misc.hh:841
@ MISCREG_CNTP_TVAL_NS
Definition misc.hh:429
@ MISCREG_CNTV_CTL
Definition misc.hh:431
@ MISCREG_CNTHP_TVAL
Definition misc.hh:438
@ MISCREG_CNTVCT_EL0
Definition misc.hh:815
@ MISCREG_CNTKCTL_EL1
Definition misc.hh:828
@ MISCREG_CNTPCT
Definition misc.hh:420
@ MISCREG_CNTPS_CTL_EL1
Definition misc.hh:830
@ MISCREG_CNTHPS_CVAL_EL2
Definition misc.hh:838
@ MISCREG_CNTP_CVAL_NS
Definition misc.hh:426
@ MISCREG_CNTHPS_TVAL_EL2
Definition misc.hh:839
@ MISCREG_CNTP_TVAL_S
Definition misc.hh:430
@ MISCREG_CNTHCTL_EL2
Definition misc.hh:833
@ MISCREG_CNTP_CTL_S
Definition misc.hh:424
@ MISCREG_CNTHVS_TVAL_EL2
Definition misc.hh:846
@ MISCREG_CNTP_CVAL_EL0
Definition misc.hh:817
@ MISCREG_CNTHVS_CVAL_EL2
Definition misc.hh:845
@ MISCREG_CNTVOFF_EL2
Definition misc.hh:848
@ MISCREG_CNTHCTL
Definition misc.hh:435
@ MISCREG_CNTHPS_CTL_EL2
Definition misc.hh:837
@ MISCREG_CNTHV_TVAL_EL2
Definition misc.hh:843
@ MISCREG_CNTPS_CVAL_EL1
Definition misc.hh:831
@ MISCREG_CNTVOFF
Definition misc.hh:439
@ MISCREG_CNTHP_CTL
Definition misc.hh:436
@ MISCREG_CNTHP_CVAL_EL2
Definition misc.hh:835
@ MISCREG_CNTV_TVAL_EL0
Definition misc.hh:821
@ MISCREG_CNTP_CTL_NS
Definition misc.hh:423
@ MISCREG_CNTP_TVAL_EL0
Definition misc.hh:818
@ MISCREG_CNTHP_TVAL_EL2
Definition misc.hh:836
@ MISCREG_CNTHP_CVAL
Definition misc.hh:437
@ MISCREG_CNTHVS_CTL_EL2
Definition misc.hh:844
@ MISCREG_CNTHP_CTL_EL2
Definition misc.hh:834
@ MISCREG_CNTP_CVAL_S
Definition misc.hh:427
@ MISCREG_CNTKCTL
Definition misc.hh:434
@ MISCREG_CNTHV_CVAL_EL2
Definition misc.hh:842
@ MISCREG_CNTFRQ_EL0
Definition misc.hh:813
@ MISCREG_CNTV_CVAL_EL0
Definition misc.hh:820
const Addr PageBytes
Definition page_size.hh:53
const char *const miscRegName[]
Definition misc.hh:1815
Bitfield< 0 > p
Bitfield< 5, 3 > reg
Definition types.hh:92
Bitfield< 15 > system
Definition misc.hh:1032
Bitfield< 63 > val
Definition misc.hh:804
Bitfield< 3 > addr
Definition types.hh:84
Tick Frequency
The simulated frequency of curTick(). (In ticks per second)
Definition core.cc:47
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
uint64_t RegVal
Definition types.hh:173
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
std::ostream CheckpointOut
Definition serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition types.cc:40
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition types.cc:72
uint64_t Tick
Tick count type.
Definition types.hh:58
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161
const Addr MaxAddr
Definition types.hh:171
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
uint64_t eventTargetValue(uint64_t val) const
const std::string & name()
Definition trace.cc:48

Generated on Tue Jun 18 2024 16:24:02 for gem5 by doxygen 1.11.0