generic_timer.cc revision 12733
12689Sktlim@umich.edu/* 22689Sktlim@umich.edu * Copyright (c) 2013, 2015, 2017 ARM Limited 32689Sktlim@umich.edu * All rights reserved. 42689Sktlim@umich.edu * 52689Sktlim@umich.edu * The license below extends only to copyright in the software and shall 62689Sktlim@umich.edu * not be construed as granting a license to any other intellectual 72689Sktlim@umich.edu * property including but not limited to intellectual property relating 82689Sktlim@umich.edu * to a hardware implementation of the functionality of the software 92689Sktlim@umich.edu * licensed hereunder. You may use the software subject to the license 102689Sktlim@umich.edu * terms below provided that you ensure that this notice is replicated 112689Sktlim@umich.edu * unmodified and in its entirety in all distributions of the software, 122689Sktlim@umich.edu * modified or unmodified, in source code or in binary form. 132689Sktlim@umich.edu * 142689Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without 152689Sktlim@umich.edu * modification, are permitted provided that the following conditions are 162689Sktlim@umich.edu * met: redistributions of source code must retain the above copyright 172689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer; 182689Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright 192689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the 202689Sktlim@umich.edu * documentation and/or other materials provided with the distribution; 212689Sktlim@umich.edu * neither the name of the copyright holders nor the names of its 222689Sktlim@umich.edu * contributors may be used to endorse or promote products derived from 232689Sktlim@umich.edu * this software without specific prior written permission. 242689Sktlim@umich.edu * 252689Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262689Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292689Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302689Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312689Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322689Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332689Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342521SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 353960Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 364194Ssaidi@eecs.umich.edu * 371070SN/A * Authors: Giacomo Gabrielli 381070SN/A * Andreas Sandberg 392521SN/A */ 402680Sktlim@umich.edu 412521SN/A#include "dev/arm/generic_timer.hh" 422522SN/A 432037SN/A#include "arch/arm/system.hh" 4456SN/A#include "debug/Timer.hh" 455512SMichael.Adler@intel.com#include "dev/arm/base_gic.hh" 462378SN/A#include "mem/packet_access.hh" 472521SN/A#include "params/GenericTimer.hh" 482378SN/A#include "params/GenericTimerMem.hh" 494762Snate@binkert.org 504762Snate@binkert.orgSystemCounter::SystemCounter() 512378SN/A : _freq(0), _period(0), _resetTick(0), _regCntkctl(0) 522SN/A{ 532SN/A setFreq(0x01800000); 542107SN/A} 552SN/A 562SN/Avoid 572SN/ASystemCounter::setFreq(uint32_t freq) 582SN/A{ 592SN/A if (_freq != 0) { 601070SN/A // Altering the frequency after boot shouldn't be done in practice. 615034Smilesck@eecs.umich.edu warn_once("The frequency of the system counter has already been set"); 622378SN/A } 632521SN/A _freq = freq; 642640Sstever@eecs.umich.edu _period = (1.0 / freq) * SimClock::Frequency; 652640Sstever@eecs.umich.edu _resetTick = curTick(); 662378SN/A} 672378SN/A 684997Sgblack@eecs.umich.eduvoid 692378SN/ASystemCounter::serialize(CheckpointOut &cp) const 702902Ssaidi@eecs.umich.edu{ 712SN/A SERIALIZE_SCALAR(_regCntkctl); 721070SN/A SERIALIZE_SCALAR(_regCnthctl); 731070SN/A SERIALIZE_SCALAR(_freq); 741070SN/A SERIALIZE_SCALAR(_period); 752378SN/A SERIALIZE_SCALAR(_resetTick); 761070SN/A} 774838Ssaidi@eecs.umich.edu 784838Ssaidi@eecs.umich.eduvoid 791070SN/ASystemCounter::unserialize(CheckpointIn &cp) 802520SN/A{ 812520SN/A // We didn't handle CNTKCTL in this class before, assume it's zero 822520SN/A // if it isn't present. 832520SN/A if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl)) 842520SN/A _regCntkctl = 0; 852520SN/A if (!UNSERIALIZE_OPT_SCALAR(_regCnthctl)) 862520SN/A _regCnthctl = 0; 872520SN/A UNSERIALIZE_SCALAR(_freq); 882520SN/A UNSERIALIZE_SCALAR(_period); 892521SN/A UNSERIALIZE_SCALAR(_resetTick); 902521SN/A} 912521SN/A 922521SN/A 932520SN/A 941070SN/AArchTimer::ArchTimer(const std::string &name, 952158SN/A SimObject &parent, 961070SN/A SystemCounter &sysctr, 974762Snate@binkert.org const Interrupt &interrupt) 983812Ssaidi@eecs.umich.edu : _name(name), _parent(parent), _systemCounter(sysctr), 993812Ssaidi@eecs.umich.edu _interrupt(interrupt), 1003812Ssaidi@eecs.umich.edu _control(0), _counterLimit(0), _offset(0), 1013812Ssaidi@eecs.umich.edu _counterLimitReachedEvent([this]{ counterLimitReached(); }, name) 1024762Snate@binkert.org{ 1035222Sksewell@umich.edu} 1045222Sksewell@umich.edu 1053812Ssaidi@eecs.umich.eduvoid 1064762Snate@binkert.orgArchTimer::counterLimitReached() 1071070SN/A{ 1083812Ssaidi@eecs.umich.edu _control.istatus = 1; 1093812Ssaidi@eecs.umich.edu 1101070SN/A if (!_control.enable) 1113812Ssaidi@eecs.umich.edu return; 1123812Ssaidi@eecs.umich.edu 1133812Ssaidi@eecs.umich.edu DPRINTF(Timer, "Counter limit reached\n"); 1143812Ssaidi@eecs.umich.edu if (!_control.imask) { 1151070SN/A if (scheduleEvents()) { 1163812Ssaidi@eecs.umich.edu DPRINTF(Timer, "Causing interrupt\n"); 1173812Ssaidi@eecs.umich.edu _interrupt.send(); 1183812Ssaidi@eecs.umich.edu } else { 1191070SN/A DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n"); 1203812Ssaidi@eecs.umich.edu } 1213812Ssaidi@eecs.umich.edu } 1221070SN/A} 1233812Ssaidi@eecs.umich.edu 1243812Ssaidi@eecs.umich.eduvoid 1251074SN/AArchTimer::updateCounter() 1263812Ssaidi@eecs.umich.edu{ 1273812Ssaidi@eecs.umich.edu if (_counterLimitReachedEvent.scheduled()) 1281074SN/A _parent.deschedule(_counterLimitReachedEvent); 1293812Ssaidi@eecs.umich.edu if (value() >= _counterLimit) { 1303812Ssaidi@eecs.umich.edu counterLimitReached(); 1313812Ssaidi@eecs.umich.edu } else { 1323812Ssaidi@eecs.umich.edu _control.istatus = 0; 1333812Ssaidi@eecs.umich.edu if (scheduleEvents()) { 1342378SN/A const auto period(_systemCounter.period()); 1352378SN/A _parent.schedule(_counterLimitReachedEvent, 1361070SN/A curTick() + (_counterLimit - value()) * period); 137878SN/A } 1382SN/A } 1392SN/A} 1402SN/A 1412SN/Avoid 1422378SN/AArchTimer::setCompareValue(uint64_t val) 1431070SN/A{ 1441070SN/A _counterLimit = val; 1452378SN/A updateCounter(); 1462378SN/A} 1472378SN/A 1482378SN/Avoid 1492SN/AArchTimer::setTimerValue(uint32_t val) 1502SN/A{ 1511808SN/A setCompareValue(value() + sext<32>(val)); 1524095Sbinkertn@umich.edu} 1531808SN/A 1542901Ssaidi@eecs.umich.eduvoid 1554762Snate@binkert.orgArchTimer::setControl(uint32_t val) 1562901Ssaidi@eecs.umich.edu{ 1572901Ssaidi@eecs.umich.edu ArchTimerCtrl new_ctl = val; 1582901Ssaidi@eecs.umich.edu if ((new_ctl.enable && !new_ctl.imask) && 1592901Ssaidi@eecs.umich.edu !(_control.enable && !_control.imask)) { 1602901Ssaidi@eecs.umich.edu // Re-evalute the timer condition 1613960Sgblack@eecs.umich.edu if (_counterLimit >= value()) { 1623960Sgblack@eecs.umich.edu _control.istatus = 1; 1634095Sbinkertn@umich.edu 1644095Sbinkertn@umich.edu DPRINTF(Timer, "Causing interrupt in control\n"); 1654095Sbinkertn@umich.edu //_interrupt.send(); 1663960Sgblack@eecs.umich.edu } 1673960Sgblack@eecs.umich.edu } 168180SN/A _control.enable = new_ctl.enable; 1695712Shsul@eecs.umich.edu _control.imask = new_ctl.imask; 1702SN/A} 1715712Shsul@eecs.umich.edu 1725712Shsul@eecs.umich.eduvoid 1735712Shsul@eecs.umich.eduArchTimer::setOffset(uint64_t val) 1745712Shsul@eecs.umich.edu{ 1751806SN/A _offset = val; 1761806SN/A updateCounter(); 1772680Sktlim@umich.edu} 1782680Sktlim@umich.edu 1791806SN/Auint64_t 1802680Sktlim@umich.eduArchTimer::value() const 1811806SN/A{ 1821806SN/A return _systemCounter.value() - _offset; 1832680Sktlim@umich.edu} 1841806SN/A 1851070SN/Avoid 1865512SMichael.Adler@intel.comArchTimer::serialize(CheckpointOut &cp) const 1875512SMichael.Adler@intel.com{ 1884095Sbinkertn@umich.edu paramOut(cp, "control_serial", _control); 1895512SMichael.Adler@intel.com SERIALIZE_SCALAR(_counterLimit); 1904095Sbinkertn@umich.edu SERIALIZE_SCALAR(_offset); 1914095Sbinkertn@umich.edu} 1924095Sbinkertn@umich.edu 1934095Sbinkertn@umich.eduvoid 1944095Sbinkertn@umich.eduArchTimer::unserialize(CheckpointIn &cp) 1954095Sbinkertn@umich.edu{ 1964095Sbinkertn@umich.edu paramIn(cp, "control_serial", _control); 1971070SN/A // We didn't serialize an offset before we added support for the 1984095Sbinkertn@umich.edu // virtual timer. Consider it optional to maintain backwards 1994095Sbinkertn@umich.edu // compatibility. 2004095Sbinkertn@umich.edu if (!UNSERIALIZE_OPT_SCALAR(_offset)) 2014095Sbinkertn@umich.edu _offset = 0; 2024095Sbinkertn@umich.edu 2031070SN/A // We no longer schedule an event here because we may enter KVM 2041070SN/A // emulation. The event creation is delayed until drainResume(). 2051806SN/A} 206180SN/A 20775SN/ADrainState 208180SN/AArchTimer::drain() 2091129SN/A{ 2101129SN/A if (_counterLimitReachedEvent.scheduled()) 2115713Shsul@eecs.umich.edu _parent.deschedule(_counterLimitReachedEvent); 2122114SN/A 2132680Sktlim@umich.edu return DrainState::Drained; 2144194Ssaidi@eecs.umich.edu} 2155713Shsul@eecs.umich.edu 2161129SN/Avoid 2171129SN/AArchTimer::drainResume() 2181129SN/A{ 2195713Shsul@eecs.umich.edu updateCounter(); 220180SN/A} 2215713Shsul@eecs.umich.edu 2222680Sktlim@umich.eduvoid 2235713Shsul@eecs.umich.eduArchTimer::Interrupt::send() 224180SN/A{ 225180SN/A if (_ppi) { 2265713Shsul@eecs.umich.edu _gic.sendPPInt(_irq, _cpu); 2275713Shsul@eecs.umich.edu } else { 2285713Shsul@eecs.umich.edu _gic.sendInt(_irq); 2292SN/A } 2302SN/A} 2312378SN/A 2322378SN/A 2332378SN/Avoid 2342378SN/AArchTimer::Interrupt::clear() 2352378SN/A{ 2362378SN/A if (_ppi) { 2373162Ssaidi@eecs.umich.edu _gic.clearPPInt(_irq, _cpu); 2383162Ssaidi@eecs.umich.edu } else { 2392378SN/A _gic.clearInt(_irq); 2402378SN/A } 2412378SN/A} 2422378SN/A 2431070SN/A 2441070SN/AGenericTimer::GenericTimer(GenericTimerParams *p) 2451070SN/A : ClockedObject(p), 2462378SN/A system(*p->system), 2471984SN/A gic(p->gic), 2485183Ssaidi@eecs.umich.edu irqPhysS(p->int_phys_s), 2495183Ssaidi@eecs.umich.edu irqPhysNS(p->int_phys_ns), 2505183Ssaidi@eecs.umich.edu irqVirt(p->int_virt), 2511070SN/A irqHyp(p->int_hyp) 2521070SN/A{ 2531070SN/A fatal_if(!p->system, "No system specified, can't instantiate timer.\n"); 2541070SN/A system.setGenericTimer(this); 2551070SN/A} 2561070SN/A 2572378SN/Avoid 2581984SN/AGenericTimer::serialize(CheckpointOut &cp) const 2595183Ssaidi@eecs.umich.edu{ 2605183Ssaidi@eecs.umich.edu paramOut(cp, "cpu_count", timers.size()); 2615183Ssaidi@eecs.umich.edu 2621070SN/A systemCounter.serializeSection(cp, "sys_counter"); 2632SN/A 2642SN/A for (int i = 0; i < timers.size(); ++i) { 2652SN/A const CoreTimers &core(*timers[i]); 2662SN/A 2672SN/A // This should really be phys_timerN, but we are stuck with 2682SN/A // arch_timer for backwards compatibility. 2692SN/A core.physNS.serializeSection(cp, csprintf("arch_timer%d", i)); 2702SN/A core.physS.serializeSection(cp, csprintf("phys_s_timer%d", i)); 2712SN/A core.virt.serializeSection(cp, csprintf("virt_timer%d", i)); 2722SN/A core.hyp.serializeSection(cp, csprintf("hyp_timer%d", i)); 2732SN/A } 2742SN/A} 2752SN/A 2762SN/Avoid 2772SN/AGenericTimer::unserialize(CheckpointIn &cp) 2782SN/A{ 2792SN/A systemCounter.unserializeSection(cp, "sys_counter"); 2802SN/A 2812902Ssaidi@eecs.umich.edu // Try to unserialize the CPU count. Old versions of the timer 2822902Ssaidi@eecs.umich.edu // model assumed a 8 CPUs, so we fall back to that if the field 2832902Ssaidi@eecs.umich.edu // isn't present. 2844762Snate@binkert.org static const unsigned OLD_CPU_MAX = 8; 2852424SN/A unsigned cpu_count; 2864762Snate@binkert.org if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) { 2874762Snate@binkert.org warn("Checkpoint does not contain CPU count, assuming %i CPUs\n", 2882424SN/A OLD_CPU_MAX); 2895530Snate@binkert.org cpu_count = OLD_CPU_MAX; 2902424SN/A } 2912424SN/A 2922424SN/A for (int i = 0; i < cpu_count; ++i) { 293 CoreTimers &core(getTimers(i)); 294 // This should really be phys_timerN, but we are stuck with 295 // arch_timer for backwards compatibility. 296 core.physNS.unserializeSection(cp, csprintf("arch_timer%d", i)); 297 core.physS.unserializeSection(cp, csprintf("phys_s_timer%d", i)); 298 core.virt.unserializeSection(cp, csprintf("virt_timer%d", i)); 299 core.hyp.unserializeSection(cp, csprintf("hyp_timer%d", i)); 300 } 301} 302 303 304GenericTimer::CoreTimers & 305GenericTimer::getTimers(int cpu_id) 306{ 307 if (cpu_id >= timers.size()) 308 createTimers(cpu_id + 1); 309 310 return *timers[cpu_id]; 311} 312 313void 314GenericTimer::createTimers(unsigned cpus) 315{ 316 assert(timers.size() < cpus); 317 318 const unsigned old_cpu_count(timers.size()); 319 timers.resize(cpus); 320 for (unsigned i = old_cpu_count; i < cpus; ++i) { 321 timers[i].reset( 322 new CoreTimers(*this, system, i, 323 irqPhysS, irqPhysNS, irqVirt, irqHyp)); 324 } 325} 326 327 328void 329GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val) 330{ 331 CoreTimers &core(getTimers(cpu)); 332 333 switch (reg) { 334 case MISCREG_CNTFRQ: 335 case MISCREG_CNTFRQ_EL0: 336 systemCounter.setFreq(val); 337 return; 338 339 case MISCREG_CNTKCTL: 340 case MISCREG_CNTKCTL_EL1: 341 systemCounter.setKernelControl(val); 342 return; 343 344 case MISCREG_CNTHCTL: 345 case MISCREG_CNTHCTL_EL2: 346 systemCounter.setHypControl(val); 347 return; 348 349 // Physical timer (NS) 350 case MISCREG_CNTP_CVAL_NS: 351 case MISCREG_CNTP_CVAL_EL0: 352 core.physNS.setCompareValue(val); 353 return; 354 355 case MISCREG_CNTP_TVAL_NS: 356 case MISCREG_CNTP_TVAL_EL0: 357 core.physNS.setTimerValue(val); 358 return; 359 360 case MISCREG_CNTP_CTL_NS: 361 case MISCREG_CNTP_CTL_EL0: 362 core.physNS.setControl(val); 363 return; 364 365 // Count registers 366 case MISCREG_CNTPCT: 367 case MISCREG_CNTPCT_EL0: 368 case MISCREG_CNTVCT: 369 case MISCREG_CNTVCT_EL0: 370 warn("Ignoring write to read only count register: %s\n", 371 miscRegName[reg]); 372 return; 373 374 // Virtual timer 375 case MISCREG_CNTVOFF: 376 case MISCREG_CNTVOFF_EL2: 377 core.virt.setOffset(val); 378 return; 379 380 case MISCREG_CNTV_CVAL: 381 case MISCREG_CNTV_CVAL_EL0: 382 core.virt.setCompareValue(val); 383 return; 384 385 case MISCREG_CNTV_TVAL: 386 case MISCREG_CNTV_TVAL_EL0: 387 core.virt.setTimerValue(val); 388 return; 389 390 case MISCREG_CNTV_CTL: 391 case MISCREG_CNTV_CTL_EL0: 392 core.virt.setControl(val); 393 return; 394 395 // Physical timer (S) 396 case MISCREG_CNTP_CTL_S: 397 case MISCREG_CNTPS_CTL_EL1: 398 core.physS.setControl(val); 399 return; 400 401 case MISCREG_CNTP_CVAL_S: 402 case MISCREG_CNTPS_CVAL_EL1: 403 core.physS.setCompareValue(val); 404 return; 405 406 case MISCREG_CNTP_TVAL_S: 407 case MISCREG_CNTPS_TVAL_EL1: 408 core.physS.setTimerValue(val); 409 return; 410 411 // Hyp phys. timer, non-secure 412 case MISCREG_CNTHP_CTL: 413 case MISCREG_CNTHP_CTL_EL2: 414 core.hyp.setControl(val); 415 return; 416 417 case MISCREG_CNTHP_CVAL: 418 case MISCREG_CNTHP_CVAL_EL2: 419 core.hyp.setCompareValue(val); 420 return; 421 422 case MISCREG_CNTHP_TVAL: 423 case MISCREG_CNTHP_TVAL_EL2: 424 core.hyp.setTimerValue(val); 425 return; 426 427 default: 428 warn("Writing to unknown register: %s\n", miscRegName[reg]); 429 return; 430 } 431} 432 433 434MiscReg 435GenericTimer::readMiscReg(int reg, unsigned cpu) 436{ 437 CoreTimers &core(getTimers(cpu)); 438 439 switch (reg) { 440 case MISCREG_CNTFRQ: 441 case MISCREG_CNTFRQ_EL0: 442 return systemCounter.freq(); 443 444 case MISCREG_CNTKCTL: 445 case MISCREG_CNTKCTL_EL1: 446 return systemCounter.getKernelControl(); 447 448 case MISCREG_CNTHCTL: 449 case MISCREG_CNTHCTL_EL2: 450 return systemCounter.getHypControl(); 451 452 // Physical timer 453 case MISCREG_CNTP_CVAL_NS: 454 case MISCREG_CNTP_CVAL_EL0: 455 return core.physNS.compareValue(); 456 457 case MISCREG_CNTP_TVAL_NS: 458 case MISCREG_CNTP_TVAL_EL0: 459 return core.physNS.timerValue(); 460 461 case MISCREG_CNTP_CTL_EL0: 462 case MISCREG_CNTP_CTL_NS: 463 return core.physNS.control(); 464 465 case MISCREG_CNTPCT: 466 case MISCREG_CNTPCT_EL0: 467 return core.physNS.value(); 468 469 470 // Virtual timer 471 case MISCREG_CNTVCT: 472 case MISCREG_CNTVCT_EL0: 473 return core.virt.value(); 474 475 case MISCREG_CNTVOFF: 476 case MISCREG_CNTVOFF_EL2: 477 return core.virt.offset(); 478 479 case MISCREG_CNTV_CVAL: 480 case MISCREG_CNTV_CVAL_EL0: 481 return core.virt.compareValue(); 482 483 case MISCREG_CNTV_TVAL: 484 case MISCREG_CNTV_TVAL_EL0: 485 return core.virt.timerValue(); 486 487 case MISCREG_CNTV_CTL: 488 case MISCREG_CNTV_CTL_EL0: 489 return core.virt.control(); 490 491 // PL1 phys. timer, secure 492 case MISCREG_CNTP_CTL_S: 493 case MISCREG_CNTPS_CTL_EL1: 494 return core.physS.control(); 495 496 case MISCREG_CNTP_CVAL_S: 497 case MISCREG_CNTPS_CVAL_EL1: 498 return core.physS.compareValue(); 499 500 case MISCREG_CNTP_TVAL_S: 501 case MISCREG_CNTPS_TVAL_EL1: 502 return core.physS.timerValue(); 503 504 // HYP phys. timer (NS) 505 case MISCREG_CNTHP_CTL: 506 case MISCREG_CNTHP_CTL_EL2: 507 return core.hyp.control(); 508 509 case MISCREG_CNTHP_CVAL: 510 case MISCREG_CNTHP_CVAL_EL2: 511 return core.hyp.compareValue(); 512 513 case MISCREG_CNTHP_TVAL: 514 case MISCREG_CNTHP_TVAL_EL2: 515 return core.hyp.timerValue(); 516 517 default: 518 warn("Reading from unknown register: %s\n", miscRegName[reg]); 519 return 0; 520 } 521} 522 523 524 525GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p) 526 : PioDevice(p), 527 ctrlRange(RangeSize(p->base, TheISA::PageBytes)), 528 timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)), 529 addrRanges{ctrlRange, timerRange}, 530 systemCounter(), 531 physTimer(csprintf("%s.phys_timer0", name()), 532 *this, systemCounter, 533 ArchTimer::Interrupt(*p->gic, p->int_phys)), 534 virtTimer(csprintf("%s.virt_timer0", name()), 535 *this, systemCounter, 536 ArchTimer::Interrupt(*p->gic, p->int_virt)) 537{ 538} 539 540void 541GenericTimerMem::serialize(CheckpointOut &cp) const 542{ 543 paramOut(cp, "timer_count", 1); 544 545 systemCounter.serializeSection(cp, "sys_counter"); 546 547 physTimer.serializeSection(cp, "phys_timer0"); 548 virtTimer.serializeSection(cp, "virt_timer0"); 549} 550 551void 552GenericTimerMem::unserialize(CheckpointIn &cp) 553{ 554 systemCounter.unserializeSection(cp, "sys_counter"); 555 556 unsigned timer_count; 557 UNSERIALIZE_SCALAR(timer_count); 558 // The timer count variable is just here for future versions where 559 // we support more than one set of timers. 560 if (timer_count != 1) 561 panic("Incompatible checkpoint: Only one set of timers supported"); 562 563 physTimer.unserializeSection(cp, "phys_timer0"); 564 virtTimer.unserializeSection(cp, "virt_timer0"); 565} 566 567Tick 568GenericTimerMem::read(PacketPtr pkt) 569{ 570 const unsigned size(pkt->getSize()); 571 const Addr addr(pkt->getAddr()); 572 uint64_t value; 573 574 pkt->makeResponse(); 575 if (ctrlRange.contains(addr)) { 576 value = ctrlRead(addr - ctrlRange.start(), size); 577 } else if (timerRange.contains(addr)) { 578 value = timerRead(addr - timerRange.start(), size); 579 } else { 580 panic("Invalid address: 0x%x\n", addr); 581 } 582 583 DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size); 584 585 if (size == 8) { 586 pkt->set<uint64_t>(value); 587 } else if (size == 4) { 588 pkt->set<uint32_t>(value); 589 } else { 590 panic("Unexpected access size: %i\n", size); 591 } 592 593 return 0; 594} 595 596Tick 597GenericTimerMem::write(PacketPtr pkt) 598{ 599 const unsigned size(pkt->getSize()); 600 if (size != 8 && size != 4) 601 panic("Unexpected access size\n"); 602 603 const Addr addr(pkt->getAddr()); 604 const uint64_t value(size == 8 ? 605 pkt->get<uint64_t>() : pkt->get<uint32_t>()); 606 607 DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size); 608 if (ctrlRange.contains(addr)) { 609 ctrlWrite(addr - ctrlRange.start(), size, value); 610 } else if (timerRange.contains(addr)) { 611 timerWrite(addr - timerRange.start(), size, value); 612 } else { 613 panic("Invalid address: 0x%x\n", addr); 614 } 615 616 pkt->makeResponse(); 617 return 0; 618} 619 620uint64_t 621GenericTimerMem::ctrlRead(Addr addr, size_t size) const 622{ 623 if (size == 4) { 624 switch (addr) { 625 case CTRL_CNTFRQ: 626 return systemCounter.freq(); 627 628 case CTRL_CNTTIDR: 629 return 0x3; // Frame 0 implemented with virtual timers 630 631 case CTRL_CNTNSAR: 632 case CTRL_CNTACR_BASE: 633 warn("Reading from unimplemented control register (0x%x)\n", addr); 634 return 0; 635 636 case CTRL_CNTVOFF_LO_BASE: 637 return virtTimer.offset(); 638 639 case CTRL_CNTVOFF_HI_BASE: 640 return virtTimer.offset() >> 32; 641 642 default: 643 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 644 return 0; 645 } 646 } else if (size == 8) { 647 switch (addr) { 648 case CTRL_CNTVOFF_LO_BASE: 649 return virtTimer.offset(); 650 651 default: 652 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 653 return 0; 654 } 655 } else { 656 panic("Invalid access size: %i\n", size); 657 } 658} 659 660void 661GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value) 662{ 663 if (size == 4) { 664 switch (addr) { 665 case CTRL_CNTFRQ: 666 case CTRL_CNTNSAR: 667 case CTRL_CNTTIDR: 668 case CTRL_CNTACR_BASE: 669 warn("Write to unimplemented control register (0x%x)\n", addr); 670 return; 671 672 case CTRL_CNTVOFF_LO_BASE: 673 virtTimer.setOffset( 674 insertBits(virtTimer.offset(), 31, 0, value)); 675 return; 676 677 case CTRL_CNTVOFF_HI_BASE: 678 virtTimer.setOffset( 679 insertBits(virtTimer.offset(), 63, 32, value)); 680 return; 681 682 default: 683 warn("Ignoring write to unexpected address (0x%x:%i)\n", 684 addr, size); 685 return; 686 } 687 } else if (size == 8) { 688 switch (addr) { 689 case CTRL_CNTVOFF_LO_BASE: 690 virtTimer.setOffset(value); 691 return; 692 693 default: 694 warn("Ignoring write to unexpected address (0x%x:%i)\n", 695 addr, size); 696 return; 697 } 698 } else { 699 panic("Invalid access size: %i\n", size); 700 } 701} 702 703uint64_t 704GenericTimerMem::timerRead(Addr addr, size_t size) const 705{ 706 if (size == 4) { 707 switch (addr) { 708 case TIMER_CNTPCT_LO: 709 return physTimer.value(); 710 711 case TIMER_CNTPCT_HI: 712 return physTimer.value() >> 32; 713 714 case TIMER_CNTVCT_LO: 715 return virtTimer.value(); 716 717 case TIMER_CNTVCT_HI: 718 return virtTimer.value() >> 32; 719 720 case TIMER_CNTFRQ: 721 return systemCounter.freq(); 722 723 case TIMER_CNTEL0ACR: 724 warn("Read from unimplemented timer register (0x%x)\n", addr); 725 return 0; 726 727 case CTRL_CNTVOFF_LO_BASE: 728 return virtTimer.offset(); 729 730 case CTRL_CNTVOFF_HI_BASE: 731 return virtTimer.offset() >> 32; 732 733 case TIMER_CNTP_CVAL_LO: 734 return physTimer.compareValue(); 735 736 case TIMER_CNTP_CVAL_HI: 737 return physTimer.compareValue() >> 32; 738 739 case TIMER_CNTP_TVAL: 740 return physTimer.timerValue(); 741 742 case TIMER_CNTP_CTL: 743 return physTimer.control(); 744 745 case TIMER_CNTV_CVAL_LO: 746 return virtTimer.compareValue(); 747 748 case TIMER_CNTV_CVAL_HI: 749 return virtTimer.compareValue() >> 32; 750 751 case TIMER_CNTV_TVAL: 752 return virtTimer.timerValue(); 753 754 case TIMER_CNTV_CTL: 755 return virtTimer.control(); 756 757 default: 758 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 759 return 0; 760 } 761 } else if (size == 8) { 762 switch (addr) { 763 case TIMER_CNTPCT_LO: 764 return physTimer.value(); 765 766 case TIMER_CNTVCT_LO: 767 return virtTimer.value(); 768 769 case CTRL_CNTVOFF_LO_BASE: 770 return virtTimer.offset(); 771 772 case TIMER_CNTP_CVAL_LO: 773 return physTimer.compareValue(); 774 775 case TIMER_CNTV_CVAL_LO: 776 return virtTimer.compareValue(); 777 778 default: 779 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 780 return 0; 781 } 782 } else { 783 panic("Invalid access size: %i\n", size); 784 } 785} 786 787void 788GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value) 789{ 790 if (size == 4) { 791 switch (addr) { 792 case TIMER_CNTEL0ACR: 793 warn("Unimplemented timer register (0x%x)\n", addr); 794 return; 795 796 case TIMER_CNTP_CVAL_LO: 797 physTimer.setCompareValue( 798 insertBits(physTimer.compareValue(), 31, 0, value)); 799 return; 800 801 case TIMER_CNTP_CVAL_HI: 802 physTimer.setCompareValue( 803 insertBits(physTimer.compareValue(), 63, 32, value)); 804 return; 805 806 case TIMER_CNTP_TVAL: 807 physTimer.setTimerValue(value); 808 return; 809 810 case TIMER_CNTP_CTL: 811 physTimer.setControl(value); 812 return; 813 814 case TIMER_CNTV_CVAL_LO: 815 virtTimer.setCompareValue( 816 insertBits(virtTimer.compareValue(), 31, 0, value)); 817 return; 818 819 case TIMER_CNTV_CVAL_HI: 820 virtTimer.setCompareValue( 821 insertBits(virtTimer.compareValue(), 63, 32, value)); 822 return; 823 824 case TIMER_CNTV_TVAL: 825 virtTimer.setTimerValue(value); 826 return; 827 828 case TIMER_CNTV_CTL: 829 virtTimer.setControl(value); 830 return; 831 832 default: 833 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size); 834 return; 835 } 836 } else if (size == 8) { 837 switch (addr) { 838 case TIMER_CNTP_CVAL_LO: 839 return physTimer.setCompareValue(value); 840 841 case TIMER_CNTV_CVAL_LO: 842 return virtTimer.setCompareValue(value); 843 844 default: 845 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size); 846 return; 847 } 848 } else { 849 panic("Invalid access size: %i\n", size); 850 } 851} 852 853GenericTimer * 854GenericTimerParams::create() 855{ 856 return new GenericTimer(this); 857} 858 859GenericTimerMem * 860GenericTimerMemParams::create() 861{ 862 return new GenericTimerMem(this); 863} 864