arch-arm: Explicitly implement I/DTLBI Ops in TLB

At the moment the ITLBI and DTLBI operations where implicitly
implemented as generic TLBIs

e.g:

* DTLBIASID, ITLBIASID = TLBIASID

This was possible as a single TLB was either an instruction TLB
or a data TLB and no generic/shared TLB option was available.
In other words, an ITLBI Op to an ITB was invalidating all entries
as we were sure the ITB was not containing data entries.

With shared TLBs, this doesn't hold true and we need to explicitly
implement I/DTLBIs

JIRA: https://gem5.atlassian.net/browse/GEM5-790

Change-Id: I39a4add7674f6008dacaedfd1fd90560d264048e
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/48148
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
2021-07-08 14:33:58 +01:00
parent a23f39bc19
commit 395c6d4fa3
2 changed files with 145 additions and 5 deletions

View File

@@ -228,6 +228,56 @@ TLB::flush(const TLBIALL& tlbi_op)
stats.flushTlb++;
}
void
TLB::flush(const ITLBIALL& tlbi_op)
{
DPRINTF(TLB, "Flushing all ITLB 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->type & TypeTLB::instruction && te->valid &&
tlbi_op.secureLookup == !te->nstid &&
(te->vmid == vmid || tlbi_op.el2Enabled) && el_match) {
DPRINTF(TLB, " - %s\n", te->print());
te->valid = false;
stats.flushedEntries++;
}
++x;
}
stats.flushTlb++;
}
void
TLB::flush(const DTLBIALL& tlbi_op)
{
DPRINTF(TLB, "Flushing all DTLB 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->type & TypeTLB::data && te->valid &&
tlbi_op.secureLookup == !te->nstid &&
(te->vmid == vmid || tlbi_op.el2Enabled) && el_match) {
DPRINTF(TLB, " - %s\n", te->print());
te->valid = false;
stats.flushedEntries++;
}
++x;
}
stats.flushTlb++;
}
void
TLB::flush(const TLBIALLEL &tlbi_op)
{
@@ -307,7 +357,29 @@ TLB::flush(const TLBIMVA &tlbi_op)
"(%s lookup)\n", tlbi_op.addr, tlbi_op.asid,
(tlbi_op.secureLookup ? "secure" : "non-secure"));
_flushMva(tlbi_op.addr, tlbi_op.asid, tlbi_op.secureLookup, false,
tlbi_op.targetEL, tlbi_op.inHost);
tlbi_op.targetEL, tlbi_op.inHost, TypeTLB::unified);
stats.flushTlbMvaAsid++;
}
void
TLB::flush(const ITLBIMVA &tlbi_op)
{
DPRINTF(TLB, "Flushing ITLB entries with mva: %#x, asid: %#x "
"(%s lookup)\n", tlbi_op.addr, tlbi_op.asid,
(tlbi_op.secureLookup ? "secure" : "non-secure"));
_flushMva(tlbi_op.addr, tlbi_op.asid, tlbi_op.secureLookup, false,
tlbi_op.targetEL, tlbi_op.inHost, TypeTLB::instruction);
stats.flushTlbMvaAsid++;
}
void
TLB::flush(const DTLBIMVA &tlbi_op)
{
DPRINTF(TLB, "Flushing DTLB entries with mva: %#x, asid: %#x "
"(%s lookup)\n", tlbi_op.addr, tlbi_op.asid,
(tlbi_op.secureLookup ? "secure" : "non-secure"));
_flushMva(tlbi_op.addr, tlbi_op.asid, tlbi_op.secureLookup, false,
tlbi_op.targetEL, tlbi_op.inHost, TypeTLB::data);
stats.flushTlbMvaAsid++;
}
@@ -336,6 +408,58 @@ TLB::flush(const TLBIASID &tlbi_op)
stats.flushTlbAsid++;
}
void
TLB::flush(const ITLBIASID &tlbi_op)
{
DPRINTF(TLB, "Flushing ITLB entries with asid: %#x (%s lookup)\n",
tlbi_op.asid, (tlbi_op.secureLookup ? "secure" : "non-secure"));
int x = 0 ;
TlbEntry *te;
while (x < size) {
te = &table[x];
if (te->type & TypeTLB::instruction &&
te->valid && te->asid == tlbi_op.asid &&
tlbi_op.secureLookup == !te->nstid &&
(te->vmid == vmid || tlbi_op.el2Enabled) &&
te->checkELMatch(tlbi_op.targetEL, tlbi_op.inHost)) {
te->valid = false;
DPRINTF(TLB, " - %s\n", te->print());
stats.flushedEntries++;
}
++x;
}
stats.flushTlbAsid++;
}
void
TLB::flush(const DTLBIASID &tlbi_op)
{
DPRINTF(TLB, "Flushing DTLB entries with asid: %#x (%s lookup)\n",
tlbi_op.asid, (tlbi_op.secureLookup ? "secure" : "non-secure"));
int x = 0 ;
TlbEntry *te;
while (x < size) {
te = &table[x];
if (te->type & TypeTLB::data &&
te->valid && te->asid == tlbi_op.asid &&
tlbi_op.secureLookup == !te->nstid &&
(te->vmid == vmid || tlbi_op.el2Enabled) &&
te->checkELMatch(tlbi_op.targetEL, tlbi_op.inHost)) {
te->valid = false;
DPRINTF(TLB, " - %s\n", te->print());
stats.flushedEntries++;
}
++x;
}
stats.flushTlbAsid++;
}
void
TLB::flush(const TLBIMVAA &tlbi_op) {
@@ -343,13 +467,14 @@ TLB::flush(const TLBIMVAA &tlbi_op) {
tlbi_op.addr,
(tlbi_op.secureLookup ? "secure" : "non-secure"));
_flushMva(tlbi_op.addr, 0xbeef, tlbi_op.secureLookup, true,
tlbi_op.targetEL, tlbi_op.inHost);
tlbi_op.targetEL, tlbi_op.inHost, TypeTLB::unified);
stats.flushTlbMva++;
}
void
TLB::_flushMva(Addr mva, uint64_t asn, bool secure_lookup,
bool ignore_asn, ExceptionLevel target_el, bool in_host)
bool ignore_asn, ExceptionLevel target_el, bool in_host,
TypeTLB entry_type)
{
TlbEntry *te;
// D5.7.2: Sign-extend address to 64 bits
@@ -360,7 +485,8 @@ TLB::_flushMva(Addr mva, uint64_t asn, bool secure_lookup,
te = lookup(mva, asn, vmid, hyp, secure_lookup, true, ignore_asn,
target_el, in_host, BaseMMU::Read);
while (te != NULL) {
if (secure_lookup == !te->nstid) {
bool matching_type = (te->type & entry_type);
if (matching_type && secure_lookup == !te->nstid) {
DPRINTF(TLB, " - %s\n", te->print());
te->valid = false;
stats.flushedEntries++;