From fc6879097b04643f6345adad39e54f44afb85d2f Mon Sep 17 00:00:00 2001 From: Dylan Johnson Date: Tue, 2 Aug 2016 10:38:02 +0100 Subject: [PATCH] arm: Fix EL perceived at TLB for address translation instructions During address translation instructions (such as AT S1E1R_Xt) the exception level can be different than the current exception level. This patch fixes how the TLB determines what EL to use during these instructions. Change-Id: Ia9ce229404de9e284bc1f7479fd2c580efd55f8f --- src/arch/arm/isa.cc | 46 +++++++++++++++++++++++++++------------------ src/arch/arm/tlb.cc | 28 +++++++++++++++++++++++++-- src/arch/arm/tlb.hh | 14 ++++++++++++-- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index 2300b925e..016e1eca0 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -1698,62 +1698,62 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) switch(misc_reg) { case MISCREG_AT_S1E1R_Xt: flags = TLB::MustBeOne; - tranType = TLB::S1CTran; + tranType = TLB::S1E1Tran; mode = BaseTLB::Read; break; case MISCREG_AT_S1E1W_Xt: flags = TLB::MustBeOne; - tranType = TLB::S1CTran; + tranType = TLB::S1E1Tran; mode = BaseTLB::Write; break; case MISCREG_AT_S1E0R_Xt: flags = TLB::MustBeOne | TLB::UserMode; - tranType = TLB::S1CTran; + tranType = TLB::S1E0Tran; mode = BaseTLB::Read; break; case MISCREG_AT_S1E0W_Xt: flags = TLB::MustBeOne | TLB::UserMode; - tranType = TLB::S1CTran; + tranType = TLB::S1E0Tran; mode = BaseTLB::Write; break; case MISCREG_AT_S1E2R_Xt: flags = TLB::MustBeOne; - tranType = TLB::HypMode; + tranType = TLB::S1E2Tran; mode = BaseTLB::Read; break; case MISCREG_AT_S1E2W_Xt: flags = TLB::MustBeOne; - tranType = TLB::HypMode; + tranType = TLB::S1E2Tran; mode = BaseTLB::Write; break; case MISCREG_AT_S12E0R_Xt: flags = TLB::MustBeOne | TLB::UserMode; - tranType = TLB::S1S2NsTran; + tranType = TLB::S12E0Tran; mode = BaseTLB::Read; break; case MISCREG_AT_S12E0W_Xt: flags = TLB::MustBeOne | TLB::UserMode; - tranType = TLB::S1S2NsTran; + tranType = TLB::S12E0Tran; mode = BaseTLB::Write; break; case MISCREG_AT_S12E1R_Xt: flags = TLB::MustBeOne; - tranType = TLB::S1S2NsTran; + tranType = TLB::S12E1Tran; mode = BaseTLB::Read; break; case MISCREG_AT_S12E1W_Xt: flags = TLB::MustBeOne; - tranType = TLB::S1S2NsTran; + tranType = TLB::S12E1Tran; mode = BaseTLB::Write; break; case MISCREG_AT_S1E3R_Xt: flags = TLB::MustBeOne; - tranType = TLB::HypMode; // There is no TZ mode defined. + tranType = TLB::S1E3Tran; mode = BaseTLB::Read; break; case MISCREG_AT_S1E3W_Xt: flags = TLB::MustBeOne; - tranType = TLB::HypMode; // There is no TZ mode defined. + tranType = TLB::S1E3Tran; mode = BaseTLB::Write; break; } @@ -1788,12 +1788,22 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) // Set fault bit and FSR FSR fsr = armFault->getFsr(tc); - newVal = ((fsr >> 9) & 1) << 11; - // rearange fault status - newVal |= ((fsr >> 0) & 0x3f) << 1; - newVal |= 0x1; // F bit - newVal |= ((armFault->iss() >> 7) & 0x1) << 8; - newVal |= armFault->isStage2() ? 0x200 : 0; + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + if (cpsr.width) { // AArch32 + newVal = ((fsr >> 9) & 1) << 11; + // rearrange fault status + newVal |= ((fsr >> 0) & 0x3f) << 1; + newVal |= 0x1; // F bit + newVal |= ((armFault->iss() >> 7) & 0x1) << 8; + newVal |= armFault->isStage2() ? 0x200 : 0; + } else { // AArch64 + newVal = 1; // F bit + newVal |= fsr << 1; // FST + // TODO: DDI 0487A.f D7-2083, AbortFault's s1ptw bit. + newVal |= armFault->isStage2() ? 1 << 8 : 0; // PTW + newVal |= armFault->isStage2() ? 1 << 9 : 0; // S + newVal |= 1 << 11; // RES1 + } DPRINTF(MiscRegs, "MISCREG: Translated addr %#x fault fsr %#x: PAR: %#x\n", val, fsr, newVal); diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index 864f0c28c..536fa51cd 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -1220,7 +1220,30 @@ TLB::updateMiscReg(ThreadContext *tc, ArmTranslationType tranType) (opModeToEL(op_mode) == EL0 && ELIs64(tc, EL1)); if (aarch64) { // AArch64 - aarch64EL = (ExceptionLevel) (uint8_t) cpsr.el; + // determine EL we need to translate in + switch (tranType) { + case S1E0Tran: + case S12E0Tran: + aarch64EL = EL0; + break; + case S1E1Tran: + case S12E1Tran: + aarch64EL = EL1; + break; + case S1E2Tran: + aarch64EL = EL2; + break; + case S1E3Tran: + aarch64EL = EL3; + break; + case NormalTran: + case S1CTran: + case S1S2NsTran: + case HypMode: + aarch64EL = (ExceptionLevel) (uint8_t) cpsr.el; + break; + } + switch (aarch64EL) { case EL0: case EL1: @@ -1258,7 +1281,8 @@ TLB::updateMiscReg(ThreadContext *tc, ArmTranslationType tranType) // compute it for every translation. stage2Req = isStage2 || (hcr.vm && !isHyp && !isSecure && - !(tranType & S1CTran) && (aarch64EL < EL2)); + !(tranType & S1CTran) && (aarch64EL < EL2) && + !(tranType & S1E1Tran)); // <--- FIX THIS HACK directToStage2 = !isStage2 && stage2Req && !sctlr.m; } else { vmid = 0; diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index 298c603b9..ef05bb421 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 ARM Limited + * Copyright (c) 2010-2013, 2016 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -127,7 +127,17 @@ class TLB : public BaseTLB HypMode = 0x2, // Secure code operating as if it wasn't (required by some Address // Translate operations) - S1S2NsTran = 0x4 + S1S2NsTran = 0x4, + // Address translation instructions (eg AT S1E0R_Xt) need to be handled + // in special ways during translation because they could need to act + // like a different EL than the current EL. The following flags are + // for these instructions + S1E0Tran = 0x8, + S1E1Tran = 0x10, + S1E2Tran = 0x20, + S1E3Tran = 0x40, + S12E0Tran = 0x80, + S12E1Tran = 0x100 }; protected: TlbEntry* table; // the Page Table