generic_timer.cc revision 12101:f3e183c78529
1/* 2 * Copyright (c) 2013, 2015, 2017 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(_freq); 73 SERIALIZE_SCALAR(_period); 74 SERIALIZE_SCALAR(_resetTick); 75} 76 77void 78SystemCounter::unserialize(CheckpointIn &cp) 79{ 80 // We didn't handle CNTKCTL in this class before, assume it's zero 81 // if it isn't present. 82 if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl)) 83 _regCntkctl = 0; 84 UNSERIALIZE_SCALAR(_freq); 85 UNSERIALIZE_SCALAR(_period); 86 UNSERIALIZE_SCALAR(_resetTick); 87} 88 89 90 91ArchTimer::ArchTimer(const std::string &name, 92 SimObject &parent, 93 SystemCounter &sysctr, 94 const Interrupt &interrupt) 95 : _name(name), _parent(parent), _systemCounter(sysctr), 96 _interrupt(interrupt), 97 _control(0), _counterLimit(0), _offset(0), 98 _counterLimitReachedEvent([this]{ counterLimitReached(); }, name) 99{ 100} 101 102void 103ArchTimer::counterLimitReached() 104{ 105 _control.istatus = 1; 106 107 if (!_control.enable) 108 return; 109 110 DPRINTF(Timer, "Counter limit reached\n"); 111 if (!_control.imask) { 112 DPRINTF(Timer, "Causing interrupt\n"); 113 _interrupt.send(); 114 } 115} 116 117void 118ArchTimer::updateCounter() 119{ 120 if (_counterLimitReachedEvent.scheduled()) 121 _parent.deschedule(_counterLimitReachedEvent); 122 if (value() >= _counterLimit) { 123 counterLimitReached(); 124 } else { 125 const auto period(_systemCounter.period()); 126 _control.istatus = 0; 127 _parent.schedule(_counterLimitReachedEvent, 128 curTick() + (_counterLimit - value()) * period); 129 } 130} 131 132void 133ArchTimer::setCompareValue(uint64_t val) 134{ 135 _counterLimit = val; 136 updateCounter(); 137} 138 139void 140ArchTimer::setTimerValue(uint32_t val) 141{ 142 setCompareValue(value() + sext<32>(val)); 143} 144 145void 146ArchTimer::setControl(uint32_t val) 147{ 148 ArchTimerCtrl new_ctl = val; 149 if ((new_ctl.enable && !new_ctl.imask) && 150 !(_control.enable && !_control.imask)) { 151 // Re-evalute the timer condition 152 if (_counterLimit >= value()) { 153 _control.istatus = 1; 154 155 DPRINTF(Timer, "Causing interrupt in control\n"); 156 //_interrupt.send(); 157 } 158 } 159 _control.enable = new_ctl.enable; 160 _control.imask = new_ctl.imask; 161} 162 163void 164ArchTimer::setOffset(uint64_t val) 165{ 166 _offset = val; 167 updateCounter(); 168} 169 170uint64_t 171ArchTimer::value() const 172{ 173 return _systemCounter.value() - _offset; 174} 175 176void 177ArchTimer::serialize(CheckpointOut &cp) const 178{ 179 paramOut(cp, "control_serial", _control); 180 SERIALIZE_SCALAR(_counterLimit); 181 SERIALIZE_SCALAR(_offset); 182} 183 184void 185ArchTimer::unserialize(CheckpointIn &cp) 186{ 187 paramIn(cp, "control_serial", _control); 188 // We didn't serialize an offset before we added support for the 189 // virtual timer. Consider it optional to maintain backwards 190 // compatibility. 191 if (!UNSERIALIZE_OPT_SCALAR(_offset)) 192 _offset = 0; 193 194 // We no longer schedule an event here because we may enter KVM 195 // emulation. The event creation is delayed until drainResume(). 196} 197 198DrainState 199ArchTimer::drain() 200{ 201 if (_counterLimitReachedEvent.scheduled()) 202 _parent.deschedule(_counterLimitReachedEvent); 203 204 return DrainState::Drained; 205} 206 207void 208ArchTimer::drainResume() 209{ 210 updateCounter(); 211} 212 213void 214ArchTimer::Interrupt::send() 215{ 216 if (_ppi) { 217 _gic.sendPPInt(_irq, _cpu); 218 } else { 219 _gic.sendInt(_irq); 220 } 221} 222 223 224void 225ArchTimer::Interrupt::clear() 226{ 227 if (_ppi) { 228 _gic.clearPPInt(_irq, _cpu); 229 } else { 230 _gic.clearInt(_irq); 231 } 232} 233 234 235GenericTimer::GenericTimer(GenericTimerParams *p) 236 : SimObject(p), 237 gic(p->gic), 238 irqPhys(p->int_phys), 239 irqVirt(p->int_virt) 240{ 241 fatal_if(!p->system, "No system specified, can't instantiate timer.\n"); 242 p->system->setGenericTimer(this); 243} 244 245void 246GenericTimer::serialize(CheckpointOut &cp) const 247{ 248 paramOut(cp, "cpu_count", timers.size()); 249 250 systemCounter.serializeSection(cp, "sys_counter"); 251 252 for (int i = 0; i < timers.size(); ++i) { 253 const CoreTimers &core(*timers[i]); 254 255 // This should really be phys_timerN, but we are stuck with 256 // arch_timer for backwards compatibility. 257 core.phys.serializeSection(cp, csprintf("arch_timer%d", i)); 258 core.virt.serializeSection(cp, csprintf("virt_timer%d", i)); 259 } 260} 261 262void 263GenericTimer::unserialize(CheckpointIn &cp) 264{ 265 systemCounter.unserializeSection(cp, "sys_counter"); 266 267 // Try to unserialize the CPU count. Old versions of the timer 268 // model assumed a 8 CPUs, so we fall back to that if the field 269 // isn't present. 270 static const unsigned OLD_CPU_MAX = 8; 271 unsigned cpu_count; 272 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) { 273 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n", 274 OLD_CPU_MAX); 275 cpu_count = OLD_CPU_MAX; 276 } 277 278 for (int i = 0; i < cpu_count; ++i) { 279 CoreTimers &core(getTimers(i)); 280 // This should really be phys_timerN, but we are stuck with 281 // arch_timer for backwards compatibility. 282 core.phys.unserializeSection(cp, csprintf("arch_timer%d", i)); 283 core.virt.unserializeSection(cp, csprintf("virt_timer%d", i)); 284 } 285} 286 287 288GenericTimer::CoreTimers & 289GenericTimer::getTimers(int cpu_id) 290{ 291 if (cpu_id >= timers.size()) 292 createTimers(cpu_id + 1); 293 294 return *timers[cpu_id]; 295} 296 297void 298GenericTimer::createTimers(unsigned cpus) 299{ 300 assert(timers.size() < cpus); 301 302 const unsigned old_cpu_count(timers.size()); 303 timers.resize(cpus); 304 for (unsigned i = old_cpu_count; i < cpus; ++i) { 305 timers[i].reset( 306 new CoreTimers(*this, i, irqPhys, irqVirt)); 307 } 308} 309 310 311void 312GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val) 313{ 314 // This method might have been called from another context if we 315 // are running in multi-core KVM. Migrate to the SimObject's event 316 // queue to prevent surprising race conditions. 317 EventQueue::ScopedMigration migrate(eventQueue()); 318 319 CoreTimers &core(getTimers(cpu)); 320 321 switch (reg) { 322 case MISCREG_CNTFRQ: 323 case MISCREG_CNTFRQ_EL0: 324 systemCounter.setFreq(val); 325 return; 326 327 case MISCREG_CNTKCTL: 328 case MISCREG_CNTKCTL_EL1: 329 systemCounter.setKernelControl(val); 330 return; 331 332 // Physical timer 333 case MISCREG_CNTP_CVAL: 334 case MISCREG_CNTP_CVAL_NS: 335 case MISCREG_CNTP_CVAL_EL0: 336 core.phys.setCompareValue(val); 337 return; 338 339 case MISCREG_CNTP_TVAL: 340 case MISCREG_CNTP_TVAL_NS: 341 case MISCREG_CNTP_TVAL_EL0: 342 core.phys.setTimerValue(val); 343 return; 344 345 case MISCREG_CNTP_CTL: 346 case MISCREG_CNTP_CTL_NS: 347 case MISCREG_CNTP_CTL_EL0: 348 core.phys.setControl(val); 349 return; 350 351 // Count registers 352 case MISCREG_CNTPCT: 353 case MISCREG_CNTPCT_EL0: 354 case MISCREG_CNTVCT: 355 case MISCREG_CNTVCT_EL0: 356 warn("Ignoring write to read only count register: %s\n", 357 miscRegName[reg]); 358 return; 359 360 // Virtual timer 361 case MISCREG_CNTVOFF: 362 case MISCREG_CNTVOFF_EL2: 363 core.virt.setOffset(val); 364 return; 365 366 case MISCREG_CNTV_CVAL: 367 case MISCREG_CNTV_CVAL_EL0: 368 core.virt.setCompareValue(val); 369 return; 370 371 case MISCREG_CNTV_TVAL: 372 case MISCREG_CNTV_TVAL_EL0: 373 core.virt.setTimerValue(val); 374 return; 375 376 case MISCREG_CNTV_CTL: 377 case MISCREG_CNTV_CTL_EL0: 378 core.virt.setControl(val); 379 return; 380 381 // PL1 phys. timer, secure 382 case MISCREG_CNTP_CTL_S: 383 case MISCREG_CNTPS_CVAL_EL1: 384 case MISCREG_CNTPS_TVAL_EL1: 385 case MISCREG_CNTPS_CTL_EL1: 386 /* FALLTHROUGH */ 387 388 // PL2 phys. timer, non-secure 389 case MISCREG_CNTHCTL: 390 case MISCREG_CNTHCTL_EL2: 391 case MISCREG_CNTHP_CVAL: 392 case MISCREG_CNTHP_CVAL_EL2: 393 case MISCREG_CNTHP_TVAL: 394 case MISCREG_CNTHP_TVAL_EL2: 395 case MISCREG_CNTHP_CTL: 396 case MISCREG_CNTHP_CTL_EL2: 397 warn("Writing to unimplemented register: %s\n", 398 miscRegName[reg]); 399 return; 400 401 default: 402 warn("Writing to unknown register: %s\n", miscRegName[reg]); 403 return; 404 } 405} 406 407 408MiscReg 409GenericTimer::readMiscReg(int reg, unsigned cpu) 410{ 411 // This method might have been called from another context if we 412 // are running in multi-core KVM. Migrate to the SimObject's event 413 // queue to prevent surprising race conditions. 414 EventQueue::ScopedMigration migrate(eventQueue()); 415 416 CoreTimers &core(getTimers(cpu)); 417 418 switch (reg) { 419 case MISCREG_CNTFRQ: 420 case MISCREG_CNTFRQ_EL0: 421 return systemCounter.freq(); 422 423 case MISCREG_CNTKCTL: 424 case MISCREG_CNTKCTL_EL1: 425 return systemCounter.getKernelControl(); 426 427 // Physical timer 428 case MISCREG_CNTP_CVAL: 429 case MISCREG_CNTP_CVAL_EL0: 430 return core.phys.compareValue(); 431 432 case MISCREG_CNTP_TVAL: 433 case MISCREG_CNTP_TVAL_EL0: 434 return core.phys.timerValue(); 435 436 case MISCREG_CNTP_CTL: 437 case MISCREG_CNTP_CTL_EL0: 438 case MISCREG_CNTP_CTL_NS: 439 return core.phys.control(); 440 441 case MISCREG_CNTPCT: 442 case MISCREG_CNTPCT_EL0: 443 return core.phys.value(); 444 445 446 // Virtual timer 447 case MISCREG_CNTVCT: 448 case MISCREG_CNTVCT_EL0: 449 return core.virt.value(); 450 451 case MISCREG_CNTVOFF: 452 case MISCREG_CNTVOFF_EL2: 453 return core.virt.offset(); 454 455 case MISCREG_CNTV_CVAL: 456 case MISCREG_CNTV_CVAL_EL0: 457 return core.virt.compareValue(); 458 459 case MISCREG_CNTV_TVAL: 460 case MISCREG_CNTV_TVAL_EL0: 461 return core.virt.timerValue(); 462 463 case MISCREG_CNTV_CTL: 464 case MISCREG_CNTV_CTL_EL0: 465 return core.virt.control(); 466 467 // PL1 phys. timer, secure 468 case MISCREG_CNTP_CTL_S: 469 case MISCREG_CNTPS_CVAL_EL1: 470 case MISCREG_CNTPS_TVAL_EL1: 471 case MISCREG_CNTPS_CTL_EL1: 472 /* FALLTHROUGH */ 473 474 // PL2 phys. timer, non-secure 475 case MISCREG_CNTHCTL: 476 case MISCREG_CNTHCTL_EL2: 477 case MISCREG_CNTHP_CVAL: 478 case MISCREG_CNTHP_CVAL_EL2: 479 case MISCREG_CNTHP_TVAL: 480 case MISCREG_CNTHP_TVAL_EL2: 481 case MISCREG_CNTHP_CTL: 482 case MISCREG_CNTHP_CTL_EL2: 483 warn("Reading from unimplemented register: %s\n", 484 miscRegName[reg]); 485 return 0; 486 487 488 default: 489 warn("Reading from unknown register: %s\n", miscRegName[reg]); 490 return 0; 491 } 492} 493 494 495 496GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p) 497 : PioDevice(p), 498 ctrlRange(RangeSize(p->base, TheISA::PageBytes)), 499 timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)), 500 addrRanges{ctrlRange, timerRange}, 501 systemCounter(), 502 physTimer(csprintf("%s.phys_timer0", name()), 503 *this, systemCounter, 504 ArchTimer::Interrupt(*p->gic, p->int_phys)), 505 virtTimer(csprintf("%s.virt_timer0", name()), 506 *this, systemCounter, 507 ArchTimer::Interrupt(*p->gic, p->int_virt)) 508{ 509} 510 511void 512GenericTimerMem::serialize(CheckpointOut &cp) const 513{ 514 paramOut(cp, "timer_count", 1); 515 516 systemCounter.serializeSection(cp, "sys_counter"); 517 518 physTimer.serializeSection(cp, "phys_timer0"); 519 virtTimer.serializeSection(cp, "virt_timer0"); 520} 521 522void 523GenericTimerMem::unserialize(CheckpointIn &cp) 524{ 525 systemCounter.unserializeSection(cp, "sys_counter"); 526 527 unsigned timer_count; 528 UNSERIALIZE_SCALAR(timer_count); 529 // The timer count variable is just here for future versions where 530 // we support more than one set of timers. 531 if (timer_count != 1) 532 panic("Incompatible checkpoint: Only one set of timers supported"); 533 534 physTimer.unserializeSection(cp, "phys_timer0"); 535 virtTimer.unserializeSection(cp, "virt_timer0"); 536} 537 538Tick 539GenericTimerMem::read(PacketPtr pkt) 540{ 541 const unsigned size(pkt->getSize()); 542 const Addr addr(pkt->getAddr()); 543 uint64_t value; 544 545 pkt->makeResponse(); 546 if (ctrlRange.contains(addr)) { 547 value = ctrlRead(addr - ctrlRange.start(), size); 548 } else if (timerRange.contains(addr)) { 549 value = timerRead(addr - timerRange.start(), size); 550 } else { 551 panic("Invalid address: 0x%x\n", addr); 552 } 553 554 DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size); 555 556 if (size == 8) { 557 pkt->set<uint64_t>(value); 558 } else if (size == 4) { 559 pkt->set<uint32_t>(value); 560 } else { 561 panic("Unexpected access size: %i\n", size); 562 } 563 564 return 0; 565} 566 567Tick 568GenericTimerMem::write(PacketPtr pkt) 569{ 570 const unsigned size(pkt->getSize()); 571 if (size != 8 && size != 4) 572 panic("Unexpected access size\n"); 573 574 const Addr addr(pkt->getAddr()); 575 const uint64_t value(size == 8 ? 576 pkt->get<uint64_t>() : pkt->get<uint32_t>()); 577 578 DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size); 579 if (ctrlRange.contains(addr)) { 580 ctrlWrite(addr - ctrlRange.start(), size, value); 581 } else if (timerRange.contains(addr)) { 582 timerWrite(addr - timerRange.start(), size, value); 583 } else { 584 panic("Invalid address: 0x%x\n", addr); 585 } 586 587 pkt->makeResponse(); 588 return 0; 589} 590 591uint64_t 592GenericTimerMem::ctrlRead(Addr addr, size_t size) const 593{ 594 if (size == 4) { 595 switch (addr) { 596 case CTRL_CNTFRQ: 597 return systemCounter.freq(); 598 599 case CTRL_CNTTIDR: 600 return 0x3; // Frame 0 implemented with virtual timers 601 602 case CTRL_CNTNSAR: 603 case CTRL_CNTACR_BASE: 604 warn("Reading from unimplemented control register (0x%x)\n", addr); 605 return 0; 606 607 case CTRL_CNTVOFF_LO_BASE: 608 return virtTimer.offset(); 609 610 case CTRL_CNTVOFF_HI_BASE: 611 return virtTimer.offset() >> 32; 612 613 default: 614 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 615 return 0; 616 } 617 } else if (size == 8) { 618 switch (addr) { 619 case CTRL_CNTVOFF_LO_BASE: 620 return virtTimer.offset(); 621 622 default: 623 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 624 return 0; 625 } 626 } else { 627 panic("Invalid access size: %i\n", size); 628 } 629} 630 631void 632GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value) 633{ 634 if (size == 4) { 635 switch (addr) { 636 case CTRL_CNTFRQ: 637 case CTRL_CNTNSAR: 638 case CTRL_CNTTIDR: 639 case CTRL_CNTACR_BASE: 640 warn("Write to unimplemented control register (0x%x)\n", addr); 641 return; 642 643 case CTRL_CNTVOFF_LO_BASE: 644 virtTimer.setOffset( 645 insertBits(virtTimer.offset(), 31, 0, value)); 646 return; 647 648 case CTRL_CNTVOFF_HI_BASE: 649 virtTimer.setOffset( 650 insertBits(virtTimer.offset(), 63, 32, value)); 651 return; 652 653 default: 654 warn("Ignoring write to unexpected address (0x%x:%i)\n", 655 addr, size); 656 return; 657 } 658 } else if (size == 8) { 659 switch (addr) { 660 case CTRL_CNTVOFF_LO_BASE: 661 virtTimer.setOffset(value); 662 return; 663 664 default: 665 warn("Ignoring write to unexpected address (0x%x:%i)\n", 666 addr, size); 667 return; 668 } 669 } else { 670 panic("Invalid access size: %i\n", size); 671 } 672} 673 674uint64_t 675GenericTimerMem::timerRead(Addr addr, size_t size) const 676{ 677 if (size == 4) { 678 switch (addr) { 679 case TIMER_CNTPCT_LO: 680 return physTimer.value(); 681 682 case TIMER_CNTPCT_HI: 683 return physTimer.value() >> 32; 684 685 case TIMER_CNTVCT_LO: 686 return virtTimer.value(); 687 688 case TIMER_CNTVCT_HI: 689 return virtTimer.value() >> 32; 690 691 case TIMER_CNTFRQ: 692 return systemCounter.freq(); 693 694 case TIMER_CNTEL0ACR: 695 warn("Read from unimplemented timer register (0x%x)\n", addr); 696 return 0; 697 698 case CTRL_CNTVOFF_LO_BASE: 699 return virtTimer.offset(); 700 701 case CTRL_CNTVOFF_HI_BASE: 702 return virtTimer.offset() >> 32; 703 704 case TIMER_CNTP_CVAL_LO: 705 return physTimer.compareValue(); 706 707 case TIMER_CNTP_CVAL_HI: 708 return physTimer.compareValue() >> 32; 709 710 case TIMER_CNTP_TVAL: 711 return physTimer.timerValue(); 712 713 case TIMER_CNTP_CTL: 714 return physTimer.control(); 715 716 case TIMER_CNTV_CVAL_LO: 717 return virtTimer.compareValue(); 718 719 case TIMER_CNTV_CVAL_HI: 720 return virtTimer.compareValue() >> 32; 721 722 case TIMER_CNTV_TVAL: 723 return virtTimer.timerValue(); 724 725 case TIMER_CNTV_CTL: 726 return virtTimer.control(); 727 728 default: 729 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 730 return 0; 731 } 732 } else if (size == 8) { 733 switch (addr) { 734 case TIMER_CNTPCT_LO: 735 return physTimer.value(); 736 737 case TIMER_CNTVCT_LO: 738 return virtTimer.value(); 739 740 case CTRL_CNTVOFF_LO_BASE: 741 return virtTimer.offset(); 742 743 case TIMER_CNTP_CVAL_LO: 744 return physTimer.compareValue(); 745 746 case TIMER_CNTV_CVAL_LO: 747 return virtTimer.compareValue(); 748 749 default: 750 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size); 751 return 0; 752 } 753 } else { 754 panic("Invalid access size: %i\n", size); 755 } 756} 757 758void 759GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value) 760{ 761 if (size == 4) { 762 switch (addr) { 763 case TIMER_CNTEL0ACR: 764 warn("Unimplemented timer register (0x%x)\n", addr); 765 return; 766 767 case TIMER_CNTP_CVAL_LO: 768 physTimer.setCompareValue( 769 insertBits(physTimer.compareValue(), 31, 0, value)); 770 return; 771 772 case TIMER_CNTP_CVAL_HI: 773 physTimer.setCompareValue( 774 insertBits(physTimer.compareValue(), 63, 32, value)); 775 return; 776 777 case TIMER_CNTP_TVAL: 778 physTimer.setTimerValue(value); 779 return; 780 781 case TIMER_CNTP_CTL: 782 physTimer.setControl(value); 783 return; 784 785 case TIMER_CNTV_CVAL_LO: 786 virtTimer.setCompareValue( 787 insertBits(virtTimer.compareValue(), 31, 0, value)); 788 return; 789 790 case TIMER_CNTV_CVAL_HI: 791 virtTimer.setCompareValue( 792 insertBits(virtTimer.compareValue(), 63, 32, value)); 793 return; 794 795 case TIMER_CNTV_TVAL: 796 virtTimer.setTimerValue(value); 797 return; 798 799 case TIMER_CNTV_CTL: 800 virtTimer.setControl(value); 801 return; 802 803 default: 804 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size); 805 return; 806 } 807 } else if (size == 8) { 808 switch (addr) { 809 case TIMER_CNTP_CVAL_LO: 810 return physTimer.setCompareValue(value); 811 812 case TIMER_CNTV_CVAL_LO: 813 return virtTimer.setCompareValue(value); 814 815 default: 816 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size); 817 return; 818 } 819 } else { 820 panic("Invalid access size: %i\n", size); 821 } 822} 823 824GenericTimer * 825GenericTimerParams::create() 826{ 827 return new GenericTimer(this); 828} 829 830GenericTimerMem * 831GenericTimerMemParams::create() 832{ 833 return new GenericTimerMem(this); 834} 835