dev, arm: Add support for HYP & secure timers
Change-Id: I1a4849283f9bd5b1856e1378f7cefc33fc14eebd Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-by: Curtis Dunham <curtis.dunham@arm.com> Reviewed-on: https://gem5-review.googlesource.com/10023 Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
This commit is contained in:
@@ -3176,7 +3176,6 @@ ISA::initializeMiscRegMetadata()
|
||||
.privSecure(!aarch32EL3)
|
||||
.monSecure(0);
|
||||
InitReg(MISCREG_CNTP_TVAL_S)
|
||||
.unimplemented()
|
||||
.bankedChild()
|
||||
.secure().user(1);
|
||||
InitReg(MISCREG_CNTP_CTL)
|
||||
@@ -3187,7 +3186,6 @@ ISA::initializeMiscRegMetadata()
|
||||
.privSecure(!aarch32EL3)
|
||||
.monSecure(0);
|
||||
InitReg(MISCREG_CNTP_CTL_S)
|
||||
.unimplemented()
|
||||
.bankedChild()
|
||||
.secure().user(1);
|
||||
InitReg(MISCREG_CNTV_TVAL)
|
||||
@@ -3195,13 +3193,10 @@ ISA::initializeMiscRegMetadata()
|
||||
InitReg(MISCREG_CNTV_CTL)
|
||||
.allPrivileges();
|
||||
InitReg(MISCREG_CNTHCTL)
|
||||
.unimplemented()
|
||||
.hypWrite().monNonSecureRead();
|
||||
InitReg(MISCREG_CNTHP_TVAL)
|
||||
.unimplemented()
|
||||
.hypWrite().monNonSecureRead();
|
||||
InitReg(MISCREG_CNTHP_CTL)
|
||||
.unimplemented()
|
||||
.hypWrite().monNonSecureRead();
|
||||
InitReg(MISCREG_IL1DATA0)
|
||||
.unimplemented()
|
||||
@@ -3256,7 +3251,6 @@ ISA::initializeMiscRegMetadata()
|
||||
.privSecure(!aarch32EL3)
|
||||
.monSecure(0);
|
||||
InitReg(MISCREG_CNTP_CVAL_S)
|
||||
.unimplemented()
|
||||
.bankedChild()
|
||||
.secure().user(1);
|
||||
InitReg(MISCREG_CNTV_CVAL)
|
||||
@@ -3264,7 +3258,6 @@ ISA::initializeMiscRegMetadata()
|
||||
InitReg(MISCREG_CNTVOFF)
|
||||
.hyp().monNonSecure();
|
||||
InitReg(MISCREG_CNTHP_CVAL)
|
||||
.unimplemented()
|
||||
.hypWrite().monNonSecureRead();
|
||||
InitReg(MISCREG_CPUMERRSR)
|
||||
.unimplemented()
|
||||
@@ -3936,31 +3929,23 @@ ISA::initializeMiscRegMetadata()
|
||||
.hyp().mon()
|
||||
.mapsTo(MISCREG_CNTVOFF); /* 64b */
|
||||
InitReg(MISCREG_CNTHCTL_EL2)
|
||||
.unimplemented()
|
||||
.warnNotFail()
|
||||
.mon().monNonSecureWrite(0).hypWrite()
|
||||
.mon().hyp()
|
||||
.mapsTo(MISCREG_CNTHCTL);
|
||||
InitReg(MISCREG_CNTHP_TVAL_EL2)
|
||||
.unimplemented()
|
||||
.mon().monNonSecureWrite(0).hypWrite()
|
||||
.mon().hyp()
|
||||
.mapsTo(MISCREG_CNTHP_TVAL);
|
||||
InitReg(MISCREG_CNTHP_CTL_EL2)
|
||||
.unimplemented()
|
||||
.mon().monNonSecureWrite(0).hypWrite()
|
||||
.mon().hyp()
|
||||
.mapsTo(MISCREG_CNTHP_CTL);
|
||||
InitReg(MISCREG_CNTHP_CVAL_EL2)
|
||||
.unimplemented()
|
||||
.mon().monNonSecureWrite(0).hypWrite()
|
||||
.mon().hyp()
|
||||
.mapsTo(MISCREG_CNTHP_CVAL); /* 64b */
|
||||
InitReg(MISCREG_CNTPS_TVAL_EL1)
|
||||
.unimplemented()
|
||||
.mon().monNonSecureWrite(0).hypWrite();
|
||||
.mon().privSecure();
|
||||
InitReg(MISCREG_CNTPS_CTL_EL1)
|
||||
.unimplemented()
|
||||
.mon().monNonSecureWrite(0).hypWrite();
|
||||
.mon().privSecure();
|
||||
InitReg(MISCREG_CNTPS_CVAL_EL1)
|
||||
.unimplemented()
|
||||
.mon().monNonSecureWrite(0).hypWrite();
|
||||
.mon().privSecure();
|
||||
InitReg(MISCREG_IL1DATA0_EL1)
|
||||
.allPrivileges().exceptUserMode();
|
||||
InitReg(MISCREG_IL1DATA1_EL1)
|
||||
|
||||
@@ -418,10 +418,10 @@ class GenericTimer(ClockedObject):
|
||||
cxx_header = "dev/arm/generic_timer.hh"
|
||||
system = Param.ArmSystem(Parent.any, "system")
|
||||
gic = Param.BaseGic(Parent.any, "GIC to use for interrupting")
|
||||
# @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_phys_s = Param.UInt32("Physical (S) timer interrupt number")
|
||||
int_phys_ns = Param.UInt32("Physical (NS) timer interrupt number")
|
||||
int_virt = Param.UInt32("Virtual timer interrupt number")
|
||||
int_hyp = Param.UInt32("Hypervisor timer interrupt number")
|
||||
|
||||
def generateDeviceTree(self, state):
|
||||
node = FdtNode("timer")
|
||||
@@ -429,9 +429,12 @@ class GenericTimer(ClockedObject):
|
||||
node.appendCompatible(["arm,cortex-a15-timer",
|
||||
"arm,armv7-timer",
|
||||
"arm,armv8-timer"])
|
||||
node.append(FdtPropertyWords("interrupts",
|
||||
[1, int(self.int_phys) - 16, 0xf08,
|
||||
1, int(self.int_virt) - 16, 0xf08]))
|
||||
node.append(FdtPropertyWords("interrupts", [
|
||||
1, int(self.int_phys_s) - 16, 0xf08,
|
||||
1, int(self.int_phys_ns) - 16, 0xf08,
|
||||
1, int(self.int_virt) - 16, 0xf08,
|
||||
1, int(self.int_hyp) - 16, 0xf08,
|
||||
]))
|
||||
clock = state.phandle(self.clk_domain.unproxy(self))
|
||||
node.append(FdtPropertyWords("clocks", clock))
|
||||
|
||||
@@ -900,7 +903,8 @@ class VExpress_EMM(RealView):
|
||||
conf_base=0x30000000, conf_size='256MB', conf_device_bits=16,
|
||||
pci_pio_base=0)
|
||||
|
||||
generic_timer = GenericTimer(int_phys=29, int_virt=27)
|
||||
generic_timer = GenericTimer(int_phys_s=29, int_phys_ns=30,
|
||||
int_virt=27, int_hyp=26)
|
||||
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)
|
||||
@@ -1118,7 +1122,8 @@ Interrupts:
|
||||
Gicv2mFrame(spi_base=256, spi_len=64, addr=0x2c1c0000),
|
||||
]
|
||||
|
||||
generic_timer = GenericTimer(int_phys=29, int_virt=27)
|
||||
generic_timer = GenericTimer(int_phys_s=29, int_phys_ns=30,
|
||||
int_virt=27, int_hyp=26)
|
||||
|
||||
hdlcd = HDLcd(pxl_clk=dcc.osc_pxl,
|
||||
pio_addr=0x2b000000, int_num=95)
|
||||
|
||||
@@ -69,6 +69,7 @@ void
|
||||
SystemCounter::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
SERIALIZE_SCALAR(_regCntkctl);
|
||||
SERIALIZE_SCALAR(_regCnthctl);
|
||||
SERIALIZE_SCALAR(_freq);
|
||||
SERIALIZE_SCALAR(_period);
|
||||
SERIALIZE_SCALAR(_resetTick);
|
||||
@@ -81,6 +82,8 @@ SystemCounter::unserialize(CheckpointIn &cp)
|
||||
// if it isn't present.
|
||||
if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
|
||||
_regCntkctl = 0;
|
||||
if (!UNSERIALIZE_OPT_SCALAR(_regCnthctl))
|
||||
_regCnthctl = 0;
|
||||
UNSERIALIZE_SCALAR(_freq);
|
||||
UNSERIALIZE_SCALAR(_period);
|
||||
UNSERIALIZE_SCALAR(_resetTick);
|
||||
@@ -242,8 +245,10 @@ GenericTimer::GenericTimer(GenericTimerParams *p)
|
||||
: ClockedObject(p),
|
||||
system(*p->system),
|
||||
gic(p->gic),
|
||||
irqPhys(p->int_phys),
|
||||
irqVirt(p->int_virt)
|
||||
irqPhysS(p->int_phys_s),
|
||||
irqPhysNS(p->int_phys_ns),
|
||||
irqVirt(p->int_virt),
|
||||
irqHyp(p->int_hyp)
|
||||
{
|
||||
fatal_if(!p->system, "No system specified, can't instantiate timer.\n");
|
||||
system.setGenericTimer(this);
|
||||
@@ -261,8 +266,10 @@ GenericTimer::serialize(CheckpointOut &cp) const
|
||||
|
||||
// This should really be phys_timerN, but we are stuck with
|
||||
// arch_timer for backwards compatibility.
|
||||
core.phys.serializeSection(cp, csprintf("arch_timer%d", i));
|
||||
core.physNS.serializeSection(cp, csprintf("arch_timer%d", i));
|
||||
core.physS.serializeSection(cp, csprintf("phys_s_timer%d", i));
|
||||
core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
|
||||
core.hyp.serializeSection(cp, csprintf("hyp_timer%d", i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,8 +293,10 @@ GenericTimer::unserialize(CheckpointIn &cp)
|
||||
CoreTimers &core(getTimers(i));
|
||||
// This should really be phys_timerN, but we are stuck with
|
||||
// arch_timer for backwards compatibility.
|
||||
core.phys.unserializeSection(cp, csprintf("arch_timer%d", i));
|
||||
core.physNS.unserializeSection(cp, csprintf("arch_timer%d", i));
|
||||
core.physS.unserializeSection(cp, csprintf("phys_s_timer%d", i));
|
||||
core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
|
||||
core.hyp.unserializeSection(cp, csprintf("hyp_timer%d", i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +319,8 @@ GenericTimer::createTimers(unsigned cpus)
|
||||
timers.resize(cpus);
|
||||
for (unsigned i = old_cpu_count; i < cpus; ++i) {
|
||||
timers[i].reset(
|
||||
new CoreTimers(*this, system, i, irqPhys, irqVirt));
|
||||
new CoreTimers(*this, system, i,
|
||||
irqPhysS, irqPhysNS, irqVirt, irqHyp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,23 +341,25 @@ GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
|
||||
systemCounter.setKernelControl(val);
|
||||
return;
|
||||
|
||||
// Physical timer
|
||||
case MISCREG_CNTP_CVAL:
|
||||
case MISCREG_CNTHCTL:
|
||||
case MISCREG_CNTHCTL_EL2:
|
||||
systemCounter.setHypControl(val);
|
||||
return;
|
||||
|
||||
// Physical timer (NS)
|
||||
case MISCREG_CNTP_CVAL_NS:
|
||||
case MISCREG_CNTP_CVAL_EL0:
|
||||
core.phys.setCompareValue(val);
|
||||
core.physNS.setCompareValue(val);
|
||||
return;
|
||||
|
||||
case MISCREG_CNTP_TVAL:
|
||||
case MISCREG_CNTP_TVAL_NS:
|
||||
case MISCREG_CNTP_TVAL_EL0:
|
||||
core.phys.setTimerValue(val);
|
||||
core.physNS.setTimerValue(val);
|
||||
return;
|
||||
|
||||
case MISCREG_CNTP_CTL:
|
||||
case MISCREG_CNTP_CTL_NS:
|
||||
case MISCREG_CNTP_CTL_EL0:
|
||||
core.phys.setControl(val);
|
||||
core.physNS.setControl(val);
|
||||
return;
|
||||
|
||||
// Count registers
|
||||
@@ -380,24 +392,36 @@ GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
|
||||
core.virt.setControl(val);
|
||||
return;
|
||||
|
||||
// PL1 phys. timer, secure
|
||||
// Physical timer (S)
|
||||
case MISCREG_CNTP_CTL_S:
|
||||
case MISCREG_CNTPS_CVAL_EL1:
|
||||
case MISCREG_CNTPS_TVAL_EL1:
|
||||
case MISCREG_CNTPS_CTL_EL1:
|
||||
M5_FALLTHROUGH;
|
||||
core.physS.setControl(val);
|
||||
return;
|
||||
|
||||
// PL2 phys. timer, non-secure
|
||||
case MISCREG_CNTHCTL:
|
||||
case MISCREG_CNTHCTL_EL2:
|
||||
case MISCREG_CNTHP_CVAL:
|
||||
case MISCREG_CNTHP_CVAL_EL2:
|
||||
case MISCREG_CNTHP_TVAL:
|
||||
case MISCREG_CNTHP_TVAL_EL2:
|
||||
case MISCREG_CNTP_CVAL_S:
|
||||
case MISCREG_CNTPS_CVAL_EL1:
|
||||
core.physS.setCompareValue(val);
|
||||
return;
|
||||
|
||||
case MISCREG_CNTP_TVAL_S:
|
||||
case MISCREG_CNTPS_TVAL_EL1:
|
||||
core.physS.setTimerValue(val);
|
||||
return;
|
||||
|
||||
// Hyp phys. timer, non-secure
|
||||
case MISCREG_CNTHP_CTL:
|
||||
case MISCREG_CNTHP_CTL_EL2:
|
||||
warn("Writing to unimplemented register: %s\n",
|
||||
miscRegName[reg]);
|
||||
core.hyp.setControl(val);
|
||||
return;
|
||||
|
||||
case MISCREG_CNTHP_CVAL:
|
||||
case MISCREG_CNTHP_CVAL_EL2:
|
||||
core.hyp.setCompareValue(val);
|
||||
return;
|
||||
|
||||
case MISCREG_CNTHP_TVAL:
|
||||
case MISCREG_CNTHP_TVAL_EL2:
|
||||
core.hyp.setTimerValue(val);
|
||||
return;
|
||||
|
||||
default:
|
||||
@@ -421,23 +445,26 @@ GenericTimer::readMiscReg(int reg, unsigned cpu)
|
||||
case MISCREG_CNTKCTL_EL1:
|
||||
return systemCounter.getKernelControl();
|
||||
|
||||
case MISCREG_CNTHCTL:
|
||||
case MISCREG_CNTHCTL_EL2:
|
||||
return systemCounter.getHypControl();
|
||||
|
||||
// Physical timer
|
||||
case MISCREG_CNTP_CVAL:
|
||||
case MISCREG_CNTP_CVAL_NS:
|
||||
case MISCREG_CNTP_CVAL_EL0:
|
||||
return core.phys.compareValue();
|
||||
return core.physNS.compareValue();
|
||||
|
||||
case MISCREG_CNTP_TVAL:
|
||||
case MISCREG_CNTP_TVAL_NS:
|
||||
case MISCREG_CNTP_TVAL_EL0:
|
||||
return core.phys.timerValue();
|
||||
return core.physNS.timerValue();
|
||||
|
||||
case MISCREG_CNTP_CTL:
|
||||
case MISCREG_CNTP_CTL_EL0:
|
||||
case MISCREG_CNTP_CTL_NS:
|
||||
return core.phys.control();
|
||||
return core.physNS.control();
|
||||
|
||||
case MISCREG_CNTPCT:
|
||||
case MISCREG_CNTPCT_EL0:
|
||||
return core.phys.value();
|
||||
return core.physNS.value();
|
||||
|
||||
|
||||
// Virtual timer
|
||||
@@ -463,24 +490,29 @@ GenericTimer::readMiscReg(int reg, unsigned cpu)
|
||||
|
||||
// PL1 phys. timer, secure
|
||||
case MISCREG_CNTP_CTL_S:
|
||||
case MISCREG_CNTPS_CVAL_EL1:
|
||||
case MISCREG_CNTPS_TVAL_EL1:
|
||||
case MISCREG_CNTPS_CTL_EL1:
|
||||
M5_FALLTHROUGH;
|
||||
return core.physS.control();
|
||||
|
||||
// PL2 phys. timer, non-secure
|
||||
case MISCREG_CNTHCTL:
|
||||
case MISCREG_CNTHCTL_EL2:
|
||||
case MISCREG_CNTHP_CVAL:
|
||||
case MISCREG_CNTHP_CVAL_EL2:
|
||||
case MISCREG_CNTHP_TVAL:
|
||||
case MISCREG_CNTHP_TVAL_EL2:
|
||||
case MISCREG_CNTP_CVAL_S:
|
||||
case MISCREG_CNTPS_CVAL_EL1:
|
||||
return core.physS.compareValue();
|
||||
|
||||
case MISCREG_CNTP_TVAL_S:
|
||||
case MISCREG_CNTPS_TVAL_EL1:
|
||||
return core.physS.timerValue();
|
||||
|
||||
// HYP phys. timer (NS)
|
||||
case MISCREG_CNTHP_CTL:
|
||||
case MISCREG_CNTHP_CTL_EL2:
|
||||
warn("Reading from unimplemented register: %s\n",
|
||||
miscRegName[reg]);
|
||||
return 0;
|
||||
return core.hyp.control();
|
||||
|
||||
case MISCREG_CNTHP_CVAL:
|
||||
case MISCREG_CNTHP_CVAL_EL2:
|
||||
return core.hyp.compareValue();
|
||||
|
||||
case MISCREG_CNTHP_TVAL:
|
||||
case MISCREG_CNTHP_TVAL_EL2:
|
||||
return core.hyp.timerValue();
|
||||
|
||||
default:
|
||||
warn("Reading from unknown register: %s\n", miscRegName[reg]);
|
||||
|
||||
@@ -69,7 +69,10 @@ class SystemCounter : public Serializable
|
||||
/// Tick when the counter was reset.
|
||||
Tick _resetTick;
|
||||
|
||||
/// Kernel event stream control register
|
||||
uint32_t _regCntkctl;
|
||||
/// Hypervisor event stream control register
|
||||
uint32_t _regCnthctl;
|
||||
|
||||
public:
|
||||
SystemCounter();
|
||||
@@ -94,6 +97,9 @@ class SystemCounter : public Serializable
|
||||
void setKernelControl(uint32_t val) { _regCntkctl = val; }
|
||||
uint32_t getKernelControl() { return _regCntkctl; }
|
||||
|
||||
void setHypControl(uint32_t val) { _regCnthctl = val; }
|
||||
uint32_t getHypControl() { return _regCnthctl; }
|
||||
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
void unserialize(CheckpointIn &cp) override;
|
||||
|
||||
@@ -241,24 +247,37 @@ class GenericTimer : public ClockedObject
|
||||
protected:
|
||||
struct CoreTimers {
|
||||
CoreTimers(GenericTimer &parent, ArmSystem &system, unsigned cpu,
|
||||
unsigned _irqPhys, unsigned _irqVirt)
|
||||
: irqPhys(*parent.gic, _irqPhys, cpu),
|
||||
unsigned _irqPhysS, unsigned _irqPhysNS,
|
||||
unsigned _irqVirt, unsigned _irqHyp)
|
||||
: irqPhysS(*parent.gic, _irqPhysS, cpu),
|
||||
irqPhysNS(*parent.gic, _irqPhysNS, cpu),
|
||||
irqVirt(*parent.gic, _irqVirt, cpu),
|
||||
irqHyp(*parent.gic, _irqHyp, cpu),
|
||||
physS(csprintf("%s.phys_s_timer%d", parent.name(), cpu),
|
||||
system, parent, parent.systemCounter,
|
||||
irqPhysS),
|
||||
// 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),
|
||||
system, parent, parent.systemCounter,
|
||||
irqPhys),
|
||||
physNS(csprintf("%s.arch_timer%d", parent.name(), cpu),
|
||||
system, parent, parent.systemCounter,
|
||||
irqPhysNS),
|
||||
virt(csprintf("%s.virt_timer%d", parent.name(), cpu),
|
||||
system, parent, parent.systemCounter,
|
||||
irqVirt)
|
||||
irqVirt),
|
||||
hyp(csprintf("%s.hyp_timer%d", parent.name(), cpu),
|
||||
system, parent, parent.systemCounter,
|
||||
irqHyp)
|
||||
{}
|
||||
|
||||
ArchTimer::Interrupt irqPhys;
|
||||
ArchTimer::Interrupt irqPhysS;
|
||||
ArchTimer::Interrupt irqPhysNS;
|
||||
ArchTimer::Interrupt irqVirt;
|
||||
ArchTimer::Interrupt irqHyp;
|
||||
|
||||
ArchTimerKvm phys;
|
||||
ArchTimerKvm physS;
|
||||
ArchTimerKvm physNS;
|
||||
ArchTimerKvm virt;
|
||||
ArchTimerKvm hyp;
|
||||
|
||||
private:
|
||||
// Disable copying
|
||||
@@ -281,11 +300,16 @@ class GenericTimer : public ClockedObject
|
||||
/// Pointer to the GIC, needed to trigger timer interrupts.
|
||||
BaseGic *const gic;
|
||||
|
||||
/// Physical timer interrupt
|
||||
const unsigned irqPhys;
|
||||
/// Physical timer interrupt (S)
|
||||
const unsigned irqPhysS;
|
||||
/// Physical timer interrupt (NS)
|
||||
const unsigned irqPhysNS;
|
||||
|
||||
/// Virtual timer interrupt
|
||||
const unsigned irqVirt;
|
||||
|
||||
/// Hypervisor timer interrupt
|
||||
const unsigned irqHyp;
|
||||
};
|
||||
|
||||
class GenericTimerISA : public ArmISA::BaseISADevice
|
||||
|
||||
Reference in New Issue
Block a user