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 §ion) 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 §ion) 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 §ion) 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