/*
- * Copyright (c) 2013, 2015 ARM Limited
+ * Copyright (c) 2013, 2015, 2017 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
: _name(name), _parent(parent), _systemCounter(sysctr),
_interrupt(interrupt),
_control(0), _counterLimit(0), _offset(0),
- _counterLimitReachedEvent(this)
+ _counterLimitReachedEvent([this]{ counterLimitReached(); }, name)
{
}
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");
+ }
}
}
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);
+ }
}
}
paramOut(cp, "control_serial", _control);
SERIALIZE_SCALAR(_counterLimit);
SERIALIZE_SCALAR(_offset);
-
- const bool event_scheduled(_counterLimitReachedEvent.scheduled());
- SERIALIZE_SCALAR(event_scheduled);
- if (event_scheduled) {
- const Tick event_time(_counterLimitReachedEvent.when());
- SERIALIZE_SCALAR(event_time);
- }
}
void
// compatibility.
if (!UNSERIALIZE_OPT_SCALAR(_offset))
_offset = 0;
- bool event_scheduled;
- UNSERIALIZE_SCALAR(event_scheduled);
- if (event_scheduled) {
- Tick event_time;
- UNSERIALIZE_SCALAR(event_time);
- _parent.schedule(_counterLimitReachedEvent, event_time);
- }
+
+ // We no longer schedule an event here because we may enter KVM
+ // emulation. The event creation is delayed until drainResume().
+}
+
+DrainState
+ArchTimer::drain()
+{
+ if (_counterLimitReachedEvent.scheduled())
+ _parent.deschedule(_counterLimitReachedEvent);
+
+ return DrainState::Drained;
+}
+
+void
+ArchTimer::drainResume()
+{
+ updateCounter();
}
void
GenericTimer::GenericTimer(GenericTimerParams *p)
: SimObject(p),
+ system(*p->system),
gic(p->gic),
irqPhys(p->int_phys),
irqVirt(p->int_virt)
{
- dynamic_cast<ArmSystem &>(*p->system).setGenericTimer(this);
+ fatal_if(!p->system, "No system specified, can't instantiate timer.\n");
+ system.setGenericTimer(this);
}
void
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));
}
}
void
GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
{
+ // This method might have been called from another context if we
+ // are running in multi-core KVM. Migrate to the SimObject's event
+ // queue to prevent surprising race conditions.
+ EventQueue::ScopedMigration migrate(eventQueue());
+
CoreTimers &core(getTimers(cpu));
switch (reg) {
MiscReg
GenericTimer::readMiscReg(int reg, unsigned cpu)
{
+ // This method might have been called from another context if we
+ // are running in multi-core KVM. Migrate to the SimObject's event
+ // queue to prevent surprising race conditions.
+ EventQueue::ScopedMigration migrate(eventQueue());
+
CoreTimers &core(getTimers(cpu));
switch (reg) {