| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2020 Metempsy Technology Consulting |
| // All rights reserved |
| // |
| // The license below extends only to copyright in the software and shall |
| // not be construed as granting a license to any other intellectual |
| // property including but not limited to intellectual property relating |
| // to a hardware implementation of the functionality of the software |
| // licensed hereunder. You may use the software subject to the license |
| // terms below provided that you ensure that this notice is replicated |
| // unmodified and in its entirety in all distributions of the software, |
| // modified or unmodified, in source code or in binary form. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer; |
| // redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution; |
| // neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "arch/arm/pauth_helpers.hh" |
| |
| #include "arch/arm/faults.hh" |
| #include "base/bitfield.hh" |
| |
| using namespace ArmISA; |
| using namespace std; |
| |
| bool |
| ArmISA::calculateTBI(ThreadContext* tc, ExceptionLevel el, |
| uint64_t ptr, bool data) |
| { |
| bool tbi = false; |
| if (upperAndLowerRange(tc, el)) { |
| |
| ExceptionLevel s1_el = s1TranslationRegime(tc, el); |
| assert (s1_el == EL1 || s1_el == EL2); |
| TCR tcr = (s1_el == EL1) ? tc->readMiscReg(MISCREG_TCR_EL1): |
| tc->readMiscReg(MISCREG_TCR_EL2); |
| bool b55 = bits(ptr, 55) == 1; |
| if (data) |
| tbi = b55 ? tcr.tbi1 == 1 : tcr.tbi0 == 1; |
| else |
| tbi = b55 ? (tcr.tbi1 == 1 && tcr.tbid1 == 0) : |
| (tcr.tbi0 == 1 && tcr.tbid0 == 0); |
| |
| } |
| else if (el == EL2) { |
| TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2); |
| tbi = data ? tcr.tbi == 1 : (tcr.tbi == 1 && tcr.tbid == 0); |
| } |
| else if (el == EL3) { |
| TCR tcr = tc->readMiscReg(MISCREG_TCR_EL3); |
| tbi = data ? tcr.tbi == 1 : (tcr.tbi == 1 && tcr.tbid == 0); |
| } |
| return tbi; |
| } |
| |
| int |
| ArmISA::calculateBottomPACBit(ThreadContext* tc, ExceptionLevel el, |
| bool top_bit) |
| { |
| uint32_t tsz_field; |
| bool using64k; |
| if (upperAndLowerRange(tc, el)) { |
| ExceptionLevel s1_el = s1TranslationRegime(tc, el); |
| assert (s1_el == EL1 || s1_el == EL2); |
| if (s1_el == EL1) { |
| // EL1 translation regime registers |
| TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1); |
| tsz_field = top_bit ? (uint32_t)tcr.t1sz : (uint32_t)tcr.t0sz; |
| using64k = top_bit ? tcr.tg1 == 0x3 : tcr.tg0 == 0x1; |
| } else { |
| // EL2 translation regime registers |
| TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2); |
| assert (ArmSystem::haveEL(tc, EL2)); |
| tsz_field = top_bit? (uint32_t)tcr.t1sz : (uint32_t)tcr.t0sz; |
| using64k = top_bit ? tcr.tg1 == 0x3 : tcr.tg0 == 0x1; |
| } |
| } else { |
| TCR tcr2 = tc->readMiscReg(MISCREG_TCR_EL2); |
| TCR tcr3 = tc->readMiscReg(MISCREG_TCR_EL3); |
| tsz_field = el == EL2 ? (uint32_t)tcr2.t0sz: (uint32_t)tcr3.t0sz; |
| using64k = el == EL2 ? tcr2.tg0 == 0x1 : tcr3.tg0 == 0x1 ; |
| } |
| uint32_t max_limit_tsz_field = using64k ? 47 : 48; |
| tsz_field = min(tsz_field, max_limit_tsz_field); |
| const AA64MMFR2 mm_fr2 = tc->readMiscReg(MISCREG_ID_AA64MMFR2_EL1); |
| |
| uint32_t tszmin = (using64k && (bool)mm_fr2.varange) ? 12 : 16; |
| tsz_field = max(tsz_field, tszmin); |
| |
| return (64-tsz_field); |
| } |
| |
| Fault |
| ArmISA::trapPACUse(ThreadContext *tc, ExceptionLevel target_el) |
| { |
| assert(ArmSystem::haveEL(tc, target_el) && |
| target_el != EL0 && (target_el >= currEL(tc))); |
| |
| switch (target_el) { |
| case EL2: |
| return std::make_shared<HypervisorTrap>(0x0, 0, EC_TRAPPED_PAC); |
| case EL3: |
| return std::make_shared<SecureMonitorTrap>(0x0, 0, EC_TRAPPED_PAC); |
| default: |
| return NoFault; |
| } |
| } |
| |
| uint64_t |
| ArmISA::addPAC (ThreadContext* tc, ExceptionLevel el, uint64_t ptr, |
| uint64_t modifier, uint64_t k1, uint64_t k0, bool data) |
| { |
| uint64_t PAC; |
| uint64_t result; |
| uint64_t ext_ptr; |
| bool selbit; |
| |
| bool tbi = calculateTBI(tc, el, ptr, data); |
| int top_bit = tbi ? 55 : 63; |
| bool b55 = bits(ptr, 55); |
| bool b63 = bits(ptr, 63); |
| // If tagged pointers are in use for a regime with two TTBRs,use bit<55> of |
| // the pointer to select between upper and lower ranges, and preserve this. |
| // This handles the awkward case where there is apparently no correct |
| // choice between the upper and lower address range - ie an addr of |
| // 1xxxxxxx0... with TBI0=0 and TBI1=1 and 0xxxxxxx1 with TBI1=0 and TBI0=1 |
| |
| if (upperAndLowerRange(tc, el)) { |
| ExceptionLevel s1_el = s1TranslationRegime(tc, el); |
| assert (s1_el == EL1 || s1_el == EL2); |
| if (s1_el == EL1) { |
| // EL1 translation regime registers |
| TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1); |
| if (data) { |
| selbit = (tcr.tbi1 == 1 || tcr.tbi0 == 1) ? b55: b63; |
| } else { |
| selbit = ((tcr.tbi1 == 1 && tcr.tbid1 == 0) |
| || (tcr.tbi0 == 1 && tcr.tbid0 == 0)) ? b55 : b63; |
| } |
| } else { |
| // EL2 translation regime registers |
| TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2); |
| bool have_el2 = ArmSystem::haveEL(tc, EL2); |
| if (data) { |
| selbit = (have_el2 && |
| (tcr.tbi0 == 1 || tcr.tbi1 == 1))? b55: b63; |
| } |
| else |
| { |
| selbit = (have_el2 && |
| ((tcr.tbi1 == 1 && tcr.tbid1 == 0) || |
| (tcr.tbi0 == 1 && tcr.tbid0 == 0)))? b55: b63; |
| } |
| } |
| } else { |
| selbit = tbi ? b55: b63; |
| } |
| |
| int bottom_PAC_bit = calculateBottomPACBit(tc, el, selbit); |
| // The pointer authentication code field takes all the available |
| // bits in between |
| |
| uint32_t nbits = (top_bit+1) - bottom_PAC_bit; |
| uint64_t pacbits = ((uint64_t)0x1 << nbits) -1; // 2^n -1; |
| uint64_t mask = pacbits << bottom_PAC_bit; // creates mask |
| |
| if (selbit) { |
| ext_ptr = ptr | mask; |
| } else { |
| ext_ptr = ptr & ~mask; |
| } |
| |
| PAC = QARMA::computePAC(ext_ptr, modifier, k1, k0); |
| // Check if the ptr has good extension bits and corrupt the |
| // pointer authentication code if not; |
| uint64_t t = bits(ptr, top_bit, bottom_PAC_bit); |
| if (t != 0x0 && t != pacbits) { |
| PAC ^= ((uint64_t)0x1 << (top_bit-1)); |
| } |
| // Preserve the determination between upper and lower address |
| // at bit<55> and insert PAC |
| if (tbi) { |
| // ptr<63:56>:selbit:PAC<54:bottom_PAC_bit>:ptr<bottom_PAC_bit-1:0>; |
| result = ptr & 0xFF00000000000000; |
| } else { |
| // PAC<63:56>:selbit:PAC<54:bottom_PAC_bit>:ptr<bottom_PAC_bit-1:0>; |
| result = PAC & 0xFF00000000000000; |
| } |
| |
| uint64_t masked_PAC = PAC & 0x007FFFFFFFFFFFFF; |
| uint64_t pacbit_mask = ((uint64_t)0x1 << bottom_PAC_bit) -1; |
| uint64_t masked_ptr = ptr & pacbit_mask; |
| |
| masked_PAC &= ~pacbit_mask; |
| result |= ((uint64_t)selbit << 55) | masked_PAC | masked_ptr; |
| |
| return result; |
| } |
| |
| |
| uint64_t |
| ArmISA::auth(ThreadContext *tc, ExceptionLevel el, uint64_t ptr, |
| uint64_t modifier, uint64_t k1, uint64_t k0, bool data, |
| uint8_t errorcode) |
| { |
| uint64_t PAC; |
| uint64_t result; |
| uint64_t original_ptr; |
| // Reconstruct the extension field used of adding the PAC to the pointer |
| bool tbi = calculateTBI(tc, el, ptr, data); |
| bool selbit = (bool) bits(ptr, 55); |
| |
| int bottom_PAC_bit = calculateBottomPACBit(tc, el, selbit); |
| |
| uint32_t top_tbi = tbi? 56: 64; |
| uint32_t nbits = top_tbi - bottom_PAC_bit; |
| uint64_t pacbits = ((uint64_t)0x1 << nbits) -1; // 2^n -1; |
| uint64_t mask = (pacbits << bottom_PAC_bit); // creates mask |
| |
| if (selbit) { |
| original_ptr = ptr | mask; |
| } else { |
| original_ptr = ptr & ~mask; |
| } |
| |
| |
| PAC = QARMA::computePAC(original_ptr, modifier, k1, k0); |
| // Check pointer authentication code |
| |
| // <bottom_PAC_bit:0> |
| uint64_t low_mask = ((uint64_t)0x1 << bottom_PAC_bit) -1; |
| // <54:bottom_PAC_bit> |
| uint64_t pac_mask = 0x007FFFFFFFFFFFFF & ~low_mask; |
| |
| uint64_t masked_pac = PAC & pac_mask; |
| uint64_t masked_ptr = ptr & pac_mask; |
| |
| if (tbi) { |
| if (masked_pac == masked_ptr) { |
| result = original_ptr; |
| } else { |
| uint64_t mask2= ~((uint64_t)0x3 << 53); |
| result = original_ptr & mask2; |
| result |= (uint64_t)errorcode << 53; |
| } |
| } else { |
| if ((masked_pac == masked_ptr) && ((PAC >>56)==(ptr >> 56))) { |
| result = original_ptr; |
| } else { |
| uint64_t mask2 = ~((uint64_t)0x3 << 61); |
| result = original_ptr & mask2; |
| result |= (uint64_t)errorcode << 61; |
| } |
| } |
| return result; |
| } |
| |
| Fault |
| ArmISA::authDA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out) |
| { |
| /* |
| Returns a 64-bit value containing X, but replacing the pointer |
| authentication code field bits with the extension of the address bits. |
| The instruction checks a pointer |
| authentication code in the pointer authentication code field bits of X, |
| using the same algorithm and key as AddPACDA(). |
| */ |
| |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APDAKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APDAKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.enda : (bool)sc2.enda; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| enable = sc1.enda; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL2: |
| enable = sc2.enda; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL3: |
| enable = sc3.enda; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| default: |
| // Unreachable |
| break; |
| } |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else { |
| *out = auth(tc, el, X, Y, hi_key, lo_key, true, 0x1); |
| } |
| return NoFault; |
| } |
| |
| Fault |
| ArmISA::authDB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out) |
| { |
| /* |
| Returns a 64-bit value containing X, but replacing the pointer |
| authentication code field bits with the extension of the address bits. |
| The instruction checks a pointer |
| authentication code in the pointer authentication code field bits of X, |
| using the same algorithm and key as AddPACDA(). |
| */ |
| |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APDBKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APDBKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.endb : (bool)sc2.endb; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| enable = sc1.endb; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL2: |
| enable = sc2.endb; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL3: |
| enable = sc3.endb; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| default: |
| //unreachable |
| break; |
| } |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = auth(tc, el, X, Y, hi_key, lo_key, true, 0x2); |
| |
| return NoFault; |
| } |
| |
| |
| Fault |
| ArmISA::authIA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out) |
| { |
| /* |
| Returns a 64-bit value containing X, but replacing the pointer |
| authentication code field bits with the extension of the address bits. |
| The instruction checks a pointer |
| authentication code in the pointer authentication code field bits of X, |
| using the same algorithm and key as AddPACDA(). |
| */ |
| |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APIAKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APIAKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.enia : (bool)sc2.enia; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| { |
| enable = sc1.enia; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL2: |
| { |
| enable = sc2.enia; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL3: |
| { |
| enable = sc3.enia; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| } |
| default: |
| //unreachable |
| break; |
| } |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = auth(tc, el, X, Y, hi_key, lo_key, false, 0x1); |
| |
| return NoFault; |
| } |
| |
| Fault |
| ArmISA::authIB(ThreadContext *tc, uint64_t X, uint64_t Y, uint64_t* out) |
| { |
| /* |
| Returns a 64-bit value containing X, but replacing the pointer |
| authentication code field bits with the extension of the address bits. |
| The instruction checks a pointer |
| authentication code in the pointer authentication code field bits of X, |
| using the same algorithm and key as AddPACDA(). |
| */ |
| |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APIBKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APIBKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.enib : (bool)sc2.enib; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| { |
| enable = sc1.enib; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL2: |
| { |
| enable = sc2.enib; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL3: |
| { |
| enable = sc3.enib; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| } |
| default: |
| //unreachable |
| break; |
| } |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = auth(tc, el, X, Y, hi_key, lo_key, false, 0x2); |
| |
| return NoFault; |
| } |
| |
| |
| |
| Fault |
| ArmISA::addPACDA(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out) |
| { |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APDAKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APDAKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.enda : (bool)sc2.enda; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| { |
| enable = sc1.enda; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL2: |
| { |
| enable = sc2.enda; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL3: |
| { |
| enable = sc3.enda; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| } |
| } |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = addPAC(tc, el, X, Y, hi_key, lo_key, true); |
| |
| return NoFault; |
| } |
| |
| |
| Fault |
| ArmISA::addPACDB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out) |
| { |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APDBKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APDBKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.endb : (bool)sc2.endb; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| enable = sc1.endb; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL2: |
| enable = sc2.endb; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL3: |
| enable = sc3.endb; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| default: |
| // unreachable |
| break; |
| } |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = addPAC(tc, el, X, Y, hi_key, lo_key, true); |
| |
| return NoFault; |
| } |
| |
| |
| Fault |
| ArmISA::addPACGA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out) |
| { |
| bool trapEL2; |
| bool trapEL3; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APGAKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APGAKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCR sc3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == '0' || hcr.e2h == 0)); |
| trapEL3 = have_el3 && sc3.api == 0; |
| break; |
| case EL1: |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && sc3.api == 0; |
| break; |
| case EL2: |
| trapEL2 = false; |
| trapEL3 = have_el3 && sc3.api == 0; |
| break; |
| case EL3: |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| default: |
| //unreachable |
| break; |
| } |
| if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = QARMA::computePAC(X, Y, hi_key, lo_key) & 0xFFFFFFFF00000000; |
| |
| return NoFault; |
| } |
| |
| |
| Fault |
| ArmISA::addPACIA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out){ |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APIAKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APIAKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.enia : (bool)sc2.enia; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| enable = sc1.enia; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL2: |
| enable = sc2.enia; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL3: |
| enable = sc3.enia; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| default: |
| //unreachable |
| break; |
| } |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = addPAC(tc, el, X, Y, hi_key, lo_key, false); |
| |
| return NoFault; |
| } |
| |
| Fault |
| ArmISA::addPACIB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out){ |
| bool trapEL2; |
| bool trapEL3; |
| bool enable; |
| |
| uint64_t hi_key= tc->readMiscReg(MISCREG_APIBKeyHi_EL1); |
| uint64_t lo_key= tc->readMiscReg(MISCREG_APIBKeyLo_EL1); |
| |
| ExceptionLevel el = currEL(tc); |
| SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1); |
| SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2); |
| SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3); |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| { |
| bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1; |
| enable = IsEL1Regime ? (bool)sc1.enib : (bool)sc2.enib; |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| } |
| case EL1: |
| enable = sc1.enib; |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL2: |
| enable = sc2.enib; |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL3: |
| enable = sc3.enib; |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| default: |
| // Unnaccessible |
| break; |
| } |
| |
| if (!enable) |
| *out = X; |
| else if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = addPAC(tc, el, X, Y, hi_key, lo_key, false); |
| |
| return NoFault; |
| } |
| |
| |
| |
| Fault |
| ArmISA::stripPAC(ThreadContext* tc, uint64_t A, bool data, uint64_t* out){ |
| bool trapEL2; |
| bool trapEL3; |
| |
| uint64_t ptr; |
| |
| ExceptionLevel el = currEL(tc); |
| |
| bool tbi = calculateTBI(tc, el, A, data); |
| bool selbit = (bool) bits(A, 55); |
| int bottom_PAC_bit = calculateBottomPACBit(tc, el, selbit); |
| |
| int top_bit = tbi ? 55 : 63; |
| uint32_t nbits = (top_bit+1) - bottom_PAC_bit; |
| uint64_t pacbits = ((uint64_t)0x1 << nbits) -1; // 2^n -1; |
| uint64_t mask = pacbits << bottom_PAC_bit; // creates mask |
| |
| |
| if (selbit) { |
| ptr = A | mask; |
| } else { |
| ptr = A & ~mask; |
| } |
| |
| SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3); |
| HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); |
| bool have_el3 = ArmSystem::haveEL(tc, EL3); |
| |
| switch (el) |
| { |
| case EL0: |
| trapEL2 = (EL2Enabled(tc) && hcr.api == 0 && |
| (hcr.tge == 0 || hcr.e2h == 0)); |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL1: |
| trapEL2 = EL2Enabled(tc) && hcr.api == 0; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL2: |
| trapEL2 = false; |
| trapEL3 = have_el3 && scr3.api == 0; |
| break; |
| case EL3: |
| trapEL2 = false; |
| trapEL3 = false; |
| break; |
| default: |
| // Unnaccessible |
| break; |
| } |
| if (trapEL2) |
| return trapPACUse(tc, EL2); |
| else if (trapEL3) |
| return trapPACUse(tc, EL3); |
| else |
| *out = ptr; |
| |
| return NoFault; |
| } |
| |