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