summaryrefslogtreecommitdiff
path: root/src/dev
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev')
-rw-r--r--src/dev/arm/RealView.py9
-rw-r--r--src/dev/arm/generic_timer.cc50
-rw-r--r--src/dev/arm/generic_timer.hh19
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 &section)
{
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 &section)
// 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