arch-arm: Implement ARMv8.1-PAN, Privileged access never
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Mon, 29 Jul 2019 11:38:12 +0000 (12:38 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Mon, 5 Aug 2019 15:50:57 +0000 (15:50 +0000)
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 <giacomo.travaglini@arm.com>
Change-Id: I94a76311711739dd2394c72944d88ba9321fd159
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/19729
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
17 files changed:
src/arch/arm/ArmISA.py
src/arch/arm/ArmSystem.py
src/arch/arm/faults.cc
src/arch/arm/faults.hh
src/arch/arm/insts/misc64.cc
src/arch/arm/insts/static_inst.cc
src/arch/arm/isa.cc
src/arch/arm/isa.hh
src/arch/arm/isa/formats/aarch64.isa
src/arch/arm/isa/insts/data64.isa
src/arch/arm/miscregs.cc
src/arch/arm/miscregs.hh
src/arch/arm/miscregs_types.hh
src/arch/arm/system.cc
src/arch/arm/system.hh
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh

index 3d30e5f6e88686c3ee8ce807afcea8fe25441bae..3c1f7dd1141284c2949743acefad28d9b2491c43 100644 (file)
@@ -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")
index ec30e0bf67ecb38bda8df5f65c56d06a5845a706..daf94a97e08c9d171cf75ad8bf3733014640e9c4 100644 (file)
@@ -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")
index a03c917037e7d3e9a16a71609a5fda17d348a47d..0f279fab4cf8c16c7ba3f415ef2b4ac7643ce281 100644 (file)
@@ -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
index d14983d28d86bdf423a27aef76b4d391b8adf253..5e68875f5979df76212137bce57047d66ddc4406 100644 (file)
@@ -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
index cf625ebefb8b296a674375460f25143a212dbefe..2d0422f62f27cd1809ef69f5cf278eb92a488a56 100644 (file)
@@ -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");
     }
index cc0e8f3f20b30642547d3fbeb1f0f426c5484c20..ec705909c12bd7a5c442df83ceb4e6e732aef1c7 100644 (file)
@@ -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);
index cdc44cdb9d37bdc1e81efdbaf79b0697d702e81f..23738c6ae37cdd2712153cb538ba30686e2ec921 100644 (file)
@@ -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));
index b4689d74e9d09a665d007af8c3cc9288e0a27fc3..63051cd8310a26dc897254e21611e316596e8066 100644 (file)
@@ -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);
index 144ff88ca8d8eb484297ab4f9471e6b1b8d55a25..82770ebc6a5c368df0d2c21957cc6100e6cb15d9 100644 (file)
@@ -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(
index b3e03d67d2fce17fba53106194248f92a7efee80..bb0334372e3a5b9b7a03cfc51f33e62aa0558f4e 100644 (file)
@@ -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<UndefinedInstruction>(
-                                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<UndefinedInstruction>(
+                                    machInst, false,
+                                    mnemonic);
+            }
+
+            if (!canWriteAArch64SysReg(misc_index,
+                Scr64, Cpsr, xc->tcBase())) {
+
+                    return std::make_shared<UndefinedInstruction>(
+                                    machInst, 0, EC_TRAPPED_MSR_MRS_64,
+                                    mnemonic);
             }
 
         '''
index 5fd7d2c534f41904993550fbde1f0cc68bf366b9..7283b205f7679203420947c70e653c83fd6779e9 100644 (file)
@@ -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)
index feef79e7350d324574a8ef99785efcc978567cfc..a95168bf37c2289998be6f79b19e9d5004de3a01 100644 (file)
@@ -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,
index c0eafdaacb5dfce15debcfadb5e712a9b2fdb921..0d6775ec97b5ca5506dd8ba2b8ad5c63102d9752 100644 (file)
@@ -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
index aa487767f2e2b6cbc83d01654eb256fc2f7b8c45..874e3b0212a8a770307e984b81a1ecba51fdb34a 100644 (file)
@@ -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
index 263dd289ec3349e66b7bacde2eb4e54a748de623..e09f4770608f9ba710d29a1782b9d8807539f846 100644 (file)
@@ -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; }
index 872f351c6b92e94a2571a1f349be69f08f80b851..848bd5b26527a24c382db53ae58dc77753799644 100644 (file)
@@ -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,
index a84e945f439ef1d0c8317311659417139eef1fdf..ea78a21b5dcceb0c6ce16fd1d9b8cdf1a4baf9bf 100644 (file)
@@ -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