arch-arm: Proper support for NonSecure IPA space in Secure state
Change-Id: Ie2e2278ecdc5213db74999e3561b2918937c2c2e Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
This commit is contained in:
@@ -339,14 +339,7 @@ TlbiOp64::tlbiIpaS2(ThreadContext *tc, RegVal value,
|
||||
bool last_level, TlbiAttr attrs)
|
||||
{
|
||||
if (EL2Enabled(tc)) {
|
||||
if (ss == SecurityState::Secure && bits(value, 63)) {
|
||||
ss = SecurityState::NonSecure;
|
||||
}
|
||||
|
||||
const int top_bit = ArmSystem::physAddrRange(tc) == 52 ?
|
||||
39 : 35;
|
||||
TLBIIPA tlbi_op(TranslationRegime::EL10, ss,
|
||||
static_cast<Addr>(bits(value, top_bit, 0)) << 12,
|
||||
TLBIIPA tlbi_op(tc, TranslationRegime::EL10, ss, value,
|
||||
last_level, attrs);
|
||||
|
||||
if (shareable) {
|
||||
@@ -398,11 +391,7 @@ TlbiOp64::tlbiRipaS2(ThreadContext *tc, RegVal value,
|
||||
bool last_level, TlbiAttr attrs)
|
||||
{
|
||||
if (EL2Enabled(tc)) {
|
||||
if (ss == SecurityState::Secure && bits(value, 63)) {
|
||||
ss = SecurityState::NonSecure;
|
||||
}
|
||||
|
||||
TLBIRIPA tlbi_op(TranslationRegime::EL10, ss, value,
|
||||
TLBIRIPA tlbi_op(tc, TranslationRegime::EL10, ss, value,
|
||||
last_level, attrs);
|
||||
|
||||
if (shareable) {
|
||||
|
||||
@@ -1385,11 +1385,11 @@ MMU::tranTypeEL(CPSR cpsr, SCR scr, ArmTranslationType type)
|
||||
Fault
|
||||
MMU::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool timing, bool functional,
|
||||
SecurityState ss, ArmTranslationType tran_type,
|
||||
SecurityState ss, PASpace ipaspace, ArmTranslationType tran_type,
|
||||
bool stage2)
|
||||
{
|
||||
return getTE(te, req, tc, mode, translation, timing, functional,
|
||||
ss, tran_type, stage2 ? s2State : s1State);
|
||||
ss, ipaspace, tran_type, stage2 ? s2State : s1State);
|
||||
}
|
||||
|
||||
TlbEntry*
|
||||
@@ -1416,7 +1416,7 @@ MMU::lookup(Addr va, uint16_t asid, vmid_t vmid, SecurityState ss,
|
||||
Fault
|
||||
MMU::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool timing, bool functional,
|
||||
SecurityState ss, ArmTranslationType tran_type,
|
||||
SecurityState ss, PASpace ipaspace, ArmTranslationType tran_type,
|
||||
CachedState& state)
|
||||
{
|
||||
// In a 2-stage system, the IPA->PA translation can be started via this
|
||||
@@ -1459,7 +1459,7 @@ MMU::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode,
|
||||
fault = getTableWalker(mode, state.isStage2)->walk(
|
||||
req, tc, state.asid, state.vmid, mode,
|
||||
translation, timing, functional, ss,
|
||||
tran_type, state.stage2DescReq, *te);
|
||||
ipaspace, tran_type, state.stage2DescReq, *te);
|
||||
|
||||
// for timing mode, return and wait for table walk,
|
||||
if (timing || fault != NoFault) {
|
||||
@@ -1482,12 +1482,16 @@ MMU::getResultTe(TlbEntry **te, const RequestPtr &req,
|
||||
Fault fault;
|
||||
|
||||
if (state.isStage2) {
|
||||
PASpace ipaspace = state.securityState == SecurityState::Secure ?
|
||||
PASpace::Secure : PASpace::NonSecure;
|
||||
|
||||
// We are already in the stage 2 TLB. Grab the table entry for stage
|
||||
// 2 only. We are here because stage 1 translation is disabled.
|
||||
TlbEntry *s2_te = nullptr;
|
||||
// Get the stage 2 table entry
|
||||
fault = getTE(&s2_te, req, tc, mode, translation, timing, functional,
|
||||
state.securityState, state.curTranType, state);
|
||||
state.securityState, ipaspace,
|
||||
state.curTranType, state);
|
||||
// Check permissions of stage 2
|
||||
if (isCompleteTranslation(s2_te) && (fault == NoFault)) {
|
||||
if (state.aarch64)
|
||||
@@ -1505,7 +1509,8 @@ MMU::getResultTe(TlbEntry **te, const RequestPtr &req,
|
||||
|
||||
// Get the stage 1 table entry
|
||||
fault = getTE(&s1_te, req, tc, mode, translation, timing, functional,
|
||||
state.securityState, state.curTranType, state);
|
||||
state.securityState, PASpace::NonSecure,
|
||||
state.curTranType, state);
|
||||
// only proceed if we have a valid table entry
|
||||
if (isCompleteTranslation(s1_te) && (fault == NoFault)) {
|
||||
// Check stage 1 permissions before checking stage 2
|
||||
|
||||
@@ -412,12 +412,14 @@ class MMU : public BaseMMU
|
||||
Fault getTE(TlbEntry **te, const RequestPtr &req,
|
||||
ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool timing, bool functional,
|
||||
SecurityState ss, ArmTranslationType tran_type,
|
||||
SecurityState ss, PASpace ipaspace,
|
||||
ArmTranslationType tran_type,
|
||||
bool stage2);
|
||||
Fault getTE(TlbEntry **te, const RequestPtr &req,
|
||||
ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool timing, bool functional,
|
||||
SecurityState ss, ArmTranslationType tran_type,
|
||||
SecurityState ss, PASpace ipaspace,
|
||||
ArmTranslationType tran_type,
|
||||
CachedState &state);
|
||||
|
||||
Fault getResultTe(TlbEntry **te, const RequestPtr &req,
|
||||
|
||||
@@ -241,6 +241,8 @@ struct TlbEntry : public Serializable
|
||||
bool ns;
|
||||
// Security state of the translation regime
|
||||
SecurityState ss;
|
||||
// IPA Space (stage2 entries only)
|
||||
PASpace ipaSpace;
|
||||
// Translation regime on insert, AARCH64 EL0&1, AARCH32 -> el=1
|
||||
TranslationRegime regime;
|
||||
// This is used to distinguish between instruction and data entries
|
||||
@@ -272,6 +274,7 @@ struct TlbEntry : public Serializable
|
||||
domain(DomainType::Client), mtype(MemoryType::StronglyOrdered),
|
||||
longDescFormat(false), global(false), valid(true),
|
||||
ns(true), ss(SecurityState::NonSecure),
|
||||
ipaSpace(PASpace::NonSecure),
|
||||
regime(TranslationRegime::EL10),
|
||||
type(TypeTLB::unified), partial(false),
|
||||
nonCacheable(uncacheable),
|
||||
@@ -292,6 +295,7 @@ struct TlbEntry : public Serializable
|
||||
domain(DomainType::Client), mtype(MemoryType::StronglyOrdered),
|
||||
longDescFormat(false), global(false), valid(false),
|
||||
ns(true), ss(SecurityState::NonSecure),
|
||||
ipaSpace(PASpace::NonSecure),
|
||||
regime(TranslationRegime::EL10),
|
||||
type(TypeTLB::unified), partial(false), nonCacheable(false),
|
||||
shareable(false), outerShareable(false), xn(0), pxn(0),
|
||||
|
||||
@@ -655,6 +655,10 @@ namespace ArmISA
|
||||
Bitfield<19> vs; // Only defined for VTCR_EL2
|
||||
Bitfield<21> ha; // Only defined for VTCR_EL2
|
||||
Bitfield<22> hd; // Only defined for VTCR_EL2
|
||||
Bitfield<29> nsw; // Only defined for VTCR_EL2
|
||||
Bitfield<29> sw; // Only defined for VSTCR_EL2
|
||||
Bitfield<30> nsa; // Only defined for VTCR_EL2
|
||||
Bitfield<30> sa; // Only defined for VSTCR_EL2
|
||||
EndBitUnion(VTCR_t)
|
||||
|
||||
BitUnion32(PRRR)
|
||||
|
||||
@@ -57,7 +57,7 @@ Fault
|
||||
Stage2LookUp::getTe(ThreadContext *tc, TlbEntry *destTe)
|
||||
{
|
||||
fault = mmu->getTE(&stage2Te, req, tc, mode, this, timing,
|
||||
functional, ss, tranType, true);
|
||||
functional, ss, ipaSpace, tranType, true);
|
||||
|
||||
// Call finish if we're done already
|
||||
if ((fault != NoFault) || (stage2Te != NULL)) {
|
||||
@@ -193,7 +193,7 @@ Stage2LookUp::finish(const Fault &_fault, const RequestPtr &req,
|
||||
if ((fault == NoFault) && (stage2Te == NULL)) {
|
||||
// OLD_LOOK: stage2Tlb
|
||||
fault = mmu->getTE(&stage2Te, req, tc, mode, this,
|
||||
timing, functional, ss, tranType, true);
|
||||
timing, functional, ss, ipaSpace, tranType, true);
|
||||
}
|
||||
|
||||
// Now we have the stage 2 table entry we need to merge it with the stage
|
||||
|
||||
@@ -73,6 +73,7 @@ class Stage2LookUp : public BaseMMU::Translation
|
||||
bool complete;
|
||||
bool selfDelete;
|
||||
SecurityState ss;
|
||||
PASpace ipaSpace;
|
||||
|
||||
public:
|
||||
Stage2LookUp(MMU *_mmu, TlbEntry s1_te, const RequestPtr &_req,
|
||||
@@ -82,7 +83,8 @@ class Stage2LookUp : public BaseMMU::Translation
|
||||
: mmu(_mmu), stage1Te(s1_te), s1Req(_req),
|
||||
transState(_transState), mode(_mode), timing(_timing),
|
||||
functional(_functional), tranType(_tranType), stage2Te(nullptr),
|
||||
fault(NoFault), complete(false), selfDelete(false), ss(_ss)
|
||||
fault(NoFault), complete(false), selfDelete(false), ss(_ss),
|
||||
ipaSpace(s1_te.ns ? PASpace::NonSecure : PASpace::Secure)
|
||||
{
|
||||
req = std::make_shared<Request>();
|
||||
req->setVirt(s1_te.pAddr(s1Req->getVaddr()), s1Req->getSize(),
|
||||
|
||||
@@ -295,7 +295,8 @@ Fault
|
||||
TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
|
||||
vmid_t _vmid, MMU::Mode _mode,
|
||||
MMU::Translation *_trans, bool _timing, bool _functional,
|
||||
SecurityState ss, MMU::ArmTranslationType tranType,
|
||||
SecurityState ss, PASpace ipaspace,
|
||||
MMU::ArmTranslationType tranType,
|
||||
bool _stage2Req, const TlbEntry *walk_entry)
|
||||
{
|
||||
assert(!(_functional && _timing));
|
||||
@@ -344,6 +345,7 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
|
||||
if (isStage2) {
|
||||
currState->regime = TranslationRegime::EL10;
|
||||
currState->aarch64 = ELIs64(_tc, EL2);
|
||||
currState->ipaSpace = ipaspace;
|
||||
} else {
|
||||
currState->regime =
|
||||
translationRegime(_tc, currState->el);
|
||||
@@ -382,7 +384,8 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
|
||||
currState->hcr = currState->tc->readMiscReg(MISCREG_HCR_EL2);
|
||||
if (isStage2) {
|
||||
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL1);
|
||||
if (currState->secureLookup) {
|
||||
if (currState->ss == SecurityState::Secure &&
|
||||
currState->ipaSpace == PASpace::Secure) {
|
||||
currState->vtcr =
|
||||
currState->tc->readMiscReg(MISCREG_VSTCR_EL2);
|
||||
} else {
|
||||
@@ -905,12 +908,19 @@ TableWalker::processWalkAArch64()
|
||||
switch (currState->regime) {
|
||||
case TranslationRegime::EL10:
|
||||
if (isStage2) {
|
||||
if (currState->secureLookup) {
|
||||
if (currState->ss == SecurityState::Secure &&
|
||||
currState->ipaSpace == PASpace::Secure) {
|
||||
// Secure EL1&0 Secure IPA
|
||||
DPRINTF(TLB, " - Selecting VSTTBR_EL2 (AArch64 stage 2)\n");
|
||||
ttbr = currState->tc->readMiscReg(MISCREG_VSTTBR_EL2);
|
||||
currState->secureLookup = !currState->vtcr.sw;
|
||||
} else {
|
||||
// Secure EL1&0 NonSecure IPA or NonSecure EL1&0
|
||||
DPRINTF(TLB, " - Selecting VTTBR_EL2 (AArch64 stage 2)\n");
|
||||
ttbr = currState->tc->readMiscReg(MISCREG_VTTBR_EL2);
|
||||
currState->secureLookup = currState->ss == SecurityState::Secure ?
|
||||
!currState->vtcr.nsw : // Secure EL1&0 NonSecure IPA
|
||||
false; // NonSecure EL1&0
|
||||
}
|
||||
tsz = 64 - currState->vtcr.t0sz64;
|
||||
tg = GrainMap_tg0[currState->vtcr.tg0];
|
||||
@@ -1809,8 +1819,10 @@ TableWalker::doLongDescriptor()
|
||||
case LongDescriptor::Table:
|
||||
{
|
||||
// Set hierarchical permission flags
|
||||
currState->secureLookup = currState->secureLookup &&
|
||||
currState->longDesc.secureTable();
|
||||
if (!isStage2) {
|
||||
currState->secureLookup = currState->secureLookup &&
|
||||
currState->longDesc.secureTable();
|
||||
}
|
||||
currState->longDescData->rwTable =
|
||||
currState->longDescData->rwTable &&
|
||||
(currState->longDesc.rwTable() || currState->hpd);
|
||||
@@ -2246,6 +2258,7 @@ TableWalker::insertPartialTableEntry(LongDescriptor &descriptor)
|
||||
te.lookupLevel = descriptor.lookupLevel;
|
||||
te.ns = !descriptor.secure(have_security, currState);
|
||||
te.ss = currState->ss;
|
||||
te.ipaSpace = currState->ipaSpace; // Used by stage2 entries only
|
||||
te.type = TypeTLB::unified;
|
||||
|
||||
te.regime = currState->regime;
|
||||
@@ -2292,6 +2305,7 @@ TableWalker::insertTableEntry(DescriptorBase &descriptor, bool long_descriptor)
|
||||
te.lookupLevel = descriptor.lookupLevel;
|
||||
te.ns = !descriptor.secure(have_security, currState);
|
||||
te.ss = currState->ss;
|
||||
te.ipaSpace = currState->ipaSpace; // Used by stage2 entries only
|
||||
te.xn = descriptor.xn();
|
||||
te.type = currState->mode == BaseMMU::Execute ?
|
||||
TypeTLB::instruction : TypeTLB::data;
|
||||
|
||||
@@ -493,8 +493,13 @@ class TableWalker : public ClockedObject
|
||||
secure(bool have_security, WalkerState *currState) const override
|
||||
{
|
||||
if (type() == Block || type() == Page) {
|
||||
return have_security &&
|
||||
(currState->secureLookup && !bits(data, 5));
|
||||
if (isStage2) {
|
||||
return have_security && currState->secureLookup &&
|
||||
!currState->vtcr.nsa;
|
||||
} else {
|
||||
return have_security &&
|
||||
(currState->secureLookup && !bits(data, 5));
|
||||
}
|
||||
} else {
|
||||
return have_security && currState->secureLookup;
|
||||
}
|
||||
@@ -906,6 +911,11 @@ class TableWalker : public ClockedObject
|
||||
* long descriptor table attributes. */
|
||||
bool secureLookup = false;
|
||||
|
||||
/** IPA space (Secure vs NonSecure); stage2 only.
|
||||
* This depends on whether the stage1 translation targeted
|
||||
* a secure or non-secure IPA space */
|
||||
PASpace ipaSpace;
|
||||
|
||||
/** True if table walks are uncacheable (for table descriptors) */
|
||||
bool isUncacheable;
|
||||
|
||||
@@ -1143,6 +1153,7 @@ class TableWalker : public ClockedObject
|
||||
uint16_t asid, vmid_t _vmid,
|
||||
BaseMMU::Mode mode, BaseMMU::Translation *_trans,
|
||||
bool timing, bool functional, SecurityState ss,
|
||||
PASpace ipaspace,
|
||||
MMU::ArmTranslationType tran_type, bool stage2,
|
||||
const TlbEntry *walk_entry);
|
||||
|
||||
|
||||
@@ -328,7 +328,8 @@ TLBIIPA::matchEntry(TlbEntry* te, vmid_t vmid) const
|
||||
{
|
||||
TlbEntry::Lookup lookup_data = lookupGen(vmid);
|
||||
|
||||
return te->match(lookup_data) && (!lastLevel || !te->partial);
|
||||
return te->match(lookup_data) && (!lastLevel || !te->partial) &&
|
||||
ipaSpace == te->ipaSpace;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -371,9 +372,10 @@ TLBIRIPA::matchEntry(TlbEntry* te, vmid_t vmid) const
|
||||
|
||||
auto addr_match = te->match(lookup_data) && (!lastLevel || !te->partial);
|
||||
if (addr_match) {
|
||||
return tgMap[rangeData.tg] == te->tg &&
|
||||
(resTLBIttl(rangeData.tg, rangeData.ttl) ||
|
||||
rangeData.ttl == te->lookupLevel);
|
||||
return ipaSpace == te->ipaSpace &&
|
||||
tgMap[rangeData.tg] == te->tg &&
|
||||
(resTLBIttl(rangeData.tg, rangeData.ttl) ||
|
||||
rangeData.ttl == te->lookupLevel);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -409,9 +409,37 @@ class TLBIIPA : public TLBIOp
|
||||
public:
|
||||
TLBIIPA(TranslationRegime _target_regime, SecurityState _ss, Addr _addr,
|
||||
bool last_level, Attr _attr=Attr::None)
|
||||
: TLBIOp(_target_regime, _ss, _attr), addr(_addr), lastLevel(last_level)
|
||||
: TLBIOp(_target_regime, _ss, _attr),
|
||||
addr(_addr),
|
||||
lastLevel(last_level),
|
||||
ipaSpace(PASpace::NonSecure)
|
||||
{}
|
||||
|
||||
TLBIIPA(ThreadContext *tc, TranslationRegime _target_regime,
|
||||
SecurityState _ss, RegVal val,
|
||||
bool last_level, Attr _attr=Attr::None)
|
||||
: TLBIOp(_target_regime, _ss, _attr),
|
||||
addr(0),
|
||||
lastLevel(last_level),
|
||||
ipaSpace(PASpace::NonSecure)
|
||||
{
|
||||
const int top_bit = ArmSystem::physAddrRange(tc) == 52 ?
|
||||
39 : 35;
|
||||
addr = static_cast<Addr>(bits(val, top_bit, 0)) << 12;
|
||||
|
||||
switch (ss) {
|
||||
case SecurityState::NonSecure:
|
||||
ipaSpace = PASpace::NonSecure;
|
||||
break;
|
||||
case SecurityState::Secure:
|
||||
ipaSpace = bits(val, 63) ?
|
||||
PASpace::NonSecure : PASpace::Secure;
|
||||
break;
|
||||
default:
|
||||
panic("Invalid SecurityState\n");
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(ThreadContext* tc) override;
|
||||
|
||||
bool matchEntry(TlbEntry *entry, vmid_t curr_vmid) const override;
|
||||
@@ -424,6 +452,7 @@ class TLBIIPA : public TLBIOp
|
||||
|
||||
Addr addr;
|
||||
bool lastLevel;
|
||||
PASpace ipaSpace;
|
||||
};
|
||||
|
||||
/** TLB Range Invalidate by VA */
|
||||
@@ -456,11 +485,13 @@ class TLBIRMVAA : public TLBIRange, public TLBIMVAA
|
||||
class TLBIRIPA : public TLBIRange, public TLBIIPA
|
||||
{
|
||||
public:
|
||||
TLBIRIPA(TranslationRegime _target_regime, SecurityState _ss,
|
||||
TLBIRIPA(ThreadContext *tc, TranslationRegime _target_regime, SecurityState _ss,
|
||||
RegVal val, bool last_level, Attr _attr)
|
||||
: TLBIRange(val),
|
||||
TLBIIPA(_target_regime, _ss, startAddress(), last_level, _attr)
|
||||
{}
|
||||
TLBIIPA(tc, _target_regime, _ss, val, last_level, _attr)
|
||||
{
|
||||
addr = startAddress();
|
||||
}
|
||||
|
||||
bool matchEntry(TlbEntry *entry, vmid_t curr_vmid) const override;
|
||||
};
|
||||
|
||||
@@ -275,6 +275,13 @@ namespace ArmISA
|
||||
Secure
|
||||
};
|
||||
|
||||
/** Physical Address Space */
|
||||
enum class PASpace
|
||||
{
|
||||
NonSecure,
|
||||
Secure
|
||||
};
|
||||
|
||||
enum ExceptionLevel
|
||||
{
|
||||
EL0 = 0,
|
||||
|
||||
Reference in New Issue
Block a user