arch-arm: Revamp of AArch64 S1 access permission logic
This patch is revamping/simplifying the access permission logic in the ArmMMU (ArmMMU::s1PermBits64) by matching more closely the Arm architecture reference manual pseudocode. It also fixes VHE access permission: previous version was not considering the EL2&0 translation regime. Now EL2&0 is handled correctly through the new hasUnprivRegime method Change-Id: I2689738f36a35c35cc4f2ef8af68ee2a3eef65e8 Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/60969 Maintainer: Andreas Sandberg <andreas.sandberg@arm.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -619,7 +619,7 @@ std::pair<bool, bool>
|
||||
MMU::s1PermBits64(TlbEntry *te, const RequestPtr &req, Mode mode,
|
||||
ThreadContext *tc, CachedState &state, bool r, bool w, bool x)
|
||||
{
|
||||
bool grant = false, grant_read = true;
|
||||
bool grant = false, grant_read = true, grant_write = true, grant_exec = true;
|
||||
|
||||
const uint8_t ap = te->ap & 0b11; // 2-bit access protection field
|
||||
const bool is_priv = state.isPriv && !(req->getFlags() & UserMode);
|
||||
@@ -628,11 +628,6 @@ MMU::s1PermBits64(TlbEntry *te, const RequestPtr &req, Mode mode,
|
||||
uint8_t xn = te->xn;
|
||||
uint8_t pxn = te->pxn;
|
||||
|
||||
if (ArmSystem::haveEL(tc, EL3) && state.isSecure &&
|
||||
te->ns && state.scr.sif) {
|
||||
xn = true;
|
||||
}
|
||||
|
||||
DPRINTF(TLBVerbose, "Checking S1 permissions: ap:%d, xn:%d, pxn:%d, r:%d, "
|
||||
"w:%d, x:%d, is_priv: %d, wxn: %d\n", ap, xn,
|
||||
pxn, r, w, x, is_priv, wxn);
|
||||
@@ -642,101 +637,84 @@ MMU::s1PermBits64(TlbEntry *te, const RequestPtr &req, Mode mode,
|
||||
}
|
||||
|
||||
ExceptionLevel regime = !is_priv ? EL0 : state.aarch64EL;
|
||||
switch (regime) {
|
||||
case EL0:
|
||||
{
|
||||
grant_read = ap & 0x1;
|
||||
uint8_t perm = (ap << 2) | (xn << 1) | pxn;
|
||||
switch (perm) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 8:
|
||||
case 9:
|
||||
grant = x;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
grant = r || w || (x && !wxn);
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
grant = r || w;
|
||||
break;
|
||||
case 12:
|
||||
case 13:
|
||||
grant = r || x;
|
||||
break;
|
||||
case 14:
|
||||
case 15:
|
||||
grant = r;
|
||||
break;
|
||||
default:
|
||||
grant = false;
|
||||
}
|
||||
if (hasUnprivRegime(regime, state)) {
|
||||
bool pr = false;
|
||||
bool pw = false;
|
||||
bool ur = false;
|
||||
bool uw = false;
|
||||
// Apply leaf permissions
|
||||
switch (ap) {
|
||||
case 0b00: // Privileged access
|
||||
pr = 1; pw = 1; ur = 0; uw = 0;
|
||||
break;
|
||||
case 0b01: // No effect
|
||||
pr = 1; pw = 1; ur = 1; uw = 1;
|
||||
break;
|
||||
case 0b10: // Read-only, privileged access
|
||||
pr = 1; pw = 0; ur = 0; uw = 0;
|
||||
break;
|
||||
case 0b11: // Read-only
|
||||
pr = 1; pw = 0; ur = 1; uw = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case EL1:
|
||||
{
|
||||
uint8_t perm = (ap << 2) | (xn << 1) | pxn;
|
||||
switch (perm) {
|
||||
case 0:
|
||||
case 2:
|
||||
grant = r || w || (x && !wxn);
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
// regions that are writeable at EL0 should not be
|
||||
// executable at EL1
|
||||
grant = r || w;
|
||||
break;
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
grant = r || x;
|
||||
break;
|
||||
case 9:
|
||||
case 11:
|
||||
case 13:
|
||||
case 15:
|
||||
grant = r;
|
||||
break;
|
||||
default:
|
||||
grant = false;
|
||||
}
|
||||
|
||||
// Locations writable by unprivileged cannot be executed by privileged
|
||||
const bool px = !(pxn || uw);
|
||||
const bool ux = !xn;
|
||||
|
||||
grant_read = is_priv ? pr : ur;
|
||||
grant_write = is_priv ? pw : uw;
|
||||
grant_exec = is_priv ? px : ux;
|
||||
} else {
|
||||
switch (bits(ap, 1)) {
|
||||
case 0b0: // No effect
|
||||
grant_read = 1; grant_write = 1;
|
||||
break;
|
||||
case 0b1: // Read-Only
|
||||
grant_read = 1; grant_write = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case EL2:
|
||||
case EL3:
|
||||
{
|
||||
uint8_t perm = (ap & 0x2) | xn;
|
||||
switch (perm) {
|
||||
case 0:
|
||||
grant = r || w || (x && !wxn);
|
||||
break;
|
||||
case 1:
|
||||
grant = r || w;
|
||||
break;
|
||||
case 2:
|
||||
grant = r || x;
|
||||
break;
|
||||
case 3:
|
||||
grant = r;
|
||||
break;
|
||||
default:
|
||||
grant = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
grant_exec = !xn;
|
||||
}
|
||||
|
||||
// Do not allow execution from writable location
|
||||
// if wxn is set
|
||||
grant_exec = grant_exec && !(wxn && grant_write);
|
||||
|
||||
if (ArmSystem::haveEL(tc, EL3) && state.isSecure && te->ns) {
|
||||
grant_exec = grant_exec && !state.scr.sif;
|
||||
}
|
||||
|
||||
if (x) {
|
||||
grant = grant_exec;
|
||||
} else if (req->isAtomic()) {
|
||||
grant = grant_read && grant_write;
|
||||
} else if (w) {
|
||||
grant = grant_write;
|
||||
} else {
|
||||
grant = grant_read;
|
||||
}
|
||||
|
||||
return std::make_pair(grant, grant_read);
|
||||
}
|
||||
|
||||
bool
|
||||
MMU::hasUnprivRegime(ExceptionLevel el, CachedState &state)
|
||||
{
|
||||
switch (el) {
|
||||
case EL0:
|
||||
case EL1:
|
||||
// EL1&0
|
||||
return true;
|
||||
case EL2:
|
||||
// EL2&0 or EL2
|
||||
return state.hcr.e2h;
|
||||
case EL3:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MMU::faultPAN(ThreadContext *tc, uint8_t ap, const RequestPtr &req, Mode mode,
|
||||
const bool is_priv, CachedState &state)
|
||||
|
||||
@@ -446,6 +446,8 @@ class MMU : public BaseMMU
|
||||
bool faultPAN(ThreadContext *tc, uint8_t ap, const RequestPtr &req,
|
||||
Mode mode, const bool is_priv, CachedState &state);
|
||||
|
||||
bool hasUnprivRegime(ExceptionLevel el, CachedState &state);
|
||||
|
||||
std::pair<bool, bool> s1PermBits64(
|
||||
TlbEntry *te, const RequestPtr &req, Mode mode,
|
||||
ThreadContext *tc, CachedState &state, bool r, bool w, bool x);
|
||||
|
||||
Reference in New Issue
Block a user