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 using namespace ArmISA
;
55 SystemCounter::SystemCounter(const SystemCounterParams
&p
)
63 _freqUpdateEvent([this]{ freqUpdateCallback(); }, name()),
66 fatal_if(_freqTable
.empty(), "SystemCounter::SystemCounter: Base "
67 "frequency not provided\n");
68 // Store the table end marker as a 32-bit zero word
69 _freqTable
.push_back(0);
70 fatal_if(_freqTable
.size() > MAX_FREQ_ENTRIES
,
71 "SystemCounter::SystemCounter: Architecture states a maximum of 1004 "
72 "frequency table entries, limit surpassed\n");
73 // Set the active frequency to be the base
74 _freq
= _freqTable
.front();
75 _period
= (1.0 / _freq
) * SimClock::Frequency
;
79 SystemCounter::validateCounterRef(SystemCounter
*const sys_cnt
)
81 fatal_if(!sys_cnt
, "SystemCounter::validateCounterRef: No valid system "
82 "counter, can't instantiate system timers\n");
86 SystemCounter::enable()
88 DPRINTF(Timer
, "SystemCounter::enable: Counter enabled\n");
94 SystemCounter::disable()
96 DPRINTF(Timer
, "SystemCounter::disable: Counter disabled\n");
102 SystemCounter::value()
110 SystemCounter::updateValue()
113 _value
+ ((curTick() - _updateTick
) / _period
) * _increment
;
114 if (new_value
> _value
) {
121 SystemCounter::setValue(uint64_t new_value
)
124 warn("Explicit value set with counter enabled, UNKNOWNN result\n");
131 SystemCounter::whenValue(uint64_t cur_val
, uint64_t target_val
) const
133 Tick when
= curTick();
134 if (target_val
> cur_val
) {
135 uint64_t num_cycles
=
136 std::ceil((target_val
- cur_val
) / ((double) _increment
));
137 // Take into account current cycle remaining ticks
138 Tick rem_ticks
= _period
- (curTick() % _period
);
139 if (rem_ticks
< _period
) {
143 when
+= num_cycles
* _period
;
149 SystemCounter::whenValue(uint64_t target_val
)
151 return whenValue(value(), target_val
);
155 SystemCounter::updateTick()
157 _updateTick
= curTick() - (curTick() % _period
);
161 SystemCounter::freqUpdateSchedule(size_t new_freq_entry
)
163 if (new_freq_entry
< _freqTable
.size()) {
164 auto &new_freq
= _freqTable
[new_freq_entry
];
165 if (new_freq
!= _freq
) {
166 _nextFreqEntry
= new_freq_entry
;
167 // Wait until the value for which the lowest frequency increment
168 // is a exact divisor. This covers both high to low and low to
170 uint64_t new_incr
= _freqTable
[0] / new_freq
;
171 uint64_t target_val
= value();
172 target_val
+= target_val
% std::max(_increment
, new_incr
);
173 reschedule(_freqUpdateEvent
, whenValue(target_val
), true);
179 SystemCounter::freqUpdateCallback()
181 DPRINTF(Timer
, "SystemCounter::freqUpdateCallback: Changing counter "
185 _activeFreqEntry
= _nextFreqEntry
;
186 _freq
= _freqTable
[_activeFreqEntry
];
187 _increment
= _freqTable
[0] / _freq
;
188 _period
= (1.0 / _freq
) * SimClock::Frequency
;
193 SystemCounter::registerListener(SystemCounterListener
*listener
)
195 _listeners
.push_back(listener
);
199 SystemCounter::notifyListeners() const
201 for (auto &listener
: _listeners
)
206 SystemCounter::serialize(CheckpointOut
&cp
) const
208 DPRINTF(Timer
, "SystemCounter::serialize: Serializing\n");
209 SERIALIZE_SCALAR(_enabled
);
210 SERIALIZE_SCALAR(_freq
);
211 SERIALIZE_SCALAR(_value
);
212 SERIALIZE_SCALAR(_increment
);
213 SERIALIZE_CONTAINER(_freqTable
);
214 SERIALIZE_SCALAR(_activeFreqEntry
);
215 SERIALIZE_SCALAR(_updateTick
);
216 bool pending_freq_update
= _freqUpdateEvent
.scheduled();
217 SERIALIZE_SCALAR(pending_freq_update
);
218 if (pending_freq_update
) {
219 Tick when_freq_update
= _freqUpdateEvent
.when();
220 SERIALIZE_SCALAR(when_freq_update
);
222 SERIALIZE_SCALAR(_nextFreqEntry
);
226 SystemCounter::unserialize(CheckpointIn
&cp
)
228 DPRINTF(Timer
, "SystemCounter::unserialize: Unserializing\n");
229 UNSERIALIZE_SCALAR(_enabled
);
230 UNSERIALIZE_SCALAR(_freq
);
231 UNSERIALIZE_SCALAR(_value
);
232 UNSERIALIZE_SCALAR(_increment
);
233 UNSERIALIZE_CONTAINER(_freqTable
);
234 UNSERIALIZE_SCALAR(_activeFreqEntry
);
235 UNSERIALIZE_SCALAR(_updateTick
);
236 bool pending_freq_update
;
237 UNSERIALIZE_SCALAR(pending_freq_update
);
238 if (pending_freq_update
) {
239 Tick when_freq_update
;
240 UNSERIALIZE_SCALAR(when_freq_update
);
241 reschedule(_freqUpdateEvent
, when_freq_update
, true);
243 UNSERIALIZE_SCALAR(_nextFreqEntry
);
245 _period
= (1.0 / _freq
) * SimClock::Frequency
;
248 ArchTimer::ArchTimer(const std::string
&name
,
250 SystemCounter
&sysctr
,
251 ArmInterruptPin
*interrupt
)
252 : _name(name
), _parent(parent
), _systemCounter(sysctr
),
253 _interrupt(interrupt
),
254 _control(0), _counterLimit(0), _offset(0),
255 _counterLimitReachedEvent([this]{ counterLimitReached(); }, name
)
257 _systemCounter
.registerListener(this);
261 ArchTimer::counterLimitReached()
263 if (!_control
.enable
)
266 DPRINTF(Timer
, "Counter limit reached\n");
267 _control
.istatus
= 1;
268 if (!_control
.imask
) {
269 if (scheduleEvents()) {
270 DPRINTF(Timer
, "Causing interrupt\n");
273 DPRINTF(Timer
, "Kvm mode; skipping simulated interrupt\n");
279 ArchTimer::updateCounter()
281 if (_counterLimitReachedEvent
.scheduled())
282 _parent
.deschedule(_counterLimitReachedEvent
);
283 if (value() >= _counterLimit
) {
284 counterLimitReached();
286 // Clear the interurpt when timers conditions are not met
287 if (_interrupt
->active()) {
288 DPRINTF(Timer
, "Clearing interrupt\n");
292 _control
.istatus
= 0;
294 if (scheduleEvents()) {
295 _parent
.schedule(_counterLimitReachedEvent
,
296 whenValue(_counterLimit
));
302 ArchTimer::setCompareValue(uint64_t val
)
309 ArchTimer::setTimerValue(uint32_t val
)
311 setCompareValue(value() + sext
<32>(val
));
315 ArchTimer::setControl(uint32_t val
)
317 ArchTimerCtrl old_ctl
= _control
, new_ctl
= val
;
318 _control
.enable
= new_ctl
.enable
;
319 _control
.imask
= new_ctl
.imask
;
320 _control
.istatus
= old_ctl
.istatus
;
321 // Timer unmasked or enabled
322 if ((old_ctl
.imask
&& !new_ctl
.imask
) ||
323 (!old_ctl
.enable
&& new_ctl
.enable
))
325 // Timer masked or disabled
326 else if ((!old_ctl
.imask
&& new_ctl
.imask
) ||
327 (old_ctl
.enable
&& !new_ctl
.enable
)) {
329 if (_interrupt
->active()) {
330 DPRINTF(Timer
, "Clearing interrupt\n");
331 // We are clearing the interrupt but we are not
332 // setting istatus to 0 as we are doing
333 // in the updateCounter.
334 // istatus signals that Timer conditions are met.
335 // It shouldn't depend on masking.
336 // if enable is zero. istatus is unknown.
343 ArchTimer::setOffset(uint64_t val
)
350 ArchTimer::value() const
352 return _systemCounter
.value() - _offset
;
362 ArchTimer::serialize(CheckpointOut
&cp
) const
364 paramOut(cp
, "control_serial", _control
);
365 SERIALIZE_SCALAR(_counterLimit
);
366 SERIALIZE_SCALAR(_offset
);
370 ArchTimer::unserialize(CheckpointIn
&cp
)
372 paramIn(cp
, "control_serial", _control
);
373 // We didn't serialize an offset before we added support for the
374 // virtual timer. Consider it optional to maintain backwards
376 if (!UNSERIALIZE_OPT_SCALAR(_offset
))
379 // We no longer schedule an event here because we may enter KVM
380 // emulation. The event creation is delayed until drainResume().
386 if (_counterLimitReachedEvent
.scheduled())
387 _parent
.deschedule(_counterLimitReachedEvent
);
389 return DrainState::Drained
;
393 ArchTimer::drainResume()
398 GenericTimer::GenericTimer(const GenericTimerParams
&p
)
400 systemCounter(*p
.counter
),
403 SystemCounter::validateCounterRef(p
.counter
);
404 fatal_if(!p
.system
, "GenericTimer::GenericTimer: No system specified, "
405 "can't instantiate architected timers\n");
406 system
.setGenericTimer(this);
409 const GenericTimerParams
&
410 GenericTimer::params() const
412 return dynamic_cast<const GenericTimerParams
&>(_params
);
416 GenericTimer::serialize(CheckpointOut
&cp
) const
418 paramOut(cp
, "cpu_count", timers
.size());
420 for (int i
= 0; i
< timers
.size(); ++i
) {
421 const CoreTimers
&core(*timers
[i
]);
422 core
.serializeSection(cp
, csprintf("pe_implementation%d", i
));
427 GenericTimer::unserialize(CheckpointIn
&cp
)
429 // Try to unserialize the CPU count. Old versions of the timer
430 // model assumed a 8 CPUs, so we fall back to that if the field
432 static const unsigned OLD_CPU_MAX
= 8;
434 if (!UNSERIALIZE_OPT_SCALAR(cpu_count
)) {
435 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
437 cpu_count
= OLD_CPU_MAX
;
440 // We cannot assert for equality here because CPU timers are dynamically
441 // created on the first miscreg access. Therefore, if we take the checkpoint
442 // before any timer registers have been accessed, the number of counters
443 // is actually smaller than the total number of CPUs.
444 if (cpu_count
> system
.threads
.size()) {
445 fatal("The simulated system has been initialized with %d CPUs, "
446 "but the Generic Timer checkpoint expects %d CPUs. Consider "
447 "restoring the checkpoint specifying %d CPUs.",
448 system
.threads
.size(), cpu_count
, cpu_count
);
451 for (int i
= 0; i
< cpu_count
; ++i
) {
452 CoreTimers
&core(getTimers(i
));
453 core
.unserializeSection(cp
, csprintf("pe_implementation%d", i
));
457 GenericTimer::CoreTimers
&
458 GenericTimer::getTimers(int cpu_id
)
460 if (cpu_id
>= timers
.size())
461 createTimers(cpu_id
+ 1);
463 return *timers
[cpu_id
];
467 GenericTimer::createTimers(unsigned cpus
)
469 assert(timers
.size() < cpus
);
470 auto &p
= static_cast<const GenericTimerParams
&>(_params
);
472 const unsigned old_cpu_count(timers
.size());
474 for (unsigned i
= old_cpu_count
; i
< cpus
; ++i
) {
476 ThreadContext
*tc
= system
.threads
[i
];
479 new CoreTimers(*this, system
, i
,
480 p
.int_phys_s
->get(tc
),
481 p
.int_phys_ns
->get(tc
),
483 p
.int_hyp
->get(tc
)));
488 GenericTimer::handleStream(CoreTimers::EventStream
*ev_stream
,
489 ArchTimer
*timer
, RegVal old_cnt_ctl
, RegVal cnt_ctl
)
491 uint64_t evnten
= bits(cnt_ctl
, 2);
492 uint64_t old_evnten
= bits(old_cnt_ctl
, 2);
493 uint8_t old_trans_to
= ev_stream
->transitionTo
;
494 uint8_t old_trans_bit
= ev_stream
->transitionBit
;
495 ev_stream
->transitionTo
= !bits(cnt_ctl
, 3);
496 ev_stream
->transitionBit
= bits(cnt_ctl
, 7, 4);
497 // Reschedule the Event Stream if enabled and any change in
499 if (evnten
&& ((old_evnten
!= evnten
) ||
500 (old_trans_to
!= ev_stream
->transitionTo
) ||
501 (old_trans_bit
!= ev_stream
->transitionBit
))) {
503 Tick when
= timer
->whenValue(
504 ev_stream
->eventTargetValue(timer
->value()));
505 reschedule(ev_stream
->event
, when
, true);
506 } else if (old_evnten
&& !evnten
) {
507 // Event Stream generation disabled
508 if (ev_stream
->event
.scheduled())
509 deschedule(ev_stream
->event
);
514 GenericTimer::setMiscReg(int reg
, unsigned cpu
, RegVal val
)
516 CoreTimers
&core(getTimers(cpu
));
517 ThreadContext
*tc
= system
.threads
[cpu
];
521 case MISCREG_CNTFRQ_EL0
:
523 warn_if(core
.cntfrq
!= systemCounter
.freq(), "CNTFRQ configured freq "
524 "does not match the system counter freq\n");
526 case MISCREG_CNTKCTL
:
527 case MISCREG_CNTKCTL_EL1
:
529 if (ELIsInHost(tc
, currEL(tc
))) {
530 tc
->setMiscReg(MISCREG_CNTHCTL_EL2
, val
);
533 RegVal old_cnt_ctl
= core
.cntkctl
;
536 ArchTimer
*timer
= &core
.virt
;
537 CoreTimers::EventStream
*ev_stream
= &core
.virtEvStream
;
539 handleStream(ev_stream
, timer
, old_cnt_ctl
, val
);
542 case MISCREG_CNTHCTL
:
543 case MISCREG_CNTHCTL_EL2
:
545 RegVal old_cnt_ctl
= core
.cnthctl
;
548 ArchTimer
*timer
= &core
.physNS
;
549 CoreTimers::EventStream
*ev_stream
= &core
.physEvStream
;
551 handleStream(ev_stream
, timer
, old_cnt_ctl
, val
);
554 // Physical timer (NS)
555 case MISCREG_CNTP_CVAL_NS
:
556 case MISCREG_CNTP_CVAL_EL0
:
557 core
.physNS
.setCompareValue(val
);
560 case MISCREG_CNTP_TVAL_NS
:
561 case MISCREG_CNTP_TVAL_EL0
:
562 core
.physNS
.setTimerValue(val
);
565 case MISCREG_CNTP_CTL_NS
:
566 case MISCREG_CNTP_CTL_EL0
:
567 core
.physNS
.setControl(val
);
572 case MISCREG_CNTPCT_EL0
:
574 case MISCREG_CNTVCT_EL0
:
575 warn("Ignoring write to read only count register: %s\n",
580 case MISCREG_CNTVOFF
:
581 case MISCREG_CNTVOFF_EL2
:
582 core
.virt
.setOffset(val
);
585 case MISCREG_CNTV_CVAL
:
586 case MISCREG_CNTV_CVAL_EL0
:
587 core
.virt
.setCompareValue(val
);
590 case MISCREG_CNTV_TVAL
:
591 case MISCREG_CNTV_TVAL_EL0
:
592 core
.virt
.setTimerValue(val
);
595 case MISCREG_CNTV_CTL
:
596 case MISCREG_CNTV_CTL_EL0
:
597 core
.virt
.setControl(val
);
600 // Physical timer (S)
601 case MISCREG_CNTP_CTL_S
:
602 case MISCREG_CNTPS_CTL_EL1
:
603 core
.physS
.setControl(val
);
606 case MISCREG_CNTP_CVAL_S
:
607 case MISCREG_CNTPS_CVAL_EL1
:
608 core
.physS
.setCompareValue(val
);
611 case MISCREG_CNTP_TVAL_S
:
612 case MISCREG_CNTPS_TVAL_EL1
:
613 core
.physS
.setTimerValue(val
);
616 // Hyp phys. timer, non-secure
617 case MISCREG_CNTHP_CTL
:
618 case MISCREG_CNTHP_CTL_EL2
:
619 core
.hyp
.setControl(val
);
622 case MISCREG_CNTHP_CVAL
:
623 case MISCREG_CNTHP_CVAL_EL2
:
624 core
.hyp
.setCompareValue(val
);
627 case MISCREG_CNTHP_TVAL
:
628 case MISCREG_CNTHP_TVAL_EL2
:
629 core
.hyp
.setTimerValue(val
);
633 warn("Writing to unknown register: %s\n", miscRegName
[reg
]);
640 GenericTimer::readMiscReg(int reg
, unsigned cpu
)
642 CoreTimers
&core(getTimers(cpu
));
646 case MISCREG_CNTFRQ_EL0
:
648 case MISCREG_CNTKCTL
:
649 case MISCREG_CNTKCTL_EL1
:
650 return core
.cntkctl
& 0x00000000ffffffff;
651 case MISCREG_CNTHCTL
:
652 case MISCREG_CNTHCTL_EL2
:
653 return core
.cnthctl
& 0x00000000ffffffff;
655 case MISCREG_CNTP_CVAL_NS
:
656 case MISCREG_CNTP_CVAL_EL0
:
657 return core
.physNS
.compareValue();
659 case MISCREG_CNTP_TVAL_NS
:
660 case MISCREG_CNTP_TVAL_EL0
:
661 return core
.physNS
.timerValue();
663 case MISCREG_CNTP_CTL_EL0
:
664 case MISCREG_CNTP_CTL_NS
:
665 return core
.physNS
.control();
668 case MISCREG_CNTPCT_EL0
:
669 return core
.physNS
.value();
674 case MISCREG_CNTVCT_EL0
:
675 return core
.virt
.value();
677 case MISCREG_CNTVOFF
:
678 case MISCREG_CNTVOFF_EL2
:
679 return core
.virt
.offset();
681 case MISCREG_CNTV_CVAL
:
682 case MISCREG_CNTV_CVAL_EL0
:
683 return core
.virt
.compareValue();
685 case MISCREG_CNTV_TVAL
:
686 case MISCREG_CNTV_TVAL_EL0
:
687 return core
.virt
.timerValue();
689 case MISCREG_CNTV_CTL
:
690 case MISCREG_CNTV_CTL_EL0
:
691 return core
.virt
.control();
693 // PL1 phys. timer, secure
694 case MISCREG_CNTP_CTL_S
:
695 case MISCREG_CNTPS_CTL_EL1
:
696 return core
.physS
.control();
698 case MISCREG_CNTP_CVAL_S
:
699 case MISCREG_CNTPS_CVAL_EL1
:
700 return core
.physS
.compareValue();
702 case MISCREG_CNTP_TVAL_S
:
703 case MISCREG_CNTPS_TVAL_EL1
:
704 return core
.physS
.timerValue();
706 // HYP phys. timer (NS)
707 case MISCREG_CNTHP_CTL
:
708 case MISCREG_CNTHP_CTL_EL2
:
709 return core
.hyp
.control();
711 case MISCREG_CNTHP_CVAL
:
712 case MISCREG_CNTHP_CVAL_EL2
:
713 return core
.hyp
.compareValue();
715 case MISCREG_CNTHP_TVAL
:
716 case MISCREG_CNTHP_TVAL_EL2
:
717 return core
.hyp
.timerValue();
720 warn("Reading from unknown register: %s\n", miscRegName
[reg
]);
725 GenericTimer::CoreTimers::CoreTimers(GenericTimer
&_parent
,
726 ArmSystem
&system
, unsigned cpu
,
727 ArmInterruptPin
*_irqPhysS
, ArmInterruptPin
*_irqPhysNS
,
728 ArmInterruptPin
*_irqVirt
, ArmInterruptPin
*_irqHyp
)
730 cntfrq(parent
.params().cntfrq
),
731 threadContext(system
.threads
[cpu
]),
733 irqPhysNS(_irqPhysNS
),
736 physS(csprintf("%s.phys_s_timer%d", parent
.name(), cpu
),
737 system
, parent
, parent
.systemCounter
,
739 // This should really be phys_timerN, but we are stuck with
740 // arch_timer for backwards compatibility.
741 physNS(csprintf("%s.arch_timer%d", parent
.name(), cpu
),
742 system
, parent
, parent
.systemCounter
,
744 virt(csprintf("%s.virt_timer%d", parent
.name(), cpu
),
745 system
, parent
, parent
.systemCounter
,
747 hyp(csprintf("%s.hyp_timer%d", parent
.name(), cpu
),
748 system
, parent
, parent
.systemCounter
,
751 EventFunctionWrapper([this]{ physEventStreamCallback(); },
752 csprintf("%s.phys_event_gen%d", parent
.name(), cpu
)), 0, 0
755 EventFunctionWrapper([this]{ virtEventStreamCallback(); },
756 csprintf("%s.virt_event_gen%d", parent
.name(), cpu
)), 0, 0
762 GenericTimer::CoreTimers::physEventStreamCallback()
764 eventStreamCallback();
765 schedNextEvent(physEvStream
, physNS
);
769 GenericTimer::CoreTimers::virtEventStreamCallback()
771 eventStreamCallback();
772 schedNextEvent(virtEvStream
, virt
);
776 GenericTimer::CoreTimers::eventStreamCallback() const
778 sendEvent(threadContext
);
779 threadContext
->getCpuPtr()->wakeup(threadContext
->threadId());
783 GenericTimer::CoreTimers::schedNextEvent(EventStream
&ev_stream
,
786 parent
.reschedule(ev_stream
.event
, timer
.whenValue(
787 ev_stream
.eventTargetValue(timer
.value())), true);
791 GenericTimer::CoreTimers::notify()
793 schedNextEvent(virtEvStream
, virt
);
794 schedNextEvent(physEvStream
, physNS
);
798 GenericTimer::CoreTimers::serialize(CheckpointOut
&cp
) const
800 SERIALIZE_SCALAR(cntfrq
);
801 SERIALIZE_SCALAR(cntkctl
);
802 SERIALIZE_SCALAR(cnthctl
);
804 const bool phys_ev_scheduled
= physEvStream
.event
.scheduled();
805 SERIALIZE_SCALAR(phys_ev_scheduled
);
806 if (phys_ev_scheduled
) {
807 const Tick phys_ev_when
= physEvStream
.event
.when();
808 SERIALIZE_SCALAR(phys_ev_when
);
810 SERIALIZE_SCALAR(physEvStream
.transitionTo
);
811 SERIALIZE_SCALAR(physEvStream
.transitionBit
);
813 const bool virt_ev_scheduled
= virtEvStream
.event
.scheduled();
814 SERIALIZE_SCALAR(virt_ev_scheduled
);
815 if (virt_ev_scheduled
) {
816 const Tick virt_ev_when
= virtEvStream
.event
.when();
817 SERIALIZE_SCALAR(virt_ev_when
);
819 SERIALIZE_SCALAR(virtEvStream
.transitionTo
);
820 SERIALIZE_SCALAR(virtEvStream
.transitionBit
);
822 physS
.serializeSection(cp
, "phys_s_timer");
823 physNS
.serializeSection(cp
, "phys_ns_timer");
824 virt
.serializeSection(cp
, "virt_timer");
825 hyp
.serializeSection(cp
, "hyp_timer");
829 GenericTimer::CoreTimers::unserialize(CheckpointIn
&cp
)
831 UNSERIALIZE_SCALAR(cntfrq
);
832 UNSERIALIZE_SCALAR(cntkctl
);
833 UNSERIALIZE_SCALAR(cnthctl
);
835 bool phys_ev_scheduled
;
836 UNSERIALIZE_SCALAR(phys_ev_scheduled
);
837 if (phys_ev_scheduled
) {
839 UNSERIALIZE_SCALAR(phys_ev_when
);
840 parent
.reschedule(physEvStream
.event
, phys_ev_when
, true);
842 UNSERIALIZE_SCALAR(physEvStream
.transitionTo
);
843 UNSERIALIZE_SCALAR(physEvStream
.transitionBit
);
845 bool virt_ev_scheduled
;
846 UNSERIALIZE_SCALAR(virt_ev_scheduled
);
847 if (virt_ev_scheduled
) {
849 UNSERIALIZE_SCALAR(virt_ev_when
);
850 parent
.reschedule(virtEvStream
.event
, virt_ev_when
, true);
852 UNSERIALIZE_SCALAR(virtEvStream
.transitionTo
);
853 UNSERIALIZE_SCALAR(virtEvStream
.transitionBit
);
855 physS
.unserializeSection(cp
, "phys_s_timer");
856 physNS
.unserializeSection(cp
, "phys_ns_timer");
857 virt
.unserializeSection(cp
, "virt_timer");
858 hyp
.unserializeSection(cp
, "hyp_timer");
862 GenericTimerISA::setMiscReg(int reg
, RegVal val
)
864 DPRINTF(Timer
, "Setting %s := 0x%x\n", miscRegName
[reg
], val
);
865 parent
.setMiscReg(reg
, cpu
, val
);
869 GenericTimerISA::readMiscReg(int reg
)
871 RegVal value
= parent
.readMiscReg(reg
, cpu
);
872 DPRINTF(Timer
, "Reading %s as 0x%x\n", miscRegName
[reg
], value
);
876 GenericTimerFrame::GenericTimerFrame(const GenericTimerFrameParams
&p
)
878 timerRange(RangeSize(p
.cnt_base
, ArmSystem::PageBytes
)),
879 addrRanges({timerRange
}),
880 systemCounter(*p
.counter
),
881 physTimer(csprintf("%s.phys_timer", name()),
882 *this, systemCounter
, p
.int_phys
->get()),
883 virtTimer(csprintf("%s.virt_timer", name()),
884 *this, systemCounter
,
887 system(*dynamic_cast<ArmSystem
*>(sys
))
889 SystemCounter::validateCounterRef(p
.counter
);
890 // Expose optional CNTEL0Base register frame
891 if (p
.cnt_el0_base
!= MaxAddr
) {
892 timerEl0Range
= RangeSize(p
.cnt_el0_base
, ArmSystem::PageBytes
);
893 accessBitsEl0
= 0x303;
894 addrRanges
.push_back(timerEl0Range
);
896 for (auto &range
: addrRanges
)
897 GenericTimerMem::validateFrameRange(range
);
901 GenericTimerFrame::serialize(CheckpointOut
&cp
) const
903 SERIALIZE_SCALAR(accessBits
);
905 SERIALIZE_SCALAR(accessBitsEl0
);
906 SERIALIZE_SCALAR(nonSecureAccess
);
908 physTimer
.serializeSection(cp
, "phys_timer");
909 virtTimer
.serializeSection(cp
, "virt_timer");
913 GenericTimerFrame::unserialize(CheckpointIn
&cp
)
915 UNSERIALIZE_SCALAR(accessBits
);
917 UNSERIALIZE_SCALAR(accessBitsEl0
);
918 UNSERIALIZE_SCALAR(nonSecureAccess
);
920 physTimer
.unserializeSection(cp
, "phys_timer");
921 virtTimer
.unserializeSection(cp
, "virt_timer");
925 GenericTimerFrame::getVirtOffset() const
927 return virtTimer
.offset();
931 GenericTimerFrame::setVirtOffset(uint64_t new_offset
)
933 virtTimer
.setOffset(new_offset
);
937 GenericTimerFrame::hasEl0View() const
939 return timerEl0Range
.valid();
943 GenericTimerFrame::getAccessBits() const
949 GenericTimerFrame::setAccessBits(uint8_t data
)
951 accessBits
= data
& 0x3f;
955 GenericTimerFrame::hasNonSecureAccess() const
957 return nonSecureAccess
;
961 GenericTimerFrame::setNonSecureAccess()
963 nonSecureAccess
= true;
967 GenericTimerFrame::hasReadableVoff() const
969 return accessBits
.rvoff
;
973 GenericTimerFrame::getAddrRanges() const
979 GenericTimerFrame::read(PacketPtr pkt
)
981 const Addr addr
= pkt
->getAddr();
982 const size_t size
= pkt
->getSize();
983 const bool is_sec
= pkt
->isSecure();
984 panic_if(size
!= 4 && size
!= 8,
985 "GenericTimerFrame::read: Invalid size %i\n", size
);
990 if (timerRange
.contains(addr
)) {
991 offset
= addr
- timerRange
.start();
992 } else if (hasEl0View() && timerEl0Range
.contains(addr
)) {
993 offset
= addr
- timerEl0Range
.start();
996 panic("GenericTimerFrame::read: Invalid address: 0x%x\n", addr
);
999 resp
= timerRead(offset
, size
, is_sec
, to_el0
);
1001 DPRINTF(Timer
, "GenericTimerFrame::read: 0x%x<-0x%x(%i) [S = %u]\n", resp
,
1002 addr
, size
, is_sec
);
1004 pkt
->setUintX(resp
, ByteOrder::little
);
1005 pkt
->makeResponse();
1010 GenericTimerFrame::write(PacketPtr pkt
)
1012 const Addr addr
= pkt
->getAddr();
1013 const size_t size
= pkt
->getSize();
1014 const bool is_sec
= pkt
->isSecure();
1015 panic_if(size
!= 4 && size
!= 8,
1016 "GenericTimerFrame::write: Invalid size %i\n", size
);
1018 bool to_el0
= false;
1019 const uint64_t data
= pkt
->getUintX(ByteOrder::little
);
1021 if (timerRange
.contains(addr
)) {
1022 offset
= addr
- timerRange
.start();
1023 } else if (hasEl0View() && timerEl0Range
.contains(addr
)) {
1024 offset
= addr
- timerEl0Range
.start();
1027 panic("GenericTimerFrame::write: Invalid address: 0x%x\n", addr
);
1030 timerWrite(offset
, size
, data
, is_sec
, to_el0
);
1032 DPRINTF(Timer
, "GenericTimerFrame::write: 0x%x->0x%x(%i) [S = %u]\n", data
,
1033 addr
, size
, is_sec
);
1035 pkt
->makeResponse();
1040 GenericTimerFrame::timerRead(Addr addr
, size_t size
, bool is_sec
,
1043 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
) &&
1048 case TIMER_CNTPCT_LO
:
1049 if (!accessBits
.rpct
|| (to_el0
&& !accessBitsEl0
.pcten
))
1052 return physTimer
.value();
1054 case TIMER_CNTPCT_HI
:
1055 if (!accessBits
.rpct
|| (to_el0
&& !accessBitsEl0
.pcten
))
1058 return physTimer
.value() >> 32;
1061 if ((!accessBits
.rfrq
) ||
1062 (to_el0
&& (!accessBitsEl0
.pcten
&& !accessBitsEl0
.vcten
)))
1065 return systemCounter
.freq();
1067 case TIMER_CNTEL0ACR
:
1068 if (!hasEl0View() || to_el0
)
1071 return accessBitsEl0
;
1073 case TIMER_CNTP_CVAL_LO
:
1074 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1077 return physTimer
.compareValue();
1079 case TIMER_CNTP_CVAL_HI
:
1080 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1083 return physTimer
.compareValue() >> 32;
1085 case TIMER_CNTP_TVAL
:
1086 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1089 return physTimer
.timerValue();
1090 case TIMER_CNTP_CTL
:
1091 if (!accessBits
.rwpt
|| (to_el0
&& !accessBitsEl0
.pten
))
1094 return physTimer
.control();
1096 case TIMER_CNTVCT_LO
:
1097 if (!accessBits
.rvct
|| (to_el0
&& !accessBitsEl0
.vcten
))
1100 return virtTimer
.value();
1102 case TIMER_CNTVCT_HI
:
1103 if (!accessBits
.rvct
|| (to_el0
&& !accessBitsEl0
.vcten
))
1106 return virtTimer
.value() >> 32;
1108 case TIMER_CNTVOFF_LO
:
1109 if (!accessBits
.rvoff
|| (to_el0
))
1112 return virtTimer
.offset();
1114 case TIMER_CNTVOFF_HI
:
1115 if (!accessBits
.rvoff
|| (to_el0
))
1118 return virtTimer
.offset() >> 32;
1120 case TIMER_CNTV_CVAL_LO
:
1121 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1124 return virtTimer
.compareValue();
1126 case TIMER_CNTV_CVAL_HI
:
1127 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1130 return virtTimer
.compareValue() >> 32;
1132 case TIMER_CNTV_TVAL
:
1133 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1136 return virtTimer
.timerValue();
1138 case TIMER_CNTV_CTL
:
1139 if (!accessBits
.rwvt
|| (to_el0
&& !accessBitsEl0
.vten
))
1142 return virtTimer
.control();
1145 warn("GenericTimerFrame::timerRead: Unexpected address (0x%x:%i), "
1146 "assuming RAZ\n", addr
, size
);
1152 GenericTimerFrame::timerWrite(Addr addr
, size_t size
, uint64_t data
,
1153 bool is_sec
, bool to_el0
)
1155 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
) &&
1160 case TIMER_CNTPCT_LO
... TIMER_CNTPCT_HI
:
1161 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTPCT]\n",
1166 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTFRQ]\n",
1170 case TIMER_CNTEL0ACR
:
1171 if (!hasEl0View() || to_el0
)
1174 insertBits(accessBitsEl0
, 9, 8, data
);
1175 insertBits(accessBitsEl0
, 1, 0, data
);
1178 case TIMER_CNTP_CVAL_LO
:
1179 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1181 data
= size
== 4 ? insertBits(physTimer
.compareValue(),
1182 31, 0, data
) : data
;
1183 physTimer
.setCompareValue(data
);
1186 case TIMER_CNTP_CVAL_HI
:
1187 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1189 data
= insertBits(physTimer
.compareValue(), 63, 32, data
);
1190 physTimer
.setCompareValue(data
);
1193 case TIMER_CNTP_TVAL
:
1194 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1196 physTimer
.setTimerValue(data
);
1199 case TIMER_CNTP_CTL
:
1200 if ((!accessBits
.rwpt
) || (to_el0
&& !accessBitsEl0
.pten
))
1202 physTimer
.setControl(data
);
1205 case TIMER_CNTVCT_LO
... TIMER_CNTVCT_HI
:
1206 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVCT]\n",
1209 case TIMER_CNTVOFF_LO
... TIMER_CNTVOFF_HI
:
1210 warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVOFF]\n",
1214 case TIMER_CNTV_CVAL_LO
:
1215 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1217 data
= size
== 4 ? insertBits(virtTimer
.compareValue(),
1218 31, 0, data
) : data
;
1219 virtTimer
.setCompareValue(data
);
1222 case TIMER_CNTV_CVAL_HI
:
1223 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1225 data
= insertBits(virtTimer
.compareValue(), 63, 32, data
);
1226 virtTimer
.setCompareValue(data
);
1229 case TIMER_CNTV_TVAL
:
1230 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1232 virtTimer
.setTimerValue(data
);
1235 case TIMER_CNTV_CTL
:
1236 if ((!accessBits
.rwvt
) || (to_el0
&& !accessBitsEl0
.vten
))
1238 virtTimer
.setControl(data
);
1242 warn("GenericTimerFrame::timerWrite: Unexpected address (0x%x:%i), "
1243 "assuming WI\n", addr
, size
);
1247 GenericTimerMem::GenericTimerMem(const GenericTimerMemParams
&p
)
1249 counterCtrlRange(RangeSize(p
.cnt_control_base
, ArmSystem::PageBytes
)),
1250 counterStatusRange(RangeSize(p
.cnt_read_base
, ArmSystem::PageBytes
)),
1251 timerCtrlRange(RangeSize(p
.cnt_ctl_base
, ArmSystem::PageBytes
)),
1253 addrRanges
{counterCtrlRange
, counterStatusRange
, timerCtrlRange
},
1254 systemCounter(*p
.counter
),
1256 system(*dynamic_cast<ArmSystem
*>(sys
))
1258 SystemCounter::validateCounterRef(p
.counter
);
1259 for (auto &range
: addrRanges
)
1260 GenericTimerMem::validateFrameRange(range
);
1261 fatal_if(frames
.size() > MAX_TIMER_FRAMES
,
1262 "GenericTimerMem::GenericTimerMem: Architecture states a maximum of "
1263 "8 memory-mapped timer frames, limit surpassed\n");
1264 // Initialize CNTTIDR with each frame's features
1265 for (int i
= 0; i
< frames
.size(); i
++) {
1266 uint32_t features
= 0x1;
1268 if (frames
[i
]->hasEl0View())
1271 replaceBits(cnttidr
, (i
+ 1) * 4 - 1, i
* 4, features
);
1276 GenericTimerMem::validateFrameRange(const AddrRange
&range
)
1278 fatal_if(range
.start() % ArmSystem::PageBytes
,
1279 "GenericTimerMem::validateFrameRange: Architecture states each "
1280 "register frame should be in a separate memory page, specified "
1281 "range base address [0x%x] is not compliant\n");
1285 GenericTimerMem::validateAccessPerm(ArmSystem
&sys
, bool is_sec
)
1287 return !sys
.haveSecurity() || is_sec
;
1291 GenericTimerMem::getAddrRanges() const
1297 GenericTimerMem::read(PacketPtr pkt
)
1299 const Addr addr
= pkt
->getAddr();
1300 const size_t size
= pkt
->getSize();
1301 const bool is_sec
= pkt
->isSecure();
1302 panic_if(size
!= 4 && size
!= 8,
1303 "GenericTimerMem::read: Invalid size %i\n", size
);
1306 if (counterCtrlRange
.contains(addr
))
1307 resp
= counterCtrlRead(addr
- counterCtrlRange
.start(), size
, is_sec
);
1308 else if (counterStatusRange
.contains(addr
))
1309 resp
= counterStatusRead(addr
- counterStatusRange
.start(), size
);
1310 else if (timerCtrlRange
.contains(addr
))
1311 resp
= timerCtrlRead(addr
- timerCtrlRange
.start(), size
, is_sec
);
1313 panic("GenericTimerMem::read: Invalid address: 0x%x\n", addr
);
1315 DPRINTF(Timer
, "GenericTimerMem::read: 0x%x<-0x%x(%i) [S = %u]\n", resp
,
1316 addr
, size
, is_sec
);
1318 pkt
->setUintX(resp
, ByteOrder::little
);
1319 pkt
->makeResponse();
1324 GenericTimerMem::write(PacketPtr pkt
)
1326 const Addr addr
= pkt
->getAddr();
1327 const size_t size
= pkt
->getSize();
1328 const bool is_sec
= pkt
->isSecure();
1329 panic_if(size
!= 4 && size
!= 8,
1330 "GenericTimerMem::write: Invalid size %i\n", size
);
1332 const uint64_t data
= pkt
->getUintX(ByteOrder::little
);
1333 if (counterCtrlRange
.contains(addr
))
1334 counterCtrlWrite(addr
- counterCtrlRange
.start(), size
, data
, is_sec
);
1335 else if (counterStatusRange
.contains(addr
))
1336 counterStatusWrite(addr
- counterStatusRange
.start(), size
, data
);
1337 else if (timerCtrlRange
.contains(addr
))
1338 timerCtrlWrite(addr
- timerCtrlRange
.start(), size
, data
, is_sec
);
1340 panic("GenericTimerMem::write: Invalid address: 0x%x\n", addr
);
1342 DPRINTF(Timer
, "GenericTimerMem::write: 0x%x->0x%x(%i) [S = %u]\n", data
,
1343 addr
, size
, is_sec
);
1345 pkt
->makeResponse();
1350 GenericTimerMem::counterCtrlRead(Addr addr
, size_t size
, bool is_sec
) const
1352 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
))
1355 case COUNTER_CTRL_CNTCR
:
1358 cntcr
.en
= systemCounter
.enabled();
1359 cntcr
.fcreq
= systemCounter
.activeFreqEntry();
1362 case COUNTER_CTRL_CNTSR
:
1365 cntsr
.fcack
= systemCounter
.activeFreqEntry();
1368 case COUNTER_CTRL_CNTCV_LO
: return systemCounter
.value();
1369 case COUNTER_CTRL_CNTCV_HI
: return systemCounter
.value() >> 32;
1370 case COUNTER_CTRL_CNTSCR
: return 0;
1371 case COUNTER_CTRL_CNTID
: return 0;
1374 auto &freq_table
= systemCounter
.freqTable();
1375 for (int i
= 0; i
< (freq_table
.size() - 1); i
++) {
1376 Addr offset
= COUNTER_CTRL_CNTFID
+ (i
* 0x4);
1378 return freq_table
[i
];
1380 warn("GenericTimerMem::counterCtrlRead: Unexpected address "
1381 "(0x%x:%i), assuming RAZ\n", addr
, size
);
1388 GenericTimerMem::counterCtrlWrite(Addr addr
, size_t size
, uint64_t data
,
1391 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
))
1395 case COUNTER_CTRL_CNTCR
:
1398 if (!systemCounter
.enabled() && val
.en
)
1399 systemCounter
.enable();
1400 else if (systemCounter
.enabled() && !val
.en
)
1401 systemCounter
.disable();
1404 warn("GenericTimerMem::counterCtrlWrite: Halt-on-debug is not "
1407 warn("GenericTimerMem::counterCtrlWrite: Counter Scaling is not "
1409 if (val
.fcreq
!= systemCounter
.activeFreqEntry())
1410 systemCounter
.freqUpdateSchedule(val
.fcreq
);
1414 case COUNTER_CTRL_CNTSR
:
1415 warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTSR]\n",
1419 case COUNTER_CTRL_CNTCV_LO
:
1420 data
= size
== 4 ? insertBits(systemCounter
.value(), 31, 0, data
)
1422 systemCounter
.setValue(data
);
1425 case COUNTER_CTRL_CNTCV_HI
:
1426 data
= insertBits(systemCounter
.value(), 63, 32, data
);
1427 systemCounter
.setValue(data
);
1430 case COUNTER_CTRL_CNTSCR
:
1433 case COUNTER_CTRL_CNTID
:
1434 warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTID]\n",
1440 auto &freq_table
= systemCounter
.freqTable();
1441 for (int i
= 0; i
< (freq_table
.size() - 1); i
++) {
1442 Addr offset
= COUNTER_CTRL_CNTFID
+ (i
* 0x4);
1443 if (addr
== offset
) {
1444 freq_table
[i
] = data
;
1445 // This is changing the currently selected frequency
1446 if (i
== systemCounter
.activeFreqEntry()) {
1447 // We've changed the frequency in the table entry,
1448 // however the counter will still work with the
1449 // current one until transition is completed
1450 systemCounter
.freqUpdateSchedule(i
);
1455 warn("GenericTimerMem::counterCtrlWrite: Unexpected address "
1456 "(0x%x:%i), assuming WI\n", addr
, size
);
1462 GenericTimerMem::counterStatusRead(Addr addr
, size_t size
) const
1465 case COUNTER_STATUS_CNTCV_LO
: return systemCounter
.value();
1466 case COUNTER_STATUS_CNTCV_HI
: return systemCounter
.value() >> 32;
1468 warn("GenericTimerMem::counterStatusRead: Unexpected address "
1469 "(0x%x:%i), assuming RAZ\n", addr
, size
);
1475 GenericTimerMem::counterStatusWrite(Addr addr
, size_t size
, uint64_t data
)
1478 case COUNTER_STATUS_CNTCV_LO
... COUNTER_STATUS_CNTCV_HI
:
1479 warn("GenericTimerMem::counterStatusWrite: RO reg (0x%x) [CNTCV]\n",
1483 warn("GenericTimerMem::counterStatusWrite: Unexpected address "
1484 "(0x%x:%i), assuming WI\n", addr
, size
);
1489 GenericTimerMem::timerCtrlRead(Addr addr
, size_t size
, bool is_sec
) const
1492 case TIMER_CTRL_CNTFRQ
:
1493 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return 0;
1494 return systemCounter
.freq();
1495 case TIMER_CTRL_CNTNSAR
:
1497 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return 0;
1498 uint32_t cntnsar
= 0x0;
1499 for (int i
= 0; i
< frames
.size(); i
++) {
1500 if (frames
[i
]->hasNonSecureAccess())
1501 cntnsar
|= 0x1 << i
;
1505 case TIMER_CTRL_CNTTIDR
: return cnttidr
;
1507 for (int i
= 0; i
< frames
.size(); i
++) {
1508 Addr cntacr_off
= TIMER_CTRL_CNTACR
+ (i
* 0x4);
1509 Addr cntvoff_lo_off
= TIMER_CTRL_CNTVOFF_LO
+ (i
* 0x4);
1510 Addr cntvoff_hi_off
= TIMER_CTRL_CNTVOFF_HI
+ (i
* 0x4);
1511 // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1513 bool hit
= addr
== cntacr_off
|| addr
== cntvoff_lo_off
||
1514 addr
== cntvoff_hi_off
;
1516 GenericTimerMem::validateAccessPerm(system
, is_sec
) ||
1517 frames
[i
]->hasNonSecureAccess();
1518 if (hit
&& !has_access
) return 0;
1519 if (addr
== cntacr_off
)
1520 return frames
[i
]->getAccessBits();
1521 if (addr
== cntvoff_lo_off
|| addr
== cntvoff_hi_off
) {
1522 return addr
== cntvoff_lo_off
? frames
[i
]->getVirtOffset()
1523 : frames
[i
]->getVirtOffset() >> 32;
1526 warn("GenericTimerMem::timerCtrlRead: Unexpected address (0x%x:%i), "
1527 "assuming RAZ\n", addr
, size
);
1533 GenericTimerMem::timerCtrlWrite(Addr addr
, size_t size
, uint64_t data
,
1537 case TIMER_CTRL_CNTFRQ
:
1538 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return;
1539 warn_if(data
!= systemCounter
.freq(),
1540 "GenericTimerMem::timerCtrlWrite: CNTFRQ configured freq "
1541 "does not match the counter freq, ignoring\n");
1543 case TIMER_CTRL_CNTNSAR
:
1544 if (!GenericTimerMem::validateAccessPerm(system
, is_sec
)) return;
1545 for (int i
= 0; i
< frames
.size(); i
++) {
1546 // Check if the CNTNSAR.NS bit is set for this frame
1547 if (data
& (0x1 << i
))
1548 frames
[i
]->setNonSecureAccess();
1551 case TIMER_CTRL_CNTTIDR
:
1552 warn("GenericTimerMem::timerCtrlWrite: RO reg (0x%x) [CNTTIDR]\n",
1556 for (int i
= 0; i
< frames
.size(); i
++) {
1557 Addr cntacr_off
= TIMER_CTRL_CNTACR
+ (i
* 0x4);
1558 Addr cntvoff_lo_off
= TIMER_CTRL_CNTVOFF_LO
+ (i
* 0x4);
1559 Addr cntvoff_hi_off
= TIMER_CTRL_CNTVOFF_HI
+ (i
* 0x4);
1560 // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1562 bool hit
= addr
== cntacr_off
|| addr
== cntvoff_lo_off
||
1563 addr
== cntvoff_hi_off
;
1565 GenericTimerMem::validateAccessPerm(system
, is_sec
) ||
1566 frames
[i
]->hasNonSecureAccess();
1567 if (hit
&& !has_access
) return;
1568 if (addr
== cntacr_off
) {
1569 frames
[i
]->setAccessBits(data
);
1572 if (addr
== cntvoff_lo_off
|| addr
== cntvoff_hi_off
) {
1573 if (addr
== cntvoff_lo_off
)
1574 data
= size
== 4 ? insertBits(frames
[i
]->getVirtOffset(),
1575 31, 0, data
) : data
;
1577 data
= insertBits(frames
[i
]->getVirtOffset(),
1579 frames
[i
]->setVirtOffset(data
);
1583 warn("GenericTimerMem::timerCtrlWrite: Unexpected address "
1584 "(0x%x:%i), assuming WI\n", addr
, size
);