2 * Copyright (c) 2013, 2015, 2017-2018,2020 ARM Limited
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.
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.
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.
38 #include "dev/arm/generic_timer.hh"
42 #include "arch/arm/system.hh"
43 #include "arch/arm/utility.hh"
44 #include "cpu/base.hh"
45 #include "debug/Timer.hh"
46 #include "dev/arm/base_gic.hh"
47 #include "mem/packet_access.hh"
48 #include "params/GenericTimer.hh"
49 #include "params/GenericTimerFrame.hh"
50 #include "params/GenericTimerMem.hh"
51 #include "params/SystemCounter.hh"
53 SystemCounter::SystemCounter(SystemCounterParams
*const p
)
61 _freqUpdateEvent([this]{ freqUpdateCallback(); }, name()),
64 fatal_if(_freqTable
.empty(), "SystemCounter::SystemCounter: Base "
65 "frequency not provided\n");
66 // Store the table end marker as a 32-bit zero word
67 _freqTable
.push_back(0);
68 fatal_if(_freqTable
.size() > MAX_FREQ_ENTRIES
,
69 "SystemCounter::SystemCounter: Architecture states a maximum of 1004 "
70 "frequency table entries, limit surpassed\n");
71 // Set the active frequency to be the base
72 _freq
= _freqTable
.front();
73 _period
= (1.0 / _freq
) * SimClock::Frequency
;
77 SystemCounter::validateCounterRef(SystemCounter
*const sys_cnt
)
79 fatal_if(!sys_cnt
, "SystemCounter::validateCounterRef: No valid system "
80 "counter, can't instantiate system timers\n");
84 SystemCounter::enable()
86 DPRINTF(Timer
, "SystemCounter::enable: Counter enabled\n");
92 SystemCounter::disable()
94 DPRINTF(Timer
, "SystemCounter::disable: Counter disabled\n");
100 SystemCounter::value()
108 SystemCounter::updateValue()
111 _value
+ ((curTick() - _updateTick
) / _period
) * _increment
;
112 if (new_value
> _value
) {
119 SystemCounter::setValue(uint64_t new_value
)
122 warn("Explicit value set with counter enabled, UNKNOWNN result\n");
129 SystemCounter::whenValue(uint64_t cur_val
, uint64_t target_val
) const
131 Tick when
= curTick();
132 if (target_val
> cur_val
) {
133 uint64_t num_cycles
=
134 std::ceil((target_val
- cur_val
) / ((double) _increment
));
135 // Take into account current cycle remaining ticks
136 Tick rem_ticks
= _period
- (curTick() % _period
);
137 if (rem_ticks
< _period
) {
141 when
+= num_cycles
* _period
;
147 SystemCounter::whenValue(uint64_t target_val
)
149 return whenValue(value(), target_val
);
153 SystemCounter::updateTick()
155 _updateTick
= curTick() - (curTick() % _period
);
159 SystemCounter::freqUpdateSchedule(size_t new_freq_entry
)
161 if (new_freq_entry
< _freqTable
.size()) {
162 auto &new_freq
= _freqTable
[new_freq_entry
];
163 if (new_freq
!= _freq
) {
164 _nextFreqEntry
= new_freq_entry
;
165 // Wait until the value for which the lowest frequency increment
166 // is a exact divisor. This covers both high to low and low to
168 uint64_t new_incr
= _freqTable
[0] / new_freq
;
169 uint64_t target_val
= value();
170 target_val
+= target_val
% std::max(_increment
, new_incr
);
171 reschedule(_freqUpdateEvent
, whenValue(target_val
), true);
177 SystemCounter::freqUpdateCallback()
179 DPRINTF(Timer
, "SystemCounter::freqUpdateCallback: Changing counter "
183 _activeFreqEntry
= _nextFreqEntry
;
184 _freq
= _freqTable
[_activeFreqEntry
];
185 _increment
= _freqTable
[0] / _freq
;
186 _period
= (1.0 / _freq
) * SimClock::Frequency
;
191 SystemCounter::registerListener(SystemCounterListener
*listener
)
193 _listeners
.push_back(listener
);
197 SystemCounter::notifyListeners() const
199 for (auto &listener
: _listeners
)
204 SystemCounter::serialize(CheckpointOut
&cp
) const
206 DPRINTF(Timer
, "SystemCounter::serialize: Serializing\n");
207 SERIALIZE_SCALAR(_enabled
);
208 SERIALIZE_SCALAR(_freq
);
209 SERIALIZE_SCALAR(_value
);
210 SERIALIZE_SCALAR(_increment
);
211 SERIALIZE_CONTAINER(_freqTable
);
212 SERIALIZE_SCALAR(_activeFreqEntry
);
213 SERIALIZE_SCALAR(_updateTick
);
214 bool pending_freq_update
= _freqUpdateEvent
.scheduled();
215 SERIALIZE_SCALAR(pending_freq_update
);
216 if (pending_freq_update
) {
217 Tick when_freq_update
= _freqUpdateEvent
.when();
218 SERIALIZE_SCALAR(when_freq_update
);
220 SERIALIZE_SCALAR(_nextFreqEntry
);
224 SystemCounter::unserialize(CheckpointIn
&cp
)
226 DPRINTF(Timer
, "SystemCounter::unserialize: Unserializing\n");
227 UNSERIALIZE_SCALAR(_enabled
);
228 UNSERIALIZE_SCALAR(_freq
);
229 UNSERIALIZE_SCALAR(_value
);
230 UNSERIALIZE_SCALAR(_increment
);
231 UNSERIALIZE_CONTAINER(_freqTable
);
232 UNSERIALIZE_SCALAR(_activeFreqEntry
);
233 UNSERIALIZE_SCALAR(_updateTick
);
234 bool pending_freq_update
;
235 UNSERIALIZE_SCALAR(pending_freq_update
);
236 if (pending_freq_update
) {
237 Tick when_freq_update
;
238 UNSERIALIZE_SCALAR(when_freq_update
);
239 reschedule(_freqUpdateEvent
, when_freq_update
, true);
241 UNSERIALIZE_SCALAR(_nextFreqEntry
);
243 _period
= (1.0 / _freq
) * SimClock::Frequency
;
246 ArchTimer::ArchTimer(const std::string
&name
,
248 SystemCounter
&sysctr
,
249 ArmInterruptPin
*interrupt
)
250 : _name(name
), _parent(parent
), _systemCounter(sysctr
),
251 _interrupt(interrupt
),
252 _control(0), _counterLimit(0), _offset(0),
253 _counterLimitReachedEvent([this]{ counterLimitReached(); }, name
)
255 _systemCounter
.registerListener(this);
259 ArchTimer::counterLimitReached()
261 if (!_control
.enable
)
264 DPRINTF(Timer
, "Counter limit reached\n");
265 _control
.istatus
= 1;
266 if (!_control
.imask
) {
267 if (scheduleEvents()) {
268 DPRINTF(Timer
, "Causing interrupt\n");
271 DPRINTF(Timer
, "Kvm mode; skipping simulated interrupt\n");
277 ArchTimer::updateCounter()
279 if (_counterLimitReachedEvent
.scheduled())
280 _parent
.deschedule(_counterLimitReachedEvent
);
281 if (value() >= _counterLimit
) {
282 counterLimitReached();
284 // Clear the interurpt when timers conditions are not met
285 if (_interrupt
->active()) {
286 DPRINTF(Timer
, "Clearing interrupt\n");
290 _control
.istatus
= 0;
292 if (scheduleEvents()) {
293 _parent
.schedule(_counterLimitReachedEvent
,
294 whenValue(_counterLimit
));
300 ArchTimer::setCompareValue(uint64_t val
)
307 ArchTimer::setTimerValue(uint32_t val
)
309 setCompareValue(value() + sext
<32>(val
));
313 ArchTimer::setControl(uint32_t val
)
315 ArchTimerCtrl old_ctl
= _control
, new_ctl
= val
;
316 _control
.enable
= new_ctl
.enable
;
317 _control
.imask
= new_ctl
.imask
;
318 _control
.istatus
= old_ctl
.istatus
;
319 // Timer unmasked or enabled
320 if ((old_ctl
.imask
&& !new_ctl
.imask
) ||
321 (!old_ctl
.enable
&& new_ctl
.enable
))
323 // Timer masked or disabled
324 else if ((!old_ctl
.imask
&& new_ctl
.imask
) ||
325 (old_ctl
.enable
&& !new_ctl
.enable
)) {
327 if (_interrupt
->active()) {
328 DPRINTF(Timer
, "Clearing interrupt\n");
329 // We are clearing the interrupt but we are not
330 // setting istatus to 0 as we are doing
331 // in the updateCounter.
332 // istatus signals that Timer conditions are met.
333 // It shouldn't depend on masking.
334 // if enable is zero. istatus is unknown.
341 ArchTimer::setOffset(uint64_t val
)
348 ArchTimer::value() const
350 return _systemCounter
.value() - _offset
;
360 ArchTimer::serialize(CheckpointOut
&cp
) const
362 paramOut(cp
, "control_serial", _control
);
363 SERIALIZE_SCALAR(_counterLimit
);
364 SERIALIZE_SCALAR(_offset
);
368 ArchTimer::unserialize(CheckpointIn
&cp
)
370 paramIn(cp
, "control_serial", _control
);
371 // We didn't serialize an offset before we added support for the
372 // virtual timer. Consider it optional to maintain backwards
374 if (!UNSERIALIZE_OPT_SCALAR(_offset
))
377 // We no longer schedule an event here because we may enter KVM
378 // emulation. The event creation is delayed until drainResume().
384 if (_counterLimitReachedEvent
.scheduled())
385 _parent
.deschedule(_counterLimitReachedEvent
);
387 return DrainState::Drained
;
391 ArchTimer::drainResume()
396 GenericTimer::GenericTimer(GenericTimerParams
*const p
)
398 systemCounter(*p
->counter
),
401 SystemCounter::validateCounterRef(p
->counter
);
402 fatal_if(!p
->system
, "GenericTimer::GenericTimer: No system specified, "
403 "can't instantiate architected timers\n");
404 system
.setGenericTimer(this);
407 const GenericTimerParams
*
408 GenericTimer::params() const
410 return dynamic_cast<const GenericTimerParams
*>(_params
);
414 GenericTimer::serialize(CheckpointOut
&cp
) const
416 paramOut(cp
, "cpu_count", timers
.size());
418 for (int i
= 0; i
< timers
.size(); ++i
) {
419 const CoreTimers
&core(*timers
[i
]);
420 core
.serializeSection(cp
, csprintf("pe_implementation%d", i
));
425 GenericTimer::unserialize(CheckpointIn
&cp
)
427 // Try to unserialize the CPU count. Old versions of the timer
428 // model assumed a 8 CPUs, so we fall back to that if the field
430 static const unsigned OLD_CPU_MAX
= 8;
432 if (!UNSERIALIZE_OPT_SCALAR(cpu_count
)) {
433 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
435 cpu_count
= OLD_CPU_MAX
;
438 // We cannot assert for equality here because CPU timers are dynamically
439 // created on the first miscreg access. Therefore, if we take the checkpoint
440 // before any timer registers have been accessed, the number of counters
441 // is actually smaller than the total number of CPUs.
442 if (cpu_count
> system
.threads
.size()) {
443 fatal("The simulated system has been initialized with %d CPUs, "
444 "but the Generic Timer checkpoint expects %d CPUs. Consider "
445 "restoring the checkpoint specifying %d CPUs.",
446 system
.threads
.size(), cpu_count
, cpu_count
);
449 for (int i
= 0; i
< cpu_count
; ++i
) {
450 CoreTimers
&core(getTimers(i
));
451 core
.unserializeSection(cp
, csprintf("pe_implementation%d", i
));
455 GenericTimer::CoreTimers
&
456 GenericTimer::getTimers(int cpu_id
)
458 if (cpu_id
>= timers
.size())
459 createTimers(cpu_id
+ 1);
461 return *timers
[cpu_id
];
465 GenericTimer::createTimers(unsigned cpus
)
467 assert(timers
.size() < cpus
);
468 auto p
= static_cast<const GenericTimerParams
*>(_params
);
470 const unsigned old_cpu_count(timers
.size());
472 for (unsigned i
= old_cpu_count
; i
< cpus
; ++i
) {
474 ThreadContext
*tc
= system
.threads
[i
];
477 new CoreTimers(*this, system
, i
,
478 p
->int_phys_s
->get(tc
),
479 p
->int_phys_ns
->get(tc
),
480 p
->int_virt
->get(tc
),
481 p
->int_hyp
->get(tc
)));
486 GenericTimer::handleStream(CoreTimers::EventStream
*ev_stream
,
487 ArchTimer
*timer
, RegVal old_cnt_ctl
, RegVal cnt_ctl
)
489 uint64_t evnten
= bits(cnt_ctl
, 2);
490 uint64_t old_evnten
= bits(old_cnt_ctl
, 2);
491 uint8_t old_trans_to
= ev_stream
->transitionTo
;
492 uint8_t old_trans_bit
= ev_stream
->transitionBit
;
493 ev_stream
->transitionTo
= !bits(cnt_ctl
, 3);
494 ev_stream
->transitionBit
= bits(cnt_ctl
, 7, 4);
495 // Reschedule the Event Stream if enabled and any change in
497 if (evnten
&& ((old_evnten
!= evnten
) ||
498 (old_trans_to
!= ev_stream
->transitionTo
) ||
499 (old_trans_bit
!= ev_stream
->transitionBit
))) {
501 Tick when
= timer
->whenValue(
502 ev_stream
->eventTargetValue(timer
->value()));
503 reschedule(ev_stream
->event
, when
, true);
504 } else if (old_evnten
&& !evnten
) {
505 // Event Stream generation disabled
506 if (ev_stream
->event
.scheduled())
507 deschedule(ev_stream
->event
);
512 GenericTimer::setMiscReg(int reg
, unsigned cpu
, RegVal val
)
514 CoreTimers
&core(getTimers(cpu
));
515 ThreadContext
*tc
= system
.threads
[cpu
];
519 case MISCREG_CNTFRQ_EL0
:
521 warn_if(core
.cntfrq
!= systemCounter
.freq(), "CNTFRQ configured freq "
522 "does not match the system counter freq\n");
524 case MISCREG_CNTKCTL
:
525 case MISCREG_CNTKCTL_EL1
:
527 if (ELIsInHost(tc
, currEL(tc
))) {
528 tc
->setMiscReg(MISCREG_CNTHCTL_EL2
, val
);
531 RegVal old_cnt_ctl
= core
.cntkctl
;
534 ArchTimer
*timer
= &core
.virt
;
535 CoreTimers::EventStream
*ev_stream
= &core
.virtEvStream
;
537 handleStream(ev_stream
, timer
, old_cnt_ctl
, val
);
540 case MISCREG_CNTHCTL
:
541 case MISCREG_CNTHCTL_EL2
:
543 RegVal old_cnt_ctl
= core
.cnthctl
;
546 ArchTimer
*timer
= &core
.physNS
;
547 CoreTimers::EventStream
*ev_stream
= &core
.physEvStream
;
549 handleStream(ev_stream
, timer
, old_cnt_ctl
, val
);
552 // Physical timer (NS)
553 case MISCREG_CNTP_CVAL_NS
:
554 case MISCREG_CNTP_CVAL_EL0
:
555 core
.physNS
.setCompareValue(val
);
558 case MISCREG_CNTP_TVAL_NS
:
559 case MISCREG_CNTP_TVAL_EL0
:
560 core
.physNS
.setTimerValue(val
);
563 case MISCREG_CNTP_CTL_NS
:
564 case MISCREG_CNTP_CTL_EL0
:
565 core
.physNS
.setControl(val
);
570 case MISCREG_CNTPCT_EL0
:
572 case MISCREG_CNTVCT_EL0
:
573 warn("Ignoring write to read only count register: %s\n",
578 case MISCREG_CNTVOFF
:
579 case MISCREG_CNTVOFF_EL2
:
580 core
.virt
.setOffset(val
);
583 case MISCREG_CNTV_CVAL
:
584 case MISCREG_CNTV_CVAL_EL0
:
585 core
.virt
.setCompareValue(val
);
588 case MISCREG_CNTV_TVAL
:
589 case MISCREG_CNTV_TVAL_EL0
:
590 core
.virt
.setTimerValue(val
);
593 case MISCREG_CNTV_CTL
:
594 case MISCREG_CNTV_CTL_EL0
:
595 core
.virt
.setControl(val
);
598 // Physical timer (S)
599 case MISCREG_CNTP_CTL_S
:
600 case MISCREG_CNTPS_CTL_EL1
:
601 core
.physS
.setControl(val
);
604 case MISCREG_CNTP_CVAL_S
:
605 case MISCREG_CNTPS_CVAL_EL1
:
606 core
.physS
.setCompareValue(val
);
609 case MISCREG_CNTP_TVAL_S
:
610 case MISCREG_CNTPS_TVAL_EL1
:
611 core
.physS
.setTimerValue(val
);
614 // Hyp phys. timer, non-secure
615 case MISCREG_CNTHP_CTL
:
616 case MISCREG_CNTHP_CTL_EL2
:
617 core
.hyp
.setControl(val
);
620 case MISCREG_CNTHP_CVAL
:
621 case MISCREG_CNTHP_CVAL_EL2
:
622 core
.hyp
.setCompareValue(val
);
625 case MISCREG_CNTHP_TVAL
:
626 case MISCREG_CNTHP_TVAL_EL2
:
627 core
.hyp
.setTimerValue(val
);
631 warn("Writing to unknown register: %s\n", miscRegName
[reg
]);
638 GenericTimer::readMiscReg(int reg
, unsigned cpu
)
640 CoreTimers
&core(getTimers(cpu
));
644 case MISCREG_CNTFRQ_EL0
:
646 case MISCREG_CNTKCTL
:
647 case MISCREG_CNTKCTL_EL1
:
648 return core
.cntkctl
& 0x00000000ffffffff;
649 case MISCREG_CNTHCTL
:
650 case MISCREG_CNTHCTL_EL2
:
651 return core
.cnthctl
& 0x00000000ffffffff;
653 case MISCREG_CNTP_CVAL_NS
:
654 case MISCREG_CNTP_CVAL_EL0
:
655 return core
.physNS
.compareValue();
657 case MISCREG_CNTP_TVAL_NS
:
658 case MISCREG_CNTP_TVAL_EL0
:
659 return core
.physNS
.timerValue();
661 case MISCREG_CNTP_CTL_EL0
:
662 case MISCREG_CNTP_CTL_NS
:
663 return core
.physNS
.control();
666 case MISCREG_CNTPCT_EL0
:
667 return core
.physNS
.value();
672 case MISCREG_CNTVCT_EL0
:
673 return core
.virt
.value();
675 case MISCREG_CNTVOFF
:
676 case MISCREG_CNTVOFF_EL2
:
677 return core
.virt
.offset();
679 case MISCREG_CNTV_CVAL
:
680 case MISCREG_CNTV_CVAL_EL0
:
681 return core
.virt
.compareValue();
683 case MISCREG_CNTV_TVAL
:
684 case MISCREG_CNTV_TVAL_EL0
:
685 return core
.virt
.timerValue();
687 case MISCREG_CNTV_CTL
:
688 case MISCREG_CNTV_CTL_EL0
:
689 return core
.virt
.control();
691 // PL1 phys. timer, secure
692 case MISCREG_CNTP_CTL_S
:
693 case MISCREG_CNTPS_CTL_EL1
:
694 return core
.physS
.control();
696 case MISCREG_CNTP_CVAL_S
:
697 case MISCREG_CNTPS_CVAL_EL1
:
698 return core
.physS
.compareValue();
700 case MISCREG_CNTP_TVAL_S
:
701 case MISCREG_CNTPS_TVAL_EL1
:
702 return core
.physS
.timerValue();
704 // HYP phys. timer (NS)
705 case MISCREG_CNTHP_CTL
:
706 case MISCREG_CNTHP_CTL_EL2
:
707 return core
.hyp
.control();
709 case MISCREG_CNTHP_CVAL
:
710 case MISCREG_CNTHP_CVAL_EL2
:
711 return core
.hyp
.compareValue();
713 case MISCREG_CNTHP_TVAL
:
714 case MISCREG_CNTHP_TVAL_EL2
:
715 return core
.hyp
.timerValue();
718 warn("Reading from unknown register: %s\n", miscRegName
[reg
]);
723 GenericTimer::CoreTimers::CoreTimers(GenericTimer
&_parent
,
724 ArmSystem
&system
, unsigned cpu
,
725 ArmInterruptPin
*_irqPhysS
, ArmInterruptPin
*_irqPhysNS
,
726 ArmInterruptPin
*_irqVirt
, ArmInterruptPin
*_irqHyp
)
728 cntfrq(parent
.params()->cntfrq
),
729 threadContext(system
.threads
[cpu
]),
731 irqPhysNS(_irqPhysNS
),
734 physS(csprintf("%s.phys_s_timer%d", parent
.name(), cpu
),
735 system
, parent
, parent
.systemCounter
,
737 // This should really be phys_timerN, but we are stuck with
738 // arch_timer for backwards compatibility.
739 physNS(csprintf("%s.arch_timer%d", parent
.name(), cpu
),
740 system
, parent
, parent
.systemCounter
,
742 virt(csprintf("%s.virt_timer%d", parent
.name(), cpu
),
743 system
, parent
, parent
.systemCounter
,
745 hyp(csprintf("%s.hyp_timer%d", parent
.name(), cpu
),
746 system
, parent
, parent
.systemCounter
,
749 EventFunctionWrapper([this]{ physEventStreamCallback(); },
750 csprintf("%s.phys_event_gen%d", parent
.name(), cpu
)), 0, 0
753 EventFunctionWrapper([this]{ virtEventStreamCallback(); },
754 csprintf("%s.virt_event_gen%d", parent
.name(), cpu
)), 0, 0
760 GenericTimer::CoreTimers::physEventStreamCallback()
762 eventStreamCallback();
763 schedNextEvent(physEvStream
, physNS
);
767 GenericTimer::CoreTimers::virtEventStreamCallback()
769 eventStreamCallback();
770 schedNextEvent(virtEvStream
, virt
);
774 GenericTimer::CoreTimers::eventStreamCallback() const
776 sendEvent(threadContext
);
777 threadContext
->getCpuPtr()->wakeup(threadContext
->threadId());
781 GenericTimer::CoreTimers::schedNextEvent(EventStream
&ev_stream
,
784 parent
.reschedule(ev_stream
.event
, timer
.whenValue(
785 ev_stream
.eventTargetValue(timer
.value())), true);
789 GenericTimer::CoreTimers::notify()
791 schedNextEvent(virtEvStream
, virt
);
792 schedNextEvent(physEvStream
, physNS
);
796 GenericTimer::CoreTimers::serialize(CheckpointOut
&cp
) const
798 SERIALIZE_SCALAR(cntfrq
);
799 SERIALIZE_SCALAR(cntkctl
);
800 SERIALIZE_SCALAR(cnthctl
);
802 const bool phys_ev_scheduled
= physEvStream
.event
.scheduled();
803 SERIALIZE_SCALAR(phys_ev_scheduled
);
804 if (phys_ev_scheduled
) {
805 const Tick phys_ev_when
= physEvStream
.event
.when();
806 SERIALIZE_SCALAR(phys_ev_when
);
808 SERIALIZE_SCALAR(physEvStream
.transitionTo
);
809 SERIALIZE_SCALAR(physEvStream
.transitionBit
);
811 const bool virt_ev_scheduled
= virtEvStream
.event
.scheduled();
812 SERIALIZE_SCALAR(virt_ev_scheduled
);
813 if (virt_ev_scheduled
) {
814 const Tick virt_ev_when
= virtEvStream
.event
.when();
815 SERIALIZE_SCALAR(virt_ev_when
);
817 SERIALIZE_SCALAR(virtEvStream
.transitionTo
);
818 SERIALIZE_SCALAR(virtEvStream
.transitionBit
);
820 physS
.serializeSection(cp
, "phys_s_timer");
821 physNS
.serializeSection(cp
, "phys_ns_timer");
822 virt
.serializeSection(cp
, "virt_timer");
823 hyp
.serializeSection(cp
, "hyp_timer");
827 GenericTimer::CoreTimers::unserialize(CheckpointIn
&cp
)
829 UNSERIALIZE_SCALAR(cntfrq
);
830 UNSERIALIZE_SCALAR(cntkctl
);
831 UNSERIALIZE_SCALAR(cnthctl
);
833 bool phys_ev_scheduled
;
834 UNSERIALIZE_SCALAR(phys_ev_scheduled
);
835 if (phys_ev_scheduled
) {
837 UNSERIALIZE_SCALAR(phys_ev_when
);
838 parent
.reschedule(physEvStream
.event
, phys_ev_when
, true);
840 UNSERIALIZE_SCALAR(physEvStream
.transitionTo
);
841 UNSERIALIZE_SCALAR(physEvStream
.transitionBit
);
843 bool virt_ev_scheduled
;
844 UNSERIALIZE_SCALAR(virt_ev_scheduled
);
845 if (virt_ev_scheduled
) {
847 UNSERIALIZE_SCALAR(virt_ev_when
);
848 parent
.reschedule(virtEvStream
.event
, virt_ev_when
, true);
850 UNSERIALIZE_SCALAR(virtEvStream
.transitionTo
);
851 UNSERIALIZE_SCALAR(virtEvStream
.transitionBit
);
853 physS
.unserializeSection(cp
, "phys_s_timer");
854 physNS
.unserializeSection(cp
, "phys_ns_timer");
855 virt
.unserializeSection(cp
, "virt_timer");
856 hyp
.unserializeSection(cp
, "hyp_timer");
860 GenericTimerISA::setMiscReg(int reg
, RegVal val
)
862 DPRINTF(Timer
, "Setting %s := 0x%x\n", miscRegName
[reg
], val
);
863 parent
.setMiscReg(reg
, cpu
, val
);
867 GenericTimerISA::readMiscReg(int reg
)
869 RegVal value
= parent
.readMiscReg(reg
, cpu
);
870 DPRINTF(Timer
, "Reading %s as 0x%x\n", miscRegName
[reg
], value
);
874 GenericTimerFrame::GenericTimerFrame(GenericTimerFrameParams
*const p
)
876 timerRange(RangeSize(p
->cnt_base
, ArmSystem::PageBytes
)),
877 addrRanges({timerRange
}),
878 systemCounter(*p
->counter
),
879 physTimer(csprintf("%s.phys_timer", name()),
880 *this, systemCounter
, p
->int_phys
->get()),
881 virtTimer(csprintf("%s.virt_timer", name()),
882 *this, systemCounter
,
885 system(*dynamic_cast<ArmSystem
*>(sys
))
887 SystemCounter::validateCounterRef(p
->counter
);
888 // Expose optional CNTEL0Base register frame
889 if (p
->cnt_el0_base
!= MaxAddr
) {
890 timerEl0Range
= RangeSize(p
->cnt_el0_base
, ArmSystem::PageBytes
);
891 accessBitsEl0
= 0x303;
892 addrRanges
.push_back(timerEl0Range
);
894 for (auto &range
: addrRanges
)
895 GenericTimerMem::validateFrameRange(range
);
899 GenericTimerFrame::serialize(CheckpointOut
&cp
) const
901 SERIALIZE_SCALAR(accessBits
);
903 SERIALIZE_SCALAR(accessBitsEl0
);
904 SERIALIZE_SCALAR(nonSecureAccess
);
906 physTimer
.serializeSection(cp
, "phys_timer");
907 virtTimer
.serializeSection(cp
, "virt_timer");
911 GenericTimerFrame::unserialize(CheckpointIn
&cp
)
913 UNSERIALIZE_SCALAR(accessBits
);
915 UNSERIALIZE_SCALAR(accessBitsEl0
);
916 UNSERIALIZE_SCALAR(nonSecureAccess
);
918 physTimer
.unserializeSection(cp
, "phys_timer");
919 virtTimer
.unserializeSection(cp
, "virt_timer");
923 GenericTimerFrame::getVirtOffset() const
925 return virtTimer
.offset();
929 GenericTimerFrame::setVirtOffset(uint64_t new_offset
)
931 virtTimer
.setOffset(new_offset
);
935 GenericTimerFrame::hasEl0View() const
937 return timerEl0Range
.valid();
941 GenericTimerFrame::getAccessBits() const
947 GenericTimerFrame::setAccessBits(uint8_t data
)
949 accessBits
= data
& 0x3f;
953 GenericTimerFrame::hasNonSecureAccess() const
955 return nonSecureAccess
;
959 GenericTimerFrame::setNonSecureAccess()
961 nonSecureAccess
= true;
965 GenericTimerFrame::hasReadableVoff() const
967 return accessBits
.rvoff
;
971 GenericTimerFrame::getAddrRanges() const
977 GenericTimerFrame::read(PacketPtr pkt
)
979 const Addr addr
= pkt
->getAddr();
980 const size_t size
= pkt
->getSize();
981 const bool is_sec
= pkt
->isSecure();
982 panic_if(size
!= 4 && size
!= 8,
983 "GenericTimerFrame::read: Invalid size %i\n", size
);
988 if (timerRange
.contains(addr
)) {
989 offset
= addr
- timerRange
.start();
990 } else if (hasEl0View() && timerEl0Range
.contains(addr
)) {
991 offset
= addr
- timerEl0Range
.start();
994 panic("GenericTimerFrame::read: Invalid address: 0x%x\n", addr
);
997 resp
= timerRead(offset
, size
, is_sec
, to_el0
);
999 DPRINTF(Timer
, "GenericTimerFrame::read: 0x%x<-0x%x(%i) [S = %u]\n", resp
,
1000 addr
, size
, is_sec
);
1002 pkt
->setUintX(resp
, ByteOrder::little
);
1003 pkt
->makeResponse();
1008 GenericTimerFrame::write(PacketPtr pkt
)
1010 const Addr addr
= pkt
->getAddr();
1011 const size_t size
= pkt
->getSize();
1012 const bool is_sec
= pkt
->isSecure();
1013 panic_if(size
!= 4 && size
!= 8,
1014 "GenericTimerFrame::write: Invalid size %i\n", size
);
1016 bool to_el0
= false;
1017 const uint64_t data
= pkt
->getUintX(ByteOrder::little
);
1019 if (timerRange
.contains(addr
)) {
1020 offset
= addr
- timerRange
.start();
1021 } else if (hasEl0View() && timerEl0Range
.contains(addr
)) {
1022 offset
= addr
- timerEl0Range
.start();
1025 panic("GenericTimerFrame::write: Invalid address: 0x%x\n", addr
);
1028 timerWrite(offset
, size
, data
, is_sec
, to_el0
);
1030 DPRINTF(Timer
, "GenericTimerFrame::write: 0x%x->0x%x(%i) [S = %u]\n", data
,
1031 addr
, size
, is_sec
);
1033 pkt
->makeResponse();
1038 GenericTimerFrame::timerRead(Addr addr
, size_t size
, bool is_sec
,
1041 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
) &&
1046 case TIMER_CNTPCT_LO
:
1047 if (!accessBits
.rpct
|| (to_el0
&& !accessBitsEl0
.pcten
))
1050 return physTimer
.value();
1052 case TIMER_CNTPCT_HI
:
1053 if (!accessBits
.rpct
|| (to_el0
&& !accessBitsEl0
.pcten
))
1056 return physTimer
.value() >> 32;
1059 if ((!accessBits
.rfrq
) ||
1060 (to_el0
&& (!accessBitsEl0
.pcten
&& !accessBitsEl0
.vcten
)))
1063 return systemCounter
.freq();
1065 case TIMER_CNTEL0ACR
:
1066 if (!hasEl0View() || to_el0
)
1069 return accessBitsEl0
;
1071 case TIMER_CNTP_CVAL_LO
:
1072 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1075 return physTimer
.compareValue();
1077 case TIMER_CNTP_CVAL_HI
:
1078 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1081 return physTimer
.compareValue() >> 32;
1083 case TIMER_CNTP_TVAL
:
1084 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1087 return physTimer
.timerValue();
1088 case TIMER_CNTP_CTL
:
1089 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1092 return physTimer
.control();
1094 case TIMER_CNTVCT_LO
:
1095 if (!accessBits
.rvct
|| (to_el0
&& !accessBitsEl0
.vcten
))
1098 return virtTimer
.value();
1100 case TIMER_CNTVCT_HI
:
1101 if (!accessBits
.rvct
|| (to_el0
&& !accessBitsEl0
.vcten
))
1104 return virtTimer
.value() >> 32;
1106 case TIMER_CNTVOFF_LO
:
1107 if (!accessBits
.rvoff
|| (to_el0
))
1110 return virtTimer
.offset();
1112 case TIMER_CNTVOFF_HI
:
1113 if (!accessBits
.rvoff
|| (to_el0
))
1116 return virtTimer
.offset() >> 32;
1118 case TIMER_CNTV_CVAL_LO
:
1119 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1122 return virtTimer
.compareValue();
1124 case TIMER_CNTV_CVAL_HI
:
1125 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1128 return virtTimer
.compareValue() >> 32;
1130 case TIMER_CNTV_TVAL
:
1131 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1134 return virtTimer
.timerValue();
1136 case TIMER_CNTV_CTL
:
1137 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1140 return virtTimer
.control();
1143 warn("GenericTimerFrame::timerRead: Unexpected address (0x%x:%i), "
1144 "assuming RAZ\n", addr
, size
);
1150 GenericTimerFrame::timerWrite(Addr addr
, size_t size
, uint64_t data
,
1151 bool is_sec
, bool to_el0
)
1153 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
) &&
1158 case TIMER_CNTPCT_LO
... TIMER_CNTPCT_HI
:
1159 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTPCT]\n",
1164 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTFRQ]\n",
1168 case TIMER_CNTEL0ACR
:
1169 if (!hasEl0View() || to_el0
)
1172 insertBits(accessBitsEl0
, 9, 8, data
);
1173 insertBits(accessBitsEl0
, 1, 0, data
);
1176 case TIMER_CNTP_CVAL_LO
:
1177 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1179 data
= size
== 4 ? insertBits(physTimer
.compareValue(),
1180 31, 0, data
) : data
;
1181 physTimer
.setCompareValue(data
);
1184 case TIMER_CNTP_CVAL_HI
:
1185 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1187 data
= insertBits(physTimer
.compareValue(), 63, 32, data
);
1188 physTimer
.setCompareValue(data
);
1191 case TIMER_CNTP_TVAL
:
1192 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1194 physTimer
.setTimerValue(data
);
1197 case TIMER_CNTP_CTL
:
1198 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1200 physTimer
.setControl(data
);
1203 case TIMER_CNTVCT_LO
... TIMER_CNTVCT_HI
:
1204 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVCT]\n",
1207 case TIMER_CNTVOFF_LO
... TIMER_CNTVOFF_HI
:
1208 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVOFF]\n",
1212 case TIMER_CNTV_CVAL_LO
:
1213 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1215 data
= size
== 4 ? insertBits(virtTimer
.compareValue(),
1216 31, 0, data
) : data
;
1217 virtTimer
.setCompareValue(data
);
1220 case TIMER_CNTV_CVAL_HI
:
1221 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1223 data
= insertBits(virtTimer
.compareValue(), 63, 32, data
);
1224 virtTimer
.setCompareValue(data
);
1227 case TIMER_CNTV_TVAL
:
1228 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1230 virtTimer
.setTimerValue(data
);
1233 case TIMER_CNTV_CTL
:
1234 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1236 virtTimer
.setControl(data
);
1240 warn("GenericTimerFrame::timerWrite: Unexpected address (0x%x:%i), "
1241 "assuming WI\n", addr
, size
);
1245 GenericTimerMem::GenericTimerMem(GenericTimerMemParams
*const p
)
1247 counterCtrlRange(RangeSize(p
->cnt_control_base
, ArmSystem::PageBytes
)),
1248 counterStatusRange(RangeSize(p
->cnt_read_base
, ArmSystem::PageBytes
)),
1249 timerCtrlRange(RangeSize(p
->cnt_ctl_base
, ArmSystem::PageBytes
)),
1251 addrRanges
{counterCtrlRange
, counterStatusRange
, timerCtrlRange
},
1252 systemCounter(*p
->counter
),
1254 system(*dynamic_cast<ArmSystem
*>(sys
))
1256 SystemCounter::validateCounterRef(p
->counter
);
1257 for (auto &range
: addrRanges
)
1258 GenericTimerMem::validateFrameRange(range
);
1259 fatal_if(frames
.size() > MAX_TIMER_FRAMES
,
1260 "GenericTimerMem::GenericTimerMem: Architecture states a maximum of "
1261 "8 memory-mapped timer frames, limit surpassed\n");
1262 // Initialize CNTTIDR with each frame's features
1263 for (int i
= 0; i
< frames
.size(); i
++) {
1264 uint32_t features
= 0x1;
1266 if (frames
[i
]->hasEl0View())
1269 replaceBits(cnttidr
, (i
+ 1) * 4 - 1, i
* 4, features
);
1274 GenericTimerMem::validateFrameRange(const AddrRange
&range
)
1276 fatal_if(range
.start() % ArmSystem::PageBytes
,
1277 "GenericTimerMem::validateFrameRange: Architecture states each "
1278 "register frame should be in a separate memory page, specified "
1279 "range base address [0x%x] is not compliant\n");
1283 GenericTimerMem::validateAccessPerm(ArmSystem
&sys
, bool is_sec
)
1285 return !sys
.haveSecurity() || is_sec
;
1289 GenericTimerMem::getAddrRanges() const
1295 GenericTimerMem::read(PacketPtr pkt
)
1297 const Addr addr
= pkt
->getAddr();
1298 const size_t size
= pkt
->getSize();
1299 const bool is_sec
= pkt
->isSecure();
1300 panic_if(size
!= 4 && size
!= 8,
1301 "GenericTimerMem::read: Invalid size %i\n", size
);
1304 if (counterCtrlRange
.contains(addr
))
1305 resp
= counterCtrlRead(addr
- counterCtrlRange
.start(), size
, is_sec
);
1306 else if (counterStatusRange
.contains(addr
))
1307 resp
= counterStatusRead(addr
- counterStatusRange
.start(), size
);
1308 else if (timerCtrlRange
.contains(addr
))
1309 resp
= timerCtrlRead(addr
- timerCtrlRange
.start(), size
, is_sec
);
1311 panic("GenericTimerMem::read: Invalid address: 0x%x\n", addr
);
1313 DPRINTF(Timer
, "GenericTimerMem::read: 0x%x<-0x%x(%i) [S = %u]\n", resp
,
1314 addr
, size
, is_sec
);
1316 pkt
->setUintX(resp
, ByteOrder::little
);
1317 pkt
->makeResponse();
1322 GenericTimerMem::write(PacketPtr pkt
)
1324 const Addr addr
= pkt
->getAddr();
1325 const size_t size
= pkt
->getSize();
1326 const bool is_sec
= pkt
->isSecure();
1327 panic_if(size
!= 4 && size
!= 8,
1328 "GenericTimerMem::write: Invalid size %i\n", size
);
1330 const uint64_t data
= pkt
->getUintX(ByteOrder::little
);
1331 if (counterCtrlRange
.contains(addr
))
1332 counterCtrlWrite(addr
- counterCtrlRange
.start(), size
, data
, is_sec
);
1333 else if (counterStatusRange
.contains(addr
))
1334 counterStatusWrite(addr
- counterStatusRange
.start(), size
, data
);
1335 else if (timerCtrlRange
.contains(addr
))
1336 timerCtrlWrite(addr
- timerCtrlRange
.start(), size
, data
, is_sec
);
1338 panic("GenericTimerMem::write: Invalid address: 0x%x\n", addr
);
1340 DPRINTF(Timer
, "GenericTimerMem::write: 0x%x->0x%x(%i) [S = %u]\n", data
,
1341 addr
, size
, is_sec
);
1343 pkt
->makeResponse();
1348 GenericTimerMem::counterCtrlRead(Addr addr
, size_t size
, bool is_sec
) const
1350 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
))
1353 case COUNTER_CTRL_CNTCR
:
1356 cntcr
.en
= systemCounter
.enabled();
1357 cntcr
.fcreq
= systemCounter
.activeFreqEntry();
1360 case COUNTER_CTRL_CNTSR
:
1363 cntsr
.fcack
= systemCounter
.activeFreqEntry();
1366 case COUNTER_CTRL_CNTCV_LO
: return systemCounter
.value();
1367 case COUNTER_CTRL_CNTCV_HI
: return systemCounter
.value() >> 32;
1368 case COUNTER_CTRL_CNTSCR
: return 0;
1369 case COUNTER_CTRL_CNTID
: return 0;
1372 auto &freq_table
= systemCounter
.freqTable();
1373 for (int i
= 0; i
< (freq_table
.size() - 1); i
++) {
1374 Addr offset
= COUNTER_CTRL_CNTFID
+ (i
* 0x4);
1376 return freq_table
[i
];
1378 warn("GenericTimerMem::counterCtrlRead: Unexpected address "
1379 "(0x%x:%i), assuming RAZ\n", addr
, size
);
1386 GenericTimerMem::counterCtrlWrite(Addr addr
, size_t size
, uint64_t data
,
1389 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
))
1393 case COUNTER_CTRL_CNTCR
:
1396 if (!systemCounter
.enabled() && val
.en
)
1397 systemCounter
.enable();
1398 else if (systemCounter
.enabled() && !val
.en
)
1399 systemCounter
.disable();
1402 warn("GenericTimerMem::counterCtrlWrite: Halt-on-debug is not "
1405 warn("GenericTimerMem::counterCtrlWrite: Counter Scaling is not "
1407 if (val
.fcreq
!= systemCounter
.activeFreqEntry())
1408 systemCounter
.freqUpdateSchedule(val
.fcreq
);
1412 case COUNTER_CTRL_CNTSR
:
1413 warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTSR]\n",
1417 case COUNTER_CTRL_CNTCV_LO
:
1418 data
= size
== 4 ? insertBits(systemCounter
.value(), 31, 0, data
)
1420 systemCounter
.setValue(data
);
1423 case COUNTER_CTRL_CNTCV_HI
:
1424 data
= insertBits(systemCounter
.value(), 63, 32, data
);
1425 systemCounter
.setValue(data
);
1428 case COUNTER_CTRL_CNTSCR
:
1431 case COUNTER_CTRL_CNTID
:
1432 warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTID]\n",
1438 auto &freq_table
= systemCounter
.freqTable();
1439 for (int i
= 0; i
< (freq_table
.size() - 1); i
++) {
1440 Addr offset
= COUNTER_CTRL_CNTFID
+ (i
* 0x4);
1441 if (addr
== offset
) {
1442 freq_table
[i
] = data
;
1443 // This is changing the currently selected frequency
1444 if (i
== systemCounter
.activeFreqEntry()) {
1445 // We've changed the frequency in the table entry,
1446 // however the counter will still work with the
1447 // current one until transition is completed
1448 systemCounter
.freqUpdateSchedule(i
);
1453 warn("GenericTimerMem::counterCtrlWrite: Unexpected address "
1454 "(0x%x:%i), assuming WI\n", addr
, size
);
1460 GenericTimerMem::counterStatusRead(Addr addr
, size_t size
) const
1463 case COUNTER_STATUS_CNTCV_LO
: return systemCounter
.value();
1464 case COUNTER_STATUS_CNTCV_HI
: return systemCounter
.value() >> 32;
1466 warn("GenericTimerMem::counterStatusRead: Unexpected address "
1467 "(0x%x:%i), assuming RAZ\n", addr
, size
);
1473 GenericTimerMem::counterStatusWrite(Addr addr
, size_t size
, uint64_t data
)
1476 case COUNTER_STATUS_CNTCV_LO
... COUNTER_STATUS_CNTCV_HI
:
1477 warn("GenericTimerMem::counterStatusWrite: RO reg (0x%x) [CNTCV]\n",
1481 warn("GenericTimerMem::counterStatusWrite: Unexpected address "
1482 "(0x%x:%i), assuming WI\n", addr
, size
);
1487 GenericTimerMem::timerCtrlRead(Addr addr
, size_t size
, bool is_sec
) const
1490 case TIMER_CTRL_CNTFRQ
:
1491 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return 0;
1492 return systemCounter
.freq();
1493 case TIMER_CTRL_CNTNSAR
:
1495 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return 0;
1496 uint32_t cntnsar
= 0x0;
1497 for (int i
= 0; i
< frames
.size(); i
++) {
1498 if (frames
[i
]->hasNonSecureAccess())
1499 cntnsar
|= 0x1 << i
;
1503 case TIMER_CTRL_CNTTIDR
: return cnttidr
;
1505 for (int i
= 0; i
< frames
.size(); i
++) {
1506 Addr cntacr_off
= TIMER_CTRL_CNTACR
+ (i
* 0x4);
1507 Addr cntvoff_lo_off
= TIMER_CTRL_CNTVOFF_LO
+ (i
* 0x4);
1508 Addr cntvoff_hi_off
= TIMER_CTRL_CNTVOFF_HI
+ (i
* 0x4);
1509 // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1511 bool hit
= addr
== cntacr_off
|| addr
== cntvoff_lo_off
||
1512 addr
== cntvoff_hi_off
;
1514 GenericTimerMem::validateAccessPerm(system
, is_sec
) ||
1515 frames
[i
]->hasNonSecureAccess();
1516 if (hit
&& !has_access
) return 0;
1517 if (addr
== cntacr_off
)
1518 return frames
[i
]->getAccessBits();
1519 if (addr
== cntvoff_lo_off
|| addr
== cntvoff_hi_off
) {
1520 return addr
== cntvoff_lo_off
? frames
[i
]->getVirtOffset()
1521 : frames
[i
]->getVirtOffset() >> 32;
1524 warn("GenericTimerMem::timerCtrlRead: Unexpected address (0x%x:%i), "
1525 "assuming RAZ\n", addr
, size
);
1531 GenericTimerMem::timerCtrlWrite(Addr addr
, size_t size
, uint64_t data
,
1535 case TIMER_CTRL_CNTFRQ
:
1536 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return;
1537 warn_if(data
!= systemCounter
.freq(),
1538 "GenericTimerMem::timerCtrlWrite: CNTFRQ configured freq "
1539 "does not match the counter freq, ignoring\n");
1541 case TIMER_CTRL_CNTNSAR
:
1542 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return;
1543 for (int i
= 0; i
< frames
.size(); i
++) {
1544 // Check if the CNTNSAR.NS bit is set for this frame
1545 if (data
& (0x1 << i
))
1546 frames
[i
]->setNonSecureAccess();
1549 case TIMER_CTRL_CNTTIDR
:
1550 warn("GenericTimerMem::timerCtrlWrite: RO reg (0x%x) [CNTTIDR]\n",
1554 for (int i
= 0; i
< frames
.size(); i
++) {
1555 Addr cntacr_off
= TIMER_CTRL_CNTACR
+ (i
* 0x4);
1556 Addr cntvoff_lo_off
= TIMER_CTRL_CNTVOFF_LO
+ (i
* 0x4);
1557 Addr cntvoff_hi_off
= TIMER_CTRL_CNTVOFF_HI
+ (i
* 0x4);
1558 // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1560 bool hit
= addr
== cntacr_off
|| addr
== cntvoff_lo_off
||
1561 addr
== cntvoff_hi_off
;
1563 GenericTimerMem::validateAccessPerm(system
, is_sec
) ||
1564 frames
[i
]->hasNonSecureAccess();
1565 if (hit
&& !has_access
) return;
1566 if (addr
== cntacr_off
) {
1567 frames
[i
]->setAccessBits(data
);
1570 if (addr
== cntvoff_lo_off
|| addr
== cntvoff_hi_off
) {
1571 if (addr
== cntvoff_lo_off
)
1572 data
= size
== 4 ? insertBits(frames
[i
]->getVirtOffset(),
1573 31, 0, data
) : data
;
1575 data
= insertBits(frames
[i
]->getVirtOffset(),
1577 frames
[i
]->setVirtOffset(data
);
1581 warn("GenericTimerMem::timerCtrlWrite: Unexpected address "
1582 "(0x%x:%i), assuming WI\n", addr
, size
);
1587 SystemCounterParams::create()
1589 return new SystemCounter(this);
1593 GenericTimerParams::create()
1595 return new GenericTimer(this);
1599 GenericTimerFrameParams::create()
1601 return new GenericTimerFrame(this);
1605 GenericTimerMemParams::create()
1607 return new GenericTimerMem(this);