arch-arm: This commit adds Pointer Authentication feature.
authorJordi Vaquero <jordi.vaquero@metempsy.com>
Tue, 4 Feb 2020 16:37:37 +0000 (17:37 +0100)
committerJordi Vaquero <jordi.vaquero@metempsy.com>
Thu, 6 Feb 2020 22:22:54 +0000 (22:22 +0000)
+ ArmISA.py: Enabling the feature adding  QARMA algorithm as default.
+ faults.cc/faults.hh: Add PACTrapFault
+ includes/insts.isa: Adding new isa files.
+ aarch64.isa: Add decode part for PAC instructions
+ pauth.isa: Isa for PAC instructions
+ misc64.isa: PAC instructions templates
+ miscregs.cc/hh/types: New Registers for PAC Key low/high.
+ types.hh: Modification of system registers that were incomplete
            for ARMv8
+ utility.hh: Add isSecureEL2 enabled. The function is there but will
              always return false for now.
+ pauth_helpers.hh/cc: Implementation of auxiliar functions and derivates.
+ qarma.hh/cc: This functions follow ARMv8 reference pseudo code
              implementing QARMA block cipher algorithms.

Change-Id: I3095a1279204206d9a816a4fb7fc176c18f9680b
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/25024
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
28 files changed:
src/arch/arm/ArmISA.py
src/arch/arm/SConscript
src/arch/arm/faults.cc
src/arch/arm/insts/branch64.cc
src/arch/arm/insts/branch64.hh
src/arch/arm/insts/misc.cc
src/arch/arm/insts/misc.hh
src/arch/arm/insts/misc64.cc
src/arch/arm/isa/formats/aarch64.isa
src/arch/arm/isa/includes.isa
src/arch/arm/isa/insts/branch64.isa
src/arch/arm/isa/insts/insts.isa
src/arch/arm/isa/insts/ldr64.isa
src/arch/arm/isa/insts/pauth.isa [new file with mode: 0644]
src/arch/arm/isa/templates/branch64.isa
src/arch/arm/isa/templates/misc64.isa
src/arch/arm/miscregs.cc
src/arch/arm/miscregs.hh
src/arch/arm/miscregs_types.hh
src/arch/arm/pauth_helpers.cc [new file with mode: 0644]
src/arch/arm/pauth_helpers.hh [new file with mode: 0644]
src/arch/arm/qarma.cc [new file with mode: 0644]
src/arch/arm/qarma.hh [new file with mode: 0644]
src/arch/arm/table_walker.cc
src/arch/arm/tlb.cc
src/arch/arm/types.hh
src/arch/arm/utility.cc
src/arch/arm/utility.hh

index 9fb7fdfbf4fabf58a656409623dcca351d4c5052..f0bcfbf2c1b82fb329a550555e09b9397774c2eb 100644 (file)
@@ -102,8 +102,9 @@ class ArmISA(BaseISA):
     # !CRC32 | !SHA2 | !SHA1 | !AES
     id_aa64isar0_el1 = Param.UInt64(0x0000000000000000,
         "AArch64 Instruction Set Attribute Register 0")
-    # Reserved for future expansion
-    id_aa64isar1_el1 = Param.UInt64(0x0000000000000000,
+
+    # GPI = 0x0 | GPA = 0x1| API=0x0 | APA=0x1
+    id_aa64isar1_el1 = Param.UInt64(0x0000000001000010,
         "AArch64 Instruction Set Attribute Register 1")
 
     # 4K | 64K | !16K | !BigEndEL0 | !SNSMem | !BigEnd | 8b ASID | 40b PA
index caea1c470550657b1a2f87d3127f73d961c61ab2..8e00ba966ece8b51e8a44968ff8a5d6980239ca3 100644 (file)
@@ -76,8 +76,10 @@ if env['TARGET_ISA'] == 'arm':
     Source('freebsd/system.cc')
     Source('miscregs.cc')
     Source('nativetrace.cc')
+    Source('pauth_helpers.cc')
     Source('pmu.cc')
     Source('process.cc')
+    Source('qarma.cc')
     Source('remote_gdb.cc')
     Source('semihosting.cc')
     Source('stacktrace.cc')
index bd38fdccb1546949e1e8ad81360f61e85c6507dd..9b42d0c3356ee1460205c409e9b273f72925a23e 100644 (file)
@@ -693,7 +693,7 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst)
     ArmStaticInst *arm_inst M5_VAR_USED = instrAnnotate(inst);
 
     // Set PC to start of exception handler
-    Addr new_pc = purifyTaggedAddr(vec_address, tc, toEL);
+    Addr new_pc = purifyTaggedAddr(vec_address, tc, toEL, true);
     DPRINTF(Faults, "Invoking Fault (AArch64 target EL):%s cpsr:%#x PC:%#x "
             "elr:%#x newVec: %#x %s\n", name(), cpsr, curr_pc, ret_addr,
             new_pc, arm_inst ? csprintf("inst: %#x", arm_inst->encoding()) :
index d0a4f29244676887d312450ff6fe5ee6cf83649f..1c47b42f3fc26632573efbd295e7a56ac686da61 100644 (file)
@@ -99,6 +99,18 @@ BranchReg64::generateDisassembly(
     return ss.str();
 }
 
+std::string
+BranchRegReg64::generateDisassembly(
+        Addr pc, const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss, "", false);
+    printIntReg(ss, op1);
+    ccprintf(ss, ", ");
+    printIntReg(ss, op2);
+    return ss.str();
+}
+
 std::string
 BranchRet64::generateDisassembly(
         Addr pc, const SymbolTable *symtab) const
@@ -110,6 +122,17 @@ BranchRet64::generateDisassembly(
     return ss.str();
 }
 
+std::string
+BranchRetA64::generateDisassembly(
+        Addr pc, const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss, "", false);
+    if (op1 != INTREG_X30)
+        printIntReg(ss, op1);
+    return ss.str();
+}
+
 std::string
 BranchEret64::generateDisassembly(
         Addr pc, const SymbolTable *symtab) const
@@ -119,6 +142,15 @@ BranchEret64::generateDisassembly(
     return ss.str();
 }
 
+std::string
+BranchEretA64::generateDisassembly(
+        Addr pc, const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss, "", false);
+    return ss.str();
+}
+
 std::string
 BranchImmReg64::generateDisassembly(
         Addr pc, const SymbolTable *symtab) const
index 731c1869cc70a32b72b227a5b7426faa34d3b4e7..8bde1a05a33bf927faedca9ea98322bf8d19d8de 100644 (file)
@@ -81,6 +81,23 @@ class BranchImmCond64 : public BranchImm64
             Addr pc, const SymbolTable *symtab) const override;
 };
 
+// Branch to a target computed with two registers
+class BranchRegReg64 : public ArmStaticInst
+{
+  protected:
+    IntRegIndex op1;
+    IntRegIndex op2;
+
+  public:
+    BranchRegReg64(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
+                IntRegIndex _op1, IntRegIndex _op2) :
+        ArmStaticInst(mnem, _machInst, __opClass), op1(_op1), op2(_op2)
+    {}
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
 // Branch to a target computed with a register
 class BranchReg64 : public ArmStaticInst
 {
@@ -110,6 +127,19 @@ class BranchRet64 : public BranchReg64
             Addr pc, const SymbolTable *symtab) const override;
 };
 
+// RetAA/RetAB instruction
+class BranchRetA64 : public BranchRegReg64
+{
+  public:
+    BranchRetA64(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
+        BranchRegReg64(mnem, _machInst, __opClass, INTREG_X30,
+                       makeSP(INTREG_SPX))
+    {}
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
 // Eret instruction
 class BranchEret64 : public ArmStaticInst
 {
@@ -122,6 +152,20 @@ class BranchEret64 : public ArmStaticInst
             Addr pc, const SymbolTable *symtab) const override;
 };
 
+// EretA/B instruction
+class BranchEretA64 : public ArmStaticInst
+{
+  protected:
+    IntRegIndex op1;
+
+  public:
+    BranchEretA64(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
+        ArmStaticInst(mnem, _machInst, __opClass), op1(makeSP(INTREG_SPX))
+    {}
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
 // Branch to a target computed with an immediate and a register
 class BranchImmReg64 : public ArmStaticInst
 {
index 14b3458439b87f7bf26ec55ed90cabc742b44ea6..b38aa8795ad8eb7a54cd2527805abbf3a9bb008c 100644 (file)
@@ -200,6 +200,14 @@ RegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
     return ss.str();
 }
 
+std::string
+RegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    printMnemonic(ss);
+    printIntReg(ss, dest);
+    return ss.str();
+}
 std::string
 RegRegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
 {
index e1f27433dcb181c10264259023b42b02623525c4..f1d09630fbb5453b4f9564e931c3dc75d42857f7 100644 (file)
@@ -179,6 +179,20 @@ class RegRegOp : public PredOp
             Addr pc, const SymbolTable *symtab) const override;
 };
 
+class RegOp : public PredOp
+{
+  protected:
+    IntRegIndex dest;
+
+    RegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
+             IntRegIndex _dest) :
+        PredOp(mnem, _machInst, __opClass), dest(_dest)
+    {}
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
 class RegImmRegOp : public PredOp
 {
   protected:
index 9bb4026c49a0089b93756e006dbbc173b52a36d2..d42d0a123af83b3afe6612f88f9e9f434235b96a 100644 (file)
@@ -216,6 +216,18 @@ MiscRegOp64::checkEL2Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
             trap_to_hyp = hcr.tacr && el == EL1;
             break;
 
+          case MISCREG_APDAKeyHi_EL1:
+          case MISCREG_APDAKeyLo_EL1:
+          case MISCREG_APDBKeyHi_EL1:
+          case MISCREG_APDBKeyLo_EL1:
+          case MISCREG_APGAKeyHi_EL1:
+          case MISCREG_APGAKeyLo_EL1:
+          case MISCREG_APIAKeyHi_EL1:
+          case MISCREG_APIAKeyLo_EL1:
+          case MISCREG_APIBKeyHi_EL1:
+          case MISCREG_APIBKeyLo_EL1:
+            trap_to_hyp = el==EL1 && hcr.apk == 0;
+            break;
           // @todo: Trap implementation-dependent functionality based on
           // hcr.tidcp
 
@@ -296,7 +308,7 @@ MiscRegOp64::checkEL3Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
                           uint32_t &immediate) const
 {
     const CPTR cptr = tc->readMiscReg(MISCREG_CPTR_EL3);
-
+    const SCR scr = tc->readMiscReg(MISCREG_SCR_EL3);
     bool trap_to_mon = false;
 
     switch (misc_reg) {
@@ -319,6 +331,18 @@ MiscRegOp64::checkEL3Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
             trap_to_mon = cptr.tcpac;
         }
         break;
+      case MISCREG_APDAKeyHi_EL1:
+      case MISCREG_APDAKeyLo_EL1:
+      case MISCREG_APDBKeyHi_EL1:
+      case MISCREG_APDBKeyLo_EL1:
+      case MISCREG_APGAKeyHi_EL1:
+      case MISCREG_APGAKeyLo_EL1:
+      case MISCREG_APIAKeyHi_EL1:
+      case MISCREG_APIAKeyLo_EL1:
+      case MISCREG_APIBKeyHi_EL1:
+      case MISCREG_APIBKeyLo_EL1:
+        trap_to_mon = (el==EL1 || el==EL2) && scr.apk==0 && ELIs64(tc, EL3);
+        break;
       default:
         break;
     }
index 838ceddbbb213e99ec54ff38f6251f5881696615..55959f50615b530ff4fb65bdedbd8105894f0c8b 100644 (file)
@@ -311,22 +311,24 @@ namespace Aarch64
                                 return new SevInst(machInst);
                               case 0x5:
                                 return new SevlInst(machInst);
+                              case 0x7:
+                                return new Xpaclri(machInst, INTREG_X30);
                             }
                             break;
                           case 0x1:
                             switch (op2) {
                               case 0x0:
-                                return new WarnUnimplemented(
-                                        "pacia", machInst);
+                                return new Pacia1716(machInst, INTREG_X17,
+                                                               INTREG_X16);
                               case 0x2:
-                                return new WarnUnimplemented(
-                                        "pacib", machInst);
+                                return new Pacib1716(machInst, INTREG_X17,
+                                                               INTREG_X16);
                               case 0x4:
-                                return new WarnUnimplemented(
-                                        "autia", machInst);
+                                return new Autia1716(machInst, INTREG_X17,
+                                                               INTREG_X16);
                               case 0x6:
-                                return new WarnUnimplemented(
-                                        "autib", machInst);
+                                return new Autib1716(machInst, INTREG_X17,
+                                                               INTREG_X16);
                             }
                             break;
                           case 0x2:
@@ -348,21 +350,29 @@ namespace Aarch64
                           case 0x3:
                             switch (op2) {
                               case 0x0:
+                                return new Paciaz(machInst,
+                                         INTREG_X30, makeZero(INTREG_X31));
                               case 0x1:
-                                return new WarnUnimplemented(
-                                        "pacia", machInst);
+                                return new Paciasp(machInst,
+                                         INTREG_X30, makeSP(INTREG_SPX));
                               case 0x2:
+                                return new Pacibz(machInst,
+                                         INTREG_X30, makeZero(INTREG_X31));
                               case 0x3:
-                                return new WarnUnimplemented(
-                                        "pacib", machInst);
+                                return new Pacibsp(machInst,
+                                         INTREG_X30, makeSP(INTREG_SPX));
                               case 0x4:
+                                return new Autiaz(machInst,
+                                         INTREG_X30, makeZero(INTREG_X31));
                               case 0x5:
-                                return new WarnUnimplemented(
-                                        "autia", machInst);
+                                return new Autiasp(machInst,
+                                         INTREG_X30, makeSP(INTREG_SPX));
                               case 0x6:
+                                return new Autibz(machInst,
+                                         INTREG_X30, makeZero(INTREG_X31));
                               case 0x7:
-                                return new WarnUnimplemented(
-                                        "autib", machInst);
+                                return new Autibsp(machInst,
+                                         INTREG_X30, makeSP(INTREG_SPX));
                             }
                             break;
                           case 0x4:
@@ -504,26 +514,72 @@ namespace Aarch64
             } else if (bits(machInst, 25) == 0x1) {
                 uint8_t opc = bits(machInst, 24, 21);
                 uint8_t op2 = bits(machInst, 20, 16);
-                uint8_t op3 = bits(machInst, 15, 10);
+                uint8_t op3 = bits(machInst, 15, 12);
                 IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5);
+                IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 4, 0);
                 uint8_t op4 = bits(machInst, 4, 0);
-                if (op2 != 0x1f || op3 != 0x0 || op4 != 0x0)
+                if (op2 != 0x1f || op3 != 0x0)
                     return new Unknown64(machInst);
                 switch (opc) {
                   case 0x0:
-                    return new Br64(machInst, rn);
+                    if (bits(machInst, 11) == 0)
+                        return new Br64(machInst, rn);
+                    else if (op4 != 0x1f)
+                        return new Unknown64(machInst);
+                    // 24(Z):0, 11(A):1
+                    if (bits(machInst, 10) == 0)
+                        return new Braaz(machInst, rn);
+                    else
+                        return new Brabz(machInst, rn);
                   case 0x1:
-                    return new Blr64(machInst, rn);
+                    if (bits(machInst, 11) == 0)
+                        return new Blr64(machInst, rn);
+                    else if (op4 != 0x1f)
+                        return new Unknown64(machInst);
+                    // 24(Z):0, 11(A):1
+                    if (bits(machInst, 10) == 0)
+                        return new Blraaz(machInst, rn);
+                    else
+                        return new Blrabz(machInst, rn);
                   case 0x2:
-                    return new Ret64(machInst, rn);
+                    if (op4 == 0x1f) {
+                        bool m = bits(machInst, 10);
+                        if (m)
+                            return new Retab(machInst);
+                        else
+                            return new Retaa(machInst);
+                    } else
+                        return new Ret64(machInst, rn);
                   case 0x4:
                     if (rn != 0x1f)
                         return new Unknown64(machInst);
-                    return new Eret64(machInst);
+                    if (bits(machInst, 11) == 0)
+                        return new Eret64(machInst);
+                    else if (op4 != 0x1f)
+                        return new Unknown64(machInst);
+                    // 24(Z):0, 11(A):1
+                    if (bits(machInst, 10) == 0)
+                        return new Eretaa(machInst);
+                    else
+                        return new Eretab(machInst);
                   case 0x5:
                     if (rn != 0x1f)
                         return new Unknown64(machInst);
                     return new FailUnimplemented("dret", machInst);
+                  case 0x8:
+                    if (bits(machInst, 11) == 0)
+                        return new Unknown64(machInst);
+                    if (bits(machInst, 10) == 0)
+                        return new Braa(machInst, rn, makeSP(rm));
+                    else
+                        return new Brab(machInst, rn, makeSP(rm));
+                  case 0x9:
+                    if (bits(machInst, 11) == 0)
+                        return new Unknown64(machInst);
+                    if (bits(machInst, 10) == 0)
+                        return new Blraa(machInst, rn, makeSP(rm));
+                    else
+                        return new Blrab(machInst, rn, makeSP(rm));
                   default:
                     return new Unknown64(machInst);
                 }
@@ -1482,6 +1538,35 @@ namespace Aarch64
                             return decodeAtomicArithOp(machInst);
                         }
                     }
+                  case 0x1:
+                  case 0x3:
+                    {
+                        IntRegIndex rt = (IntRegIndex)(uint32_t)
+                                           bits(machInst, 4, 0);
+                        IntRegIndex rn = (IntRegIndex)(uint32_t)
+                                           bits(machInst, 9, 5);
+                        uint8_t  s = bits(machInst, 22);
+                        uint64_t imm9 = bits(machInst, 20, 12);
+                        uint64_t imm10 = sext<10>(s<<9 | imm9)<<3;
+                        uint8_t val = bits(machInst, 23)<<1
+                                      | bits(machInst, 11);
+                        switch (val) {
+                          case 0x0:
+                            return new LDRAA_REG(machInst, rt,
+                                                 makeSP(rn), imm10);
+                          case 0x1:
+                            return new LDRAA_PRE(machInst, rt,
+                                                 makeSP(rn), imm10);
+                          case 0x2:
+                            return new LDRAB_REG(machInst, rt,
+                                                 makeSP(rn), imm10);
+                          case 0x3:
+                            return new LDRAB_PRE(machInst, rt,
+                                                 makeSP(rn), imm10);
+                          default:
+                            M5_UNREACHABLE;
+                        }
+                    }
                   case 0x2:
                     {
                         if (!bits(machInst, 14))
@@ -2016,6 +2101,8 @@ namespace Aarch64
                         return new Asrv64(machInst, rdzr, rn, rm);
                       case 0xb:
                         return new Rorv64(machInst, rdzr, rn, rm);
+                     case 0xc:
+                        return new Pacga(machInst, rd, rn, makeSP(rm));
                       case 0x10:
                         return new Crc32b64(machInst, rdzr, rn, rm);
                       case 0x11:
@@ -2036,8 +2123,93 @@ namespace Aarch64
                         return new Unknown64(machInst);
                     }
                 } else {
-                    if (bits(machInst, 20, 16) != 0 ||
-                            bits(machInst, 29) != 0) {
+                    uint8_t dm = bits(machInst, 20, 14);
+                    switch(dm){
+                        case 0x4:
+                        {
+                          uint8_t zflags = bits(machInst, 13, 10);
+                          switch (zflags) {
+                            case 0x0:
+                                return new Pacia(machInst, rd, makeSP(rn));
+                            case 0x1:
+                                return new Pacib(machInst, rd, makeSP(rn));
+                            case 0x2:
+                                return new Pacda(machInst, rd, makeSP(rn));
+                            case 0x3:
+                                return new Pacdb(machInst, rd, makeSP(rn));
+                            case 0x4:
+                                return new Autia(machInst, rd, makeSP(rn));
+                            case 0x5:
+                                return new Autib(machInst, rd, makeSP(rn));
+                            case 0x6:
+                                return new Autda(machInst, rd, makeSP(rn));
+                            case 0x7:
+                                return new Autdb(machInst, rd, makeSP(rn));
+                            case 0x8:
+                                if (rn == 0x1f)
+                                    return new Paciza(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            case 0x9:
+                                if (rn == 0x1f)
+                                    return new Pacizb(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            case 0xa:
+                                if (rn == 0x1f)
+                                    return new Pacdza(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            case 0xb:
+                                if (rn == 0x1f)
+                                    return new Pacdzb(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            case 0xc:
+                                if (rn == 0x1f)
+                                    return new Autiza(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            case 0xd:
+                                if (rn == 0x1f)
+                                    return new Autizb(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            case 0xe:
+                                if (rn == 0x1f)
+                                    return new Autdza(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            case 0xf:
+                                if (rn == 0x1f)
+                                    return new Autdzb(machInst, rd,
+                                                      makeZero(INTREG_X31));
+                                else
+                                    return new Unknown64(machInst);
+                            default:
+                                return new Unknown64(machInst);
+                          }
+                        }
+                        case 0x5:
+                          {
+                            if (rn != 0x1f)
+                                return new Unknown64(machInst);
+                            bool d = bits(machInst,10);
+                            if (d)
+                                return new Xpacd(machInst, rd);
+                            else
+                                return new Xpaci(machInst, rd);
+                          }
+                    }
+                    if (dm != 0 || bits(machInst, 29) != 0) {
+                        // dm !=0 and dm != 0x1
                         return new Unknown64(machInst);
                     }
                     uint8_t switchVal = bits(machInst, 15, 10);
index d584d8225862d2ab951d22165e2bb92754f7cc2e..9b4b5727bb739c68a27d1849332385f14b41ae8c 100644 (file)
@@ -99,6 +99,7 @@ output exec {{
 #include "arch/arm/interrupts.hh"
 #include "arch/arm/isa.hh"
 #include "arch/arm/isa_traits.hh"
+#include "arch/arm/pauth_helpers.hh"
 #include "arch/arm/utility.hh"
 #include "arch/generic/memhelpers.hh"
 #include "base/condcodes.hh"
index 356114ec79139b6fbcd06d2525fb12e7a4cefab6..054a24e5ecdac63e08f7ea4fc034925eab0b0c30 100644 (file)
@@ -47,7 +47,7 @@ let {{
     # B, BL
     for (mnem, link) in (("b", False), ("bl", True)):
         bCode = ('NPC = purifyTaggedAddr(RawPC + imm, xc->tcBase(), '
-                 'currEL(xc->tcBase()));\n')
+                 'currEL(xc->tcBase()), true);\n')
         instFlags = ['IsDirectControl', 'IsUncondControl']
         if (link):
             bCode += 'XLR = RawPC + 4;\n'
@@ -62,7 +62,7 @@ let {{
     # BR, BLR
     for (mnem, link) in (("br", False), ("blr", True)):
         bCode = ('NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
-                 'currEL(xc->tcBase()));\n')
+                 'currEL(xc->tcBase()), true);\n')
         instFlags = ['IsIndirectControl', 'IsUncondControl']
         if (link):
             bCode += 'XLR = RawPC + 4;\n'
@@ -74,11 +74,84 @@ let {{
         decoder_output += BranchReg64Constructor.subst(bIop)
         exec_output += BasicExecute.subst(bIop)
 
+    # BRAA, BLRAA
+    for (mnem, link) in (("Braa", False), ("Blraa", True)):
+        bCode = ' fault = authIA(xc->tcBase(), XOp1, XOp2, &XOp1);\n'
+        bCode += ('if (fault == NoFault)\n'
+                  '    NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
+                  '                     currEL(xc->tcBase()), true);\n')
+        instFlags = ['IsIndirectControl', 'IsUncondControl']
+        if (link):
+            bCode += 'XLR = RawPC + 4;\n'
+            instFlags += ['IsCall']
+
+        bIop = InstObjParams(mnem, mnem.capitalize(),
+                             "BranchRegReg64", bCode, instFlags)
+        header_output += BranchRegReg64Declare.subst(bIop)
+        decoder_output += BranchRegReg64Constructor.subst(bIop)
+        exec_output += BasicExecute.subst(bIop)
+
+    # BRAAZ, BLRAAZ
+    for (mnem, link) in (("Braaz", False), ("Blraaz", True)):
+        bCode = '''
+                fault = authIA(xc->tcBase(), XOp1, 0, &XOp1);
+                '''
+        bCode += ('if (fault == NoFault)\n'
+                  '    NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
+                  '                       currEL(xc->tcBase()), true);\n')
+        instFlags = ['IsIndirectControl', 'IsUncondControl']
+        if (link):
+            bCode += 'XLR = RawPC + 4;\n'
+            instFlags += ['IsCall']
+
+        bIop = InstObjParams(mnem, mnem.capitalize(),
+                             "BranchReg64", bCode, instFlags)
+        header_output += BranchReg64Declare.subst(bIop)
+        decoder_output += BranchReg64Constructor.subst(bIop)
+        exec_output += BasicExecute.subst(bIop)
+
+    # BRAB, BLRAB
+    for (mnem, link) in (("Brab", False), ("Blrab", True)):
+        bCode = ' fault = authIB(xc->tcBase(), XOp1, XOp2, &XOp1);\n'
+        bCode += ('if (fault == NoFault)\n'
+                  '    NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
+                  '                        currEL(xc->tcBase()), true);\n')
+        instFlags = ['IsIndirectControl', 'IsUncondControl']
+        if (link):
+            bCode += 'XLR = RawPC + 4;\n'
+            instFlags += ['IsCall']
+
+        bIop = InstObjParams(mnem, mnem.capitalize(),
+                             "BranchRegReg64", bCode, instFlags)
+        header_output += BranchRegReg64Declare.subst(bIop)
+        decoder_output += BranchRegReg64Constructor.subst(bIop)
+        exec_output += BasicExecute.subst(bIop)
+
+    # BRABZ, BLRABZ
+    for (mnem, link) in (("Brabz", False), ("Blrabz", True)):
+        bCode = '''
+                fault = authIB(xc->tcBase(), XOp1, 0, &XOp1);
+                '''
+        bCode += ('if (fault == NoFault)\n'
+                  '    NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
+                  '                        currEL(xc->tcBase()), true);\n')
+        instFlags = ['IsIndirectControl', 'IsUncondControl']
+        if (link):
+            bCode += 'XLR = RawPC + 4;\n'
+            instFlags += ['IsCall']
+
+        bIop = InstObjParams(mnem, mnem.capitalize(),
+                             "BranchReg64", bCode, instFlags)
+        header_output += BranchReg64Declare.subst(bIop)
+        decoder_output += BranchReg64Constructor.subst(bIop)
+        exec_output += BasicExecute.subst(bIop)
+
+
     # B conditional
     bCode = '''
         if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode))
             NPC = purifyTaggedAddr(RawPC + imm, xc->tcBase(),
-                                   currEL(xc->tcBase()));
+                                   currEL(xc->tcBase()), true);
         else
             NPC = NPC;
     '''
@@ -90,7 +163,7 @@ let {{
 
     # RET
     bCode = ('NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
-             'currEL(xc->tcBase()));\n')
+             'currEL(xc->tcBase()), true);\n')
     instFlags = ['IsIndirectControl', 'IsUncondControl', 'IsReturn']
 
     bIop = InstObjParams('ret', 'Ret64', "BranchRet64", bCode, instFlags)
@@ -98,6 +171,30 @@ let {{
     decoder_output += BranchReg64Constructor.subst(bIop)
     exec_output += BasicExecute.subst(bIop)
 
+    # RETAA
+    bCode = '''
+                fault = authIA(xc->tcBase(), XOp1, XOp2, &XOp1);
+                '''
+    bCode += (' if (fault == NoFault)\n'
+              '    NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
+             'currEL(xc->tcBase()), true);\n')
+    bIop = InstObjParams('retaa', 'Retaa', "BranchRetA64", bCode, instFlags)
+    header_output += BasicDeclare.subst(bIop)
+    decoder_output += BasicConstructor64.subst(bIop)
+    exec_output += BasicExecute.subst(bIop)
+
+    # RETAB
+    bCode = '''
+                fault = authIB(xc->tcBase(), XOp1, XOp2, &XOp1);
+                '''
+    bCode += (' if (fault == NoFault)\n'
+              '    NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
+             'currEL(xc->tcBase()), true);\n')
+    bIop = InstObjParams('retab', 'Retab', "BranchRetA64", bCode, instFlags)
+    header_output += BasicDeclare.subst(bIop)
+    decoder_output += BasicConstructor64.subst(bIop)
+    exec_output += BasicExecute.subst(bIop)
+
     # ERET
     bCode = '''Addr newPc;
                 CPSR cpsr = Cpsr;
@@ -120,38 +217,64 @@ let {{
                                                                   mnemonic);
                     break;
                 }
-                if (spsr.width) {
-                    // Exception return to AArch32.
-                    // 32 most significant bits are ignored
-                    newPc &= mask(32);
-
-                    if (newPc & mask(2)) {
-                        // Mask bits to avoid PC Alignment fault when returning
-                        // to AArch32
-                        if (spsr.t)
-                            newPc = newPc & ~mask(1);
-                        else
-                            newPc = newPc & ~mask(2);
+
+                %(op)s
+
+                if (fault == NoFault){
+                    if (spsr.width) {
+                        // Exception return to AArch32.
+                        // 32 most significant bits are ignored
+                        newPc &= mask(32);
+
+                        if (newPc & mask(2)) {
+                            // Mask bits to avoid PC Alignment fault
+                            // when returning  to AArch32
+                            if (spsr.t)
+                                newPc = newPc & ~mask(1);
+                            else
+                                newPc = newPc & ~mask(2);
+                        }
                     }
-                }
 
-                CPSR new_cpsr = getPSTATEFromPSR(xc->tcBase(), cpsr, spsr);
+                    CPSR new_cpsr = getPSTATEFromPSR(xc->tcBase(), cpsr, spsr);
 
-                Cpsr = new_cpsr;
-                CondCodesNZ = new_cpsr.nz;
-                CondCodesC  = new_cpsr.c;
-                CondCodesV  = new_cpsr.v;
+                    Cpsr = new_cpsr;
+                    CondCodesNZ = new_cpsr.nz;
+                    CondCodesC  = new_cpsr.c;
+                    CondCodesV  = new_cpsr.v;
 
-                NextAArch64 = !new_cpsr.width;
-                NextItState = itState(new_cpsr);
-                NPC = purifyTaggedAddr(newPc, xc->tcBase(),
-                    currEL(new_cpsr));
+                    NextAArch64 = !new_cpsr.width;
+                    NextItState = itState(new_cpsr);
+                    NPC = purifyTaggedAddr(newPc, xc->tcBase(),
+                        currEL(new_cpsr), true);
 
-                LLSCLock = 0;  // Clear exclusive monitor
-                SevMailbox = 1; //Set Event Register
+                    LLSCLock = 0;  // Clear exclusive monitor
+                    SevMailbox = 1; //Set Event Register
+                }
     '''
     instFlags = ['IsSerializeAfter', 'IsNonSpeculative', 'IsSquashAfter']
-    bIop = InstObjParams('eret', 'Eret64', "BranchEret64", bCode, instFlags)
+    bIop = InstObjParams('eret', 'Eret64', "BranchEret64",
+                          bCode%{'op': ''}, instFlags)
+    header_output += BasicDeclare.subst(bIop)
+    decoder_output += BasicConstructor64.subst(bIop)
+    exec_output += BasicExecute.subst(bIop)
+
+    # ERETAA
+    pac_code = '''
+                fault = authIA(xc->tcBase(), newPc, XOp1, &newPc);
+                '''
+    bIop = InstObjParams('eretaa', 'Eretaa', "BranchEretA64",
+                         bCode % {'op': pac_code} , instFlags)
+    header_output  += BasicDeclare.subst(bIop)
+    decoder_output += BasicConstructor64.subst(bIop)
+    exec_output    += BasicExecute.subst(bIop)
+
+    # ERETAB
+    pac_code = '''
+                fault = authIB(xc->tcBase(), newPc, XOp1, &newPc);
+                '''
+    bIop = InstObjParams('eretab', 'Eretab', "BranchEretA64",
+                         bCode % {'op': pac_code} , instFlags)
     header_output += BasicDeclare.subst(bIop)
     decoder_output += BasicConstructor64.subst(bIop)
     exec_output += BasicExecute.subst(bIop)
@@ -160,7 +283,7 @@ let {{
     for (mnem, test) in (("cbz", "=="), ("cbnz", "!=")):
         code = ('NPC = (Op164 %(test)s 0) ? '
                 'purifyTaggedAddr(RawPC + imm, xc->tcBase(), '
-                'currEL(xc->tcBase())) : NPC;\n')
+                'currEL(xc->tcBase()), true) : NPC;\n')
         code = code % {"test": test}
         iop = InstObjParams(mnem, mnem.capitalize() + "64",
                             "BranchImmReg64", code,
@@ -173,7 +296,7 @@ let {{
     for (mnem, test) in (("tbz", "=="), ("tbnz", "!=")):
         code = ('NPC = ((Op164 & imm1) %(test)s 0) ? '
                 'purifyTaggedAddr(RawPC + imm2, xc->tcBase(), '
-                'currEL(xc->tcBase())) : NPC;\n')
+                'currEL(xc->tcBase()), true) : NPC;\n')
         code = code % {"test": test}
         iop = InstObjParams(mnem, mnem.capitalize() + "64",
                             "BranchImmImmReg64", code,
index 45159e3e6f04ad93e21e4ed2114eaca679f0dd84..b4c798a4dfbed9126688d6beac8c655ec1d937d9 100644 (file)
@@ -90,6 +90,9 @@ split exec;
 ##include "fp.isa"
 ##include "fp64.isa"
 
+//AArch64 pointer authentification operations
+##include "pauth.isa"
+
 split exec;
 
 //Neon
index 801316eeb15e0bf140f45d1cdab132bfe0dd6c35..d6e4f5a1d24cdb1c1c16d5883e5e03640450dd64 100644 (file)
@@ -122,6 +122,15 @@ let {{
                     eaCode += " + (isBigEndian64(xc->tcBase()) ? 0 : 8)"
                 else:
                     eaCode += " + (isBigEndian64(xc->tcBase()) ? 8 : 0)"
+
+            if self.flavor in ("authDA", "authDB"):
+                eaCode += ";\n"
+                eaCode += "fault = %s(xc->tcBase(), "\
+                          "EA, 0, &EA);\n" % self.flavor
+                if self.writeback:
+                    eaCode += "XBase = EA;\n"
+                eaCode += "EA = EA"
+
             if not self.post:
                 eaCode += self.offset
             eaCode += ";"
@@ -381,6 +390,12 @@ let {{
         LoadPost64(mnem, NameBase + "_POST", size, sign, flavor=flavor).emit()
         LoadReg64(mnem, NameBase + "_REG", size, sign, flavor=flavor).emit()
 
+
+    LoadPre64("ldraa", "LDRAA_PRE", 8, False, flavor="authDA").emit()
+    LoadImm64("ldraa", "LDRAA_REG", 8, False, flavor="authDA").emit()
+    LoadPre64("ldrab", "LDRAB_PRE", 8, False, flavor="authDB").emit()
+    LoadImm64("ldrab", "LDRAB_REG", 8, False, flavor="authDB").emit()
+
     buildLoads64("ldrb", "LDRB64", 1, False)
     buildLoads64("ldrsb", "LDRSBW64", 1, True)
     buildLoads64("ldrsb", "LDRSBX64", 1, True, flavor="widen")
diff --git a/src/arch/arm/isa/insts/pauth.isa b/src/arch/arm/isa/insts/pauth.isa
new file mode 100644 (file)
index 0000000..0ee5aa0
--- /dev/null
@@ -0,0 +1,121 @@
+// -*- 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.
+//
+// Authors: Jordi Vaquero
+
+let {{
+
+    header_output = ""
+    decoder_output = ""
+    exec_output = ""
+
+
+    def buildPauthObject(mnem, templateBase, opcode, optArgs=[]):
+        global header_output, decoder_output, exec_output
+        pac_code = '''//uint64_t val = 0;
+                uint64_t res;
+                fault = %(op)s(xc->tcBase(), %(op1)s, %(op2)s, &res);
+                XDest = res;
+                '''
+        if templateBase=='DataX2Reg':
+            code = pac_code % {"op1": 'Op164',
+                               "op2": 'Op264',
+                               "op":  opcode }
+        else:
+            code = pac_code % {"op1": 'XDest',
+                               "op2": 'Op164',
+                               "op":  opcode }
+
+        iop = InstObjParams(mnem, mnem, templateBase+"Op", code, optArgs)
+        header_output += eval(templateBase + "Declare").subst(iop)
+        decoder_output += eval(templateBase + "Constructor").subst(iop)
+        exec_output += BasicExecute.subst(iop)
+
+    def buildXPauthObject(mnem, optArgs=[]):
+        global header_output, decoder_output, exec_output
+        templateBase = "XPauthOpRegReg"
+
+        code =  'uint64_t res;\n'\
+                'fault = stripPAC(xc->tcBase(), XDest, data, &res);\n'
+        code += 'XDest = res;'
+        regoptype = 'RegOp'
+
+        iop = InstObjParams(mnem, mnem, regoptype, code, optArgs)
+        header_output += eval(templateBase + "Declare").subst(iop)
+        decoder_output += eval(templateBase + "Constructor").subst(iop)
+        exec_output += BasicExecute.subst(iop)
+
+
+    buildPauthObject("Pacda",  "DataX1Reg", 'addPACDA')
+    buildPauthObject("Pacdza", "DataX1Reg", 'addPACDA')
+    buildPauthObject("Pacdb",  "DataX1Reg", 'addPACDB')
+    buildPauthObject("Pacdzb", "DataX1Reg", 'addPACDB')
+    buildPauthObject("Pacga",  "DataX2Reg", 'addPACGA')
+
+    buildPauthObject("Pacia",     "DataX1Reg", 'addPACIA')
+    buildPauthObject("Pacia1716", "DataX1Reg", 'addPACIA')
+    buildPauthObject("Paciasp",   "DataX1Reg", 'addPACIA')
+    buildPauthObject("Paciaz",    "DataX1Reg", 'addPACIA')
+    buildPauthObject("Paciza",    "DataX1Reg", 'addPACIA')
+
+    buildPauthObject("Pacib",     "DataX1Reg", 'addPACIB')
+    buildPauthObject("Pacib1716", "DataX1Reg", 'addPACIB')
+    buildPauthObject("Pacibsp",   "DataX1Reg", 'addPACIB')
+    buildPauthObject("Pacibz",    "DataX1Reg", 'addPACIB')
+    buildPauthObject("Pacizb",    "DataX1Reg", 'addPACIB')
+
+    buildPauthObject("Autda",     "DataX1Reg", 'authDA')
+    buildPauthObject("Autdza",    "DataX1Reg", 'authDA')
+    buildPauthObject("Autdb",     "DataX1Reg", 'authDB')
+    buildPauthObject("Autdzb",    "DataX1Reg", 'authDB')
+
+    buildPauthObject("Autia",     "DataX1Reg", 'authIA')
+    buildPauthObject("Autia1716", "DataX1Reg", 'authIA')
+    buildPauthObject("Autiasp",   "DataX1Reg", 'authIA')
+    buildPauthObject("Autiaz",    "DataX1Reg", 'authIA')
+    buildPauthObject("Autiza",    "DataX1Reg", 'authIA')
+
+    buildPauthObject("Autib",     "DataX1Reg", 'authIB')
+    buildPauthObject("Autib1716", "DataX1Reg", 'authIB')
+    buildPauthObject("Autibsp",   "DataX1Reg", 'authIB')
+    buildPauthObject("Autibz",    "DataX1Reg", 'authIB')
+    buildPauthObject("Autizb",    "DataX1Reg", 'authIB')
+
+    buildXPauthObject("Xpacd")
+    buildXPauthObject("Xpaci")
+    buildXPauthObject("Xpaclri")
+}};
index 6eadf3c7c89fcd97ea2e63356b1f7941b0155a8c..b62cdb990f4ec034497c5383a5d1b82e07f8db2b 100644 (file)
@@ -97,6 +97,26 @@ def template BranchReg64Constructor {{
     }
 }};
 
+def template BranchRegReg64Declare {{
+class %(class_name)s : public %(base_class)s
+{
+    public:
+        // Constructor
+        %(class_name)s(ExtMachInst machInst, IntRegIndex _op1,
+                       IntRegIndex _op2);
+        Fault execute(ExecContext *, Trace::InstRecord *) const override;
+};
+}};
+
+def template BranchRegReg64Constructor {{
+    %(class_name)s::%(class_name)s(ExtMachInst machInst, IntRegIndex _op1,
+                                   IntRegIndex _op2)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _op1, _op2)
+    {
+        %(constructor)s;
+    }
+}};
+
 def template BranchImmReg64Declare {{
 class %(class_name)s : public %(base_class)s
 {
index ed9b4a3ae1e1e357d8672651a2b1cfaed06c45a8..fa06d5ec4ac4d5f71dcb7160675838748690e22b 100644 (file)
@@ -179,3 +179,27 @@ def template RegMiscRegOp64Constructor {{
         %(constructor)s;
     }
 }};
+
+def template XPauthOpRegRegDeclare {{
+class %(class_name)s : public %(base_class)s
+{
+    private:
+        bool data;
+
+    public:
+        // Constructor
+        %(class_name)s(ExtMachInst machInst, IntRegIndex _dest);
+        Fault execute(ExecContext *, Trace::InstRecord *) const override;
+};
+}};
+
+def template XPauthOpRegRegConstructor {{
+    %(class_name)s::%(class_name)s(ExtMachInst machInst, IntRegIndex _dest)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
+                         _dest)
+    {
+
+        data = bits(machInst, 10);
+        %(constructor)s;
+    }
+}};
index 4785f00cd9a1d45545b05af6809eeaf41a0ce020..c25c24bb7ab6637f9791c70eba8c311e5d2afde9 100644 (file)
@@ -1937,6 +1937,39 @@ decodeAArch64SysReg(unsigned op0, unsigned op1,
                         return MISCREG_TCR_EL1;
                     }
                     break;
+                  case 0x1:
+                    switch (op2) {
+                      case 0x0:
+                        return MISCREG_APIAKeyLo_EL1;
+                      case 0x1:
+                        return MISCREG_APIAKeyHi_EL1;
+                      case 0x2:
+                        return MISCREG_APIBKeyLo_EL1;
+                      case 0x3:
+                        return MISCREG_APIBKeyHi_EL1;
+                    }
+                    break;
+                  case 0x2:
+                    switch (op2) {
+                      case 0x0:
+                        return MISCREG_APDAKeyLo_EL1;
+                      case 0x1:
+                        return MISCREG_APDAKeyHi_EL1;
+                      case 0x2:
+                        return MISCREG_APDBKeyLo_EL1;
+                      case 0x3:
+                        return MISCREG_APDBKeyHi_EL1;
+                    }
+                    break;
+
+                  case 0x3:
+                    switch (op2) {
+                      case 0x0:
+                        return MISCREG_APGAKeyLo_EL1;
+                      case 0x1:
+                        return MISCREG_APGAKeyHi_EL1;
+                    }
+                    break;
                 }
                 break;
               case 4:
@@ -2883,10 +2916,10 @@ ISA::initializeMiscRegMetadata()
     bool nTLSMD = false;
 
     // Pointer authentication (Arm 8.3+), unsupported
-    bool EnDA = false; // using APDAKey_EL1 key of instr addrs in ELs 0,1
-    bool EnDB = false; // using APDBKey_EL1 key of instr addrs in ELs 0,1
-    bool EnIA = false; // using APIAKey_EL1 key of instr addrs in ELs 0,1
-    bool EnIB = false; // using APIBKey_EL1 key of instr addrs in ELs 0,1
+    bool EnDA = true; // using APDAKey_EL1 key of instr addrs in ELs 0,1
+    bool EnDB = true; // using APDBKey_EL1 key of instr addrs in ELs 0,1
+    bool EnIA = true; // using APIAKey_EL1 key of instr addrs in ELs 0,1
+    bool EnIB = true; // using APIBKey_EL1 key of instr addrs in ELs 0,1
 
     /**
      * Some registers alias with others, and therefore need to be translated.
@@ -3968,6 +4001,28 @@ ISA::initializeMiscRegMetadata()
       .allPrivileges().exceptUserMode().writes(0);
     InitReg(MISCREG_ID_AA64MMFR2_EL1)
       .allPrivileges().exceptUserMode().writes(0);
+
+    InitReg(MISCREG_APDAKeyHi_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APDAKeyLo_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APDBKeyHi_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APDBKeyLo_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APGAKeyHi_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APGAKeyLo_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APIAKeyHi_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APIAKeyLo_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APIBKeyHi_EL1)
+      .allPrivileges().exceptUserMode();
+    InitReg(MISCREG_APIBKeyLo_EL1)
+      .allPrivileges().exceptUserMode();
+
     InitReg(MISCREG_CCSIDR_EL1)
       .allPrivileges().exceptUserMode().writes(0);
     InitReg(MISCREG_CLIDR_EL1)
index 49df42e51b72d30013bb0703070c59a25b02e34b..2618a764636183d33b9e2496096bb2371974af7f 100644 (file)
@@ -675,6 +675,18 @@ namespace ArmISA
 
         MISCREG_ID_AA64MMFR2_EL1,
 
+        //PAuth Key Regsiters
+        MISCREG_APDAKeyHi_EL1,
+        MISCREG_APDAKeyLo_EL1,
+        MISCREG_APDBKeyHi_EL1,
+        MISCREG_APDBKeyLo_EL1,
+        MISCREG_APGAKeyHi_EL1,
+        MISCREG_APGAKeyLo_EL1,
+        MISCREG_APIAKeyHi_EL1,
+        MISCREG_APIAKeyLo_EL1,
+        MISCREG_APIBKeyHi_EL1,
+        MISCREG_APIBKeyLo_EL1,
+
         // GICv3, CPU interface
         MISCREG_ICC_PMR_EL1,
         MISCREG_ICC_IAR0_EL1,
@@ -1625,6 +1637,16 @@ namespace ArmISA
         "cnthv_tval_el2",
         "id_aa64mmfr2_el1",
 
+        "apdakeyhi_el1",
+        "apdakeylo_el1",
+        "apdbkeyhi_el1",
+        "apdbkeylo_el1",
+        "apgakeyhi_el1",
+        "apgakeylo_el1",
+        "apiakeyhi_el1",
+        "apiakeylo_el1",
+        "apibkeyhi_el1",
+        "apibkeylo_el1",
         // GICv3, CPU interface
         "icc_pmr_el1",
         "icc_iar0_el1",
index 07e2262b3906576e7c8fdced8a91f4de050a1b72..89dfdb352f04e5518bf98ed6a71635630cda36b7 100644 (file)
@@ -233,6 +233,18 @@ namespace ArmISA
     EndBitUnion(HSTR)
 
     BitUnion64(HCR)
+        Bitfield<47>     fien;
+        Bitfield<46>     fwb;
+        Bitfield<45>     nv2;
+        Bitfield<44>     at;
+        Bitfield<43>     nv1;
+        Bitfield<42>     nv;
+        Bitfield<41>     api;
+        Bitfield<40>     apk;
+        Bitfield<38>     miocnce;
+        Bitfield<37>     tea;
+        Bitfield<36>     terr;
+        Bitfield<35>     tlor;
         Bitfield<34>     e2h;   // AArch64
         Bitfield<33>     id;
         Bitfield<32>     cd;
@@ -240,7 +252,6 @@ namespace ArmISA
         Bitfield<30>     trvm;  // AArch64
         Bitfield<29>     hcd;   // AArch64
         Bitfield<28>     tdz;   // AArch64
-
         Bitfield<27>     tge;
         Bitfield<26>     tvm;
         Bitfield<25>     ttlb;
@@ -294,7 +305,14 @@ namespace ArmISA
     EndBitUnion(NSACR)
 
     BitUnion32(SCR)
+        Bitfield<21> fien;
+        Bitfield<20> nmea;
+        Bitfield<19> ease;
         Bitfield<18> eel2; // AArch64 (Armv8.4-SecEL2)
+        Bitfield<17> api;
+        Bitfield<16> apk;
+        Bitfield<15> teer;
+        Bitfield<14> tlor;
         Bitfield<13> twe;
         Bitfield<12> twi;
         Bitfield<11> st;   // AArch64
@@ -313,10 +331,13 @@ namespace ArmISA
     EndBitUnion(SCR)
 
     BitUnion32(SCTLR)
+        Bitfield<31>   enia;    // ARMv8.3 PAuth
+        Bitfield<30>   enib;    // ARMv8.3 PAuth
         Bitfield<30>   te;      // Thumb Exception Enable (AArch32 only)
         Bitfield<29>   afe;     // Access flag enable (AArch32 only)
         Bitfield<28>   tre;     // TEX remap enable (AArch32 only)
         Bitfield<27>   nmfi;    // Non-maskable FIQ support (ARMv7 only)
+        Bitfield<27>   enda;    // ARMv8.3 PAuth
         Bitfield<26>   uci;     // Enable EL0 access to DC CVAU, DC CIVAC,
                                 // DC CVAC and IC IVAU instructions
                                 // (AArch64 SCTLR_EL1 only)
@@ -346,6 +367,7 @@ namespace ArmISA
         Bitfield<14>   dze;     // Enable EL0 access to DC ZVA
                                 // (AArch64 SCTLR_EL1 only)
         Bitfield<13>   v;       // Vectors bit (AArch32 only)
+        Bitfield<13>   endb;    // ARMv8.3 PAuth
         Bitfield<12>   i;       // Instruction cache enable
         Bitfield<11>   z;       // Branch prediction enable (ARMv7 only)
         Bitfield<10>   sw;      // SWP/SWPB enable (ARMv7 only)
@@ -509,6 +531,7 @@ namespace ArmISA
         Bitfield<25, 24> irgn1; // EL1
         Bitfield<27, 26> orgn1; // EL1
         Bitfield<29, 28> sh1; // EL1
+        Bitfield<29> tbid; // EL2
         Bitfield<31, 30> tg1; // EL1
         Bitfield<34, 32> ips; // EL1
         Bitfield<36> as; // EL1
@@ -518,6 +541,8 @@ namespace ArmISA
         Bitfield<40> hd;
         Bitfield<41> hpd0;
         Bitfield<42> hpd1;
+        Bitfield<51> tbid0; // EL1
+        Bitfield<52> tbid1; // EL1
     EndBitUnion(TCR)
 
     BitUnion32(HTCR)
diff --git a/src/arch/arm/pauth_helpers.cc b/src/arch/arm/pauth_helpers.cc
new file mode 100644 (file)
index 0000000..c08e818
--- /dev/null
@@ -0,0 +1,924 @@
+// -*- 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.
+//
+// Authors: Jordi Vaquero
+
+#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)
+{
+    ExceptionLevel curr_el = currEL(tc);
+    assert(ArmSystem::haveEL(tc, target_el) &&
+           target_el != EL0 && (target_el >= curr_el));
+
+    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 (s1TranslationRegime(tc, 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;
+}
+
diff --git a/src/arch/arm/pauth_helpers.hh b/src/arch/arm/pauth_helpers.hh
new file mode 100644 (file)
index 0000000..e8abb65
--- /dev/null
@@ -0,0 +1,127 @@
+// -*- 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.
+//
+// Authors: Jordi Vaquero
+
+#ifndef __ARCH_ARM_PAUTH_HELPERS_HH__
+#define __ARCH_ARM_PAUTH_HELPERS_HH__
+
+#include "arch/arm/qarma.hh"
+#include "arch/arm/system.hh"
+#include "arch/arm/types.hh"
+#include "arch/arm/utility.hh"
+#include "base/bitfield.hh"
+#include "base/bitunion.hh"
+#include "cpu/thread_context.hh"
+
+namespace ArmISA
+{
+
+  inline bool
+  upperAndLowerRange(ThreadContext* tc, ExceptionLevel el)
+  {
+      HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
+      return (el == EL1 || el == EL0 || (el == EL2 && hcr.e2h == 1));
+  }
+
+  bool
+  calculateTBI(ThreadContext* tc, ExceptionLevel el, uint64_t ptr, bool data);
+
+  int
+  calculateBottomPACBit(ThreadContext* tc, ExceptionLevel el, bool top_bit);
+
+  Fault
+  trapPACUse(ThreadContext *tc, ExceptionLevel el);
+
+
+
+  // AddPAC()
+  // ========
+  // Calculates the pointer authentication code for a 64-bit quantity
+  // and then inserts that into pointer authentication code field of that
+  // 64-bit quantity.
+
+  uint64_t
+  addPAC (ThreadContext* tc, ExceptionLevel el, uint64_t  ptr,
+          uint64_t modifier, uint64_t k1, uint64_t k0, bool data);
+
+
+  uint64_t
+  auth(ThreadContext *tc, ExceptionLevel el, uint64_t ptr, uint64_t modifier,
+       uint64_t k1, uint64_t K0, bool data, uint8_t errorcode);
+
+  Fault
+  authDA(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  Fault
+  authDB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+
+  Fault
+  authIA(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  Fault
+  authIB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  Fault
+  addPACDA(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  Fault
+  addPACDB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  Fault
+  addPACGA(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  Fault
+  addPACIA(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  Fault
+  addPACIB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out);
+
+  //  Strip()
+  //    =======
+  //      Strip() returns a 64-bit value containing A, but replacing the
+  // pointer authentication code field bits with the extension of the
+  // address bits. This can apply to either instructions or data, where,
+  // as the use of tagged pointers is distinct, it might be
+  // handled differently.
+
+  Fault
+  stripPAC(ThreadContext* tc, uint64_t A, bool data, uint64_t* out);
+
+};
+#endif //__ARCH_ARM_PAUTH_HELPERS_HH__
diff --git a/src/arch/arm/qarma.cc b/src/arch/arm/qarma.cc
new file mode 100644 (file)
index 0000000..9f611f9
--- /dev/null
@@ -0,0 +1,396 @@
+// -*- 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.
+//
+// Authors: Jordi Vaquero
+
+#include "arch/arm/qarma.hh"
+
+#include "base/bitfield.hh"
+
+using namespace QARMA;
+using namespace std;
+
+
+uint8_t
+QARMA::rotCell(uint8_t incell, int amount)
+{
+    uint8_t res =  ((incell << amount) | (incell >> (4-amount)))& 0xF;
+    return res;
+}
+
+uint8_t
+QARMA::tweakCellInvRot(uint8_t incell)
+{
+    uint8_t outcell = 0x0;
+    outcell = incell << 1;
+    uint8_t t = 0x1 & (incell ^ (incell>>3));
+    outcell |= t;
+    return outcell & 0xF;
+}
+
+uint8_t
+QARMA::tweakCellRot(uint8_t incell)
+{
+    uint8_t outcell = 0x0;
+    outcell = incell >> 1;
+    uint8_t t = 0x1 & (incell ^ (incell>>1));
+    outcell |= t<<3;
+    return outcell & 0xF;
+}
+
+BIT64
+QARMA::tweakInvShuffle(BIT64 indata)
+{
+    BIT64 outdata = 0x0;
+    outdata.b0  = tweakCellInvRot(indata.b12);
+    outdata.b1  = indata.b13;
+    outdata.b2  = indata.b5;
+    outdata.b3  = indata.b6;
+    outdata.b4  = indata.b0;
+    outdata.b5  = indata.b1;
+    outdata.b6  = tweakCellInvRot(indata.b2);
+    outdata.b7  = indata.b3;
+    outdata.b8  = tweakCellInvRot(indata.b7);
+    outdata.b9  = tweakCellInvRot(indata.b15);
+    outdata.b10 = tweakCellInvRot(indata.b14);
+    outdata.b11 = tweakCellInvRot(indata.b4);
+    outdata.b12 = indata.b8;
+    outdata.b13 = indata.b9;
+    outdata.b14 = indata.b10;
+    outdata.b15 = tweakCellInvRot(indata.b11);
+    return outdata;
+}
+
+BIT64
+QARMA::tweakShuffle(BIT64 indata)
+{
+    BIT64 outdata = 0x0;
+    outdata.b0  = indata.b4;
+    outdata.b1  = indata.b5;
+    outdata.b2  = tweakCellRot(indata.b6);
+    outdata.b3  = indata.b7;
+    outdata.b4  = tweakCellRot(indata.b11);
+    outdata.b5  = indata.b2;
+    outdata.b6  = indata.b3;
+    outdata.b7  = tweakCellRot(indata.b8);
+    outdata.b8  = indata.b12;
+    outdata.b9  = indata.b13;
+    outdata.b10 = indata.b14;
+    outdata.b11 = tweakCellRot(indata.b15);
+    outdata.b12 = tweakCellRot(indata.b0);
+    outdata.b13 = indata.b1;
+    outdata.b14 = tweakCellRot(indata.b10);
+    outdata.b15 = tweakCellRot(indata.b9);
+    return outdata;
+}
+
+
+BIT64
+QARMA::PACCellInvShuffle(BIT64 indata)
+{
+    BIT64 outdata = 0x0;
+    outdata.b0  = indata.b3;
+    outdata.b1  = indata.b6;
+    outdata.b2  = indata.b12;
+    outdata.b3  = indata.b9;
+    outdata.b4  = indata.b14;
+    outdata.b5  = indata.b11;
+    outdata.b6  = indata.b1;
+    outdata.b7  = indata.b4;
+    outdata.b8  = indata.b8;
+    outdata.b9  = indata.b13;
+    outdata.b10 = indata.b7;
+    outdata.b11 = indata.b2;
+    outdata.b12 = indata.b5;
+    outdata.b13 = indata.b0;
+    outdata.b14 = indata.b10;
+    outdata.b15 = indata.b15;
+    return outdata;
+}
+
+BIT64
+QARMA::PACCellShuffle(BIT64 indata)
+{
+    BIT64 outdata = 0x0;
+    outdata.b0  = indata.b13;
+    outdata.b1  = indata.b6;
+    outdata.b2  = indata.b11;
+    outdata.b3  = indata.b0;
+    outdata.b4  = indata.b7;
+    outdata.b5  = indata.b12;
+    outdata.b6  = indata.b1;
+    outdata.b7  = indata.b10;
+    outdata.b8  = indata.b8;
+    outdata.b9  = indata.b3;
+    outdata.b10 = indata.b14;
+    outdata.b11 = indata.b5;
+    outdata.b12 = indata.b2;
+    outdata.b13 = indata.b9;
+    outdata.b14 = indata.b4;
+    outdata.b15 = indata.b15;
+    return outdata;
+}
+
+
+uint64_t
+QARMA::PACInvSub(uint64_t tInput)
+{
+    // This is a 4-bit substitution from the PRINCE-family cipher
+    uint64_t t_output = 0x0;
+    for (int i=15; i>=0; i--) {
+        t_output = t_output << 4;
+        uint8_t b = (tInput >> i*4 ) & 0xF;
+        switch ( b ) {
+            case 0x0:
+                t_output |= 0x5;
+                break;
+            case 0x1:
+                t_output |= 0xe;
+                break;
+            case 0x2:
+                t_output |= 0xd;
+                break;
+            case 0x3:
+                t_output |= 0x8;
+                break;
+            case 0x4:
+                t_output |= 0xa;
+                break;
+            case 0x5:
+                t_output |= 0xb;
+                break;
+            case 0x6:
+                t_output |= 0x1;
+                break;
+            case 0x7:
+                t_output |= 0x9;
+                break;
+            case 0x8:
+                t_output |= 0x2;
+                break;
+            case 0x9:
+                t_output |= 0x6;
+                break;
+            case 0xa:
+                t_output |= 0xf;
+                break;
+            case 0xb:
+                t_output |= 0x0;
+                break;
+            case 0xc:
+                t_output |= 0x4;
+                break;
+            case 0xd:
+                t_output |= 0xc;
+                break;
+            case 0xe:
+                t_output |= 0x7;
+                break;
+            case 0xf:
+                t_output |= 0x3;
+                break;
+            default:
+                //unreachable
+                break;
+        }
+    }
+    return t_output;
+}
+
+uint64_t
+QARMA::PACSub(uint64_t tInput){
+    // This is a 4-bit substitution from the PRINCE-family cipher
+    uint64_t t_output = 0x0;
+    for (int i=15; i>=0; i--) {
+        t_output = t_output << 4;
+        uint8_t b = (tInput >> i*4 ) & 0xF;
+        switch ( b ) {
+            case 0x0:
+                t_output |= 0xb;
+                break;
+            case 0x1:
+                t_output |= 0x6;
+                break;
+            case 0x2:
+                t_output |= 0x8;
+                break;
+            case 0x3:
+                t_output |= 0xf;
+                break;
+            case 0x4:
+                t_output |= 0xc;
+                break;
+            case 0x5:
+                t_output |= 0x0;
+                break;
+            case 0x6:
+                t_output |= 0x9;
+                break;
+            case 0x7:
+                t_output |= 0xe;
+                break;
+            case 0x8:
+                t_output |= 0x3;
+                break;
+            case 0x9:
+                t_output |= 0x7;
+                break;
+            case 0xa:
+                t_output |= 0x4;
+                break;
+            case 0xb:
+                t_output |= 0x5;
+                break;
+            case 0xc:
+                t_output |= 0xd;
+                break;
+            case 0xd:
+                t_output |= 0x2;
+                break;
+            case 0xe:
+                t_output |= 0x1;
+                break;
+            case 0xf:
+                t_output |= 0xa;
+                break;
+            default:
+                //unreachable
+                break;
+        }
+    }
+    return t_output;
+}
+
+uint64_t
+QARMA::PACMult(uint64_t tInput)
+{
+    uint64_t t_output = 0;
+
+    for (int i=0;i<=3; i++) {
+        uint8_t b8  = (tInput >> (4*(i+8)))  & 0xF;
+        uint8_t b4  = (tInput >> (4*(i+4)))  & 0xF;
+        uint8_t b12 = (tInput >> (4*(i+12))) & 0xF;
+        uint8_t b0  = (tInput >> (4*(i)))    & 0xF;
+
+        uint64_t t0 = rotCell(b8, 1) ^ rotCell(b4, 2);
+        t0 = t0 ^ rotCell(b0, 1);
+
+        uint64_t t1 = rotCell(b12, 1) ^ rotCell(b4, 1);
+        t1 = t1 ^ rotCell(b0, 2);
+
+        uint64_t t2 = rotCell(b12, 2) ^ rotCell(b8, 1);
+        t2 = t2 ^ rotCell(b0, 1);
+
+        uint64_t t3 = rotCell(b12, 1) ^ rotCell(b8, 2);
+        t3 = t3 ^ rotCell(b4, 1);
+
+        t_output |= (t3 << (4*i));
+        t_output |= (t2 << (4*(i+4)));
+        t_output |= (t1 << (4*(i+8)));
+        t_output |= (t0 << (4*(i+12)));
+    }
+    return t_output;
+}
+
+BIT64
+QARMA::computePAC(BIT64 data, BIT64 modifier, BIT64 key0, BIT64 key1)
+{
+    BIT64 workingval;
+    BIT64 runningmod;
+    BIT64 roundkey;
+    BIT64 modk0;
+    std::array<BIT64, 5> RC;
+    RC[0] = (BIT64) 0x0000000000000000;
+    RC[1] = (BIT64) 0x13198A2E03707344;
+    RC[2] = (BIT64) 0xA4093822299F31D0;
+    RC[3] = (BIT64) 0x082EFA98EC4E6C89;
+    RC[4] = (BIT64) 0x452821E638D01377;
+
+    const BIT64 alpha = 0xC0AC29B7C97C50DD;
+    //modk0 = key0<0>:key0<63:2>:
+
+    modk0 = (key0 & 0x1) << 63;
+    modk0 = modk0 | ((key0 & ~0x3) >> 1);
+    modk0 = modk0 | ((key0.b15>>3) ^ ((key0.b0 & 0x2)>>1));
+
+    runningmod = modifier;
+    workingval = data^key0;
+    for (int i=0; i<=4; i++) {
+        roundkey = key1 ^ runningmod;
+        workingval = workingval ^ roundkey;
+        workingval = workingval ^ RC[i];
+
+        if (i > 0) {
+            workingval = PACCellShuffle(workingval);
+            workingval = PACMult(workingval);
+        }
+        workingval = PACSub(workingval);
+        runningmod = tweakShuffle(runningmod);
+    }
+    roundkey = modk0 ^ runningmod;
+    workingval = workingval ^ roundkey;
+
+    workingval = PACCellShuffle(workingval);
+    workingval = PACMult(workingval);
+    workingval = PACSub(workingval);
+    workingval = PACCellShuffle(workingval);
+    workingval = PACMult(workingval);
+    workingval = key1 ^ workingval;
+
+    workingval = PACCellInvShuffle(workingval);
+    workingval = PACInvSub(workingval);
+    workingval = PACMult(workingval);
+    workingval = PACCellInvShuffle(workingval);
+    workingval = workingval ^ key0;
+    workingval = workingval ^ runningmod;
+
+    for (int i=0; i<=4; i++) {
+        workingval = PACInvSub(workingval);
+        if (i < 4) {
+            workingval = PACMult(workingval);
+            workingval = PACCellInvShuffle(workingval);
+        }
+        runningmod = tweakInvShuffle(runningmod);
+        roundkey = key1 ^ runningmod;
+        workingval = workingval ^ RC[4-i];
+        workingval = workingval ^ roundkey;
+        workingval = workingval ^ alpha;
+    }
+    workingval = workingval ^ modk0;
+    return workingval;
+}
+
diff --git a/src/arch/arm/qarma.hh b/src/arch/arm/qarma.hh
new file mode 100644 (file)
index 0000000..91eff90
--- /dev/null
@@ -0,0 +1,95 @@
+// -*- 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.
+//
+// Authors: Jordi Vaquero
+
+#ifndef __ARCH_ARM_QARMA_HH__
+#define __ARCH_ARM_QARMA_HH__
+
+#include "base/bitfield.hh"
+#include "base/bitunion.hh"
+
+namespace QARMA
+{
+
+  BitUnion64(BIT64)
+      Bitfield<63, 60> b15;
+      Bitfield<59, 56> b14;
+      Bitfield<55, 52> b13;
+      Bitfield<51, 48> b12;
+      Bitfield<47, 44> b11;
+      Bitfield<43, 40> b10;
+      Bitfield<39, 36> b9;
+      Bitfield<35, 32> b8;
+      Bitfield<31, 28> b7;
+      Bitfield<27, 24> b6;
+      Bitfield<23, 20> b5;
+      Bitfield<19, 16> b4;
+      Bitfield<15, 12> b3;
+      Bitfield<11, 8>  b2;
+      Bitfield<7, 4>   b1;
+      Bitfield<3, 0>   b0;
+  EndBitUnion(BIT64)
+
+
+  uint8_t rotCell(uint8_t incell, int amount);
+
+  uint8_t tweakCellInvRot(uint8_t incell);
+
+  uint8_t tweakCellRot(uint8_t incell);
+
+  BIT64 tweakInvShuffle(BIT64 indata);
+
+  BIT64
+  tweakShuffle(BIT64 indata);
+
+  BIT64
+  PACCellInvShuffle(BIT64 indata);
+
+  BIT64
+  PACCellShuffle(BIT64 indata);
+
+  uint64_t PACInvSub(uint64_t tInput);
+
+  uint64_t PACSub(uint64_t tInput);
+
+  uint64_t PACMult(uint64_t tInput);
+
+  BIT64
+  computePAC(BIT64 data, BIT64 modifier, BIT64 key0, BIT64 key1);
+};
+#endif //__ARCH_ARM_QARMA_HH__
index 52e6be748ffad44c65af3ff46db6773d68ad223f..710d663e56648230102c3125fe60cc33ba4aba55 100644 (file)
@@ -261,7 +261,8 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
     currState->vaddr_tainted = currState->req->getVaddr();
     if (currState->aarch64)
         currState->vaddr = purifyTaggedAddr(currState->vaddr_tainted,
-                                            currState->tc, currState->el);
+                                            currState->tc, currState->el,
+                                            currState->mode==TLB::Execute);
     else
         currState->vaddr = currState->vaddr_tainted;
 
index ff5bc6ffc85e1c781d6e8a36b9f1a61304b08c89..5ecd7a45c80f0958e42e69df3073fc58e57220c4 100644 (file)
@@ -535,7 +535,8 @@ TLB::translateSe(const RequestPtr &req, ThreadContext *tc, Mode mode,
     Addr vaddr_tainted = req->getVaddr();
     Addr vaddr = 0;
     if (aarch64)
-        vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
+        vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, (TCR)ttbcr,
+                                 mode==Execute);
     else
         vaddr = vaddr_tainted;
     Request::Flags flags = req->getFlags();
@@ -761,7 +762,8 @@ TLB::checkPermissions64(TlbEntry *te, const RequestPtr &req, Mode mode,
     }
 
     Addr vaddr_tainted = req->getVaddr();
-    Addr vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
+    Addr vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, (TCR)ttbcr,
+                                  mode==Execute);
 
     Request::Flags flags = req->getFlags();
     bool is_fetch  = (mode == Execute);
@@ -1131,7 +1133,8 @@ TLB::translateFs(const RequestPtr &req, ThreadContext *tc, Mode mode,
     Addr vaddr_tainted = req->getVaddr();
     Addr vaddr = 0;
     if (aarch64)
-        vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
+        vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, (TCR)ttbcr,
+                                 mode==Execute);
     else
         vaddr = vaddr_tainted;
     Request::Flags flags = req->getFlags();
@@ -1454,7 +1457,8 @@ TLB::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode,
     Addr vaddr = 0;
     ExceptionLevel target_el = aarch64 ? aarch64EL : EL1;
     if (aarch64) {
-        vaddr = purifyTaggedAddr(vaddr_tainted, tc, target_el, ttbcr);
+        vaddr = purifyTaggedAddr(vaddr_tainted, tc, target_el, (TCR)ttbcr,
+                                 mode==Execute);
     } else {
         vaddr = vaddr_tainted;
     }
index a608a2046a7ca1306c578829dd00550403688e80..8e45fc454464fb9b884c0b1b3f1ddff0867816f5 100644 (file)
@@ -620,6 +620,7 @@ namespace ArmISA
         EC_TRAPPED_HCPTR           = 0x7,
         EC_TRAPPED_SIMD_FP         = 0x7,   // AArch64 alias
         EC_TRAPPED_CP10_MRC_VMRS   = 0x8,
+        EC_TRAPPED_PAC             = 0x9,
         EC_TRAPPED_BXJ             = 0xA,
         EC_TRAPPED_CP14_MCRR_MRRC  = 0xC,
         EC_ILLEGAL_INST            = 0xE,
index 44bc7372e6a294f9de6df205bd65be0573eae7cd..4d8fcc285f94113e517cf110ef37200847cfd2e1 100644 (file)
@@ -286,6 +286,21 @@ HaveVirtHostExt(ThreadContext *tc)
     return id_aa64mmfr1.vh;
 }
 
+ExceptionLevel
+s1TranslationRegime(ThreadContext* tc, ExceptionLevel el)
+{
+
+    SCR scr = tc->readMiscReg(MISCREG_SCR);
+    if (el != EL0)
+        return el;
+    else if (ArmSystem::haveEL(tc, EL3) && ELIs32(tc, EL3) && scr.ns == 0)
+        return EL3;
+    else if (ArmSystem::haveVirtualization(tc) && ELIsInHost(tc, el))
+        return EL2;
+    else
+        return EL1;
+}
+
 bool
 HaveSecureEL2Ext(ThreadContext *tc)
 {
@@ -413,69 +428,77 @@ badMode(ThreadContext *tc, OperatingMode mode)
     return unknownMode(mode) || !ArmSystem::haveEL(tc, opModeToEL(mode));
 }
 
+int
+computeAddrTop(ThreadContext *tc, bool selbit, bool isInstr,
+               TCR tcr, ExceptionLevel el)
+{
+    bool tbi = false;
+    bool tbid = false;
+    ExceptionLevel regime = s1TranslationRegime(tc, el);
+    if (ELIs32(tc, regime)) {
+        return 31;
+    } else {
+        switch (regime) {
+          case EL1:
+          {
+            //TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
+            tbi = selbit? tcr.tbi1 : tcr.tbi0;
+            tbid = selbit? tcr.tbid1 : tcr.tbid0;
+            break;
+          }
+          case EL2:
+          {
+            TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2);
+            if (ArmSystem::haveVirtualization(tc) && ELIsInHost(tc, el)) {
+                tbi = selbit? tcr.tbi1 : tcr.tbi0;
+                tbid = selbit? tcr.tbid1 : tcr.tbid0;
+            } else {
+                tbi = tcr.tbi;
+                tbid = tcr.tbid;
+            }
+            break;
+          }
+          case EL3:
+          {
+            TCR tcr = tc->readMiscReg(MISCREG_TCR_EL3);
+            tbi = tcr.tbi;
+            tbid = tcr.tbid;
+            break;
+          }
+          default:
+            break;
+        }
+
+    }
+    int res = (tbi && (!tbid || !isInstr))? 55: 63;
+    return res;
+}
 Addr
 purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
-                 TTBCR tcr)
+                 TCR tcr, bool isInstr)
 {
-    switch (el) {
-      case EL0:
-      case EL1:
-        if (bits(addr, 55, 48) == 0xFF && tcr.tbi1)
-            return addr | mask(63, 55);
-        else if (!bits(addr, 55, 48) && tcr.tbi0)
-            return bits(addr,55, 0);
-        break;
-      case EL2:
-        assert(ArmSystem::haveVirtualization(tc));
-        tcr = tc->readMiscReg(MISCREG_TCR_EL2);
-        if (tcr.tbi)
-            return addr & mask(56);
-        break;
-      case EL3:
-        assert(ArmSystem::haveSecurity(tc));
-        if (tcr.tbi)
-            return addr & mask(56);
-        break;
-      default:
-        panic("Invalid exception level");
-        break;
-    }
+    bool selbit = bits(addr, 55);
+//    TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
+    int topbit = computeAddrTop(tc, selbit, isInstr, tcr, el);
 
+    if (topbit == 63) {
+        return addr;
+    } else if (selbit && (el == EL1 || el == EL0 || ELIsInHost(tc, el))) {
+        uint64_t mask = ((uint64_t)0x1 << topbit) -1;
+        addr = addr | ~mask;
+    } else {
+        addr = bits(addr, topbit, 0);
+    }
     return addr;  // Nothing to do if this is not a tagged address
 }
 
 Addr
-purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el)
+purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
+                 bool isInstr)
 {
-    TTBCR tcr;
-
-    switch (el) {
-      case EL0:
-      case EL1:
-        tcr = tc->readMiscReg(MISCREG_TCR_EL1);
-        if (bits(addr, 55, 48) == 0xFF && tcr.tbi1)
-            return addr | mask(63, 55);
-        else if (!bits(addr, 55, 48) && tcr.tbi0)
-            return bits(addr,55, 0);
-        break;
-      case EL2:
-        assert(ArmSystem::haveVirtualization(tc));
-        tcr = tc->readMiscReg(MISCREG_TCR_EL2);
-        if (tcr.tbi)
-            return addr & mask(56);
-        break;
-      case EL3:
-        assert(ArmSystem::haveSecurity(tc));
-        tcr = tc->readMiscReg(MISCREG_TCR_EL3);
-        if (tcr.tbi)
-            return addr & mask(56);
-        break;
-      default:
-        panic("Invalid exception level");
-        break;
-    }
 
-    return addr;  // Nothing to do if this is not a tagged address
+    TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
+    return purifyTaggedAddr(addr, tc, el, tcr, isInstr);
 }
 
 Addr
index e70056d6a466b20e1502869afc8fd6924252eaae..b73824ce341716eb994a37aa57c45c713e1880a0 100644 (file)
@@ -217,6 +217,8 @@ itState(CPSR psr)
     return (uint8_t)it;
 }
 
+ExceptionLevel s1TranslationRegime(ThreadContext* tc, ExceptionLevel el);
+
 /**
  * Removes the tag from tagged addresses if that mode is enabled.
  * @param addr The address to be purified.
@@ -225,8 +227,11 @@ itState(CPSR psr)
  * @return The purified address.
  */
 Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
-                      TTBCR tcr);
-Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el);
+                      TCR tcr, bool isInstr);
+Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
+                      bool isInstr);
+int computeAddrTop(ThreadContext *tc, bool selbit, bool isInstr,
+               TTBCR tcr, ExceptionLevel el);
 
 static inline bool
 inSecureState(SCR scr, CPSR cpsr)
@@ -247,13 +252,6 @@ inSecureState(SCR scr, CPSR cpsr)
 
 bool inSecureState(ThreadContext *tc);
 
-/**
- * Return TRUE if an Exception level below EL3 is in Secure state.
- * Differs from inSecureState in that it ignores the current EL
- * or Mode in considering security state.
- */
-inline bool isSecureBelowEL3(ThreadContext *tc);
-
 bool longDescFormatInUse(ThreadContext *tc);
 
 /** This helper function is either returing the value of