generic_timer.cc revision 12971:a7fbe4a6eed7
1/* 2 * Copyright (c) 2013, 2015, 2017-2018 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 "mem/packet_access.hh" 47#include "params/GenericTimer.hh" 48#include "params/GenericTimerMem.hh" 49 50SystemCounter::SystemCounter() 51 : _freq(0), _period(0), _resetTick(0), _regCntkctl(0) 52{ 53 setFreq(0x01800000); 54} 55 56void 57SystemCounter::setFreq(uint32_t freq) 58{ 59 if (_freq != 0) { 60 // Altering the frequency after boot shouldn't be done in practice. 61 warn_once("The frequency of the system counter has already been set"); 62 } 63 _freq = freq; 64 _period = (1.0 / freq) * SimClock::Frequency; 65 _resetTick = curTick(); 66} 67 68void 69SystemCounter::serialize(CheckpointOut &cp) const 70{ 71 SERIALIZE_SCALAR(_regCntkctl); 72 SERIALIZE_SCALAR(_regCnthctl); 73 SERIALIZE_SCALAR(_freq); 74 SERIALIZE_SCALAR(_period); 75 SERIALIZE_SCALAR(_resetTick); 76} 77 78void 79SystemCounter::unserialize(CheckpointIn &cp) 80{ 81 // We didn't handle CNTKCTL in this class before, assume it's zero 82 // if it isn't present. 83 if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl)) 84 _regCntkctl = 0; 85 if (!UNSERIALIZE_OPT_SCALAR(_regCnthctl)) 86 _regCnthctl = 0; 87 UNSERIALIZE_SCALAR(_freq); 88 UNSERIALIZE_SCALAR(_period); 89 UNSERIALIZE_SCALAR(_resetTick); 90} 91 92 93 94ArchTimer::ArchTimer(const std::string &name, 95 SimObject &parent, 96 SystemCounter &sysctr, 97 const Interrupt &interrupt) 98 : _name(name), _parent(parent), _systemCounter(sysctr), 99 _interrupt(interrupt), 100 _control(0), _counterLimit(0), _offset(0), 101 _counterLimitReachedEvent([this]{ counterLimitReached(); }, name) 102{ 103} 104 105void 106ArchTimer::counterLimitReached() 107{ 108 _control.istatus = 1; 109 110 if (!_control.enable) 111 return; 112 113 DPRINTF(Timer, "Counter limit reached\n"); 114 if (!_control.imask) { 115 if (scheduleEvents()) { 116 DPRINTF(Timer, "Causing interrupt\n"); 117 _interrupt.send(); 118 } else { 119 DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n"); 120 } 121 } 122} 123 124void 125ArchTimer::updateCounter() 126{ 127 if (_counterLimitReachedEvent.scheduled()) 128 _parent.deschedule(_counterLimitReachedEvent); 129 if (value() >= _counterLimit) { 130 counterLimitReached(); 131 } else { 132 _control.istatus = 0; 133 if (scheduleEvents()) { 134 const auto period(_systemCounter.period()); 135 _parent.schedule(_counterLimitReachedEvent, 136 curTick() + (_counterLimit - value()) * period); 137 } 138 } 139} 140 141void 142ArchTimer::setCompareValue(uint64_t val) 143{ 144 _counterLimit = val; 145 updateCounter(); 146} 147 148void 149ArchTimer::setTimerValue(uint32_t val) 150{ 151 setCompareValue(value() + sext<32>(val)); 152} 153 154void 155ArchTimer::setControl(uint32_t val) 156{ 157 ArchTimerCtrl new_ctl = val; 158 if ((new_ctl.enable && !new_ctl.imask) && 159 !(_control.enable && !_control.imask)) { 160 // Re-evalute the timer condition 161 if (_counterLimit >= value()) { 162 _control.istatus = 1; 163 164 DPRINTF(Timer, "Causing interrupt in control\n"); 165 //_interrupt.send(); 166 } 167 } 168 _control.enable = new_ctl.enable; 169 _control.imask = new_ctl.imask; 170} 171 172void 173ArchTimer::setOffset(uint64_t val) 174{ 175 _offset = val; 176 updateCounter(); 177} 178 179uint64_t 180ArchTimer::value() const 181{ 182 return _systemCounter.value() - _offset; 183} 184 185void 186ArchTimer::serialize(CheckpointOut &cp) const 187{ 188 paramOut(cp, "control_serial", _control); 189 SERIALIZE_SCALAR(_counterLimit); 190 SERIALIZE_SCALAR(_offset); 191} 192 193void 194ArchTimer::unserialize(CheckpointIn &cp) 195{ 196 paramIn(cp, "control_serial", _control); 197 // We didn't serialize an offset before we added support for the 198 // virtual timer. Consider it optional to maintain backwards 199 // compatibility. 200 if (!UNSERIALIZE_OPT_SCALAR(_offset)) 201 _offset = 0; 202 203 // We no longer schedule an event here because we may enter KVM 204 // emulation. The event creation is delayed until drainResume(). 205} 206 207DrainState 208ArchTimer::drain() 209{ 210 if (_counterLimitReachedEvent.scheduled()) 211 _parent.deschedule(_counterLimitReachedEvent); 212 213 return DrainState::Drained; 214} 215 216void 217ArchTimer::drainResume() 218{ 219 updateCounter(); 220} 221 222void 223ArchTimer::Interrupt::send() 224{ 225 if (_ppi) { 226 _gic.sendPPInt(_irq, _cpu); 227 } else { 228 _gic.sendInt(_irq); 229 } 230} 231 232 233void 234ArchTimer::Interrupt::clear() 235{ 236 if (_ppi) { 237 _gic.clearPPInt(_irq, _cpu); 238 } else { 239 _gic.clearInt(_irq); 240 } 241} 242 243 244GenericTimer::GenericTimer(GenericTimerParams *p) 245 : ClockedObject(p), 246 system(*p->system), 247 gic(p->gic), 248 irqPhysS(p->int_phys_s), 249 irqPhysNS(p->int_phys_ns), 250 irqVirt(p->int_virt), 251 irqHyp(p->int_hyp) 252{ 253 fatal_if(!p->system, "No system specified, can't instantiate timer.\n"); 254 system.setGenericTimer(this); 255} 256 257void 258GenericTimer::serialize(CheckpointOut &cp) const 259{ 260 paramOut(cp, "cpu_count", timers.size()); 261 262 systemCounter.serializeSection(cp, "sys_counter"); 263 264 for (int i = 0; i < timers.size(); ++i) { 265 const CoreTimers &core(*timers[i]); 266 267 // This should really be phys_timerN, but we are stuck with 268 // arch_timer for backwards compatibility. 269 core.physNS.serializeSection(cp, csprintf("arch_timer%d", i)); 270 core.physS.serializeSection(cp, csprintf("phys_s_timer%d", i)); 271 core.virt.serializeSection(cp, csprintf("virt_timer%d", i)); 272 core.hyp.serializeSection(cp, csprintf("hyp_timer%d", i)); 273 } 274} 275 276void 277GenericTimer::unserialize(CheckpointIn &cp) 278{ 279 systemCounter.unserializeSection(cp, "sys_counter"); 280 281 // Try to unserialize the CPU count. Old versions of the timer 282 // model assumed a 8 CPUs, so we fall back to that if the field 283 // isn't present. 284 static const unsigned OLD_CPU_MAX = 8; 285 unsigned cpu_count; 286 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) { 287 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n", 288 OLD_CPU_MAX); 289 cpu_count = OLD_CPU_MAX; 290 } 291 292 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 524void 525GenericTimerISA::setMiscReg(int reg, MiscReg val) 526{ 527 DPRINTF(Timer, "Setting %s := 0x%x\n", miscRegName[reg], val); 528 parent.setMiscReg(reg, cpu, val); 529} 530 531MiscReg 532GenericTimerISA::readMiscReg(int reg) 533{ 534 MiscReg value = parent.readMiscReg(reg, cpu); 535 DPRINTF(Timer, "Reading %s as 0x%x\n", miscRegName[reg], value); 536 return value; 537} 538 539GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p) 540 : PioDevice(p), 541 ctrlRange(RangeSize(p->base, TheISA::PageBytes)), 542 timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)), 543 addrRanges{ctrlRange, timerRange}, 544 systemCounter(), 545 physTimer(csprintf("%s.phys_timer0", name()), 546 *this, systemCounter, 547 ArchTimer::Interrupt(*p->gic, p->int_phys)), 548 virtTimer(csprintf("%s.virt_timer0", name()), 549 *this, systemCounter, 550 ArchTimer::Interrupt(*p->gic, p->int_virt)) 551{ 552} 553 554void 555GenericTimerMem::serialize(CheckpointOut &cp) const 556{ 557 paramOut(cp, "timer_count", 1); 558 559 systemCounter.serializeSection(cp, "sys_counter"); 560 561 physTimer.serializeSection(cp, "phys_timer0"); 562 virtTimer.serializeSection(cp, "virt_timer0"); 563} 564 565void 566GenericTimerMem::unserialize(CheckpointIn &cp) 567{ 568 systemCounter.unserializeSection(cp, "sys_counter"); 569 570 unsigned timer_count; 571 UNSERIALIZE_SCALAR(timer_count); 572 // The timer count variable is just here for future versions where 573 // we support more than one set of timers. 574 if (timer_count != 1) 575 panic("Incompatible checkpoint: Only one set of timers supported"); 576 577 physTimer.unserializeSection(cp, "phys_timer0"); 578 virtTimer.unserializeSection(cp, "virt_timer0"); 579} 580 581Tick 582GenericTimerMem::read(PacketPtr pkt) 583{ 584 const unsigned size(pkt->getSize()); 585 const Addr addr(pkt->getAddr()); 586 uint64_t value; 587 588 pkt->makeResponse(); 589 if (ctrlRange.contains(addr)) { 590 value = ctrlRead(addr - ctrlRange.start(), size); 591 } else if (timerRange.contains(addr)) { 592 value = timerRead(addr - timerRange.start(), size); 593 } else { 594 panic("Invalid address: 0x%x\n", addr); 595 } 596 597 DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size); 598 599 if (size == 8) { 600 pkt->set<uint64_t>(value); 601 } else if (size == 4) { 602 pkt->set<uint32_t>(value); 603 } else { 604 panic("Unexpected access size: %i\n", size); 605 } 606 607 return 0; 608} 609 610Tick 611GenericTimerMem::write(PacketPtr pkt) 612{ 613 const unsigned size(pkt->getSize()); 614 if (size != 8 && size != 4) 615 panic("Unexpected access size\n"); 616 617 const Addr addr(pkt->getAddr()); 618 const uint64_t value(size == 8 ? 619 pkt->get<uint64_t>() : pkt->get<uint32_t>()); 620 621 DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size); 622 if (ctrlRange.contains(addr)) { 623 ctrlWrite(addr - ctrlRange.start(), size, value); 624 } else if (timerRange.contains(addr)) { 625 timerWrite(addr - timerRange.start(), size, value); 626 } else { 627 panic("Invalid address: 0x%x\n", addr); 628 } 629 630 pkt->makeResponse(); 631 return 0; 632} 633 634uint64_t 635GenericTimerMem::ctrlRead(Addr addr, size_t size) const 636{ 637 if (size == 4) { 638 switch (addr) { 639 case CTRL_CNTFRQ: 640 return systemCounter.freq(); 641 642 case CTRL_CNTTIDR: 643 return 0x3; // Frame 0 implemented with virtual timers 644 645 case CTRL_CNTNSAR: 646 case CTRL_CNTACR_BASE: 647 warn("Reading from unimplemented control register (0x%x)\n", addr); 648 return 0; 649 650 case CTRL_CNTVOFF_LO_BASE: 651 return virtTimer.offset(); 652 653 case CTRL_CNTVOFF_HI_BASE: 654 return virtTimer.offset() >> 32; 655 656 default: 657 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 658 return 0; 659 } 660 } else if (size == 8) { 661 switch (addr) { 662 case CTRL_CNTVOFF_LO_BASE: 663 return virtTimer.offset(); 664 665 default: 666 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 667 return 0; 668 } 669 } else { 670 panic("Invalid access size: %i\n", size); 671 } 672} 673 674void 675GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value) 676{ 677 if (size == 4) { 678 switch (addr) { 679 case CTRL_CNTFRQ: 680 case CTRL_CNTNSAR: 681 case CTRL_CNTTIDR: 682 case CTRL_CNTACR_BASE: 683 warn("Write to unimplemented control register (0x%x)\n", addr); 684 return; 685 686 case CTRL_CNTVOFF_LO_BASE: 687 virtTimer.setOffset( 688 insertBits(virtTimer.offset(), 31, 0, value)); 689 return; 690 691 case CTRL_CNTVOFF_HI_BASE: 692 virtTimer.setOffset( 693 insertBits(virtTimer.offset(), 63, 32, value)); 694 return; 695 696 default: 697 warn("Ignoring write to unexpected address (0x%x:%i)\n", 698 addr, size); 699 return; 700 } 701 } else if (size == 8) { 702 switch (addr) { 703 case CTRL_CNTVOFF_LO_BASE: 704 virtTimer.setOffset(value); 705 return; 706 707 default: 708 warn("Ignoring write to unexpected address (0x%x:%i)\n", 709 addr, size); 710 return; 711 } 712 } else { 713 panic("Invalid access size: %i\n", size); 714 } 715} 716 717uint64_t 718GenericTimerMem::timerRead(Addr addr, size_t size) const 719{ 720 if (size == 4) { 721 switch (addr) { 722 case TIMER_CNTPCT_LO: 723 return physTimer.value(); 724 725 case TIMER_CNTPCT_HI: 726 return physTimer.value() >> 32; 727 728 case TIMER_CNTVCT_LO: 729 return virtTimer.value(); 730 731 case TIMER_CNTVCT_HI: 732 return virtTimer.value() >> 32; 733 734 case TIMER_CNTFRQ: 735 return systemCounter.freq(); 736 737 case TIMER_CNTEL0ACR: 738 warn("Read from unimplemented timer register (0x%x)\n", addr); 739 return 0; 740 741 case CTRL_CNTVOFF_LO_BASE: 742 return virtTimer.offset(); 743 744 case CTRL_CNTVOFF_HI_BASE: 745 return virtTimer.offset() >> 32; 746 747 case TIMER_CNTP_CVAL_LO: 748 return physTimer.compareValue(); 749 750 case TIMER_CNTP_CVAL_HI: 751 return physTimer.compareValue() >> 32; 752 753 case TIMER_CNTP_TVAL: 754 return physTimer.timerValue(); 755 756 case TIMER_CNTP_CTL: 757 return physTimer.control(); 758 759 case TIMER_CNTV_CVAL_LO: 760 return virtTimer.compareValue(); 761 762 case TIMER_CNTV_CVAL_HI: 763 return virtTimer.compareValue() >> 32; 764 765 case TIMER_CNTV_TVAL: 766 return virtTimer.timerValue(); 767 768 case TIMER_CNTV_CTL: 769 return virtTimer.control(); 770 771 default: 772 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 773 return 0; 774 } 775 } else if (size == 8) { 776 switch (addr) { 777 case TIMER_CNTPCT_LO: 778 return physTimer.value(); 779 780 case TIMER_CNTVCT_LO: 781 return virtTimer.value(); 782 783 case CTRL_CNTVOFF_LO_BASE: 784 return virtTimer.offset(); 785 786 case TIMER_CNTP_CVAL_LO: 787 return physTimer.compareValue(); 788 789 case TIMER_CNTV_CVAL_LO: 790 return virtTimer.compareValue(); 791 792 default: 793 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 794 return 0; 795 } 796 } else { 797 panic("Invalid access size: %i\n", size); 798 } 799} 800 801void 802GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value) 803{ 804 if (size == 4) { 805 switch (addr) { 806 case TIMER_CNTEL0ACR: 807 warn("Unimplemented timer register (0x%x)\n", addr); 808 return; 809 810 case TIMER_CNTP_CVAL_LO: 811 physTimer.setCompareValue( 812 insertBits(physTimer.compareValue(), 31, 0, value)); 813 return; 814 815 case TIMER_CNTP_CVAL_HI: 816 physTimer.setCompareValue( 817 insertBits(physTimer.compareValue(), 63, 32, value)); 818 return; 819 820 case TIMER_CNTP_TVAL: 821 physTimer.setTimerValue(value); 822 return; 823 824 case TIMER_CNTP_CTL: 825 physTimer.setControl(value); 826 return; 827 828 case TIMER_CNTV_CVAL_LO: 829 virtTimer.setCompareValue( 830 insertBits(virtTimer.compareValue(), 31, 0, value)); 831 return; 832 833 case TIMER_CNTV_CVAL_HI: 834 virtTimer.setCompareValue( 835 insertBits(virtTimer.compareValue(), 63, 32, value)); 836 return; 837 838 case TIMER_CNTV_TVAL: 839 virtTimer.setTimerValue(value); 840 return; 841 842 case TIMER_CNTV_CTL: 843 virtTimer.setControl(value); 844 return; 845 846 default: 847 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size); 848 return; 849 } 850 } else if (size == 8) { 851 switch (addr) { 852 case TIMER_CNTP_CVAL_LO: 853 return physTimer.setCompareValue(value); 854 855 case TIMER_CNTV_CVAL_LO: 856 return virtTimer.setCompareValue(value); 857 858 default: 859 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size); 860 return; 861 } 862 } else { 863 panic("Invalid access size: %i\n", size); 864 } 865} 866 867GenericTimer * 868GenericTimerParams::create() 869{ 870 return new GenericTimer(this); 871} 872 873GenericTimerMem * 874GenericTimerMemParams::create() 875{ 876 return new GenericTimerMem(this); 877} 878