generic_timer.cc revision 10844:8551af601f75
1/*
2 * Copyright (c) 2013, 2015 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Gabrielli
38 *          Andreas Sandberg
39 */
40
41#include "dev/arm/generic_timer.hh"
42
43#include "arch/arm/system.hh"
44#include "debug/Timer.hh"
45#include "dev/arm/base_gic.hh"
46#include "params/GenericTimer.hh"
47
48SystemCounter::SystemCounter()
49    : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
50{
51    setFreq(0x01800000);
52}
53
54void
55SystemCounter::setFreq(uint32_t freq)
56{
57    if (_freq != 0) {
58        // Altering the frequency after boot shouldn't be done in practice.
59        warn_once("The frequency of the system counter has already been set");
60    }
61    _freq = freq;
62    _period = (1.0 / freq) * SimClock::Frequency;
63    _resetTick = curTick();
64}
65
66void
67SystemCounter::serialize(std::ostream &os) const
68{
69    SERIALIZE_SCALAR(_regCntkctl);
70    SERIALIZE_SCALAR(_freq);
71    SERIALIZE_SCALAR(_period);
72    SERIALIZE_SCALAR(_resetTick);
73}
74
75void
76SystemCounter::unserialize(Checkpoint *cp,
77                           const std::string &section)
78{
79    // We didn't handle CNTKCTL in this class before, assume it's zero
80    // if it isn't present.
81    if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
82        _regCntkctl = 0;
83    UNSERIALIZE_SCALAR(_freq);
84    UNSERIALIZE_SCALAR(_period);
85    UNSERIALIZE_SCALAR(_resetTick);
86}
87
88
89
90ArchTimer::ArchTimer(const std::string &name,
91                     SimObject &parent,
92                     SystemCounter &sysctr,
93                     const Interrupt &interrupt)
94    : _name(name), _parent(parent), _systemCounter(sysctr),
95      _interrupt(interrupt),
96      _control(0), _counterLimit(0),
97      _counterLimitReachedEvent(this)
98{
99}
100
101void
102ArchTimer::counterLimitReached()
103{
104    _control.istatus = 1;
105
106    if (!_control.enable)
107        return;
108
109    DPRINTF(Timer, "Counter limit reached\n");
110    if (!_control.imask) {
111        DPRINTF(Timer, "Causing interrupt\n");
112        _interrupt.send();
113    }
114}
115
116void
117ArchTimer::updateCounter()
118{
119    if (_counterLimitReachedEvent.scheduled())
120        _parent.deschedule(_counterLimitReachedEvent);
121    if (value() >= _counterLimit) {
122        counterLimitReached();
123    } else {
124        const auto period(_systemCounter.period());
125        _control.istatus = 0;
126        _parent.schedule(_counterLimitReachedEvent,
127             curTick() + (_counterLimit - value()) * period);
128    }
129}
130
131void
132ArchTimer::setCompareValue(uint64_t val)
133{
134    _counterLimit = val;
135    updateCounter();
136}
137
138void
139ArchTimer::setTimerValue(uint32_t val)
140{
141    setCompareValue(value() + sext<32>(val));
142}
143
144void
145ArchTimer::setControl(uint32_t val)
146{
147    ArchTimerCtrl new_ctl = val;
148    if ((new_ctl.enable && !new_ctl.imask) &&
149        !(_control.enable && !_control.imask)) {
150        // Re-evalute the timer condition
151        if (_counterLimit >= value()) {
152            _control.istatus = 1;
153
154            DPRINTF(Timer, "Causing interrupt in control\n");
155            //_interrupt.send();
156        }
157    }
158    _control.enable = new_ctl.enable;
159    _control.imask = new_ctl.imask;
160}
161
162uint64_t
163ArchTimer::value() const
164{
165    return _systemCounter.value();
166}
167
168void
169ArchTimer::serialize(std::ostream &os) const
170{
171    paramOut(os, "control_serial", _control);
172    SERIALIZE_SCALAR(_counterLimit);
173
174    const bool event_scheduled(_counterLimitReachedEvent.scheduled());
175    SERIALIZE_SCALAR(event_scheduled);
176    if (event_scheduled) {
177        const Tick event_time(_counterLimitReachedEvent.when());
178        SERIALIZE_SCALAR(event_time);
179    }
180}
181
182void
183ArchTimer::unserialize(Checkpoint *cp,
184                                         const std::string &section)
185{
186    paramIn(cp, section, "control_serial", _control);
187    bool event_scheduled;
188    UNSERIALIZE_SCALAR(event_scheduled);
189    if (event_scheduled) {
190        Tick event_time;
191        UNSERIALIZE_SCALAR(event_time);
192        _parent.schedule(_counterLimitReachedEvent, event_time);
193    }
194}
195
196void
197ArchTimer::Interrupt::send()
198{
199    if (_ppi) {
200        _gic.sendPPInt(_irq, _cpu);
201    } else {
202        _gic.sendInt(_irq);
203    }
204}
205
206
207void
208ArchTimer::Interrupt::clear()
209{
210    if (_ppi) {
211        _gic.clearPPInt(_irq, _cpu);
212    } else {
213        _gic.clearInt(_irq);
214    }
215}
216
217
218GenericTimer::GenericTimer(GenericTimerParams *p)
219    : SimObject(p),
220      gic(p->gic),
221      irqPhys(p->int_phys)
222{
223    dynamic_cast<ArmSystem &>(*p->system).setGenericTimer(this);
224}
225
226void
227GenericTimer::serialize(std::ostream &os)
228{
229    paramOut(os, "cpu_count", timers.size());
230
231    nameOut(os, csprintf("%s.sys_counter", name()));
232    systemCounter.serialize(os);
233
234    for (int i = 0; i < timers.size(); ++i) {
235        CoreTimers &core(getTimers(i));
236
237        nameOut(os, core.phys.name());
238        core.phys.serialize(os);
239    }
240}
241
242void
243GenericTimer::unserialize(Checkpoint *cp, const std::string &section)
244{
245    systemCounter.unserialize(cp, csprintf("%s.sys_counter", section));
246
247    // Try to unserialize the CPU count. Old versions of the timer
248    // model assumed a 8 CPUs, so we fall back to that if the field
249    // isn't present.
250    static const unsigned OLD_CPU_MAX = 8;
251    unsigned cpu_count;
252    if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
253        warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
254             OLD_CPU_MAX);
255        cpu_count = OLD_CPU_MAX;
256    }
257
258    for (int i = 0; i < cpu_count; ++i) {
259        CoreTimers &core(getTimers(i));
260        // This should really be phys_timerN, but we are stuck with
261        // arch_timer for backwards compatibility.
262        core.phys.unserialize(cp, csprintf("%s.arch_timer%d", section, i));
263    }
264}
265
266
267GenericTimer::CoreTimers &
268GenericTimer::getTimers(int cpu_id)
269{
270    if (cpu_id >= timers.size())
271        createTimers(cpu_id + 1);
272
273    return *timers[cpu_id];
274}
275
276void
277GenericTimer::createTimers(unsigned cpus)
278{
279    assert(timers.size() < cpus);
280
281    const unsigned old_cpu_count(timers.size());
282    timers.resize(cpus);
283    for (unsigned i = old_cpu_count; i < cpus; ++i) {
284        timers[i].reset(
285            new CoreTimers(*this, i, irqPhys));
286    }
287}
288
289
290void
291GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
292{
293    CoreTimers &core(getTimers(cpu));
294
295    switch (reg) {
296      case MISCREG_CNTFRQ:
297      case MISCREG_CNTFRQ_EL0:
298        systemCounter.setFreq(val);
299        return;
300
301      case MISCREG_CNTKCTL:
302      case MISCREG_CNTKCTL_EL1:
303        systemCounter.setKernelControl(val);
304        return;
305
306      // Physical timer
307      case MISCREG_CNTP_CVAL:
308      case MISCREG_CNTP_CVAL_NS:
309      case MISCREG_CNTP_CVAL_EL0:
310        core.phys.setCompareValue(val);
311        return;
312
313      case MISCREG_CNTP_TVAL:
314      case MISCREG_CNTP_TVAL_NS:
315      case MISCREG_CNTP_TVAL_EL0:
316        core.phys.setTimerValue(val);
317        return;
318
319      case MISCREG_CNTP_CTL:
320      case MISCREG_CNTP_CTL_NS:
321      case MISCREG_CNTP_CTL_EL0:
322        core.phys.setControl(val);
323        return;
324
325      // Count registers
326      case MISCREG_CNTPCT:
327      case MISCREG_CNTPCT_EL0:
328      case MISCREG_CNTVCT:
329      case MISCREG_CNTVCT_EL0:
330        warn("Ignoring write to read only count register: %s\n",
331             miscRegName[reg]);
332        return;
333
334      // Virtual timer
335      case MISCREG_CNTVOFF:
336      case MISCREG_CNTVOFF_EL2:
337      case MISCREG_CNTV_CVAL:
338      case MISCREG_CNTV_CVAL_EL0:
339      case MISCREG_CNTV_TVAL:
340      case MISCREG_CNTV_TVAL_EL0:
341      case MISCREG_CNTV_CTL:
342      case MISCREG_CNTV_CTL_EL0:
343        /* FALLTHROUGH */
344
345      // PL1 phys. timer, secure
346      case MISCREG_CNTP_CTL_S:
347      case MISCREG_CNTPS_CVAL_EL1:
348      case MISCREG_CNTPS_TVAL_EL1:
349      case MISCREG_CNTPS_CTL_EL1:
350        /* FALLTHROUGH */
351
352      // PL2 phys. timer, non-secure
353      case MISCREG_CNTHCTL:
354      case MISCREG_CNTHCTL_EL2:
355      case MISCREG_CNTHP_CVAL:
356      case MISCREG_CNTHP_CVAL_EL2:
357      case MISCREG_CNTHP_TVAL:
358      case MISCREG_CNTHP_TVAL_EL2:
359      case MISCREG_CNTHP_CTL:
360      case MISCREG_CNTHP_CTL_EL2:
361        warn("Writing to unimplemented register: %s\n",
362             miscRegName[reg]);
363        return;
364
365      default:
366        warn("Writing to unknown register: %s\n", miscRegName[reg]);
367        return;
368    }
369}
370
371
372MiscReg
373GenericTimer::readMiscReg(int reg, unsigned cpu)
374{
375    CoreTimers &core(getTimers(cpu));
376
377    switch (reg) {
378      case MISCREG_CNTFRQ:
379      case MISCREG_CNTFRQ_EL0:
380        return systemCounter.freq();
381
382      case MISCREG_CNTKCTL:
383      case MISCREG_CNTKCTL_EL1:
384        return systemCounter.getKernelControl();
385
386      // Physical timer
387      case MISCREG_CNTP_CVAL:
388      case MISCREG_CNTP_CVAL_EL0:
389        return core.phys.compareValue();
390
391      case MISCREG_CNTP_TVAL:
392      case MISCREG_CNTP_TVAL_EL0:
393        return core.phys.timerValue();
394
395      case MISCREG_CNTP_CTL:
396      case MISCREG_CNTP_CTL_EL0:
397      case MISCREG_CNTP_CTL_NS:
398        return core.phys.control();
399
400      case MISCREG_CNTPCT:
401      case MISCREG_CNTPCT_EL0:
402        return core.phys.value();
403
404
405      // Virtual timer
406      case MISCREG_CNTVCT:
407      case MISCREG_CNTVCT_EL0:
408        warn_once("Virtual timer not implemented, "
409                  "returning physical timer value\n");
410        return core.phys.value();
411
412      case MISCREG_CNTVOFF:
413      case MISCREG_CNTVOFF_EL2:
414      case MISCREG_CNTV_CVAL:
415      case MISCREG_CNTV_CVAL_EL0:
416      case MISCREG_CNTV_TVAL:
417      case MISCREG_CNTV_TVAL_EL0:
418      case MISCREG_CNTV_CTL:
419      case MISCREG_CNTV_CTL_EL0:
420        /* FALLTHROUGH */
421
422      // PL1 phys. timer, secure
423      case MISCREG_CNTP_CTL_S:
424      case MISCREG_CNTPS_CVAL_EL1:
425      case MISCREG_CNTPS_TVAL_EL1:
426      case MISCREG_CNTPS_CTL_EL1:
427        /* FALLTHROUGH */
428
429      // PL2 phys. timer, non-secure
430      case MISCREG_CNTHCTL:
431      case MISCREG_CNTHCTL_EL2:
432      case MISCREG_CNTHP_CVAL:
433      case MISCREG_CNTHP_CVAL_EL2:
434      case MISCREG_CNTHP_TVAL:
435      case MISCREG_CNTHP_TVAL_EL2:
436      case MISCREG_CNTHP_CTL:
437      case MISCREG_CNTHP_CTL_EL2:
438        warn("Reading from unimplemented register: %s\n",
439             miscRegName[reg]);
440        return 0;
441
442
443      default:
444        warn("Reading from unknown register: %s\n", miscRegName[reg]);
445        return 0;
446    }
447}
448
449
450GenericTimer *
451GenericTimerParams::create()
452{
453    return new GenericTimer(this);
454}
455