arch-arm: Fix implementation of TLBI ALLEx instructions

The TLBIALL op in gem5 was designed after the AArch32 TLBIALL instruction.
and was reused by the TLBI ALLEL1, ALLE2, ALLE3 logic.

This is not correct for the following reasons:

- TLBI ALLEx invalidates regardless of the VMID
- TLBI ALLEx (AArch64) is "target regime" oriented, whereas TLBIALL
  (AArch32) is "current regime" oriented

TLBIALL has a different behaviour depending on the current exception
level: if issued at EL1 it will invalidate stage1 translations only; if
at EL2, it will invalidate stage2 translations as well.

TLBI ALLEx is more standard; every TLBI ALLE1 will invalidate stage1 and
stage2 translations. This is because the instruction is not executable
from the guest (EL1)

So for TLBIALL the condition for stage2 forwarding will be:

if (!isStage2 && isHyp) {

Whereas for TLBI ALLEx will be:

if (!isStage2 && target_el == EL1) {

Change-Id: I282f2cfaecbfc883e173770e5d2578b41055bb7a
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35241
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Giacomo Travaglini
2020-09-17 17:31:55 +01:00
parent 32d88ae46c
commit ad5fa9ebe4
5 changed files with 92 additions and 7 deletions

View File

@@ -1701,7 +1701,7 @@ ISA::setMiscReg(int misc_reg, RegVal val)
{
assert64();
TLBIALL tlbiOp(EL3, true);
TLBIALLEL tlbiOp(EL3, true);
tlbiOp(tc);
return;
}
@@ -1710,7 +1710,7 @@ ISA::setMiscReg(int misc_reg, RegVal val)
{
assert64();
TLBIALL tlbiOp(EL3, true);
TLBIALLEL tlbiOp(EL3, true);
tlbiOp.broadcast(tc);
return;
}
@@ -1720,7 +1720,7 @@ ISA::setMiscReg(int misc_reg, RegVal val)
assert64();
scr = readMiscReg(MISCREG_SCR);
TLBIALL tlbiOp(EL2, haveSecurity && !scr.ns);
TLBIALLEL tlbiOp(EL2, haveSecurity && !scr.ns);
tlbiOp(tc);
return;
}
@@ -1730,12 +1730,30 @@ ISA::setMiscReg(int misc_reg, RegVal val)
assert64();
scr = readMiscReg(MISCREG_SCR);
TLBIALL tlbiOp(EL2, haveSecurity && !scr.ns);
TLBIALLEL tlbiOp(EL2, haveSecurity && !scr.ns);
tlbiOp.broadcast(tc);
return;
}
// AArch64 TLB Invalidate All, EL1
case MISCREG_TLBI_ALLE1:
{
assert64();
scr = readMiscReg(MISCREG_SCR);
TLBIALLEL tlbiOp(EL1, haveSecurity && !scr.ns);
tlbiOp(tc);
return;
}
// AArch64 TLB Invalidate All, EL1, Inner Shareable
case MISCREG_TLBI_ALLE1IS:
{
assert64();
scr = readMiscReg(MISCREG_SCR);
TLBIALLEL tlbiOp(EL1, haveSecurity && !scr.ns);
tlbiOp.broadcast(tc);
return;
}
case MISCREG_TLBI_VMALLS12E1:
// @todo: handle VMID and stage 2 to enable Virtualization
{
@@ -1759,8 +1777,6 @@ ISA::setMiscReg(int misc_reg, RegVal val)
tlbiOp(tc);
return;
}
// AArch64 TLB Invalidate All, EL1, Inner Shareable
case MISCREG_TLBI_ALLE1IS:
case MISCREG_TLBI_VMALLS12E1IS:
// @todo: handle VMID and stage 2 to enable Virtualization
{

View File

@@ -299,6 +299,36 @@ TLB::flush(const TLBIALL& tlbi_op)
}
}
void
TLB::flush(const TLBIALLEL &tlbi_op)
{
DPRINTF(TLB, "Flushing all TLB entries (%s lookup)\n",
(tlbi_op.secureLookup ? "secure" : "non-secure"));
int x = 0;
TlbEntry *te;
while (x < size) {
te = &table[x];
const bool el_match = te->checkELMatch(
tlbi_op.targetEL, tlbi_op.inHost);
if (te->valid && tlbi_op.secureLookup == !te->nstid && el_match) {
DPRINTF(TLB, " - %s\n", te->print());
te->valid = false;
stats.flushedEntries++;
}
++x;
}
stats.flushTlb++;
// If there's a second stage TLB (and we're not it)
// and if we're targeting EL1
// then flush it as well
if (!isStage2 && tlbi_op.targetEL == EL1) {
stage2Tlb->flush(tlbi_op.makeStage2());
}
}
void
TLB::flush(const TLBIALLN &tlbi_op)
{

View File

@@ -62,6 +62,7 @@ class Stage2MMU;
class TLB;
class TLBIALL;
class TLBIALLEL;
class TLBIALLN;
class TLBIMVA;
class TLBIASID;
@@ -261,7 +262,12 @@ class TLB : public BaseTLB
/** Reset the entire TLB
*/
void flush(const TLBIALL& tlbi_op);
void flush(const TLBIALL &tlbi_op);
/** Implementaton of AArch64 TLBI ALLE1(IS), ALLE2(IS), ALLE3(IS)
* instructions
*/
void flush(const TLBIALLEL &tlbi_op);
/** Remove all entries in the non secure world, depending on whether they
* were allocated in hyp mode or not

View File

@@ -68,6 +68,20 @@ DTLBIALL::operator()(ThreadContext* tc)
getMMUPtr(tc)->dflush(*this);
}
void
TLBIALLEL::operator()(ThreadContext* tc)
{
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
inHost = (hcr.tge == 1 && hcr.e2h == 1);
getMMUPtr(tc)->flush(*this);
// If CheckerCPU is connected, need to notify it of a flush
CheckerCPU *checker = tc->getCheckerCpuPtr();
if (checker) {
getMMUPtr(checker)->flush(*this);
}
}
void
TLBIASID::operator()(ThreadContext* tc)
{

View File

@@ -121,6 +121,25 @@ class DTLBIALL : public TLBIALL
void operator()(ThreadContext* tc) override;
};
/** Implementaton of AArch64 TLBI ALLE(1,2,3)(IS) instructions */
class TLBIALLEL : public TLBIOp
{
public:
TLBIALLEL(ExceptionLevel _targetEL, bool _secure)
: TLBIOp(_targetEL, _secure), inHost(false)
{}
void operator()(ThreadContext* tc) override;
TLBIALLEL
makeStage2() const
{
return TLBIALLEL(EL1, secureLookup);
}
bool inHost;
};
/** TLB Invalidate by ASID match */
class TLBIASID : public TLBIOp
{