From e1c8c1f8603672823c89e5ed4c98502350c600d6 Mon Sep 17 00:00:00 2001 From: Curtis Dunham Date: Mon, 22 May 2017 19:22:14 +0000 Subject: dev,arm: add Kvm mode of operation for CP15 timer The timer device exposed via the ARM ISA, also known as the "CP15 timer" due to its legacy coprocessor encodings, is implemented by the GenericTimerISA class. During Kvm execution, however, this functionality is directly emulated by the hardware. This commit subclasses the GenericTimer, which is (solely) used by GenericTimerISA, to facilitate Kvm in much the same way as the prior GIC changes: the gem5 model is used as the backing store for state, so checkpointing and CPU switching work correctly, but isn't used during Kvm execution. The added indirection prevents the timer device from creating events when we're just updating its state, but not actually using it for simulation. Change-Id: I427540d11ccf049c334afe318f575146aa888672 Reviewed-on: https://gem5-review.googlesource.com/3542 Reviewed-by: Andreas Sandberg Maintainer: Andreas Sandberg --- src/dev/arm/generic_timer.cc | 21 ++++++++++++++------- src/dev/arm/generic_timer.hh | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 12 deletions(-) (limited to 'src/dev/arm') diff --git a/src/dev/arm/generic_timer.cc b/src/dev/arm/generic_timer.cc index 48f70e135..6332b8f4d 100644 --- a/src/dev/arm/generic_timer.cc +++ b/src/dev/arm/generic_timer.cc @@ -109,8 +109,12 @@ ArchTimer::counterLimitReached() DPRINTF(Timer, "Counter limit reached\n"); if (!_control.imask) { - DPRINTF(Timer, "Causing interrupt\n"); - _interrupt.send(); + if (scheduleEvents()) { + DPRINTF(Timer, "Causing interrupt\n"); + _interrupt.send(); + } else { + DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n"); + } } } @@ -122,10 +126,12 @@ ArchTimer::updateCounter() if (value() >= _counterLimit) { counterLimitReached(); } else { - const auto period(_systemCounter.period()); _control.istatus = 0; - _parent.schedule(_counterLimitReachedEvent, - curTick() + (_counterLimit - value()) * period); + if (scheduleEvents()) { + const auto period(_systemCounter.period()); + _parent.schedule(_counterLimitReachedEvent, + curTick() + (_counterLimit - value()) * period); + } } } @@ -234,12 +240,13 @@ ArchTimer::Interrupt::clear() GenericTimer::GenericTimer(GenericTimerParams *p) : SimObject(p), + system(*p->system), gic(p->gic), irqPhys(p->int_phys), irqVirt(p->int_virt) { fatal_if(!p->system, "No system specified, can't instantiate timer.\n"); - p->system->setGenericTimer(this); + system.setGenericTimer(this); } void @@ -303,7 +310,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, irqVirt)); + new CoreTimers(*this, system, i, irqPhys, irqVirt)); } } diff --git a/src/dev/arm/generic_timer.hh b/src/dev/arm/generic_timer.hh index 3eec1d42e..ccfb1277f 100644 --- a/src/dev/arm/generic_timer.hh +++ b/src/dev/arm/generic_timer.hh @@ -42,6 +42,7 @@ #define __DEV_ARM_GENERIC_TIMER_HH__ #include "arch/arm/isa_device.hh" +#include "arch/arm/system.hh" #include "base/bitunion.hh" #include "dev/arm/base_gic.hh" #include "sim/core.hh" @@ -159,6 +160,8 @@ class ArchTimer : public Serializable, public Drainable void counterLimitReached(); EventFunctionWrapper _counterLimitReachedEvent; + virtual bool scheduleEvents() { return true; } + public: ArchTimer(const std::string &name, SimObject &parent, @@ -201,6 +204,28 @@ class ArchTimer : public Serializable, public Drainable ArchTimer(const ArchTimer &t); }; +class ArchTimerKvm : public ArchTimer +{ + private: + ArmSystem &system; + + public: + ArchTimerKvm(const std::string &name, + ArmSystem &system, + SimObject &parent, + SystemCounter &sysctr, + const Interrupt &interrupt) + : ArchTimer(name, parent, sysctr, interrupt), system(system) {} + + protected: + // For ArchTimer's in a GenericTimerISA with Kvm execution about + // to begin, skip rescheduling the event. + // Otherwise, we should reschedule the event (if necessary). + bool scheduleEvents() override { + return !system.validKvmEnvironment(); + } +}; + class GenericTimer : public SimObject { public: @@ -215,25 +240,25 @@ class GenericTimer : public SimObject protected: struct CoreTimers { - CoreTimers(GenericTimer &parent, unsigned cpu, + CoreTimers(GenericTimer &parent, ArmSystem &system, unsigned cpu, 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, + system, parent, parent.systemCounter, irqPhys), virt(csprintf("%s.virt_timer%d", parent.name(), cpu), - parent, parent.systemCounter, + system, parent, parent.systemCounter, irqVirt) {} ArchTimer::Interrupt irqPhys; ArchTimer::Interrupt irqVirt; - ArchTimer phys; - ArchTimer virt; + ArchTimerKvm phys; + ArchTimerKvm virt; private: // Disable copying @@ -250,6 +275,9 @@ class GenericTimer : public SimObject std::vector> timers; protected: // Configuration + /// ARM system containing this timer + ArmSystem &system; + /// Pointer to the GIC, needed to trigger timer interrupts. BaseGic *const gic; -- cgit v1.2.3