+ 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>
# !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
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')
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()) :
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
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
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
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
{
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
{
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
{
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
{
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:
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
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) {
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;
}
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:
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:
} 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);
}
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))
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:
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);
#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"
# 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'
# 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'
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;
'''
# 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)
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;
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)
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,
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,
##include "fp.isa"
##include "fp64.isa"
+//AArch64 pointer authentification operations
+##include "pauth.isa"
+
split exec;
//Neon
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 += ";"
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")
--- /dev/null
+// -*- 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")
+}};
}
}};
+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
{
%(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;
+ }
+}};
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:
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.
.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)
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,
"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",
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;
Bitfield<30> trvm; // AArch64
Bitfield<29> hcd; // AArch64
Bitfield<28> tdz; // AArch64
-
Bitfield<27> tge;
Bitfield<26> tvm;
Bitfield<25> ttlb;
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
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)
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)
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
Bitfield<40> hd;
Bitfield<41> hpd0;
Bitfield<42> hpd1;
+ Bitfield<51> tbid0; // EL1
+ Bitfield<52> tbid1; // EL1
EndBitUnion(TCR)
BitUnion32(HTCR)
--- /dev/null
+// -*- 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;
+}
+
--- /dev/null
+// -*- 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__
--- /dev/null
+// -*- 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;
+}
+
--- /dev/null
+// -*- 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__
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;
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();
}
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);
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();
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;
}
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,
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)
{
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
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.
* @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)
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