gem5  v20.0.0.2
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
generic_timer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, 2015, 2017-2018,2020 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 
38 #include "dev/arm/generic_timer.hh"
39 
40 #include <cmath>
41 
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"
52 
53 SystemCounter::SystemCounter(SystemCounterParams *const p)
54  : SimObject(p),
55  _enabled(true),
56  _value(0),
57  _increment(1),
58  _freqTable(p->freqs),
59  _activeFreqEntry(0),
60  _updateTick(0),
61  _freqUpdateEvent([this]{ freqUpdateCallback(); }, name()),
63 {
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);
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;
74 }
75 
76 void
78 {
79  fatal_if(!sys_cnt, "SystemCounter::validateCounterRef: No valid system "
80  "counter, can't instantiate system timers\n");
81 }
82 
83 void
85 {
86  DPRINTF(Timer, "SystemCounter::enable: Counter enabled\n");
87  _enabled = true;
88  updateTick();
89 }
90 
91 void
93 {
94  DPRINTF(Timer, "SystemCounter::disable: Counter disabled\n");
95  updateValue();
96  _enabled = false;
97 }
98 
99 uint64_t
101 {
102  if (_enabled)
103  updateValue();
104  return _value;
105 }
106 
107 void
109 {
110  uint64_t new_value =
112  if (new_value > _value) {
113  _value = new_value;
114  updateTick();
115  }
116 }
117 
118 void
119 SystemCounter::setValue(uint64_t new_value)
120 {
121  if (_enabled)
122  warn("Explicit value set with counter enabled, UNKNOWNN result\n");
123  _value = new_value;
124  updateTick();
125  notifyListeners();
126 }
127 
128 Tick
129 SystemCounter::whenValue(uint64_t cur_val, uint64_t target_val) const
130 {
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) {
138  when += rem_ticks;
139  num_cycles -= 1;
140  }
141  when += num_cycles * _period;
142  }
143  return when;
144 }
145 
146 Tick
147 SystemCounter::whenValue(uint64_t target_val)
148 {
149  return whenValue(value(), target_val);
150 }
151 
152 void
154 {
155  _updateTick = curTick() - (curTick() % _period);
156 }
157 
158 void
159 SystemCounter::freqUpdateSchedule(size_t new_freq_entry)
160 {
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
167  // high transitions
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);
172  }
173  }
174 }
175 
176 void
178 {
179  DPRINTF(Timer, "SystemCounter::freqUpdateCallback: Changing counter "
180  "frequency\n");
181  if (_enabled)
182  updateValue();
185  _increment = _freqTable[0] / _freq;
186  _period = (1.0 / _freq) * SimClock::Frequency;
187  notifyListeners();
188 }
189 
190 void
192 {
193  _listeners.push_back(listener);
194 }
195 
196 void
198 {
199  for (auto &listener : _listeners)
200  listener->notify();
201 }
202 
203 void
205 {
206  DPRINTF(Timer, "SystemCounter::serialize: Serializing\n");
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);
219  }
221 }
222 
223 void
225 {
226  DPRINTF(Timer, "SystemCounter::unserialize: Unserializing\n");
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);
240  }
242 
243  _period = (1.0 / _freq) * SimClock::Frequency;
244 }
245 
246 ArchTimer::ArchTimer(const std::string &name,
247  SimObject &parent,
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)
254 {
256 }
257 
258 void
260 {
261  if (!_control.enable)
262  return;
263 
264  DPRINTF(Timer, "Counter limit reached\n");
265  _control.istatus = 1;
266  if (!_control.imask) {
267  if (scheduleEvents()) {
268  DPRINTF(Timer, "Causing interrupt\n");
269  _interrupt->raise();
270  } else {
271  DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n");
272  }
273  }
274 }
275 
276 void
278 {
281  if (value() >= _counterLimit) {
283  } else {
284  _control.istatus = 0;
285  if (scheduleEvents()) {
288  }
289  }
290 }
291 
292 void
294 {
295  _counterLimit = val;
296  updateCounter();
297 }
298 
299 void
301 {
302  setCompareValue(value() + sext<32>(val));
303 }
304 
305 void
307 {
308  ArchTimerCtrl old_ctl = _control, new_ctl = val;
309  _control.enable = new_ctl.enable;
310  _control.imask = new_ctl.imask;
311  _control.istatus = old_ctl.istatus;
312  // Timer enabled
313  if (!old_ctl.enable && new_ctl.enable)
314  updateCounter();
315  // Timer disabled
316  else if (old_ctl.enable && !new_ctl.enable)
317  _control.istatus = 0;
318 }
319 
320 void
322 {
323  _offset = val;
324  updateCounter();
325 }
326 
327 uint64_t
329 {
330  return _systemCounter.value() - _offset;
331 }
332 
333 void
335 {
336  updateCounter();
337 }
338 
339 void
341 {
342  paramOut(cp, "control_serial", _control);
345 }
346 
347 void
349 {
350  paramIn(cp, "control_serial", _control);
351  // We didn't serialize an offset before we added support for the
352  // virtual timer. Consider it optional to maintain backwards
353  // compatibility.
355  _offset = 0;
356 
357  // We no longer schedule an event here because we may enter KVM
358  // emulation. The event creation is delayed until drainResume().
359 }
360 
363 {
366 
367  return DrainState::Drained;
368 }
369 
370 void
372 {
373  updateCounter();
374 }
375 
376 GenericTimer::GenericTimer(GenericTimerParams *const p)
377  : SimObject(p),
378  systemCounter(*p->counter),
379  system(*p->system)
380 {
382  fatal_if(!p->system, "GenericTimer::GenericTimer: No system specified, "
383  "can't instantiate architected timers\n");
384  system.setGenericTimer(this);
385 }
386 
387 const GenericTimerParams *
389 {
390  return dynamic_cast<const GenericTimerParams *>(_params);
391 }
392 
393 void
395 {
396  paramOut(cp, "cpu_count", timers.size());
397 
398  for (int i = 0; i < timers.size(); ++i) {
399  const CoreTimers &core(*timers[i]);
400  core.serializeSection(cp, csprintf("pe_implementation%d", i));
401  }
402 }
403 
404 void
406 {
407  // Try to unserialize the CPU count. Old versions of the timer
408  // model assumed a 8 CPUs, so we fall back to that if the field
409  // isn't present.
410  static const unsigned OLD_CPU_MAX = 8;
411  unsigned cpu_count;
412  if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
413  warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
414  OLD_CPU_MAX);
415  cpu_count = OLD_CPU_MAX;
416  }
417 
418  for (int i = 0; i < cpu_count; ++i) {
419  CoreTimers &core(getTimers(i));
420  core.unserializeSection(cp, csprintf("pe_implementation%d", i));
421  }
422 }
423 
426 {
427  if (cpu_id >= timers.size())
428  createTimers(cpu_id + 1);
429 
430  return *timers[cpu_id];
431 }
432 
433 void
435 {
436  assert(timers.size() < cpus);
437  auto p = static_cast<const GenericTimerParams *>(_params);
438 
439  const unsigned old_cpu_count(timers.size());
440  timers.resize(cpus);
441  for (unsigned i = old_cpu_count; i < cpus; ++i) {
442 
444 
445  timers[i].reset(
446  new CoreTimers(*this, system, i,
447  p->int_phys_s->get(tc),
448  p->int_phys_ns->get(tc),
449  p->int_virt->get(tc),
450  p->int_hyp->get(tc)));
451  }
452 }
453 
454 void
456  ArchTimer *timer, RegVal old_cnt_ctl, RegVal cnt_ctl)
457 {
458  uint64_t evnten = bits(cnt_ctl, 2);
459  uint64_t old_evnten = bits(old_cnt_ctl, 2);
460  uint8_t old_trans_to = ev_stream->transitionTo;
461  uint8_t old_trans_bit = ev_stream->transitionBit;
462  ev_stream->transitionTo = !bits(cnt_ctl, 3);
463  ev_stream->transitionBit = bits(cnt_ctl, 7, 4);
464  // Reschedule the Event Stream if enabled and any change in
465  // configuration
466  if (evnten && ((old_evnten != evnten) ||
467  (old_trans_to != ev_stream->transitionTo) ||
468  (old_trans_bit != ev_stream->transitionBit))) {
469 
470  Tick when = timer->whenValue(
471  ev_stream->eventTargetValue(timer->value()));
472  reschedule(ev_stream->event, when, true);
473  } else if (old_evnten && !evnten) {
474  // Event Stream generation disabled
475  if (ev_stream->event.scheduled())
476  deschedule(ev_stream->event);
477  }
478 }
479 
480 void
482 {
483  CoreTimers &core(getTimers(cpu));
485 
486  switch (reg) {
487  case MISCREG_CNTFRQ:
488  case MISCREG_CNTFRQ_EL0:
489  core.cntfrq = val;
490  warn_if(core.cntfrq != systemCounter.freq(), "CNTFRQ configured freq "
491  "does not match the system counter freq\n");
492  return;
493  case MISCREG_CNTKCTL:
494  case MISCREG_CNTKCTL_EL1:
495  {
496  if (ELIsInHost(tc, currEL(tc))) {
498  return;
499  }
500  RegVal old_cnt_ctl = core.cntkctl;
501  core.cntkctl = val;
502 
503  ArchTimer *timer = &core.virt;
504  CoreTimers::EventStream *ev_stream = &core.virtEvStream;
505 
506  handleStream(ev_stream, timer, old_cnt_ctl, val);
507  return;
508  }
509  case MISCREG_CNTHCTL:
510  case MISCREG_CNTHCTL_EL2:
511  {
512  RegVal old_cnt_ctl = core.cnthctl;
513  core.cnthctl = val;
514 
515  ArchTimer *timer = &core.physNS;
516  CoreTimers::EventStream *ev_stream = &core.physEvStream;
517 
518  handleStream(ev_stream, timer, old_cnt_ctl, val);
519  return;
520  }
521  // Physical timer (NS)
524  core.physNS.setCompareValue(val);
525  return;
526 
529  core.physNS.setTimerValue(val);
530  return;
531 
532  case MISCREG_CNTP_CTL_NS:
534  core.physNS.setControl(val);
535  return;
536 
537  // Count registers
538  case MISCREG_CNTPCT:
539  case MISCREG_CNTPCT_EL0:
540  case MISCREG_CNTVCT:
541  case MISCREG_CNTVCT_EL0:
542  warn("Ignoring write to read only count register: %s\n",
543  miscRegName[reg]);
544  return;
545 
546  // Virtual timer
547  case MISCREG_CNTVOFF:
548  case MISCREG_CNTVOFF_EL2:
549  core.virt.setOffset(val);
550  return;
551 
552  case MISCREG_CNTV_CVAL:
554  core.virt.setCompareValue(val);
555  return;
556 
557  case MISCREG_CNTV_TVAL:
559  core.virt.setTimerValue(val);
560  return;
561 
562  case MISCREG_CNTV_CTL:
564  core.virt.setControl(val);
565  return;
566 
567  // Physical timer (S)
568  case MISCREG_CNTP_CTL_S:
570  core.physS.setControl(val);
571  return;
572 
573  case MISCREG_CNTP_CVAL_S:
575  core.physS.setCompareValue(val);
576  return;
577 
578  case MISCREG_CNTP_TVAL_S:
580  core.physS.setTimerValue(val);
581  return;
582 
583  // Hyp phys. timer, non-secure
584  case MISCREG_CNTHP_CTL:
586  core.hyp.setControl(val);
587  return;
588 
589  case MISCREG_CNTHP_CVAL:
591  core.hyp.setCompareValue(val);
592  return;
593 
594  case MISCREG_CNTHP_TVAL:
596  core.hyp.setTimerValue(val);
597  return;
598 
599  default:
600  warn("Writing to unknown register: %s\n", miscRegName[reg]);
601  return;
602  }
603 }
604 
605 
606 RegVal
607 GenericTimer::readMiscReg(int reg, unsigned cpu)
608 {
609  CoreTimers &core(getTimers(cpu));
610 
611  switch (reg) {
612  case MISCREG_CNTFRQ:
613  case MISCREG_CNTFRQ_EL0:
614  return core.cntfrq;
615  case MISCREG_CNTKCTL:
616  case MISCREG_CNTKCTL_EL1:
617  return core.cntkctl & 0x00000000ffffffff;
618  case MISCREG_CNTHCTL:
619  case MISCREG_CNTHCTL_EL2:
620  return core.cnthctl & 0x00000000ffffffff;
621  // Physical timer
624  return core.physNS.compareValue();
625 
628  return core.physNS.timerValue();
629 
631  case MISCREG_CNTP_CTL_NS:
632  return core.physNS.control();
633 
634  case MISCREG_CNTPCT:
635  case MISCREG_CNTPCT_EL0:
636  return core.physNS.value();
637 
638 
639  // Virtual timer
640  case MISCREG_CNTVCT:
641  case MISCREG_CNTVCT_EL0:
642  return core.virt.value();
643 
644  case MISCREG_CNTVOFF:
645  case MISCREG_CNTVOFF_EL2:
646  return core.virt.offset();
647 
648  case MISCREG_CNTV_CVAL:
650  return core.virt.compareValue();
651 
652  case MISCREG_CNTV_TVAL:
654  return core.virt.timerValue();
655 
656  case MISCREG_CNTV_CTL:
658  return core.virt.control();
659 
660  // PL1 phys. timer, secure
661  case MISCREG_CNTP_CTL_S:
663  return core.physS.control();
664 
665  case MISCREG_CNTP_CVAL_S:
667  return core.physS.compareValue();
668 
669  case MISCREG_CNTP_TVAL_S:
671  return core.physS.timerValue();
672 
673  // HYP phys. timer (NS)
674  case MISCREG_CNTHP_CTL:
676  return core.hyp.control();
677 
678  case MISCREG_CNTHP_CVAL:
680  return core.hyp.compareValue();
681 
682  case MISCREG_CNTHP_TVAL:
684  return core.hyp.timerValue();
685 
686  default:
687  warn("Reading from unknown register: %s\n", miscRegName[reg]);
688  return 0;
689  }
690 }
691 
693  ArmSystem &system, unsigned cpu,
694  ArmInterruptPin *_irqPhysS, ArmInterruptPin *_irqPhysNS,
695  ArmInterruptPin *_irqVirt, ArmInterruptPin *_irqHyp)
696  : parent(_parent),
697  cntfrq(parent.params()->cntfrq),
698  threadContext(system.getThreadContext(cpu)),
699  irqPhysS(_irqPhysS),
700  irqPhysNS(_irqPhysNS),
701  irqVirt(_irqVirt),
702  irqHyp(_irqHyp),
703  physS(csprintf("%s.phys_s_timer%d", parent.name(), cpu),
704  system, parent, parent.systemCounter,
705  _irqPhysS),
706  // This should really be phys_timerN, but we are stuck with
707  // arch_timer for backwards compatibility.
708  physNS(csprintf("%s.arch_timer%d", parent.name(), cpu),
709  system, parent, parent.systemCounter,
710  _irqPhysNS),
711  virt(csprintf("%s.virt_timer%d", parent.name(), cpu),
712  system, parent, parent.systemCounter,
713  _irqVirt),
714  hyp(csprintf("%s.hyp_timer%d", parent.name(), cpu),
715  system, parent, parent.systemCounter,
716  _irqHyp),
717  physEvStream{
719  csprintf("%s.phys_event_gen%d", parent.name(), cpu)), 0, 0
720  },
721  virtEvStream{
723  csprintf("%s.virt_event_gen%d", parent.name(), cpu)), 0, 0
724  }
725 {
726 }
727 
728 void
730 {
733 }
734 
735 void
737 {
740 }
741 
742 void
744 {
747 }
748 
749 void
751  ArchTimer &timer)
752 {
753  parent.reschedule(ev_stream.event, timer.whenValue(
754  ev_stream.eventTargetValue(timer.value())), true);
755 }
756 
757 void
759 {
762 }
763 
764 void
766 {
770 
771  const bool phys_ev_scheduled = physEvStream.event.scheduled();
772  SERIALIZE_SCALAR(phys_ev_scheduled);
773  if (phys_ev_scheduled) {
774  const Tick phys_ev_when = physEvStream.event.when();
775  SERIALIZE_SCALAR(phys_ev_when);
776  }
779 
780  const bool virt_ev_scheduled = virtEvStream.event.scheduled();
781  SERIALIZE_SCALAR(virt_ev_scheduled);
782  if (virt_ev_scheduled) {
783  const Tick virt_ev_when = virtEvStream.event.when();
784  SERIALIZE_SCALAR(virt_ev_when);
785  }
788 
789  physS.serializeSection(cp, "phys_s_timer");
790  physNS.serializeSection(cp, "phys_ns_timer");
791  virt.serializeSection(cp, "virt_timer");
792  hyp.serializeSection(cp, "hyp_timer");
793 }
794 
795 void
797 {
801 
802  bool phys_ev_scheduled;
803  UNSERIALIZE_SCALAR(phys_ev_scheduled);
804  if (phys_ev_scheduled) {
805  Tick phys_ev_when;
806  UNSERIALIZE_SCALAR(phys_ev_when);
807  parent.reschedule(physEvStream.event, phys_ev_when, true);
808  }
811 
812  bool virt_ev_scheduled;
813  UNSERIALIZE_SCALAR(virt_ev_scheduled);
814  if (virt_ev_scheduled) {
815  Tick virt_ev_when;
816  UNSERIALIZE_SCALAR(virt_ev_when);
817  parent.reschedule(virtEvStream.event, virt_ev_when, true);
818  }
821 
822  physS.unserializeSection(cp, "phys_s_timer");
823  physNS.unserializeSection(cp, "phys_ns_timer");
824  virt.unserializeSection(cp, "virt_timer");
825  hyp.unserializeSection(cp, "hyp_timer");
826 }
827 
828 void
830 {
831  DPRINTF(Timer, "Setting %s := 0x%x\n", miscRegName[reg], val);
832  parent.setMiscReg(reg, cpu, val);
833 }
834 
835 RegVal
837 {
838  RegVal value = parent.readMiscReg(reg, cpu);
839  DPRINTF(Timer, "Reading %s as 0x%x\n", miscRegName[reg], value);
840  return value;
841 }
842 
843 GenericTimerFrame::GenericTimerFrame(GenericTimerFrameParams *const p)
844  : PioDevice(p),
845  timerRange(RangeSize(p->cnt_base, sys->getPageBytes())),
846  addrRanges({timerRange}),
847  systemCounter(*p->counter),
848  physTimer(csprintf("%s.phys_timer", name()),
849  *this, systemCounter, p->int_phys->get()),
850  virtTimer(csprintf("%s.virt_timer", name()),
851  *this, systemCounter,
852  p->int_virt->get()),
853  accessBits(0x3f),
854  system(*dynamic_cast<ArmSystem *>(sys))
855 {
857  // Expose optional CNTEL0Base register frame
858  if (p->cnt_el0_base != MaxAddr) {
859  timerEl0Range = RangeSize(p->cnt_el0_base, sys->getPageBytes());
860  accessBitsEl0 = 0x303;
861  addrRanges.push_back(timerEl0Range);
862  }
863  for (auto &range : addrRanges)
865 }
866 
867 void
869 {
870  SERIALIZE_SCALAR(accessBits);
871  if (hasEl0View())
872  SERIALIZE_SCALAR(accessBitsEl0);
874 
875  physTimer.serializeSection(cp, "phys_timer");
876  virtTimer.serializeSection(cp, "virt_timer");
877 }
878 
879 void
881 {
882  UNSERIALIZE_SCALAR(accessBits);
883  if (hasEl0View())
884  UNSERIALIZE_SCALAR(accessBitsEl0);
886 
887  physTimer.unserializeSection(cp, "phys_timer");
888  virtTimer.unserializeSection(cp, "virt_timer");
889 }
890 
891 uint64_t
893 {
894  return virtTimer.offset();
895 }
896 
897 void
899 {
900  virtTimer.setOffset(new_offset);
901 }
902 
903 bool
905 {
906  return timerEl0Range.valid();
907 }
908 
909 uint8_t
911 {
912  return accessBits;
913 }
914 
915 void
917 {
918  accessBits = data & 0x3f;
919 }
920 
921 bool
923 {
924  return nonSecureAccess;
925 }
926 
927 void
929 {
930  nonSecureAccess = true;
931 }
932 
933 bool
935 {
936  return accessBits.rvoff;
937 }
938 
941 {
942  return addrRanges;
943 }
944 
945 Tick
947 {
948  const Addr addr = pkt->getAddr();
949  const size_t size = pkt->getSize();
950  const bool is_sec = pkt->isSecure();
951  panic_if(size != 4 && size != 8,
952  "GenericTimerFrame::read: Invalid size %i\n", size);
953 
954  bool to_el0 = false;
955  uint64_t resp = 0;
956  Addr offset = 0;
957  if (timerRange.contains(addr)) {
958  offset = addr - timerRange.start();
959  } else if (hasEl0View() && timerEl0Range.contains(addr)) {
960  offset = addr - timerEl0Range.start();
961  to_el0 = true;
962  } else {
963  panic("GenericTimerFrame::read: Invalid address: 0x%x\n", addr);
964  }
965 
966  resp = timerRead(offset, size, is_sec, to_el0);
967 
968  DPRINTF(Timer, "GenericTimerFrame::read: 0x%x<-0x%x(%i) [S = %u]\n", resp,
969  addr, size, is_sec);
970 
971  pkt->setUintX(resp, LittleEndianByteOrder);
972  pkt->makeResponse();
973  return 0;
974 }
975 
976 Tick
978 {
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::write: Invalid size %i\n", size);
984 
985  bool to_el0 = false;
986  const uint64_t data = pkt->getUintX(LittleEndianByteOrder);
987  Addr offset = 0;
988  if (timerRange.contains(addr)) {
989  offset = addr - timerRange.start();
990  } else if (hasEl0View() && timerEl0Range.contains(addr)) {
991  offset = addr - timerEl0Range.start();
992  to_el0 = true;
993  } else {
994  panic("GenericTimerFrame::write: Invalid address: 0x%x\n", addr);
995  }
996 
997  timerWrite(offset, size, data, is_sec, to_el0);
998 
999  DPRINTF(Timer, "GenericTimerFrame::write: 0x%x->0x%x(%i) [S = %u]\n", data,
1000  addr, size, is_sec);
1001 
1002  pkt->makeResponse();
1003  return 0;
1004 }
1005 
1006 uint64_t
1007 GenericTimerFrame::timerRead(Addr addr, size_t size, bool is_sec,
1008  bool to_el0) const
1009 {
1011  !nonSecureAccess)
1012  return 0;
1013 
1014  switch (addr) {
1015  case TIMER_CNTPCT_LO:
1016  if (!accessBits.rpct || (to_el0 && !accessBitsEl0.pcten))
1017  return 0;
1018  else
1019  return physTimer.value();
1020 
1021  case TIMER_CNTPCT_HI:
1022  if (!accessBits.rpct || (to_el0 && !accessBitsEl0.pcten))
1023  return 0;
1024  else
1025  return physTimer.value() >> 32;
1026 
1027  case TIMER_CNTFRQ:
1028  if ((!accessBits.rfrq) ||
1029  (to_el0 && (!accessBitsEl0.pcten && !accessBitsEl0.vcten)))
1030  return 0;
1031  else
1032  return systemCounter.freq();
1033 
1034  case TIMER_CNTEL0ACR:
1035  if (!hasEl0View() || to_el0)
1036  return 0;
1037  else
1038  return accessBitsEl0;
1039 
1040  case TIMER_CNTP_CVAL_LO:
1041  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1042  return 0;
1043  else
1044  return physTimer.compareValue();
1045 
1046  case TIMER_CNTP_CVAL_HI:
1047  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1048  return 0;
1049  else
1050  return physTimer.compareValue() >> 32;
1051 
1052  case TIMER_CNTP_TVAL:
1053  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1054  return 0;
1055  else
1056  return physTimer.timerValue();
1057  case TIMER_CNTP_CTL:
1058  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1059  return 0;
1060  else
1061  return physTimer.control();
1062 
1063  case TIMER_CNTVCT_LO:
1064  if (!accessBits.rvct || (to_el0 && !accessBitsEl0.vcten))
1065  return 0;
1066  else
1067  return virtTimer.value();
1068 
1069  case TIMER_CNTVCT_HI:
1070  if (!accessBits.rvct || (to_el0 && !accessBitsEl0.vcten))
1071  return 0;
1072  else
1073  return virtTimer.value() >> 32;
1074 
1075  case TIMER_CNTVOFF_LO:
1076  if (!accessBits.rvoff || (to_el0))
1077  return 0;
1078  else
1079  return virtTimer.offset();
1080 
1081  case TIMER_CNTVOFF_HI:
1082  if (!accessBits.rvoff || (to_el0))
1083  return 0;
1084  else
1085  return virtTimer.offset() >> 32;
1086 
1087  case TIMER_CNTV_CVAL_LO:
1088  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1089  return 0;
1090  else
1091  return virtTimer.compareValue();
1092 
1093  case TIMER_CNTV_CVAL_HI:
1094  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1095  return 0;
1096  else
1097  return virtTimer.compareValue() >> 32;
1098 
1099  case TIMER_CNTV_TVAL:
1100  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1101  return 0;
1102  else
1103  return virtTimer.timerValue();
1104 
1105  case TIMER_CNTV_CTL:
1106  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1107  return 0;
1108  else
1109  return virtTimer.control();
1110 
1111  default:
1112  warn("GenericTimerFrame::timerRead: Unexpected address (0x%x:%i), "
1113  "assuming RAZ\n", addr, size);
1114  return 0;
1115  }
1116 }
1117 
1118 void
1120  bool is_sec, bool to_el0)
1121 {
1123  !nonSecureAccess)
1124  return;
1125 
1126  switch (addr) {
1128  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTPCT]\n",
1129  addr);
1130  return;
1131 
1132  case TIMER_CNTFRQ:
1133  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTFRQ]\n",
1134  addr);
1135  return;
1136 
1137  case TIMER_CNTEL0ACR:
1138  if (!hasEl0View() || to_el0)
1139  return;
1140 
1141  insertBits(accessBitsEl0, 9, 8, data);
1142  insertBits(accessBitsEl0, 1, 0, data);
1143  return;
1144 
1145  case TIMER_CNTP_CVAL_LO:
1146  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1147  return;
1148  data = size == 4 ? insertBits(physTimer.compareValue(),
1149  31, 0, data) : data;
1150  physTimer.setCompareValue(data);
1151  return;
1152 
1153  case TIMER_CNTP_CVAL_HI:
1154  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1155  return;
1156  data = insertBits(physTimer.compareValue(), 63, 32, data);
1157  physTimer.setCompareValue(data);
1158  return;
1159 
1160  case TIMER_CNTP_TVAL:
1161  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1162  return;
1163  physTimer.setTimerValue(data);
1164  return;
1165 
1166  case TIMER_CNTP_CTL:
1167  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1168  return;
1169  physTimer.setControl(data);
1170  return;
1171 
1173  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVCT]\n",
1174  addr);
1175  return;
1177  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVOFF]\n",
1178  addr);
1179  return;
1180 
1181  case TIMER_CNTV_CVAL_LO:
1182  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1183  return;
1184  data = size == 4 ? insertBits(virtTimer.compareValue(),
1185  31, 0, data) : data;
1186  virtTimer.setCompareValue(data);
1187  return;
1188 
1189  case TIMER_CNTV_CVAL_HI:
1190  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1191  return;
1192  data = insertBits(virtTimer.compareValue(), 63, 32, data);
1193  virtTimer.setCompareValue(data);
1194  return;
1195 
1196  case TIMER_CNTV_TVAL:
1197  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1198  return;
1199  virtTimer.setTimerValue(data);
1200  return;
1201 
1202  case TIMER_CNTV_CTL:
1203  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1204  return;
1205  virtTimer.setControl(data);
1206  return;
1207 
1208  default:
1209  warn("GenericTimerFrame::timerWrite: Unexpected address (0x%x:%i), "
1210  "assuming WI\n", addr, size);
1211  }
1212 }
1213 
1214 GenericTimerMem::GenericTimerMem(GenericTimerMemParams *const p)
1215  : PioDevice(p),
1216  counterCtrlRange(RangeSize(p->cnt_control_base, sys->getPageBytes())),
1217  counterStatusRange(RangeSize(p->cnt_read_base, sys->getPageBytes())),
1218  timerCtrlRange(RangeSize(p->cnt_ctl_base, sys->getPageBytes())),
1219  cnttidr(0x0),
1221  systemCounter(*p->counter),
1222  frames(p->frames),
1223  system(*dynamic_cast<ArmSystem *>(sys))
1224 {
1226  for (auto &range : addrRanges)
1228  fatal_if(frames.size() > MAX_TIMER_FRAMES,
1229  "GenericTimerMem::GenericTimerMem: Architecture states a maximum of "
1230  "8 memory-mapped timer frames, limit surpassed\n");
1231  // Initialize CNTTIDR with each frame's features
1232  for (int i = 0; i < frames.size(); i++) {
1233  uint32_t features = 0x1;
1234  features |= 0x2;
1235  if (frames[i]->hasEl0View())
1236  features |= 0x4;
1237  features <<= i * 4;
1238  replaceBits(cnttidr, (i + 1) * 4 - 1, i * 4, features);
1239  }
1240 }
1241 
1242 void
1244 {
1245  fatal_if(range.start() % TheISA::PageBytes,
1246  "GenericTimerMem::validateFrameRange: Architecture states each "
1247  "register frame should be in a separate memory page, specified "
1248  "range base address [0x%x] is not compliant\n");
1249 }
1250 
1251 bool
1253 {
1254  return !sys.haveSecurity() || is_sec;
1255 }
1256 
1259 {
1260  return addrRanges;
1261 }
1262 
1263 Tick
1265 {
1266  const Addr addr = pkt->getAddr();
1267  const size_t size = pkt->getSize();
1268  const bool is_sec = pkt->isSecure();
1269  panic_if(size != 4 && size != 8,
1270  "GenericTimerMem::read: Invalid size %i\n", size);
1271 
1272  uint64_t resp = 0;
1273  if (counterCtrlRange.contains(addr))
1274  resp = counterCtrlRead(addr - counterCtrlRange.start(), size, is_sec);
1275  else if (counterStatusRange.contains(addr))
1276  resp = counterStatusRead(addr - counterStatusRange.start(), size);
1277  else if (timerCtrlRange.contains(addr))
1278  resp = timerCtrlRead(addr - timerCtrlRange.start(), size, is_sec);
1279  else
1280  panic("GenericTimerMem::read: Invalid address: 0x%x\n", addr);
1281 
1282  DPRINTF(Timer, "GenericTimerMem::read: 0x%x<-0x%x(%i) [S = %u]\n", resp,
1283  addr, size, is_sec);
1284 
1285  pkt->setUintX(resp, LittleEndianByteOrder);
1286  pkt->makeResponse();
1287  return 0;
1288 }
1289 
1290 Tick
1292 {
1293  const Addr addr = pkt->getAddr();
1294  const size_t size = pkt->getSize();
1295  const bool is_sec = pkt->isSecure();
1296  panic_if(size != 4 && size != 8,
1297  "GenericTimerMem::write: Invalid size %i\n", size);
1298 
1299  const uint64_t data = pkt->getUintX(LittleEndianByteOrder);
1300  if (counterCtrlRange.contains(addr))
1301  counterCtrlWrite(addr - counterCtrlRange.start(), size, data, is_sec);
1302  else if (counterStatusRange.contains(addr))
1304  else if (timerCtrlRange.contains(addr))
1305  timerCtrlWrite(addr - timerCtrlRange.start(), size, data, is_sec);
1306  else
1307  panic("GenericTimerMem::write: Invalid address: 0x%x\n", addr);
1308 
1309  DPRINTF(Timer, "GenericTimerMem::write: 0x%x->0x%x(%i) [S = %u]\n", data,
1310  addr, size, is_sec);
1311 
1312  pkt->makeResponse();
1313  return 0;
1314 }
1315 
1316 uint64_t
1317 GenericTimerMem::counterCtrlRead(Addr addr, size_t size, bool is_sec) const
1318 {
1320  return 0;
1321  switch (addr) {
1322  case COUNTER_CTRL_CNTCR:
1323  {
1324  CNTCR cntcr = 0;
1325  cntcr.en = systemCounter.enabled();
1326  cntcr.fcreq = systemCounter.activeFreqEntry();
1327  return cntcr;
1328  }
1329  case COUNTER_CTRL_CNTSR:
1330  {
1331  CNTSR cntsr = 0;
1332  cntsr.fcack = systemCounter.activeFreqEntry();
1333  return cntsr;
1334  }
1335  case COUNTER_CTRL_CNTCV_LO: return systemCounter.value();
1336  case COUNTER_CTRL_CNTCV_HI: return systemCounter.value() >> 32;
1337  case COUNTER_CTRL_CNTSCR: return 0;
1338  case COUNTER_CTRL_CNTID: return 0;
1339  default:
1340  {
1341  auto &freq_table = systemCounter.freqTable();
1342  for (int i = 0; i < (freq_table.size() - 1); i++) {
1343  Addr offset = COUNTER_CTRL_CNTFID + (i * 0x4);
1344  if (addr == offset)
1345  return freq_table[i];
1346  }
1347  warn("GenericTimerMem::counterCtrlRead: Unexpected address "
1348  "(0x%x:%i), assuming RAZ\n", addr, size);
1349  return 0;
1350  }
1351  }
1352 }
1353 
1354 void
1356  bool is_sec)
1357 {
1359  return;
1360 
1361  switch (addr) {
1362  case COUNTER_CTRL_CNTCR:
1363  {
1364  CNTCR val = data;
1365  if (!systemCounter.enabled() && val.en)
1367  else if (systemCounter.enabled() && !val.en)
1369 
1370  if (val.hdbg)
1371  warn("GenericTimerMem::counterCtrlWrite: Halt-on-debug is not "
1372  "supported\n");
1373  if (val.scen)
1374  warn("GenericTimerMem::counterCtrlWrite: Counter Scaling is not "
1375  "supported\n");
1376  if (val.fcreq != systemCounter.activeFreqEntry())
1377  systemCounter.freqUpdateSchedule(val.fcreq);
1378  return;
1379  }
1380 
1381  case COUNTER_CTRL_CNTSR:
1382  warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTSR]\n",
1383  addr);
1384  return;
1385 
1386  case COUNTER_CTRL_CNTCV_LO:
1387  data = size == 4 ? insertBits(systemCounter.value(), 31, 0, data)
1388  : data;
1389  systemCounter.setValue(data);
1390  return;
1391 
1392  case COUNTER_CTRL_CNTCV_HI:
1393  data = insertBits(systemCounter.value(), 63, 32, data);
1394  systemCounter.setValue(data);
1395  return;
1396 
1397  case COUNTER_CTRL_CNTSCR:
1398  return;
1399 
1400  case COUNTER_CTRL_CNTID:
1401  warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTID]\n",
1402  addr);
1403  return;
1404 
1405  default:
1406  {
1407  auto &freq_table = systemCounter.freqTable();
1408  for (int i = 0; i < (freq_table.size() - 1); i++) {
1409  Addr offset = COUNTER_CTRL_CNTFID + (i * 0x4);
1410  if (addr == offset) {
1411  freq_table[i] = data;
1412  // This is changing the currently selected frequency
1413  if (i == systemCounter.activeFreqEntry()) {
1414  // We've changed the frequency in the table entry,
1415  // however the counter will still work with the
1416  // current one until transition is completed
1418  }
1419  return;
1420  }
1421  }
1422  warn("GenericTimerMem::counterCtrlWrite: Unexpected address "
1423  "(0x%x:%i), assuming WI\n", addr, size);
1424  }
1425  }
1426 }
1427 
1428 uint64_t
1430 {
1431  switch (addr) {
1433  case COUNTER_STATUS_CNTCV_HI: return systemCounter.value() >> 32;
1434  default:
1435  warn("GenericTimerMem::counterStatusRead: Unexpected address "
1436  "(0x%x:%i), assuming RAZ\n", addr, size);
1437  return 0;
1438  }
1439 }
1440 
1441 void
1443 {
1444  switch (addr) {
1446  warn("GenericTimerMem::counterStatusWrite: RO reg (0x%x) [CNTCV]\n",
1447  addr);
1448  return;
1449  default:
1450  warn("GenericTimerMem::counterStatusWrite: Unexpected address "
1451  "(0x%x:%i), assuming WI\n", addr, size);
1452  }
1453 }
1454 
1455 uint64_t
1456 GenericTimerMem::timerCtrlRead(Addr addr, size_t size, bool is_sec) const
1457 {
1458  switch (addr) {
1459  case TIMER_CTRL_CNTFRQ:
1460  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return 0;
1461  return systemCounter.freq();
1462  case TIMER_CTRL_CNTNSAR:
1463  {
1464  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return 0;
1465  uint32_t cntnsar = 0x0;
1466  for (int i = 0; i < frames.size(); i++) {
1467  if (frames[i]->hasNonSecureAccess())
1468  cntnsar |= 0x1 << i;
1469  }
1470  return cntnsar;
1471  }
1472  case TIMER_CTRL_CNTTIDR: return cnttidr;
1473  default:
1474  for (int i = 0; i < frames.size(); i++) {
1475  Addr cntacr_off = TIMER_CTRL_CNTACR + (i * 0x4);
1476  Addr cntvoff_lo_off = TIMER_CTRL_CNTVOFF_LO + (i * 0x4);
1477  Addr cntvoff_hi_off = TIMER_CTRL_CNTVOFF_HI + (i * 0x4);
1478  // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1479  // normal world
1480  bool hit = addr == cntacr_off || addr == cntvoff_lo_off ||
1481  addr == cntvoff_hi_off;
1482  bool has_access =
1484  frames[i]->hasNonSecureAccess();
1485  if (hit && !has_access) return 0;
1486  if (addr == cntacr_off)
1487  return frames[i]->getAccessBits();
1488  if (addr == cntvoff_lo_off || addr == cntvoff_hi_off) {
1489  return addr == cntvoff_lo_off ? frames[i]->getVirtOffset()
1490  : frames[i]->getVirtOffset() >> 32;
1491  }
1492  }
1493  warn("GenericTimerMem::timerCtrlRead: Unexpected address (0x%x:%i), "
1494  "assuming RAZ\n", addr, size);
1495  return 0;
1496  }
1497 }
1498 
1499 void
1501  bool is_sec)
1502 {
1503  switch (addr) {
1504  case TIMER_CTRL_CNTFRQ:
1505  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return;
1506  warn_if(data != systemCounter.freq(),
1507  "GenericTimerMem::timerCtrlWrite: CNTFRQ configured freq "
1508  "does not match the counter freq, ignoring\n");
1509  return;
1510  case TIMER_CTRL_CNTNSAR:
1511  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return;
1512  for (int i = 0; i < frames.size(); i++) {
1513  // Check if the CNTNSAR.NS bit is set for this frame
1514  if (data & (0x1 << i))
1515  frames[i]->setNonSecureAccess();
1516  }
1517  return;
1518  case TIMER_CTRL_CNTTIDR:
1519  warn("GenericTimerMem::timerCtrlWrite: RO reg (0x%x) [CNTTIDR]\n",
1520  addr);
1521  return;
1522  default:
1523  for (int i = 0; i < frames.size(); i++) {
1524  Addr cntacr_off = TIMER_CTRL_CNTACR + (i * 0x4);
1525  Addr cntvoff_lo_off = TIMER_CTRL_CNTVOFF_LO + (i * 0x4);
1526  Addr cntvoff_hi_off = TIMER_CTRL_CNTVOFF_HI + (i * 0x4);
1527  // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1528  // normal world
1529  bool hit = addr == cntacr_off || addr == cntvoff_lo_off ||
1530  addr == cntvoff_hi_off;
1531  bool has_access =
1533  frames[i]->hasNonSecureAccess();
1534  if (hit && !has_access) return;
1535  if (addr == cntacr_off) {
1536  frames[i]->setAccessBits(data);
1537  return;
1538  }
1539  if (addr == cntvoff_lo_off || addr == cntvoff_hi_off) {
1540  if (addr == cntvoff_lo_off)
1541  data = size == 4 ? insertBits(frames[i]->getVirtOffset(),
1542  31, 0, data) : data;
1543  else
1544  data = insertBits(frames[i]->getVirtOffset(),
1545  63, 32, data);
1546  frames[i]->setVirtOffset(data);
1547  return;
1548  }
1549  }
1550  warn("GenericTimerMem::timerCtrlWrite: Unexpected address "
1551  "(0x%x:%i), assuming WI\n", addr, size);
1552  }
1553 }
1554 
1555 SystemCounter *
1556 SystemCounterParams::create()
1557 {
1558  return new SystemCounter(this);
1559 }
1560 
1561 GenericTimer *
1562 GenericTimerParams::create()
1563 {
1564  return new GenericTimer(this);
1565 }
1566 
1568 GenericTimerFrameParams::create()
1569 {
1570  return new GenericTimerFrame(this);
1571 }
1572 
1574 GenericTimerMemParams::create()
1575 {
1576  return new GenericTimerMem(this);
1577 }
void unserialize(CheckpointIn &cp) override
Unserialize an object.
ArchTimer(const std::string &name, SimObject &parent, SystemCounter &sysctr, ArmInterruptPin *interrupt)
void setMiscReg(int misc_reg, RegVal val) override
Write to a system register belonging to this device.
const AddrRange counterCtrlRange
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:163
#define DPRINTF(x,...)
Definition: trace.hh:222
EventFunctionWrapper _counterLimitReachedEvent
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:580
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_CTRL_CNTACR
uint64_t offset() const
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:351
uint64_t _counterLimit
Programmed limit value for the upcounter ({CNTP/CNTHP/CNTV}_CVAL).
std::vector< uint32_t > _freqTable
Frequency modes table with all possible frequencies for the counter.
void setMiscReg(int misc_reg, unsigned cpu, RegVal val)
std::vector< SystemCounterListener * > _listeners
Listeners to changes in counting speed.
static const Addr TIMER_CNTV_CVAL_LO
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
static const Addr TIMER_CNTPCT_HI
Bitfield< 5, 3 > reg
Definition: types.hh:87
#define UNSERIALIZE_CONTAINER(member)
Definition: serialize.hh:829
static const Addr COUNTER_CTRL_CNTSR
void counterStatusWrite(Addr addr, size_t size, uint64_t data)
std::vector< GenericTimerFrame * > frames
Timer frame references.
Tick _updateTick
Counter cycle start Tick when the counter status affecting its value has been updated.
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
static const Addr TIMER_CNTEL0ACR
CoreTimers & getTimers(int cpu_id)
static const Addr TIMER_CNTP_TVAL
const Addr MaxAddr
Definition: types.hh:164
Bitfield< 7 > i
This module implements the global system counter and the local per-CPU architected timers as specifie...
static const Addr COUNTER_STATUS_CNTCV_HI
static const Addr COUNTER_STATUS_CNTCV_LO
bool haveSecurity() const
Returns true if this system implements the Security Extensions.
Definition: system.hh:150
bool hasReadableVoff() const
Indicates if CNTVOFF is readable for this frame.
void setVirtOffset(uint64_t new_offset)
Sets the virtual offset for this frame&#39;s virtual timer after a write to CNTVOFF.
SystemCounter & systemCounter
System counter reference.
CNTKCTL cntkctl
Kernel control register.
static const Addr TIMER_CTRL_CNTVOFF_HI
DrainState drain() override
Notify an object that it needs to drain its state.
Per-CPU architected timer.
RegVal readMiscReg(int misc_reg, unsigned cpu)
bool hasEl0View() const
Indicates if this frame implements a second EL0 view.
uint64_t counterCtrlRead(Addr addr, size_t size, bool is_sec) const
CNTControlBase (System counter control frame)
void notifyListeners(void) const
Notifies counting speed changes to listeners.
void freqUpdateCallback()
Callback for the frequency update.
bool contains(const Addr &a) const
Determine if the range contains an address.
Definition: addr_range.hh:402
ThreadContext * threadContext
Thread (HW) context associated to this PE implementation.
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
void notify(void) override
Called from the SystemCounter when a change in counting speed occurred Events should be rescheduled p...
void updateTick(void)
Updates the update tick, normalizes to the lower cycle start tick.
static const Addr TIMER_CNTPCT_LO
ip6_addr_t addr
Definition: inet.hh:330
void timerWrite(Addr addr, size_t size, uint64_t data, bool is_sec, bool to_el0)
uint64_t RegVal
Definition: types.hh:166
size_t _nextFreqEntry
uint64_t value() const
Returns the value of the counter which this timer relies on.
uint32_t cntfrq
System counter frequency as visible from this core.
const AddrRange timerRange
uint32_t freq() const
Returns the counter frequency.
Bitfield< 23, 0 > offset
Definition: types.hh:152
void unserialize(CheckpointIn &cp) override
Unserialize an object.
virtual BaseCPU * getCpuPtr()=0
const AddrRangeList addrRanges
All MMIO ranges GenericTimerMem responds to.
SystemCounter & systemCounter
System counter reference.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void registerListener(SystemCounterListener *listener)
Called from System Counter Listeners to register.
bool _enabled
Definition: statistics.cc:542
const char *const miscRegName[]
Definition: miscregs.hh:1033
Definition: cprintf.cc:40
static const Addr COUNTER_CTRL_CNTID
Tick Frequency
The simulated frequency of curTick(). (In ticks per second)
Definition: core.cc:46
ThreadContext is the external interface to all thread state for anything outside of the CPU...
void handleStream(CoreTimers::EventStream *ev_stream, ArchTimer *timer, RegVal old_cnt_ctl, RegVal cnt_ctl)
static ExceptionLevel currEL(const ThreadContext *tc)
Definition: utility.hh:141
static bool validateAccessPerm(ArmSystem &sys, bool is_sec)
Validates an MMIO access permissions.
ArmSystem & system
ARM system containing this timer.
DrainState
Object drain/handover states.
Definition: drain.hh:71
static const Addr COUNTER_CTRL_CNTCV_LO
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:171
void setTimerValue(uint32_t val)
Sets the TimerValue view of the timer.
static const Addr TIMER_CNTP_CTL
const GenericTimerParams * params() const
static const Addr TIMER_CNTV_TVAL
void setGenericTimer(GenericTimer *generic_timer)
Sets the pointer to the Generic Timer.
Definition: system.hh:168
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:334
Bitfield< 63 > val
Definition: misc.hh:769
ArchTimerCtrl _control
Value of the control register ({CNTP/CNTHP/CNTV}_CTL).
ThreadContext * getThreadContext(ContextID tid) const
Definition: system.hh:186
bool valid() const
Determine if the range is valid.
Definition: addr_range.hh:288
bool enabled() const
Indicates if the counter is enabled.
void counterLimitReached()
Called when the upcounter reaches the programmed value.
uint64_t timerRead(Addr addr, size_t size, bool is_sec, bool to_el0) const
CNTBase/CNTEL0Base (Memory-mapped timer frame)
Tick _period
Cached copy of the counter period (inverse of the frequency).
unsigned getSize() const
Definition: packet.hh:730
CoreTimers(GenericTimer &_parent, ArmSystem &system, unsigned cpu, ArmInterruptPin *_irqPhysS, ArmInterruptPin *_irqPhysNS, ArmInterruptPin *_irqVirt, ArmInterruptPin *_irqHyp)
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition: addr_range.hh:68
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:770
void setValue(uint64_t new_value)
Sets the value explicitly from writes to CNTCR.CNTCV.
void setOffset(uint64_t val)
Draining buffers pending serialization/handover.
static constexpr size_t MAX_TIMER_FRAMES
Maximum architectural number of memory-mapped timer frames.
Tick curTick()
The current simulated tick.
Definition: core.hh:44
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:158
static const Addr TIMER_CNTP_CVAL_LO
EventFunctionWrapper _freqUpdateEvent
Frequency update event handling.
uint64_t eventTargetValue(uint64_t val) const
void serialize(CheckpointOut &cp) const override
Serialize an object.
static const Addr COUNTER_CTRL_CNTCV_HI
uint64_t Tick
Tick count type.
Definition: types.hh:61
ArmSystem & system
void createTimers(unsigned cpus)
AddrRangeList addrRanges
All MMIO ranges GenericTimerFrame responds to.
void serialize(CheckpointOut &cp) const override
Serialize an object.
uint32_t cnttidr
ID register for reporting features of implemented timer frames.
const AddrRange counterStatusRange
static const Addr TIMER_CNTP_CVAL_HI
void paramOut(CheckpointOut &cp, const string &name, ExtMachInst const &machInst)
Definition: types.cc:38
#define UNSERIALIZE_OPT_SCALAR(scalar)
Definition: serialize.hh:777
void setCompareValue(uint64_t val)
Sets the CompareValue view of the timer.
void replaceBits(T &val, int first, int last, B bit_val)
A convenience function to replace bits first to last of val with bit_val in place.
Definition: bitfield.hh:156
size_t activeFreqEntry() const
Returns the currently active frequency table entry.
void counterCtrlWrite(Addr addr, size_t size, uint64_t data, bool is_sec)
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition: logging.hh:224
static constexpr size_t MAX_FREQ_ENTRIES
Maximum architectural number of frequency table entries.
Bitfield< 2 > evnten
void deschedule(Event &event)
Definition: eventq.hh:1007
uint64_t value()
Updates and returns the counter value.
Addr getAddr() const
Definition: packet.hh:720
void disable()
Disables the counter after a CNTCR.EN == 0.
uint32_t timerValue() const
Returns the TimerValue view of the timer.
SystemCounter & systemCounter
System counter reference.
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:199
static const Addr COUNTER_CTRL_CNTFID
static const Addr TIMER_CNTV_CVAL_HI
void schedule(Event &event, Tick when)
Definition: eventq.hh:998
T insertBits(T val, int first, int last, B bit_val)
Returns val with bits first to last set to the LSBs of bit_val.
Definition: bitfield.hh:131
static const Addr TIMER_CTRL_CNTFRQ
This device is the base class which all devices senstive to an address range inherit from...
Definition: io_device.hh:99
static const Addr TIMER_CNTFRQ
ArmSystem & system
static const Addr COUNTER_CTRL_CNTSCR
uint64_t timerCtrlRead(Addr addr, size_t size, bool is_sec) const
CNTCTLBase (Memory-mapped timer global control frame)
static void wakeup(ThreadID tid)
Definition: cpu_dummy.hh:48
static const Addr TIMER_CNTVOFF_HI
void serialize(CheckpointOut &cp) const override
Serialize an object.
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:1016
AddrRange timerEl0Range
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:140
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
bool nonSecureAccess
Reports whether non-secure accesses are allowed to this frame.
System * sys
Definition: io_device.hh:102
virtual bool scheduleEvents()
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:249
void enable()
Enables the counter after a CNTCR.EN == 1.
RegVal readMiscReg(int misc_reg) override
Read a system register belonging to this device.
void notify(void) override
Called from the SystemCounter when a change in counting speed occurred Events should be rescheduled p...
SystemCounter(SystemCounterParams *const p)
Tick whenValue(uint64_t target_val)
static const Addr TIMER_CNTVCT_HI
Bitfield< 15 > system
Definition: misc.hh:997
static const Addr TIMER_CNTVCT_LO
void sendEvent(ThreadContext *tc)
Send an event (SEV) to a specific PE if there isn&#39;t already a pending event.
Definition: utility.cc:165
Abstract class for elements whose events depend on the counting speed of the System Counter...
AddrRangeList getAddrRanges() const override
Every PIO device is obliged to provide an implementation that returns the address ranges the device r...
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:763
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:460
GenericTimer(GenericTimerParams *const p)
static const Addr TIMER_CTRL_CNTVOFF_LO
static const Addr TIMER_CTRL_CNTNSAR
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:931
virtual const std::string name() const
Definition: sim_object.hh:128
std::string name() const
Returns the timer name.
static const Addr TIMER_CNTVOFF_LO
Base class for ARM GIC implementations.
#define SERIALIZE_CONTAINER(member)
Definition: serialize.hh:821
virtual void raise()=0
Signal an interrupt.
std::ostream CheckpointOut
Definition: serialize.hh:63
void serialize(CheckpointOut &cp) const override
Serialize an object.
Tick whenValue(uint64_t target_val)
Returns the tick at which a certain counter value is reached.
void freqUpdateSchedule(size_t new_freq_entry)
Schedules a counter frequency update after a CNTCR.FCREQ == 1 This complies with frequency transition...
uint64_t counterStatusRead(Addr addr, size_t size) const
CNTReadBase (System counter status frame)
GenericTimerFrame(GenericTimerFrameParams *const p)
virtual int threadId() const =0
const SimObjectParams * _params
Cached copy of the object parameters.
Definition: sim_object.hh:110
void serialize(CheckpointOut &cp) const override
Serialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
uint64_t compareValue() const
Returns the CompareValue view of the timer.
void updateValue(void)
Updates the counter value.
void drainResume() override
Resume execution after a successful drain.
uint8_t getAccessBits() const
Returns the access bits for this frame.
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
Definition: types.cc:69
const Addr PageBytes
Definition: isa_traits.hh:56
static void validateFrameRange(const AddrRange &range)
Validates a Generic Timer register frame address range.
ArmInterruptPin *const _interrupt
Addr start() const
Get the start address of the range.
Definition: addr_range.hh:293
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
bool isSecure() const
Definition: packet.hh:749
static const Addr TIMER_CTRL_CNTTIDR
uint64_t _value
Counter value (as specified in CNTCV).
void timerCtrlWrite(Addr addr, size_t size, uint64_t data, bool is_sec)
void setControl(uint32_t val)
std::vector< std::unique_ptr< CoreTimers > > timers
Per-CPU physical architected timers.
#define warn(...)
Definition: logging.hh:208
bool _enabled
Indicates if the counter is enabled.
bool ELIsInHost(ThreadContext *tc, ExceptionLevel el)
Returns true if the current exception level el is executing a Host OS or an application of a Host OS ...
Definition: utility.cc:351
SystemCounter & _systemCounter
T bits(T val, int first, int last)
Extract the bitfield from position &#39;first&#39; to &#39;last&#39; (inclusive) from &#39;val&#39; and right justify it...
Definition: bitfield.hh:71
uint32_t control() const
Sets the control register.
const AddrRange timerCtrlRange
size_t _activeFreqEntry
Currently selected entry in the table, its contents should match _freq.
void setAccessBits(uint8_t data)
Updates the access bits after a write to CNTCTLBase.CNTACR.
void updateCounter()
Timer settings or the offset has changed, re-evaluate trigger condition and raise interrupt if necess...
Global system counter.
void eventStreamCallback() const
Bitfield< 0 > p
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:181
static const Addr TIMER_CNTV_CTL
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:500
std::vector< uint32_t > & freqTable()
Returns a reference to the frequency modes table.
const char data[]
CNTHCTL cnthctl
Hypervisor control register.
GenericTimer & parent
Generic Timer parent reference.
Generic representation of an Arm interrupt pin.
Definition: base_gic.hh:176
uint64_t getVirtOffset() const
Returns the virtual offset for this frame if a virtual timer is implemented.
Abstract superclass for simulation objects.
Definition: sim_object.hh:92
uint32_t _freq
Counter frequency (as specified by CNTFRQ).
ArchTimer physTimer
Physical and virtual timers.
bool hasNonSecureAccess() const
Indicates if non-secure accesses are allowed to this frame.
GenericTimerMem(GenericTimerMemParams *const p)
void schedNextEvent(EventStream &ev_stream, ArchTimer &timer)
void setNonSecureAccess()
Allows non-secure accesses after an enabling write to CNTCTLBase.CNTNSAR.
uint64_t _increment
Value increment in each counter cycle.
uint64_t _offset
Offset relative to the physical timer (CNTVOFF)
Addr getPageBytes() const
Get the page bytes for the ISA.
Definition: system.hh:266
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:178
EndBitUnion(ArchTimerCtrl) const std SimObject & _parent
Name of this timer.
static void validateCounterRef(SystemCounter *sys_cnt)
Validates a System Counter reference.

Generated on Mon Jun 8 2020 15:45:09 for gem5 by doxygen 1.8.13