summaryrefslogtreecommitdiff
path: root/src/dev
diff options
context:
space:
mode:
authorCurtis Dunham <Curtis.Dunham@arm.com>2017-05-22 19:22:14 +0000
committerAndreas Sandberg <andreas.sandberg@arm.com>2017-07-05 14:24:03 +0000
commite1c8c1f8603672823c89e5ed4c98502350c600d6 (patch)
tree8d8c921888ab7eaaeb9a14be6e0ec51445689854 /src/dev
parente2a049e089b4878d6abd8e816973b175e2be2d7c (diff)
downloadgem5-e1c8c1f8603672823c89e5ed4c98502350c600d6.tar.xz
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 <andreas.sandberg@arm.com> Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Diffstat (limited to 'src/dev')
-rw-r--r--src/dev/arm/generic_timer.cc21
-rw-r--r--src/dev/arm/generic_timer.hh38
2 files changed, 47 insertions, 12 deletions
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<std::unique_ptr<CoreTimers>> timers;
protected: // Configuration
+ /// ARM system containing this timer
+ ArmSystem &system;
+
/// Pointer to the GIC, needed to trigger timer interrupts.
BaseGic *const gic;