// MISCREG_CNTP_CTL_S
bitset<NUM_MISCREG_INFOS>(string("00110011001111100000")),
// MISCREG_CNTV_TVAL
- bitset<NUM_MISCREG_INFOS>(string("01111000000000000000")),
+ bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_CNTV_CTL
- bitset<NUM_MISCREG_INFOS>(string("01111000000000000000")),
+ bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_CNTHCTL
bitset<NUM_MISCREG_INFOS>(string("01001000000000000000")),
// MISCREG_CNTHP_TVAL
// MISCREG_CNTP_CVAL_S
bitset<NUM_MISCREG_INFOS>(string("00110011001111100000")),
// MISCREG_CNTV_CVAL
- bitset<NUM_MISCREG_INFOS>(string("01111000000000000000")),
+ bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_CNTVOFF
bitset<NUM_MISCREG_INFOS>(string("11001100000000000001")),
// MISCREG_CNTHP_CVAL
// MISCREG_CNTP_CVAL_EL0
bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_CNTV_TVAL_EL0
- bitset<NUM_MISCREG_INFOS>(string("01111000000000000000")),
+ bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_CNTV_CTL_EL0
- bitset<NUM_MISCREG_INFOS>(string("01111000000000000000")),
+ bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_CNTV_CVAL_EL0
- bitset<NUM_MISCREG_INFOS>(string("01111000000000000000")),
+ bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_PMEVCNTR0_EL0
bitset<NUM_MISCREG_INFOS>(string("11111111111111000001")),
// MISCREG_PMEVCNTR1_EL0
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'
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)
const Interrupt &interrupt)
: _name(name), _parent(parent), _systemCounter(sysctr),
_interrupt(interrupt),
- _control(0), _counterLimit(0),
+ _control(0), _counterLimit(0), _offset(0),
_counterLimitReachedEvent(this)
{
}
_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
{
paramOut(os, "control_serial", _control);
SERIALIZE_SCALAR(_counterLimit);
+ SERIALIZE_SCALAR(_offset);
const bool event_scheduled(_counterLimitReachedEvent.scheduled());
SERIALIZE_SCALAR(event_scheduled);
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) {
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);
}
nameOut(os, core.phys.name());
core.phys.serialize(os);
+
+ nameOut(os, core.virt.name());
+ core.virt.serialize(os);
}
}
// 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));
}
}
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));
}
}
// 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:
// 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:
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
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;
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
/// Physical timer interrupt
const unsigned irqPhys;
+
+ /// Virtual timer interrupt
+ const unsigned irqVirt;
};
class GenericTimerISA : public ArmISA::BaseISADevice