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 ArmInterruptPin *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->raise(); 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 222GenericTimer::GenericTimer(GenericTimerParams *p) 223 : ClockedObject(p), 224 system(*p->system) 225{ 226 fatal_if(!p->system, "No system specified, can't instantiate timer.\n"); 227 system.setGenericTimer(this); 228} 229 230const GenericTimerParams * 231GenericTimer::params() const 232{ 233 return dynamic_cast<const GenericTimerParams *>(_params); 234} 235 236void 237GenericTimer::serialize(CheckpointOut &cp) const 238{ 239 paramOut(cp, "cpu_count", timers.size()); 240 241 systemCounter.serializeSection(cp, "sys_counter"); 242 243 for (int i = 0; i < timers.size(); ++i) { 244 const CoreTimers &core(*timers[i]); 245 246 // This should really be phys_timerN, but we are stuck with 247 // arch_timer for backwards compatibility. 248 core.physNS.serializeSection(cp, csprintf("arch_timer%d", i)); 249 core.physS.serializeSection(cp, csprintf("phys_s_timer%d", i)); 250 core.virt.serializeSection(cp, csprintf("virt_timer%d", i)); 251 core.hyp.serializeSection(cp, csprintf("hyp_timer%d", i)); 252 } 253} 254 255void 256GenericTimer::unserialize(CheckpointIn &cp) 257{ 258 systemCounter.unserializeSection(cp, "sys_counter"); 259 260 // Try to unserialize the CPU count. Old versions of the timer 261 // model assumed a 8 CPUs, so we fall back to that if the field 262 // isn't present. 263 static const unsigned OLD_CPU_MAX = 8; 264 unsigned cpu_count; 265 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) { 266 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n", 267 OLD_CPU_MAX); 268 cpu_count = OLD_CPU_MAX; 269 } 270 271 for (int i = 0; i < cpu_count; ++i) { 272 CoreTimers &core(getTimers(i)); 273 // This should really be phys_timerN, but we are stuck with 274 // arch_timer for backwards compatibility. 275 core.physNS.unserializeSection(cp, csprintf("arch_timer%d", i)); 276 core.physS.unserializeSection(cp, csprintf("phys_s_timer%d", i)); 277 core.virt.unserializeSection(cp, csprintf("virt_timer%d", i)); 278 core.hyp.unserializeSection(cp, csprintf("hyp_timer%d", i)); 279 } 280} 281 282 283GenericTimer::CoreTimers & 284GenericTimer::getTimers(int cpu_id) 285{ 286 if (cpu_id >= timers.size()) 287 createTimers(cpu_id + 1); 288 289 return *timers[cpu_id]; 290} 291 292void 293GenericTimer::createTimers(unsigned cpus) 294{ 295 assert(timers.size() < cpus); 296 auto p = static_cast<const GenericTimerParams *>(_params); 297 298 const unsigned old_cpu_count(timers.size()); 299 timers.resize(cpus); 300 for (unsigned i = old_cpu_count; i < cpus; ++i) { 301 302 ThreadContext *tc = system.getThreadContext(i); 303 304 timers[i].reset( 305 new CoreTimers(*this, system, i, 306 p->int_phys_s->get(tc), 307 p->int_phys_ns->get(tc), 308 p->int_virt->get(tc), 309 p->int_hyp->get(tc))); 310 } 311} 312 313 314void 315GenericTimer::setMiscReg(int reg, unsigned cpu, RegVal val) 316{ 317 CoreTimers &core(getTimers(cpu)); 318 319 switch (reg) { 320 case MISCREG_CNTFRQ: 321 case MISCREG_CNTFRQ_EL0: 322 systemCounter.setFreq(val); 323 return; 324 325 case MISCREG_CNTKCTL: 326 case MISCREG_CNTKCTL_EL1: 327 systemCounter.setKernelControl(val); 328 return; 329 330 case MISCREG_CNTHCTL: 331 case MISCREG_CNTHCTL_EL2: 332 systemCounter.setHypControl(val); 333 return; 334 335 // Physical timer (NS) 336 case MISCREG_CNTP_CVAL_NS: 337 case MISCREG_CNTP_CVAL_EL0: 338 core.physNS.setCompareValue(val); 339 return; 340 341 case MISCREG_CNTP_TVAL_NS: 342 case MISCREG_CNTP_TVAL_EL0: 343 core.physNS.setTimerValue(val); 344 return; 345 346 case MISCREG_CNTP_CTL_NS: 347 case MISCREG_CNTP_CTL_EL0: 348 core.physNS.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 // Physical timer (S) 382 case MISCREG_CNTP_CTL_S: 383 case MISCREG_CNTPS_CTL_EL1: 384 core.physS.setControl(val); 385 return; 386 387 case MISCREG_CNTP_CVAL_S: 388 case MISCREG_CNTPS_CVAL_EL1: 389 core.physS.setCompareValue(val); 390 return; 391 392 case MISCREG_CNTP_TVAL_S: 393 case MISCREG_CNTPS_TVAL_EL1: 394 core.physS.setTimerValue(val); 395 return; 396 397 // Hyp phys. timer, non-secure 398 case MISCREG_CNTHP_CTL: 399 case MISCREG_CNTHP_CTL_EL2: 400 core.hyp.setControl(val); 401 return; 402 403 case MISCREG_CNTHP_CVAL: 404 case MISCREG_CNTHP_CVAL_EL2: 405 core.hyp.setCompareValue(val); 406 return; 407 408 case MISCREG_CNTHP_TVAL: 409 case MISCREG_CNTHP_TVAL_EL2: 410 core.hyp.setTimerValue(val); 411 return; 412 413 default: 414 warn("Writing to unknown register: %s\n", miscRegName[reg]); 415 return; 416 } 417} 418 419 420RegVal 421GenericTimer::readMiscReg(int reg, unsigned cpu) 422{ 423 CoreTimers &core(getTimers(cpu)); 424 425 switch (reg) { 426 case MISCREG_CNTFRQ: 427 case MISCREG_CNTFRQ_EL0: 428 return systemCounter.freq(); 429 430 case MISCREG_CNTKCTL: 431 case MISCREG_CNTKCTL_EL1: 432 return systemCounter.getKernelControl(); 433 434 case MISCREG_CNTHCTL: 435 case MISCREG_CNTHCTL_EL2: 436 return systemCounter.getHypControl(); 437 438 // Physical timer 439 case MISCREG_CNTP_CVAL_NS: 440 case MISCREG_CNTP_CVAL_EL0: 441 return core.physNS.compareValue(); 442 443 case MISCREG_CNTP_TVAL_NS: 444 case MISCREG_CNTP_TVAL_EL0: 445 return core.physNS.timerValue(); 446 447 case MISCREG_CNTP_CTL_EL0: 448 case MISCREG_CNTP_CTL_NS: 449 return core.physNS.control(); 450 451 case MISCREG_CNTPCT: 452 case MISCREG_CNTPCT_EL0: 453 return core.physNS.value(); 454 455 456 // Virtual timer 457 case MISCREG_CNTVCT: 458 case MISCREG_CNTVCT_EL0: 459 return core.virt.value(); 460 461 case MISCREG_CNTVOFF: 462 case MISCREG_CNTVOFF_EL2: 463 return core.virt.offset(); 464 465 case MISCREG_CNTV_CVAL: 466 case MISCREG_CNTV_CVAL_EL0: 467 return core.virt.compareValue(); 468 469 case MISCREG_CNTV_TVAL: 470 case MISCREG_CNTV_TVAL_EL0: 471 return core.virt.timerValue(); 472 473 case MISCREG_CNTV_CTL: 474 case MISCREG_CNTV_CTL_EL0: 475 return core.virt.control(); 476 477 // PL1 phys. timer, secure 478 case MISCREG_CNTP_CTL_S: 479 case MISCREG_CNTPS_CTL_EL1: 480 return core.physS.control(); 481 482 case MISCREG_CNTP_CVAL_S: 483 case MISCREG_CNTPS_CVAL_EL1: 484 return core.physS.compareValue(); 485 486 case MISCREG_CNTP_TVAL_S: 487 case MISCREG_CNTPS_TVAL_EL1: 488 return core.physS.timerValue(); 489 490 // HYP phys. timer (NS) 491 case MISCREG_CNTHP_CTL: 492 case MISCREG_CNTHP_CTL_EL2: 493 return core.hyp.control(); 494 495 case MISCREG_CNTHP_CVAL: 496 case MISCREG_CNTHP_CVAL_EL2: 497 return core.hyp.compareValue(); 498 499 case MISCREG_CNTHP_TVAL: 500 case MISCREG_CNTHP_TVAL_EL2: 501 return core.hyp.timerValue(); 502 503 default: 504 warn("Reading from unknown register: %s\n", miscRegName[reg]); 505 return 0; 506 } 507} 508 509 510void 511GenericTimerISA::setMiscReg(int reg, RegVal val) 512{ 513 DPRINTF(Timer, "Setting %s := 0x%x\n", miscRegName[reg], val); 514 parent.setMiscReg(reg, cpu, val); 515} 516 517RegVal 518GenericTimerISA::readMiscReg(int reg) 519{ 520 RegVal value = parent.readMiscReg(reg, cpu); 521 DPRINTF(Timer, "Reading %s as 0x%x\n", miscRegName[reg], value); 522 return value; 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 p->int_phys->get()), 534 virtTimer(csprintf("%s.virt_timer0", name()), 535 *this, systemCounter, 536 p->int_virt->get()) 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->setLE<uint64_t>(value); 587 } else if (size == 4) { 588 pkt->setLE<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->getLE<uint64_t>() : pkt->getLE<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