From 361bc8b47260a55902764054d3ac25694ac93f8a Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Mon, 29 Jul 2019 12:38:12 +0100 Subject: arch-arm: Implement ARMv8.1-PAN, Privileged access never ARMv8.1-PAN adds a new bit to PSTATE. When the value of this PAN state bit is 1, any privileged data access from EL1 or EL2 to a virtual memory address that is accessible at EL0 generates a Permission fault. This feature is mandatory in ARMv8.1 implementations. This feature is supported in AArch64 and AArch32 states. The ID_AA64MMFR1_EL1.PAN, ID_MMFR3_EL1.PAN, and ID_MMFR3.PAN fields identify the support for ARMv8.1-PAN. Signed-off-by: Giacomo Travaglini Change-Id: I94a76311711739dd2394c72944d88ba9321fd159 Reviewed-by: Andreas Sandberg Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/19729 Maintainer: Andreas Sandberg Tested-by: kokoro --- src/arch/arm/ArmISA.py | 4 ++-- src/arch/arm/ArmSystem.py | 4 +++- src/arch/arm/faults.cc | 21 ++++++++++++++++++--- src/arch/arm/faults.hh | 5 +++-- src/arch/arm/insts/misc64.cc | 2 ++ src/arch/arm/insts/static_inst.cc | 3 ++- src/arch/arm/isa.cc | 33 +++++++++++++++++++++++++++++---- src/arch/arm/isa.hh | 5 ++++- src/arch/arm/isa/formats/aarch64.isa | 4 ++++ src/arch/arm/isa/insts/data64.isa | 22 +++++++++++++++------- src/arch/arm/miscregs.cc | 7 ++++++- src/arch/arm/miscregs.hh | 8 +++++++- src/arch/arm/miscregs_types.hh | 6 ++++-- src/arch/arm/system.cc | 3 ++- src/arch/arm/system.hh | 8 +++++++- src/arch/arm/tlb.cc | 30 ++++++++++++++++++++++++++++++ src/arch/arm/tlb.hh | 2 ++ 17 files changed, 140 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/arch/arm/ArmISA.py b/src/arch/arm/ArmISA.py index 3d30e5f6e..3c1f7dd11 100644 --- a/src/arch/arm/ArmISA.py +++ b/src/arch/arm/ArmISA.py @@ -105,8 +105,8 @@ class ArmISA(SimObject): # 4K | 64K | !16K | !BigEndEL0 | !SNSMem | !BigEnd | 8b ASID | 40b PA id_aa64mmfr0_el1 = Param.UInt64(0x0000000000f00002, "AArch64 Memory Model Feature Register 0") - # HPDS - id_aa64mmfr1_el1 = Param.UInt64(0x0000000000001000, + # PAN | HPDS + id_aa64mmfr1_el1 = Param.UInt64(0x0000000000101000, "AArch64 Memory Model Feature Register 1") id_aa64mmfr2_el1 = Param.UInt64(0x0000000000000000, "AArch64 Memory Model Feature Register 2") diff --git a/src/arch/arm/ArmSystem.py b/src/arch/arm/ArmSystem.py index ec30e0bf6..daf94a97e 100644 --- a/src/arch/arm/ArmSystem.py +++ b/src/arch/arm/ArmSystem.py @@ -1,4 +1,4 @@ -# Copyright (c) 2009, 2012-2013, 2015-2018 ARM Limited +# Copyright (c) 2009, 2012-2013, 2015-2019 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -86,6 +86,8 @@ class ArmSystem(System): "True if SVE is implemented (ARMv8)") sve_vl = Param.SveVectorLength(1, "SVE vector length in quadwords (128-bit)") + have_pan = Param.Bool(True, + "True if Priviledge Access Never is implemented (ARMv8.1)") semihosting = Param.ArmSemihosting(NULL, "Enable support for the Arm semihosting by settings this parameter") diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc index a03c91703..0f279fab4 100644 --- a/src/arch/arm/faults.cc +++ b/src/arch/arm/faults.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012-2014, 2016-2018 ARM Limited + * Copyright (c) 2010, 2012-2014, 2016-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -448,6 +448,21 @@ ArmFault::update(ThreadContext *tc) if (fromEL > toEL) toEL = fromEL; + // Check for Set Priviledge Access Never, if PAN is supported + AA64MMFR1 mmfr1 = tc->readMiscReg(MISCREG_ID_AA64MMFR1_EL1); + if (mmfr1.pan) { + if (toEL == EL1) { + const SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL1); + span = !sctlr.span; + } + + const HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR_EL2); + if (toEL == EL2 && hcr.e2h && hcr.tge) { + const SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL2); + span = !sctlr.span; + } + } + to64 = ELIs64(tc, toEL); // The fault specific informations have been updated; it is @@ -536,6 +551,7 @@ ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) } cpsr.it1 = cpsr.it2 = 0; cpsr.j = 0; + cpsr.pan = span ? 1 : saved_cpsr.pan; tc->setMiscReg(MISCREG_CPSR, cpsr); // Make sure mailbox sets to one always @@ -635,7 +651,6 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst) spsr.q = 0; spsr.it1 = 0; spsr.j = 0; - spsr.res0_23_22 = 0; spsr.ge = 0; spsr.it2 = 0; spsr.t = 0; @@ -645,7 +660,6 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst) spsr.it2 = it.top6; spsr.it1 = it.bottom2; // Force some bitfields to 0 - spsr.res0_23_22 = 0; spsr.ss = 0; } tc->setMiscReg(spsr_idx, spsr); @@ -670,6 +684,7 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst) cpsr.daif = 0xf; cpsr.il = 0; cpsr.ss = 0; + cpsr.pan = span ? 1 : spsr.pan; tc->setMiscReg(MISCREG_CPSR, cpsr); // If we have a valid instruction then use it to annotate this fault with diff --git a/src/arch/arm/faults.hh b/src/arch/arm/faults.hh index d14983d28..5e68875f5 100644 --- a/src/arch/arm/faults.hh +++ b/src/arch/arm/faults.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012-2013, 2016-2018 ARM Limited + * Copyright (c) 2010, 2012-2013, 2016-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -82,6 +82,7 @@ class ArmFault : public FaultBase bool faultUpdated; bool hypRouted; // True if the fault has been routed to Hypervisor + bool span; // True if the fault is setting the PSTATE.PAN bit virtual Addr getVector(ThreadContext *tc); Addr getVector64(ThreadContext *tc); @@ -200,7 +201,7 @@ class ArmFault : public FaultBase ArmFault(ExtMachInst _machInst = 0, uint32_t _iss = 0) : machInst(_machInst), issRaw(_iss), from64(false), to64(false), fromEL(EL0), toEL(EL0), fromMode(MODE_UNDEFINED), - faultUpdated(false), hypRouted(false) {} + faultUpdated(false), hypRouted(false), span(false) {} // Returns the actual syndrome register to use based on the target // exception level diff --git a/src/arch/arm/insts/misc64.cc b/src/arch/arm/insts/misc64.cc index cf625ebef..2d0422f62 100644 --- a/src/arch/arm/insts/misc64.cc +++ b/src/arch/arm/insts/misc64.cc @@ -327,6 +327,8 @@ MiscRegImmOp64::miscRegImm() const { if (dest == MISCREG_SPSEL) { return imm & 0x1; + } else if (dest == MISCREG_PAN) { + return (imm & 0x1) << 22; } else { panic("Not a valid PSTATE field register\n"); } diff --git a/src/arch/arm/insts/static_inst.cc b/src/arch/arm/insts/static_inst.cc index cc0e8f3f2..ec705909c 100644 --- a/src/arch/arm/insts/static_inst.cc +++ b/src/arch/arm/insts/static_inst.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014, 2016-2018 ARM Limited + * Copyright (c) 2010-2014, 2016-2019 ARM Limited * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved * @@ -1129,6 +1129,7 @@ ArmStaticInst::getPSTATEFromPSR(ThreadContext *tc, CPSR cpsr, CPSR spsr) const new_cpsr.nz = spsr.nz; new_cpsr.c = spsr.c; new_cpsr.v = spsr.v; + new_cpsr.pan = spsr.pan; if (new_cpsr.width) { // aarch32 const ITSTATE it = getRestoredITBits(tc, spsr); diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index cdc44cdb9..23738c6ae 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2018 ARM Limited + * Copyright (c) 2010-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -91,6 +91,7 @@ ISA::ISA(Params *p) haveLargeAsid64 = system->haveLargeAsid64(); physAddrRange = system->physAddrRange(); haveSVE = system->haveSVE(); + havePAN = system->havePAN(); sveVL = system->sveVL(); } else { highestELIs64 = true; // ArmSystem::highestELIs64 does the same @@ -99,6 +100,7 @@ ISA::ISA(Params *p) haveLargeAsid64 = false; physAddrRange = 32; // dummy value haveSVE = true; + havePAN = false; sveVL = p->sve_vl_se; } @@ -391,6 +393,10 @@ ISA::initID64(const ArmISAParams *p) miscRegs[MISCREG_ID_AA64ISAR0_EL1] = insertBits( miscRegs[MISCREG_ID_AA64ISAR0_EL1], 19, 4, haveCrypto ? 0x1112 : 0x0); + // PAN + miscRegs[MISCREG_ID_AA64MMFR1_EL1] = insertBits( + miscRegs[MISCREG_ID_AA64MMFR1_EL1], 23, 20, + havePAN ? 0x1 : 0x0); } void @@ -640,6 +646,10 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc) { return miscRegs[MISCREG_CPSR] & 0xc; } + case MISCREG_PAN: + { + return miscRegs[MISCREG_CPSR] & 0x400000; + } case MISCREG_L2CTLR: { // mostly unimplemented, just set NumCPUs field from sim and return @@ -1880,6 +1890,17 @@ ISA::setMiscReg(int misc_reg, RegVal val, ThreadContext *tc) misc_reg = MISCREG_CPSR; } break; + case MISCREG_PAN: + { + // PAN is affecting data accesses + getDTBPtr(tc)->invalidateMiscReg(); + + CPSR cpsr = miscRegs[MISCREG_CPSR]; + cpsr.pan = (uint8_t) ((CPSR) newVal).pan; + newVal = cpsr; + misc_reg = MISCREG_CPSR; + } + break; case MISCREG_AT_S1E1R_Xt: case MISCREG_AT_S1E1W_Xt: case MISCREG_AT_S1E0R_Xt: @@ -2020,9 +2041,13 @@ ISA::setMiscReg(int misc_reg, RegVal val, ThreadContext *tc) case MISCREG_SPSR_EL3: case MISCREG_SPSR_EL2: case MISCREG_SPSR_EL1: - // Force bits 23:21 to 0 - newVal = val & ~(0x7 << 21); - break; + { + RegVal spsr_mask = havePAN ? + ~(0x5 << 21) : ~(0x7 << 21); + + newVal = val & spsr_mask; + break; + } case MISCREG_L2CTLR: warn("miscreg L2CTLR (%s) written with %#x. ignored...\n", miscRegName[misc_reg], uint32_t(val)); diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh index b4689d74e..63051cd83 100644 --- a/src/arch/arm/isa.hh +++ b/src/arch/arm/isa.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012-2018 ARM Limited + * Copyright (c) 2010, 2012-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -95,6 +95,7 @@ namespace ArmISA bool haveGICv3CPUInterface; uint8_t physAddrRange; bool haveSVE; + bool havePAN; /** SVE vector length in quadwords */ unsigned sveVL; @@ -686,6 +687,7 @@ namespace ArmISA SERIALIZE_SCALAR(physAddrRange); SERIALIZE_SCALAR(haveSVE); SERIALIZE_SCALAR(sveVL); + SERIALIZE_SCALAR(havePAN); } void unserialize(CheckpointIn &cp) { @@ -702,6 +704,7 @@ namespace ArmISA UNSERIALIZE_SCALAR(physAddrRange); UNSERIALIZE_SCALAR(haveSVE); UNSERIALIZE_SCALAR(sveVL); + UNSERIALIZE_SCALAR(havePAN); } void startup(ThreadContext *tc); diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa index 144ff88ca..82770ebc6 100644 --- a/src/arch/arm/isa/formats/aarch64.isa +++ b/src/arch/arm/isa/formats/aarch64.isa @@ -392,6 +392,10 @@ namespace Aarch64 // MSR immediate: moving immediate value to selected // bits of the PSTATE switch (op1 << 3 | op2) { + case 0x4: + // PAN + return new MsrImm64( + machInst, MISCREG_PAN, crm); case 0x5: // SP return new MsrImm64( diff --git a/src/arch/arm/isa/insts/data64.isa b/src/arch/arm/isa/insts/data64.isa index b3e03d67d..bb0334372 100644 --- a/src/arch/arm/isa/insts/data64.isa +++ b/src/arch/arm/isa/insts/data64.isa @@ -512,13 +512,21 @@ let {{ def buildMsrImmInst(mnem, inst_name, code): global header_output, decoder_output, exec_output msrImmPermission = ''' - if (!canWriteAArch64SysReg( - (MiscRegIndex) xc->tcBase()->flattenRegId( - RegId(MiscRegClass, dest)).index(), - Scr64, Cpsr, xc->tcBase())) { - return std::make_shared( - machInst, 0, EC_TRAPPED_MSR_MRS_64, - mnemonic); + auto misc_index = (MiscRegIndex) xc->tcBase()->flattenRegId( + RegId(MiscRegClass, dest)).index(); + + if (!miscRegInfo[misc_index][MISCREG_IMPLEMENTED]) { + return std::make_shared( + machInst, false, + mnemonic); + } + + if (!canWriteAArch64SysReg(misc_index, + Scr64, Cpsr, xc->tcBase())) { + + return std::make_shared( + machInst, 0, EC_TRAPPED_MSR_MRS_64, + mnemonic); } ''' diff --git a/src/arch/arm/miscregs.cc b/src/arch/arm/miscregs.cc index 5fd7d2c53..7283b205f 100644 --- a/src/arch/arm/miscregs.cc +++ b/src/arch/arm/miscregs.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, 2015-2018 ARM Limited + * Copyright (c) 2010-2013, 2015-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -1984,6 +1984,8 @@ decodeAArch64SysReg(unsigned op0, unsigned op1, return MISCREG_SPSEL; case 2: return MISCREG_CURRENTEL; + case 3: + return MISCREG_PAN; } break; case 6: @@ -4057,6 +4059,9 @@ ISA::initializeMiscRegMetadata() .allPrivileges().exceptUserMode(); InitReg(MISCREG_CURRENTEL) .allPrivileges().exceptUserMode().writes(0); + InitReg(MISCREG_PAN) + .allPrivileges().exceptUserMode() + .implemented(havePAN); InitReg(MISCREG_NZCV) .allPrivileges(); InitReg(MISCREG_DAIF) diff --git a/src/arch/arm/miscregs.hh b/src/arch/arm/miscregs.hh index feef79e73..a95168bf3 100644 --- a/src/arch/arm/miscregs.hh +++ b/src/arch/arm/miscregs.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2018 ARM Limited + * Copyright (c) 2010-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -930,6 +930,9 @@ namespace ArmISA MISCREG_VSESR_EL2, MISCREG_VDISR_EL2, + // PSTATE + MISCREG_PAN, + // Total number of Misc Registers: Physical + Dummy NUM_MISCREGS }; @@ -1854,6 +1857,9 @@ namespace ArmISA "disr_el1", "vsesr_el2", "vdisr_el2", + + // PSTATE + "pan", }; static_assert(sizeof(miscRegName) / sizeof(*miscRegName) == NUM_MISCREGS, diff --git a/src/arch/arm/miscregs_types.hh b/src/arch/arm/miscregs_types.hh index c0eafdaac..0d6775ec9 100644 --- a/src/arch/arm/miscregs_types.hh +++ b/src/arch/arm/miscregs_types.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2018 ARM Limited + * Copyright (c) 2010-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -55,7 +55,7 @@ namespace ArmISA Bitfield<27> q; Bitfield<26, 25> it1; Bitfield<24> j; - Bitfield<23, 22> res0_23_22; + Bitfield<22> pan; Bitfield<21> ss; // AArch64 Bitfield<20> il; // AArch64 Bitfield<19, 16> ge; @@ -322,6 +322,8 @@ namespace ArmISA Bitfield<25> ee; // Exception Endianness Bitfield<24> e0e; // Endianness of explicit data accesses at EL0 // (AArch64 SCTLR_EL1 only) + Bitfield<23> span; // Set Priviledge Access Never on taking + // an exception Bitfield<23> xp; // Extended page table enable (dropped in ARMv7) Bitfield<22> u; // Alignment (dropped in ARMv7) Bitfield<21> fi; // Fast interrupts configuration enable diff --git a/src/arch/arm/system.cc b/src/arch/arm/system.cc index aa487767f..874e3b021 100644 --- a/src/arch/arm/system.cc +++ b/src/arch/arm/system.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012-2013, 2015,2017-2018 ARM Limited + * Copyright (c) 2010, 2012-2013, 2015,2017-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -73,6 +73,7 @@ ArmSystem::ArmSystem(Params *p) _haveLargeAsid64(p->have_large_asid_64), _haveSVE(p->have_sve), _sveVL(p->sve_vl), + _havePAN(p->have_pan), _m5opRange(p->m5ops_base ? RangeSize(p->m5ops_base, 0x10000) : AddrRange(1, 0)), // Create an empty range if disabled diff --git a/src/arch/arm/system.hh b/src/arch/arm/system.hh index 263dd289e..e09f47706 100644 --- a/src/arch/arm/system.hh +++ b/src/arch/arm/system.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012-2013, 2015-2018 ARM Limited + * Copyright (c) 2010, 2012-2013, 2015-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -130,6 +130,9 @@ class ArmSystem : public System /** SVE vector length at reset, in quadwords */ const unsigned _sveVL; + /** True if Priviledge Access Never is implemented */ + const unsigned _havePAN; + /** * Range for memory-mapped m5 pseudo ops. The range will be * invalid/empty if disabled. @@ -241,6 +244,9 @@ class ArmSystem : public System /** Returns the SVE vector length at reset, in quadwords */ unsigned sveVL() const { return _sveVL; } + /** Returns true if Priviledge Access Never is implemented */ + bool havePAN() const { return _havePAN; } + /** Returns the supported physical address range in bits if the highest * implemented exception level is 64 bits (ARMv8) */ uint8_t physAddrRange64() const { return _physAddrRange64; } diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index 872f351c6..848bd5b26 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -904,6 +904,11 @@ TLB::checkPermissions64(TlbEntry *te, const RequestPtr &req, Mode mode, break; case EL1: { + if (checkPAN(tc, ap, req, mode)) { + grant = false; + break; + } + uint8_t perm = (ap << 2) | (xn << 1) | pxn; switch (perm) { case 0: @@ -938,6 +943,11 @@ TLB::checkPermissions64(TlbEntry *te, const RequestPtr &req, Mode mode, } break; case EL2: + if (checkPAN(tc, ap, req, mode)) { + grant = false; + break; + } + M5_FALLTHROUGH; case EL3: { uint8_t perm = (ap & 0x2) | xn; @@ -989,6 +999,26 @@ TLB::checkPermissions64(TlbEntry *te, const RequestPtr &req, Mode mode, return NoFault; } +bool +TLB::checkPAN(ThreadContext *tc, uint8_t ap, const RequestPtr &req, Mode mode) +{ + // The PAN bit has no effect on: + // 1) Instruction accesses. + // 2) Data Cache instructions other than DC ZVA + // 3) Address translation instructions, other than ATS1E1RP and + // ATS1E1WP when ARMv8.2-ATS1E1 is implemented. (Unimplemented in + // gem5) + // 4) Unprivileged instructions (Unimplemented in gem5) + AA64MMFR1 mmfr1 = tc->readMiscReg(MISCREG_ID_AA64MMFR1_EL1); + if (mmfr1.pan && cpsr.pan && (ap & 0x1) && mode != Execute && + (!req->isCacheMaintenance() || + (req->getFlags() & Request::CACHE_BLOCK_ZERO))) { + return true; + } else { + return false; + } +} + Fault TLB::translateFs(const RequestPtr &req, ThreadContext *tc, Mode mode, Translation *translation, bool &delay, bool timing, diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index a84e945f4..ea78a21b5 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -244,6 +244,8 @@ class TLB : public BaseTLB Fault checkPermissions(TlbEntry *te, const RequestPtr &req, Mode mode); Fault checkPermissions64(TlbEntry *te, const RequestPtr &req, Mode mode, ThreadContext *tc); + bool checkPAN(ThreadContext *tc, uint8_t ap, const RequestPtr &req, + Mode mode); /** Reset the entire TLB -- cgit v1.2.3