From: Jordi Vaquero Date: Tue, 4 Feb 2020 16:37:37 +0000 (+0100) Subject: arch-arm: This commit adds Pointer Authentication feature. X-Git-Tag: v19.0.0.0~39 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3cea7d9ce49bda49c50e756339ff1287fd55df77;p=gem5.git arch-arm: This commit adds Pointer Authentication feature. + 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 Maintainer: Giacomo Travaglini Tested-by: kokoro --- diff --git a/src/arch/arm/ArmISA.py b/src/arch/arm/ArmISA.py index 9fb7fdfbf..f0bcfbf2c 100644 --- a/src/arch/arm/ArmISA.py +++ b/src/arch/arm/ArmISA.py @@ -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 diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index caea1c470..8e00ba966 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -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') diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc index bd38fdccb..9b42d0c33 100644 --- a/src/arch/arm/faults.cc +++ b/src/arch/arm/faults.cc @@ -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()) : diff --git a/src/arch/arm/insts/branch64.cc b/src/arch/arm/insts/branch64.cc index d0a4f2924..1c47b42f3 100644 --- a/src/arch/arm/insts/branch64.cc +++ b/src/arch/arm/insts/branch64.cc @@ -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 diff --git a/src/arch/arm/insts/branch64.hh b/src/arch/arm/insts/branch64.hh index 731c1869c..8bde1a05a 100644 --- a/src/arch/arm/insts/branch64.hh +++ b/src/arch/arm/insts/branch64.hh @@ -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 { diff --git a/src/arch/arm/insts/misc.cc b/src/arch/arm/insts/misc.cc index 14b345843..b38aa8795 100644 --- a/src/arch/arm/insts/misc.cc +++ b/src/arch/arm/insts/misc.cc @@ -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 { diff --git a/src/arch/arm/insts/misc.hh b/src/arch/arm/insts/misc.hh index e1f27433d..f1d09630f 100644 --- a/src/arch/arm/insts/misc.hh +++ b/src/arch/arm/insts/misc.hh @@ -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: diff --git a/src/arch/arm/insts/misc64.cc b/src/arch/arm/insts/misc64.cc index 9bb4026c4..d42d0a123 100644 --- a/src/arch/arm/insts/misc64.cc +++ b/src/arch/arm/insts/misc64.cc @@ -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; } diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa index 838ceddbb..55959f506 100644 --- a/src/arch/arm/isa/formats/aarch64.isa +++ b/src/arch/arm/isa/formats/aarch64.isa @@ -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); diff --git a/src/arch/arm/isa/includes.isa b/src/arch/arm/isa/includes.isa index d584d8225..9b4b5727b 100644 --- a/src/arch/arm/isa/includes.isa +++ b/src/arch/arm/isa/includes.isa @@ -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" diff --git a/src/arch/arm/isa/insts/branch64.isa b/src/arch/arm/isa/insts/branch64.isa index 356114ec7..054a24e5e 100644 --- a/src/arch/arm/isa/insts/branch64.isa +++ b/src/arch/arm/isa/insts/branch64.isa @@ -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, diff --git a/src/arch/arm/isa/insts/insts.isa b/src/arch/arm/isa/insts/insts.isa index 45159e3e6..b4c798a4d 100644 --- a/src/arch/arm/isa/insts/insts.isa +++ b/src/arch/arm/isa/insts/insts.isa @@ -90,6 +90,9 @@ split exec; ##include "fp.isa" ##include "fp64.isa" +//AArch64 pointer authentification operations +##include "pauth.isa" + split exec; //Neon diff --git a/src/arch/arm/isa/insts/ldr64.isa b/src/arch/arm/isa/insts/ldr64.isa index 801316eeb..d6e4f5a1d 100644 --- a/src/arch/arm/isa/insts/ldr64.isa +++ b/src/arch/arm/isa/insts/ldr64.isa @@ -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 index 000000000..0ee5aa0e9 --- /dev/null +++ b/src/arch/arm/isa/insts/pauth.isa @@ -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") +}}; diff --git a/src/arch/arm/isa/templates/branch64.isa b/src/arch/arm/isa/templates/branch64.isa index 6eadf3c7c..b62cdb990 100644 --- a/src/arch/arm/isa/templates/branch64.isa +++ b/src/arch/arm/isa/templates/branch64.isa @@ -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 { diff --git a/src/arch/arm/isa/templates/misc64.isa b/src/arch/arm/isa/templates/misc64.isa index ed9b4a3ae..fa06d5ec4 100644 --- a/src/arch/arm/isa/templates/misc64.isa +++ b/src/arch/arm/isa/templates/misc64.isa @@ -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; + } +}}; diff --git a/src/arch/arm/miscregs.cc b/src/arch/arm/miscregs.cc index 4785f00cd..c25c24bb7 100644 --- a/src/arch/arm/miscregs.cc +++ b/src/arch/arm/miscregs.cc @@ -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) diff --git a/src/arch/arm/miscregs.hh b/src/arch/arm/miscregs.hh index 49df42e51..2618a7646 100644 --- a/src/arch/arm/miscregs.hh +++ b/src/arch/arm/miscregs.hh @@ -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", diff --git a/src/arch/arm/miscregs_types.hh b/src/arch/arm/miscregs_types.hh index 07e2262b3..89dfdb352 100644 --- a/src/arch/arm/miscregs_types.hh +++ b/src/arch/arm/miscregs_types.hh @@ -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 index 000000000..c08e8181b --- /dev/null +++ b/src/arch/arm/pauth_helpers.cc @@ -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(0x0, 0, EC_TRAPPED_PAC); + case EL3: + return std::make_shared(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; + result = ptr & 0xFF00000000000000; + } else { + // PAC<63:56>:selbit:PAC<54:bottom_PAC_bit>:ptr; + 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 + + // + 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 index 000000000..e8abb6571 --- /dev/null +++ b/src/arch/arm/pauth_helpers.hh @@ -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 index 000000000..9f611f99e --- /dev/null +++ b/src/arch/arm/qarma.cc @@ -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 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 index 000000000..91eff901a --- /dev/null +++ b/src/arch/arm/qarma.hh @@ -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__ diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 52e6be748..710d663e5 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -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; diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index ff5bc6ffc..5ecd7a45c 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -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; } diff --git a/src/arch/arm/types.hh b/src/arch/arm/types.hh index a608a2046..8e45fc454 100644 --- a/src/arch/arm/types.hh +++ b/src/arch/arm/types.hh @@ -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, diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc index 44bc7372e..4d8fcc285 100644 --- a/src/arch/arm/utility.cc +++ b/src/arch/arm/utility.cc @@ -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 diff --git a/src/arch/arm/utility.hh b/src/arch/arm/utility.hh index e70056d6a..b73824ce3 100644 --- a/src/arch/arm/utility.hh +++ b/src/arch/arm/utility.hh @@ -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