diff options
Diffstat (limited to 'src/dev')
-rw-r--r-- | src/dev/arm/RealView.py | 9 | ||||
-rw-r--r-- | src/dev/arm/generic_timer.cc | 50 | ||||
-rw-r--r-- | src/dev/arm/generic_timer.hh | 19 |
3 files changed, 63 insertions, 15 deletions
diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py index 2e58c8fa6..2d5ccc3f9 100644 --- a/src/dev/arm/RealView.py +++ b/src/dev/arm/RealView.py @@ -136,9 +136,10 @@ class GenericTimer(SimObject): cxx_header = "dev/arm/generic_timer.hh" system = Param.System(Parent.any, "system") gic = Param.BaseGic(Parent.any, "GIC to use for interrupting") - int_phys = Param.UInt32("Interrupt number used per-cpu to GIC") - # @todo: for now only one timer per CPU is supported, which is the - # normal behaviour when Security and Virt. extensions are disabled. + # @todo: for now only two timers per CPU is supported, which is the + # normal behaviour when security extensions are disabled. + int_phys = Param.UInt32("Physical timer interrupt number") + int_virt = Param.UInt32("Virtual timer interrupt number") class PL031(AmbaIntDevice): type = 'PL031' @@ -457,7 +458,7 @@ class VExpress_EMM(RealView): idreg=0x02250000, pio_addr=0x1C010000) gic = Pl390(dist_addr=0x2C001000, cpu_addr=0x2C002000) local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x2C080000) - generic_timer = GenericTimer(int_phys=29) + generic_timer = GenericTimer(int_phys=29, int_virt=27) timer0 = Sp804(int_num0=34, int_num1=34, pio_addr=0x1C110000, clock0='1MHz', clock1='1MHz') timer1 = Sp804(int_num0=35, int_num1=35, pio_addr=0x1C120000, clock0='1MHz', clock1='1MHz') clcd = Pl111(pio_addr=0x1c1f0000, int_num=46) diff --git a/src/dev/arm/generic_timer.cc b/src/dev/arm/generic_timer.cc index 642205704..1ff91d50b 100644 --- a/src/dev/arm/generic_timer.cc +++ b/src/dev/arm/generic_timer.cc @@ -93,7 +93,7 @@ ArchTimer::ArchTimer(const std::string &name, const Interrupt &interrupt) : _name(name), _parent(parent), _systemCounter(sysctr), _interrupt(interrupt), - _control(0), _counterLimit(0), + _control(0), _counterLimit(0), _offset(0), _counterLimitReachedEvent(this) { } @@ -159,10 +159,17 @@ ArchTimer::setControl(uint32_t val) _control.imask = new_ctl.imask; } +void +ArchTimer::setOffset(uint64_t val) +{ + _offset = val; + updateCounter(); +} + uint64_t ArchTimer::value() const { - return _systemCounter.value(); + return _systemCounter.value() - _offset; } void @@ -170,6 +177,7 @@ ArchTimer::serialize(std::ostream &os) const { paramOut(os, "control_serial", _control); SERIALIZE_SCALAR(_counterLimit); + SERIALIZE_SCALAR(_offset); const bool event_scheduled(_counterLimitReachedEvent.scheduled()); SERIALIZE_SCALAR(event_scheduled); @@ -184,6 +192,11 @@ ArchTimer::unserialize(Checkpoint *cp, const std::string §ion) { paramIn(cp, section, "control_serial", _control); + // We didn't serialize an offset before we added support for the + // virtual timer. Consider it optional to maintain backwards + // compatibility. + if (!UNSERIALIZE_OPT_SCALAR(_offset)) + _offset = 0; bool event_scheduled; UNSERIALIZE_SCALAR(event_scheduled); if (event_scheduled) { @@ -218,7 +231,8 @@ ArchTimer::Interrupt::clear() GenericTimer::GenericTimer(GenericTimerParams *p) : SimObject(p), gic(p->gic), - irqPhys(p->int_phys) + irqPhys(p->int_phys), + irqVirt(p->int_virt) { dynamic_cast<ArmSystem &>(*p->system).setGenericTimer(this); } @@ -236,6 +250,9 @@ GenericTimer::serialize(std::ostream &os) nameOut(os, core.phys.name()); core.phys.serialize(os); + + nameOut(os, core.virt.name()); + core.virt.serialize(os); } } @@ -260,6 +277,7 @@ GenericTimer::unserialize(Checkpoint *cp, const std::string §ion) // This should really be phys_timerN, but we are stuck with // arch_timer for backwards compatibility. core.phys.unserialize(cp, csprintf("%s.arch_timer%d", section, i)); + core.virt.unserialize(cp, csprintf("%s.virt_timer%d", section, i)); } } @@ -282,7 +300,7 @@ GenericTimer::createTimers(unsigned cpus) timers.resize(cpus); for (unsigned i = old_cpu_count; i < cpus; ++i) { timers[i].reset( - new CoreTimers(*this, i, irqPhys)); + new CoreTimers(*this, i, irqPhys, irqVirt)); } } @@ -334,13 +352,23 @@ GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val) // Virtual timer case MISCREG_CNTVOFF: case MISCREG_CNTVOFF_EL2: + core.virt.setOffset(val); + return; + case MISCREG_CNTV_CVAL: case MISCREG_CNTV_CVAL_EL0: + core.virt.setCompareValue(val); + return; + case MISCREG_CNTV_TVAL: case MISCREG_CNTV_TVAL_EL0: + core.virt.setTimerValue(val); + return; + case MISCREG_CNTV_CTL: case MISCREG_CNTV_CTL_EL0: - /* FALLTHROUGH */ + core.virt.setControl(val); + return; // PL1 phys. timer, secure case MISCREG_CNTP_CTL_S: @@ -405,19 +433,23 @@ GenericTimer::readMiscReg(int reg, unsigned cpu) // Virtual timer case MISCREG_CNTVCT: case MISCREG_CNTVCT_EL0: - warn_once("Virtual timer not implemented, " - "returning physical timer value\n"); - return core.phys.value(); + return core.virt.value(); case MISCREG_CNTVOFF: case MISCREG_CNTVOFF_EL2: + return core.virt.offset(); + case MISCREG_CNTV_CVAL: case MISCREG_CNTV_CVAL_EL0: + return core.virt.compareValue(); + case MISCREG_CNTV_TVAL: case MISCREG_CNTV_TVAL_EL0: + return core.virt.timerValue(); + case MISCREG_CNTV_CTL: case MISCREG_CNTV_CTL_EL0: - /* FALLTHROUGH */ + return core.virt.control(); // PL1 phys. timer, secure case MISCREG_CNTP_CTL_S: diff --git a/src/dev/arm/generic_timer.hh b/src/dev/arm/generic_timer.hh index 8dc921275..7e6bd2af3 100644 --- a/src/dev/arm/generic_timer.hh +++ b/src/dev/arm/generic_timer.hh @@ -145,6 +145,8 @@ class ArchTimer ArchTimerCtrl _control; /// Programmed limit value for the upcounter ({CNTP/CNTHP/CNTV}_CVAL). uint64_t _counterLimit; + /// Offset relative to the physical timer (CNTVOFF) + uint64_t _offset; /** * Timer settings or the offset has changed, re-evaluate @@ -180,6 +182,9 @@ class ArchTimer uint32_t control() const { return _control; } void setControl(uint32_t val); + uint64_t offset() const { return _offset; } + void setOffset(uint64_t val); + /// Returns the value of the counter which this timer relies on. uint64_t value() const; @@ -206,17 +211,24 @@ class GenericTimer : public SimObject protected: struct CoreTimers { CoreTimers(GenericTimer &parent, unsigned cpu, - unsigned _irqPhys) + unsigned _irqPhys, unsigned _irqVirt) : irqPhys(*parent.gic, _irqPhys, cpu), + irqVirt(*parent.gic, _irqVirt, cpu), // This should really be phys_timerN, but we are stuck with // arch_timer for backwards compatibility. phys(csprintf("%s.arch_timer%d", parent.name(), cpu), parent, parent.systemCounter, - irqPhys) + irqPhys), + virt(csprintf("%s.virt_timer%d", parent.name(), cpu), + parent, parent.systemCounter, + irqVirt) {} ArchTimer::Interrupt irqPhys; + ArchTimer::Interrupt irqVirt; + ArchTimer phys; + ArchTimer virt; private: // Disable copying @@ -238,6 +250,9 @@ class GenericTimer : public SimObject /// Physical timer interrupt const unsigned irqPhys; + + /// Virtual timer interrupt + const unsigned irqVirt; }; class GenericTimerISA : public ArmISA::BaseISADevice |