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