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 <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Jordi Vaquero
2020-02-04 17:37:37 +01:00
parent a62ea2c44f
commit 3cea7d9ce4
28 changed files with 2408 additions and 133 deletions

View File

@@ -102,8 +102,9 @@ class ArmISA(BaseISA):
# !CRC32 | !SHA2 | !SHA1 | !AES
id_aa64isar0_el1 = Param.UInt64(0x0000000000000000,
"AArch64 Instruction Set Attribute Register 0")
# Reserved for future expansion
id_aa64isar1_el1 = Param.UInt64(0x0000000000000000,
# GPI = 0x0 | GPA = 0x1| API=0x0 | APA=0x1
id_aa64isar1_el1 = Param.UInt64(0x0000000001000010,
"AArch64 Instruction Set Attribute Register 1")
# 4K | 64K | !16K | !BigEndEL0 | !SNSMem | !BigEnd | 8b ASID | 40b PA

View File

@@ -76,8 +76,10 @@ if env['TARGET_ISA'] == 'arm':
Source('freebsd/system.cc')
Source('miscregs.cc')
Source('nativetrace.cc')
Source('pauth_helpers.cc')
Source('pmu.cc')
Source('process.cc')
Source('qarma.cc')
Source('remote_gdb.cc')
Source('semihosting.cc')
Source('stacktrace.cc')

View File

@@ -693,7 +693,7 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst)
ArmStaticInst *arm_inst M5_VAR_USED = instrAnnotate(inst);
// Set PC to start of exception handler
Addr new_pc = purifyTaggedAddr(vec_address, tc, toEL);
Addr new_pc = purifyTaggedAddr(vec_address, tc, toEL, true);
DPRINTF(Faults, "Invoking Fault (AArch64 target EL):%s cpsr:%#x PC:%#x "
"elr:%#x newVec: %#x %s\n", name(), cpsr, curr_pc, ret_addr,
new_pc, arm_inst ? csprintf("inst: %#x", arm_inst->encoding()) :

View File

@@ -99,6 +99,18 @@ BranchReg64::generateDisassembly(
return ss.str();
}
std::string
BranchRegReg64::generateDisassembly(
Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
printMnemonic(ss, "", false);
printIntReg(ss, op1);
ccprintf(ss, ", ");
printIntReg(ss, op2);
return ss.str();
}
std::string
BranchRet64::generateDisassembly(
Addr pc, const SymbolTable *symtab) const
@@ -110,6 +122,17 @@ BranchRet64::generateDisassembly(
return ss.str();
}
std::string
BranchRetA64::generateDisassembly(
Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
printMnemonic(ss, "", false);
if (op1 != INTREG_X30)
printIntReg(ss, op1);
return ss.str();
}
std::string
BranchEret64::generateDisassembly(
Addr pc, const SymbolTable *symtab) const
@@ -119,6 +142,15 @@ BranchEret64::generateDisassembly(
return ss.str();
}
std::string
BranchEretA64::generateDisassembly(
Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
printMnemonic(ss, "", false);
return ss.str();
}
std::string
BranchImmReg64::generateDisassembly(
Addr pc, const SymbolTable *symtab) const

View File

@@ -81,6 +81,23 @@ class BranchImmCond64 : public BranchImm64
Addr pc, const SymbolTable *symtab) const override;
};
// Branch to a target computed with two registers
class BranchRegReg64 : public ArmStaticInst
{
protected:
IntRegIndex op1;
IntRegIndex op2;
public:
BranchRegReg64(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _op1, IntRegIndex _op2) :
ArmStaticInst(mnem, _machInst, __opClass), op1(_op1), op2(_op2)
{}
std::string generateDisassembly(
Addr pc, const SymbolTable *symtab) const override;
};
// Branch to a target computed with a register
class BranchReg64 : public ArmStaticInst
{
@@ -110,6 +127,19 @@ class BranchRet64 : public BranchReg64
Addr pc, const SymbolTable *symtab) const override;
};
// RetAA/RetAB instruction
class BranchRetA64 : public BranchRegReg64
{
public:
BranchRetA64(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
BranchRegReg64(mnem, _machInst, __opClass, INTREG_X30,
makeSP(INTREG_SPX))
{}
std::string generateDisassembly(
Addr pc, const SymbolTable *symtab) const override;
};
// Eret instruction
class BranchEret64 : public ArmStaticInst
{
@@ -122,6 +152,20 @@ class BranchEret64 : public ArmStaticInst
Addr pc, const SymbolTable *symtab) const override;
};
// EretA/B instruction
class BranchEretA64 : public ArmStaticInst
{
protected:
IntRegIndex op1;
public:
BranchEretA64(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
ArmStaticInst(mnem, _machInst, __opClass), op1(makeSP(INTREG_SPX))
{}
std::string generateDisassembly(
Addr pc, const SymbolTable *symtab) const override;
};
// Branch to a target computed with an immediate and a register
class BranchImmReg64 : public ArmStaticInst
{

View File

@@ -200,6 +200,14 @@ RegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
return ss.str();
}
std::string
RegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
printMnemonic(ss);
printIntReg(ss, dest);
return ss.str();
}
std::string
RegRegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{

View File

@@ -179,6 +179,20 @@ class RegRegOp : public PredOp
Addr pc, const SymbolTable *symtab) const override;
};
class RegOp : public PredOp
{
protected:
IntRegIndex dest;
RegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _dest) :
PredOp(mnem, _machInst, __opClass), dest(_dest)
{}
std::string generateDisassembly(
Addr pc, const SymbolTable *symtab) const override;
};
class RegImmRegOp : public PredOp
{
protected:

View File

@@ -216,6 +216,18 @@ MiscRegOp64::checkEL2Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
trap_to_hyp = hcr.tacr && el == EL1;
break;
case MISCREG_APDAKeyHi_EL1:
case MISCREG_APDAKeyLo_EL1:
case MISCREG_APDBKeyHi_EL1:
case MISCREG_APDBKeyLo_EL1:
case MISCREG_APGAKeyHi_EL1:
case MISCREG_APGAKeyLo_EL1:
case MISCREG_APIAKeyHi_EL1:
case MISCREG_APIAKeyLo_EL1:
case MISCREG_APIBKeyHi_EL1:
case MISCREG_APIBKeyLo_EL1:
trap_to_hyp = el==EL1 && hcr.apk == 0;
break;
// @todo: Trap implementation-dependent functionality based on
// hcr.tidcp
@@ -296,7 +308,7 @@ MiscRegOp64::checkEL3Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
uint32_t &immediate) const
{
const CPTR cptr = tc->readMiscReg(MISCREG_CPTR_EL3);
const SCR scr = tc->readMiscReg(MISCREG_SCR_EL3);
bool trap_to_mon = false;
switch (misc_reg) {
@@ -319,6 +331,18 @@ MiscRegOp64::checkEL3Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
trap_to_mon = cptr.tcpac;
}
break;
case MISCREG_APDAKeyHi_EL1:
case MISCREG_APDAKeyLo_EL1:
case MISCREG_APDBKeyHi_EL1:
case MISCREG_APDBKeyLo_EL1:
case MISCREG_APGAKeyHi_EL1:
case MISCREG_APGAKeyLo_EL1:
case MISCREG_APIAKeyHi_EL1:
case MISCREG_APIAKeyLo_EL1:
case MISCREG_APIBKeyHi_EL1:
case MISCREG_APIBKeyLo_EL1:
trap_to_mon = (el==EL1 || el==EL2) && scr.apk==0 && ELIs64(tc, EL3);
break;
default:
break;
}

View File

@@ -311,22 +311,24 @@ namespace Aarch64
return new SevInst(machInst);
case 0x5:
return new SevlInst(machInst);
case 0x7:
return new Xpaclri(machInst, INTREG_X30);
}
break;
case 0x1:
switch (op2) {
case 0x0:
return new WarnUnimplemented(
"pacia", machInst);
return new Pacia1716(machInst, INTREG_X17,
INTREG_X16);
case 0x2:
return new WarnUnimplemented(
"pacib", machInst);
return new Pacib1716(machInst, INTREG_X17,
INTREG_X16);
case 0x4:
return new WarnUnimplemented(
"autia", machInst);
return new Autia1716(machInst, INTREG_X17,
INTREG_X16);
case 0x6:
return new WarnUnimplemented(
"autib", machInst);
return new Autib1716(machInst, INTREG_X17,
INTREG_X16);
}
break;
case 0x2:
@@ -348,21 +350,29 @@ namespace Aarch64
case 0x3:
switch (op2) {
case 0x0:
return new Paciaz(machInst,
INTREG_X30, makeZero(INTREG_X31));
case 0x1:
return new WarnUnimplemented(
"pacia", machInst);
return new Paciasp(machInst,
INTREG_X30, makeSP(INTREG_SPX));
case 0x2:
return new Pacibz(machInst,
INTREG_X30, makeZero(INTREG_X31));
case 0x3:
return new WarnUnimplemented(
"pacib", machInst);
return new Pacibsp(machInst,
INTREG_X30, makeSP(INTREG_SPX));
case 0x4:
return new Autiaz(machInst,
INTREG_X30, makeZero(INTREG_X31));
case 0x5:
return new WarnUnimplemented(
"autia", machInst);
return new Autiasp(machInst,
INTREG_X30, makeSP(INTREG_SPX));
case 0x6:
return new Autibz(machInst,
INTREG_X30, makeZero(INTREG_X31));
case 0x7:
return new WarnUnimplemented(
"autib", machInst);
return new Autibsp(machInst,
INTREG_X30, makeSP(INTREG_SPX));
}
break;
case 0x4:
@@ -504,26 +514,72 @@ namespace Aarch64
} else if (bits(machInst, 25) == 0x1) {
uint8_t opc = bits(machInst, 24, 21);
uint8_t op2 = bits(machInst, 20, 16);
uint8_t op3 = bits(machInst, 15, 10);
uint8_t op3 = bits(machInst, 15, 12);
IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5);
IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 4, 0);
uint8_t op4 = bits(machInst, 4, 0);
if (op2 != 0x1f || op3 != 0x0 || op4 != 0x0)
if (op2 != 0x1f || op3 != 0x0)
return new Unknown64(machInst);
switch (opc) {
case 0x0:
return new Br64(machInst, rn);
if (bits(machInst, 11) == 0)
return new Br64(machInst, rn);
else if (op4 != 0x1f)
return new Unknown64(machInst);
// 24(Z):0, 11(A):1
if (bits(machInst, 10) == 0)
return new Braaz(machInst, rn);
else
return new Brabz(machInst, rn);
case 0x1:
return new Blr64(machInst, rn);
if (bits(machInst, 11) == 0)
return new Blr64(machInst, rn);
else if (op4 != 0x1f)
return new Unknown64(machInst);
// 24(Z):0, 11(A):1
if (bits(machInst, 10) == 0)
return new Blraaz(machInst, rn);
else
return new Blrabz(machInst, rn);
case 0x2:
return new Ret64(machInst, rn);
if (op4 == 0x1f) {
bool m = bits(machInst, 10);
if (m)
return new Retab(machInst);
else
return new Retaa(machInst);
} else
return new Ret64(machInst, rn);
case 0x4:
if (rn != 0x1f)
return new Unknown64(machInst);
return new Eret64(machInst);
if (bits(machInst, 11) == 0)
return new Eret64(machInst);
else if (op4 != 0x1f)
return new Unknown64(machInst);
// 24(Z):0, 11(A):1
if (bits(machInst, 10) == 0)
return new Eretaa(machInst);
else
return new Eretab(machInst);
case 0x5:
if (rn != 0x1f)
return new Unknown64(machInst);
return new FailUnimplemented("dret", machInst);
case 0x8:
if (bits(machInst, 11) == 0)
return new Unknown64(machInst);
if (bits(machInst, 10) == 0)
return new Braa(machInst, rn, makeSP(rm));
else
return new Brab(machInst, rn, makeSP(rm));
case 0x9:
if (bits(machInst, 11) == 0)
return new Unknown64(machInst);
if (bits(machInst, 10) == 0)
return new Blraa(machInst, rn, makeSP(rm));
else
return new Blrab(machInst, rn, makeSP(rm));
default:
return new Unknown64(machInst);
}
@@ -1482,6 +1538,35 @@ namespace Aarch64
return decodeAtomicArithOp(machInst);
}
}
case 0x1:
case 0x3:
{
IntRegIndex rt = (IntRegIndex)(uint32_t)
bits(machInst, 4, 0);
IntRegIndex rn = (IntRegIndex)(uint32_t)
bits(machInst, 9, 5);
uint8_t s = bits(machInst, 22);
uint64_t imm9 = bits(machInst, 20, 12);
uint64_t imm10 = sext<10>(s<<9 | imm9)<<3;
uint8_t val = bits(machInst, 23)<<1
| bits(machInst, 11);
switch (val) {
case 0x0:
return new LDRAA_REG(machInst, rt,
makeSP(rn), imm10);
case 0x1:
return new LDRAA_PRE(machInst, rt,
makeSP(rn), imm10);
case 0x2:
return new LDRAB_REG(machInst, rt,
makeSP(rn), imm10);
case 0x3:
return new LDRAB_PRE(machInst, rt,
makeSP(rn), imm10);
default:
M5_UNREACHABLE;
}
}
case 0x2:
{
if (!bits(machInst, 14))
@@ -2016,6 +2101,8 @@ namespace Aarch64
return new Asrv64(machInst, rdzr, rn, rm);
case 0xb:
return new Rorv64(machInst, rdzr, rn, rm);
case 0xc:
return new Pacga(machInst, rd, rn, makeSP(rm));
case 0x10:
return new Crc32b64(machInst, rdzr, rn, rm);
case 0x11:
@@ -2036,8 +2123,93 @@ namespace Aarch64
return new Unknown64(machInst);
}
} else {
if (bits(machInst, 20, 16) != 0 ||
bits(machInst, 29) != 0) {
uint8_t dm = bits(machInst, 20, 14);
switch(dm){
case 0x4:
{
uint8_t zflags = bits(machInst, 13, 10);
switch (zflags) {
case 0x0:
return new Pacia(machInst, rd, makeSP(rn));
case 0x1:
return new Pacib(machInst, rd, makeSP(rn));
case 0x2:
return new Pacda(machInst, rd, makeSP(rn));
case 0x3:
return new Pacdb(machInst, rd, makeSP(rn));
case 0x4:
return new Autia(machInst, rd, makeSP(rn));
case 0x5:
return new Autib(machInst, rd, makeSP(rn));
case 0x6:
return new Autda(machInst, rd, makeSP(rn));
case 0x7:
return new Autdb(machInst, rd, makeSP(rn));
case 0x8:
if (rn == 0x1f)
return new Paciza(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
case 0x9:
if (rn == 0x1f)
return new Pacizb(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
case 0xa:
if (rn == 0x1f)
return new Pacdza(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
case 0xb:
if (rn == 0x1f)
return new Pacdzb(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
case 0xc:
if (rn == 0x1f)
return new Autiza(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
case 0xd:
if (rn == 0x1f)
return new Autizb(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
case 0xe:
if (rn == 0x1f)
return new Autdza(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
case 0xf:
if (rn == 0x1f)
return new Autdzb(machInst, rd,
makeZero(INTREG_X31));
else
return new Unknown64(machInst);
default:
return new Unknown64(machInst);
}
}
case 0x5:
{
if (rn != 0x1f)
return new Unknown64(machInst);
bool d = bits(machInst,10);
if (d)
return new Xpacd(machInst, rd);
else
return new Xpaci(machInst, rd);
}
}
if (dm != 0 || bits(machInst, 29) != 0) {
// dm !=0 and dm != 0x1
return new Unknown64(machInst);
}
uint8_t switchVal = bits(machInst, 15, 10);

View File

@@ -99,6 +99,7 @@ output exec {{
#include "arch/arm/interrupts.hh"
#include "arch/arm/isa.hh"
#include "arch/arm/isa_traits.hh"
#include "arch/arm/pauth_helpers.hh"
#include "arch/arm/utility.hh"
#include "arch/generic/memhelpers.hh"
#include "base/condcodes.hh"

View File

@@ -47,7 +47,7 @@ let {{
# B, BL
for (mnem, link) in (("b", False), ("bl", True)):
bCode = ('NPC = purifyTaggedAddr(RawPC + imm, xc->tcBase(), '
'currEL(xc->tcBase()));\n')
'currEL(xc->tcBase()), true);\n')
instFlags = ['IsDirectControl', 'IsUncondControl']
if (link):
bCode += 'XLR = RawPC + 4;\n'
@@ -62,7 +62,7 @@ let {{
# BR, BLR
for (mnem, link) in (("br", False), ("blr", True)):
bCode = ('NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
'currEL(xc->tcBase()));\n')
'currEL(xc->tcBase()), true);\n')
instFlags = ['IsIndirectControl', 'IsUncondControl']
if (link):
bCode += 'XLR = RawPC + 4;\n'
@@ -74,11 +74,84 @@ let {{
decoder_output += BranchReg64Constructor.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# BRAA, BLRAA
for (mnem, link) in (("Braa", False), ("Blraa", True)):
bCode = ' fault = authIA(xc->tcBase(), XOp1, XOp2, &XOp1);\n'
bCode += ('if (fault == NoFault)\n'
' NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
' currEL(xc->tcBase()), true);\n')
instFlags = ['IsIndirectControl', 'IsUncondControl']
if (link):
bCode += 'XLR = RawPC + 4;\n'
instFlags += ['IsCall']
bIop = InstObjParams(mnem, mnem.capitalize(),
"BranchRegReg64", bCode, instFlags)
header_output += BranchRegReg64Declare.subst(bIop)
decoder_output += BranchRegReg64Constructor.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# BRAAZ, BLRAAZ
for (mnem, link) in (("Braaz", False), ("Blraaz", True)):
bCode = '''
fault = authIA(xc->tcBase(), XOp1, 0, &XOp1);
'''
bCode += ('if (fault == NoFault)\n'
' NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
' currEL(xc->tcBase()), true);\n')
instFlags = ['IsIndirectControl', 'IsUncondControl']
if (link):
bCode += 'XLR = RawPC + 4;\n'
instFlags += ['IsCall']
bIop = InstObjParams(mnem, mnem.capitalize(),
"BranchReg64", bCode, instFlags)
header_output += BranchReg64Declare.subst(bIop)
decoder_output += BranchReg64Constructor.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# BRAB, BLRAB
for (mnem, link) in (("Brab", False), ("Blrab", True)):
bCode = ' fault = authIB(xc->tcBase(), XOp1, XOp2, &XOp1);\n'
bCode += ('if (fault == NoFault)\n'
' NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
' currEL(xc->tcBase()), true);\n')
instFlags = ['IsIndirectControl', 'IsUncondControl']
if (link):
bCode += 'XLR = RawPC + 4;\n'
instFlags += ['IsCall']
bIop = InstObjParams(mnem, mnem.capitalize(),
"BranchRegReg64", bCode, instFlags)
header_output += BranchRegReg64Declare.subst(bIop)
decoder_output += BranchRegReg64Constructor.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# BRABZ, BLRABZ
for (mnem, link) in (("Brabz", False), ("Blrabz", True)):
bCode = '''
fault = authIB(xc->tcBase(), XOp1, 0, &XOp1);
'''
bCode += ('if (fault == NoFault)\n'
' NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
' currEL(xc->tcBase()), true);\n')
instFlags = ['IsIndirectControl', 'IsUncondControl']
if (link):
bCode += 'XLR = RawPC + 4;\n'
instFlags += ['IsCall']
bIop = InstObjParams(mnem, mnem.capitalize(),
"BranchReg64", bCode, instFlags)
header_output += BranchReg64Declare.subst(bIop)
decoder_output += BranchReg64Constructor.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# B conditional
bCode = '''
if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode))
NPC = purifyTaggedAddr(RawPC + imm, xc->tcBase(),
currEL(xc->tcBase()));
currEL(xc->tcBase()), true);
else
NPC = NPC;
'''
@@ -90,7 +163,7 @@ let {{
# RET
bCode = ('NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
'currEL(xc->tcBase()));\n')
'currEL(xc->tcBase()), true);\n')
instFlags = ['IsIndirectControl', 'IsUncondControl', 'IsReturn']
bIop = InstObjParams('ret', 'Ret64', "BranchRet64", bCode, instFlags)
@@ -98,6 +171,30 @@ let {{
decoder_output += BranchReg64Constructor.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# RETAA
bCode = '''
fault = authIA(xc->tcBase(), XOp1, XOp2, &XOp1);
'''
bCode += (' if (fault == NoFault)\n'
' NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
'currEL(xc->tcBase()), true);\n')
bIop = InstObjParams('retaa', 'Retaa', "BranchRetA64", bCode, instFlags)
header_output += BasicDeclare.subst(bIop)
decoder_output += BasicConstructor64.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# RETAB
bCode = '''
fault = authIB(xc->tcBase(), XOp1, XOp2, &XOp1);
'''
bCode += (' if (fault == NoFault)\n'
' NPC = purifyTaggedAddr(XOp1, xc->tcBase(), '
'currEL(xc->tcBase()), true);\n')
bIop = InstObjParams('retab', 'Retab', "BranchRetA64", bCode, instFlags)
header_output += BasicDeclare.subst(bIop)
decoder_output += BasicConstructor64.subst(bIop)
exec_output += BasicExecute.subst(bIop)
# ERET
bCode = '''Addr newPc;
CPSR cpsr = Cpsr;
@@ -120,38 +217,64 @@ let {{
mnemonic);
break;
}
if (spsr.width) {
// Exception return to AArch32.
// 32 most significant bits are ignored
newPc &= mask(32);
if (newPc & mask(2)) {
// Mask bits to avoid PC Alignment fault when returning
// to AArch32
if (spsr.t)
newPc = newPc & ~mask(1);
else
newPc = newPc & ~mask(2);
%(op)s
if (fault == NoFault){
if (spsr.width) {
// Exception return to AArch32.
// 32 most significant bits are ignored
newPc &= mask(32);
if (newPc & mask(2)) {
// Mask bits to avoid PC Alignment fault
// when returning to AArch32
if (spsr.t)
newPc = newPc & ~mask(1);
else
newPc = newPc & ~mask(2);
}
}
CPSR new_cpsr = getPSTATEFromPSR(xc->tcBase(), cpsr, spsr);
Cpsr = new_cpsr;
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), true);
LLSCLock = 0; // Clear exclusive monitor
SevMailbox = 1; //Set Event Register
}
CPSR new_cpsr = getPSTATEFromPSR(xc->tcBase(), cpsr, spsr);
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));
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,

View File

@@ -90,6 +90,9 @@ split exec;
##include "fp.isa"
##include "fp64.isa"
//AArch64 pointer authentification operations
##include "pauth.isa"
split exec;
//Neon

View File

@@ -122,6 +122,15 @@ let {{
eaCode += " + (isBigEndian64(xc->tcBase()) ? 0 : 8)"
else:
eaCode += " + (isBigEndian64(xc->tcBase()) ? 8 : 0)"
if self.flavor in ("authDA", "authDB"):
eaCode += ";\n"
eaCode += "fault = %s(xc->tcBase(), "\
"EA, 0, &EA);\n" % self.flavor
if self.writeback:
eaCode += "XBase = EA;\n"
eaCode += "EA = EA"
if not self.post:
eaCode += self.offset
eaCode += ";"
@@ -381,6 +390,12 @@ let {{
LoadPost64(mnem, NameBase + "_POST", size, sign, flavor=flavor).emit()
LoadReg64(mnem, NameBase + "_REG", size, sign, flavor=flavor).emit()
LoadPre64("ldraa", "LDRAA_PRE", 8, False, flavor="authDA").emit()
LoadImm64("ldraa", "LDRAA_REG", 8, False, flavor="authDA").emit()
LoadPre64("ldrab", "LDRAB_PRE", 8, False, flavor="authDB").emit()
LoadImm64("ldrab", "LDRAB_REG", 8, False, flavor="authDB").emit()
buildLoads64("ldrb", "LDRB64", 1, False)
buildLoads64("ldrsb", "LDRSBW64", 1, True)
buildLoads64("ldrsb", "LDRSBX64", 1, True, flavor="widen")

View File

@@ -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")
}};

View File

@@ -97,6 +97,26 @@ def template BranchReg64Constructor {{
}
}};
def template BranchRegReg64Declare {{
class %(class_name)s : public %(base_class)s
{
public:
// Constructor
%(class_name)s(ExtMachInst machInst, IntRegIndex _op1,
IntRegIndex _op2);
Fault execute(ExecContext *, Trace::InstRecord *) const override;
};
}};
def template BranchRegReg64Constructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst, IntRegIndex _op1,
IntRegIndex _op2)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _op1, _op2)
{
%(constructor)s;
}
}};
def template BranchImmReg64Declare {{
class %(class_name)s : public %(base_class)s
{

View File

@@ -179,3 +179,27 @@ def template RegMiscRegOp64Constructor {{
%(constructor)s;
}
}};
def template XPauthOpRegRegDeclare {{
class %(class_name)s : public %(base_class)s
{
private:
bool data;
public:
// Constructor
%(class_name)s(ExtMachInst machInst, IntRegIndex _dest);
Fault execute(ExecContext *, Trace::InstRecord *) const override;
};
}};
def template XPauthOpRegRegConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst, IntRegIndex _dest)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
_dest)
{
data = bits(machInst, 10);
%(constructor)s;
}
}};

View File

@@ -1937,6 +1937,39 @@ decodeAArch64SysReg(unsigned op0, unsigned op1,
return MISCREG_TCR_EL1;
}
break;
case 0x1:
switch (op2) {
case 0x0:
return MISCREG_APIAKeyLo_EL1;
case 0x1:
return MISCREG_APIAKeyHi_EL1;
case 0x2:
return MISCREG_APIBKeyLo_EL1;
case 0x3:
return MISCREG_APIBKeyHi_EL1;
}
break;
case 0x2:
switch (op2) {
case 0x0:
return MISCREG_APDAKeyLo_EL1;
case 0x1:
return MISCREG_APDAKeyHi_EL1;
case 0x2:
return MISCREG_APDBKeyLo_EL1;
case 0x3:
return MISCREG_APDBKeyHi_EL1;
}
break;
case 0x3:
switch (op2) {
case 0x0:
return MISCREG_APGAKeyLo_EL1;
case 0x1:
return MISCREG_APGAKeyHi_EL1;
}
break;
}
break;
case 4:
@@ -2883,10 +2916,10 @@ ISA::initializeMiscRegMetadata()
bool nTLSMD = false;
// Pointer authentication (Arm 8.3+), unsupported
bool EnDA = false; // using APDAKey_EL1 key of instr addrs in ELs 0,1
bool EnDB = false; // using APDBKey_EL1 key of instr addrs in ELs 0,1
bool EnIA = false; // using APIAKey_EL1 key of instr addrs in ELs 0,1
bool EnIB = false; // using APIBKey_EL1 key of instr addrs in ELs 0,1
bool EnDA = true; // using APDAKey_EL1 key of instr addrs in ELs 0,1
bool EnDB = true; // using APDBKey_EL1 key of instr addrs in ELs 0,1
bool EnIA = true; // using APIAKey_EL1 key of instr addrs in ELs 0,1
bool EnIB = true; // using APIBKey_EL1 key of instr addrs in ELs 0,1
/**
* Some registers alias with others, and therefore need to be translated.
@@ -3968,6 +4001,28 @@ ISA::initializeMiscRegMetadata()
.allPrivileges().exceptUserMode().writes(0);
InitReg(MISCREG_ID_AA64MMFR2_EL1)
.allPrivileges().exceptUserMode().writes(0);
InitReg(MISCREG_APDAKeyHi_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APDAKeyLo_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APDBKeyHi_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APDBKeyLo_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APGAKeyHi_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APGAKeyLo_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APIAKeyHi_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APIAKeyLo_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APIBKeyHi_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_APIBKeyLo_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_CCSIDR_EL1)
.allPrivileges().exceptUserMode().writes(0);
InitReg(MISCREG_CLIDR_EL1)

View File

@@ -675,6 +675,18 @@ namespace ArmISA
MISCREG_ID_AA64MMFR2_EL1,
//PAuth Key Regsiters
MISCREG_APDAKeyHi_EL1,
MISCREG_APDAKeyLo_EL1,
MISCREG_APDBKeyHi_EL1,
MISCREG_APDBKeyLo_EL1,
MISCREG_APGAKeyHi_EL1,
MISCREG_APGAKeyLo_EL1,
MISCREG_APIAKeyHi_EL1,
MISCREG_APIAKeyLo_EL1,
MISCREG_APIBKeyHi_EL1,
MISCREG_APIBKeyLo_EL1,
// GICv3, CPU interface
MISCREG_ICC_PMR_EL1,
MISCREG_ICC_IAR0_EL1,
@@ -1625,6 +1637,16 @@ namespace ArmISA
"cnthv_tval_el2",
"id_aa64mmfr2_el1",
"apdakeyhi_el1",
"apdakeylo_el1",
"apdbkeyhi_el1",
"apdbkeylo_el1",
"apgakeyhi_el1",
"apgakeylo_el1",
"apiakeyhi_el1",
"apiakeylo_el1",
"apibkeyhi_el1",
"apibkeylo_el1",
// GICv3, CPU interface
"icc_pmr_el1",
"icc_iar0_el1",

View File

@@ -233,6 +233,18 @@ namespace ArmISA
EndBitUnion(HSTR)
BitUnion64(HCR)
Bitfield<47> fien;
Bitfield<46> fwb;
Bitfield<45> nv2;
Bitfield<44> at;
Bitfield<43> nv1;
Bitfield<42> nv;
Bitfield<41> api;
Bitfield<40> apk;
Bitfield<38> miocnce;
Bitfield<37> tea;
Bitfield<36> terr;
Bitfield<35> tlor;
Bitfield<34> e2h; // AArch64
Bitfield<33> id;
Bitfield<32> cd;
@@ -240,7 +252,6 @@ namespace ArmISA
Bitfield<30> trvm; // AArch64
Bitfield<29> hcd; // AArch64
Bitfield<28> tdz; // AArch64
Bitfield<27> tge;
Bitfield<26> tvm;
Bitfield<25> ttlb;
@@ -294,7 +305,14 @@ namespace ArmISA
EndBitUnion(NSACR)
BitUnion32(SCR)
Bitfield<21> fien;
Bitfield<20> nmea;
Bitfield<19> ease;
Bitfield<18> eel2; // AArch64 (Armv8.4-SecEL2)
Bitfield<17> api;
Bitfield<16> apk;
Bitfield<15> teer;
Bitfield<14> tlor;
Bitfield<13> twe;
Bitfield<12> twi;
Bitfield<11> st; // AArch64
@@ -313,10 +331,13 @@ namespace ArmISA
EndBitUnion(SCR)
BitUnion32(SCTLR)
Bitfield<31> enia; // ARMv8.3 PAuth
Bitfield<30> enib; // ARMv8.3 PAuth
Bitfield<30> te; // Thumb Exception Enable (AArch32 only)
Bitfield<29> afe; // Access flag enable (AArch32 only)
Bitfield<28> tre; // TEX remap enable (AArch32 only)
Bitfield<27> nmfi; // Non-maskable FIQ support (ARMv7 only)
Bitfield<27> enda; // ARMv8.3 PAuth
Bitfield<26> uci; // Enable EL0 access to DC CVAU, DC CIVAC,
// DC CVAC and IC IVAU instructions
// (AArch64 SCTLR_EL1 only)
@@ -346,6 +367,7 @@ namespace ArmISA
Bitfield<14> dze; // Enable EL0 access to DC ZVA
// (AArch64 SCTLR_EL1 only)
Bitfield<13> v; // Vectors bit (AArch32 only)
Bitfield<13> endb; // ARMv8.3 PAuth
Bitfield<12> i; // Instruction cache enable
Bitfield<11> z; // Branch prediction enable (ARMv7 only)
Bitfield<10> sw; // SWP/SWPB enable (ARMv7 only)
@@ -509,6 +531,7 @@ namespace ArmISA
Bitfield<25, 24> irgn1; // EL1
Bitfield<27, 26> orgn1; // EL1
Bitfield<29, 28> sh1; // EL1
Bitfield<29> tbid; // EL2
Bitfield<31, 30> tg1; // EL1
Bitfield<34, 32> ips; // EL1
Bitfield<36> as; // EL1
@@ -518,6 +541,8 @@ namespace ArmISA
Bitfield<40> hd;
Bitfield<41> hpd0;
Bitfield<42> hpd1;
Bitfield<51> tbid0; // EL1
Bitfield<52> tbid1; // EL1
EndBitUnion(TCR)
BitUnion32(HTCR)

View File

@@ -0,0 +1,924 @@
// -*- mode:c++ -*-
// Copyright (c) 2020 Metempsy Technology Consulting
// All rights reserved
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Jordi Vaquero
#include "arch/arm/pauth_helpers.hh"
#include "arch/arm/faults.hh"
#include "base/bitfield.hh"
using namespace ArmISA;
using namespace std;
bool
ArmISA::calculateTBI(ThreadContext* tc, ExceptionLevel el,
uint64_t ptr, bool data)
{
bool tbi = false;
if (upperAndLowerRange(tc, el)) {
ExceptionLevel s1_el = s1TranslationRegime(tc, el);
assert (s1_el == EL1 || s1_el == EL2);
TCR tcr = (s1_el == EL1) ? tc->readMiscReg(MISCREG_TCR_EL1):
tc->readMiscReg(MISCREG_TCR_EL2);
bool b55 = bits(ptr, 55) == 1;
if (data)
tbi = b55 ? tcr.tbi1 == 1 : tcr.tbi0 == 1;
else
tbi = b55 ? (tcr.tbi1 == 1 && tcr.tbid1 == 0) :
(tcr.tbi0 == 1 && tcr.tbid0 == 0);
}
else if (el == EL2) {
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2);
tbi = data ? tcr.tbi == 1 : (tcr.tbi == 1 && tcr.tbid == 0);
}
else if (el == EL3) {
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL3);
tbi = data ? tcr.tbi == 1 : (tcr.tbi == 1 && tcr.tbid == 0);
}
return tbi;
}
int
ArmISA::calculateBottomPACBit(ThreadContext* tc, ExceptionLevel el,
bool top_bit)
{
uint32_t tsz_field;
bool using64k;
if (upperAndLowerRange(tc, el)) {
ExceptionLevel s1_el = s1TranslationRegime(tc, el);
assert (s1_el == EL1 || s1_el == EL2);
if (s1_el == EL1) {
// EL1 translation regime registers
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
tsz_field = top_bit ? (uint32_t)tcr.t1sz : (uint32_t)tcr.t0sz;
using64k = top_bit ? tcr.tg1 == 0x3 : tcr.tg0 == 0x1;
} else {
// EL2 translation regime registers
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2);
assert (ArmSystem::haveEL(tc, EL2));
tsz_field = top_bit? (uint32_t)tcr.t1sz : (uint32_t)tcr.t0sz;
using64k = top_bit ? tcr.tg1 == 0x3 : tcr.tg0 == 0x1;
}
} else {
TCR tcr2 = tc->readMiscReg(MISCREG_TCR_EL2);
TCR tcr3 = tc->readMiscReg(MISCREG_TCR_EL3);
tsz_field = el == EL2 ? (uint32_t)tcr2.t0sz: (uint32_t)tcr3.t0sz;
using64k = el == EL2 ? tcr2.tg0 == 0x1 : tcr3.tg0 == 0x1 ;
}
uint32_t max_limit_tsz_field = using64k ? 47 : 48;
tsz_field = min(tsz_field, max_limit_tsz_field);
const AA64MMFR2 mm_fr2 = tc->readMiscReg(MISCREG_ID_AA64MMFR2_EL1);
uint32_t tszmin = (using64k && (bool)mm_fr2.varange) ? 12 : 16;
tsz_field = max(tsz_field, tszmin);
return (64-tsz_field);
}
Fault
ArmISA::trapPACUse(ThreadContext *tc, ExceptionLevel target_el)
{
ExceptionLevel curr_el = currEL(tc);
assert(ArmSystem::haveEL(tc, target_el) &&
target_el != EL0 && (target_el >= curr_el));
switch (target_el) {
case EL2:
return std::make_shared<HypervisorTrap>(0x0, 0, EC_TRAPPED_PAC);
case EL3:
return std::make_shared<SecureMonitorTrap>(0x0, 0, EC_TRAPPED_PAC);
default:
return NoFault;
}
}
uint64_t
ArmISA::addPAC (ThreadContext* tc, ExceptionLevel el, uint64_t ptr,
uint64_t modifier, uint64_t k1, uint64_t k0, bool data)
{
uint64_t PAC;
uint64_t result;
uint64_t ext_ptr;
bool selbit;
bool tbi = calculateTBI(tc, el, ptr, data);
int top_bit = tbi ? 55 : 63;
bool b55 = bits(ptr, 55);
bool b63 = bits(ptr, 63);
// If tagged pointers are in use for a regime with two TTBRs,use bit<55> of
// the pointer to select between upper and lower ranges, and preserve this.
// This handles the awkward case where there is apparently no correct
// choice between the upper and lower address range - ie an addr of
// 1xxxxxxx0... with TBI0=0 and TBI1=1 and 0xxxxxxx1 with TBI1=0 and TBI0=1
if (upperAndLowerRange(tc, el)) {
ExceptionLevel s1_el = s1TranslationRegime(tc, el);
assert (s1_el == EL1 || s1_el == EL2);
if (s1TranslationRegime(tc, el) == EL1) {
// EL1 translation regime registers
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
if (data) {
selbit = (tcr.tbi1 == 1 || tcr.tbi0 == 1) ? b55: b63;
} else {
selbit = ((tcr.tbi1 == 1 && tcr.tbid1 == 0)
|| (tcr.tbi0 == 1 && tcr.tbid0 == 0)) ? b55 : b63;
}
} else {
// EL2 translation regime registers
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2);
bool have_el2 = ArmSystem::haveEL(tc, EL2);
if (data) {
selbit = (have_el2 &&
(tcr.tbi0 == 1 || tcr.tbi1 == 1))? b55: b63;
}
else
{
selbit = (have_el2 &&
((tcr.tbi1 == 1 && tcr.tbid1 == 0) ||
(tcr.tbi0 == 1 && tcr.tbid0 == 0)))? b55: b63;
}
}
} else {
selbit = tbi ? b55: b63;
}
int bottom_PAC_bit = calculateBottomPACBit(tc, el, selbit);
// The pointer authentication code field takes all the available
// bits in between
uint32_t nbits = (top_bit+1) - bottom_PAC_bit;
uint64_t pacbits = ((uint64_t)0x1 << nbits) -1; // 2^n -1;
uint64_t mask = pacbits << bottom_PAC_bit; // creates mask
if (selbit) {
ext_ptr = ptr | mask;
} else {
ext_ptr = ptr & ~mask;
}
PAC = QARMA::computePAC(ext_ptr, modifier, k1, k0);
// Check if the ptr has good extension bits and corrupt the
// pointer authentication code if not;
uint64_t t = bits(ptr, top_bit, bottom_PAC_bit);
if (t != 0x0 && t != pacbits) {
PAC ^= ((uint64_t)0x1 << (top_bit-1));
}
// Preserve the determination between upper and lower address
// at bit<55> and insert PAC
if (tbi) {
// ptr<63:56>:selbit:PAC<54:bottom_PAC_bit>:ptr<bottom_PAC_bit-1:0>;
result = ptr & 0xFF00000000000000;
} else {
// PAC<63:56>:selbit:PAC<54:bottom_PAC_bit>:ptr<bottom_PAC_bit-1:0>;
result = PAC & 0xFF00000000000000;
}
uint64_t masked_PAC = PAC & 0x007FFFFFFFFFFFFF;
uint64_t pacbit_mask = ((uint64_t)0x1 << bottom_PAC_bit) -1;
uint64_t masked_ptr = ptr & pacbit_mask;
masked_PAC &= ~pacbit_mask;
result |= ((uint64_t)selbit << 55) | masked_PAC | masked_ptr;
return result;
}
uint64_t
ArmISA::auth(ThreadContext *tc, ExceptionLevel el, uint64_t ptr,
uint64_t modifier, uint64_t k1, uint64_t k0, bool data,
uint8_t errorcode)
{
uint64_t PAC;
uint64_t result;
uint64_t original_ptr;
// Reconstruct the extension field used of adding the PAC to the pointer
bool tbi = calculateTBI(tc, el, ptr, data);
bool selbit = (bool) bits(ptr, 55);
int bottom_PAC_bit = calculateBottomPACBit(tc, el, selbit);
uint32_t top_tbi = tbi? 56: 64;
uint32_t nbits = top_tbi - bottom_PAC_bit;
uint64_t pacbits = ((uint64_t)0x1 << nbits) -1; // 2^n -1;
uint64_t mask = (pacbits << bottom_PAC_bit); // creates mask
if (selbit) {
original_ptr = ptr | mask;
} else {
original_ptr = ptr & ~mask;
}
PAC = QARMA::computePAC(original_ptr, modifier, k1, k0);
// Check pointer authentication code
// <bottom_PAC_bit:0>
uint64_t low_mask = ((uint64_t)0x1 << bottom_PAC_bit) -1;
// <54:bottom_PAC_bit>
uint64_t pac_mask = 0x007FFFFFFFFFFFFF & ~low_mask;
uint64_t masked_pac = PAC & pac_mask;
uint64_t masked_ptr = ptr & pac_mask;
if (tbi) {
if (masked_pac == masked_ptr) {
result = original_ptr;
} else {
uint64_t mask2= ~((uint64_t)0x3 << 53);
result = original_ptr & mask2;
result |= (uint64_t)errorcode << 53;
}
} else {
if ((masked_pac == masked_ptr) && ((PAC >>56)==(ptr >> 56))) {
result = original_ptr;
} else {
uint64_t mask2 = ~((uint64_t)0x3 << 61);
result = original_ptr & mask2;
result |= (uint64_t)errorcode << 61;
}
}
return result;
}
Fault
ArmISA::authDA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out)
{
/*
Returns a 64-bit value containing X, but replacing the pointer
authentication code field bits with the extension of the address bits.
The instruction checks a pointer
authentication code in the pointer authentication code field bits of X,
using the same algorithm and key as AddPACDA().
*/
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APDAKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APDAKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.enda : (bool)sc2.enda;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
enable = sc1.enda;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL2:
enable = sc2.enda;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL3:
enable = sc3.enda;
trapEL2 = false;
trapEL3 = false;
break;
default:
// Unreachable
break;
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else {
*out = auth(tc, el, X, Y, hi_key, lo_key, true, 0x1);
}
return NoFault;
}
Fault
ArmISA::authDB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out)
{
/*
Returns a 64-bit value containing X, but replacing the pointer
authentication code field bits with the extension of the address bits.
The instruction checks a pointer
authentication code in the pointer authentication code field bits of X,
using the same algorithm and key as AddPACDA().
*/
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APDBKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APDBKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.endb : (bool)sc2.endb;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
enable = sc1.endb;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL2:
enable = sc2.endb;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL3:
enable = sc3.endb;
trapEL2 = false;
trapEL3 = false;
break;
default:
//unreachable
break;
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = auth(tc, el, X, Y, hi_key, lo_key, true, 0x2);
return NoFault;
}
Fault
ArmISA::authIA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out)
{
/*
Returns a 64-bit value containing X, but replacing the pointer
authentication code field bits with the extension of the address bits.
The instruction checks a pointer
authentication code in the pointer authentication code field bits of X,
using the same algorithm and key as AddPACDA().
*/
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APIAKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APIAKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.enia : (bool)sc2.enia;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
{
enable = sc1.enia;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL2:
{
enable = sc2.enia;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL3:
{
enable = sc3.enia;
trapEL2 = false;
trapEL3 = false;
break;
}
default:
//unreachable
break;
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = auth(tc, el, X, Y, hi_key, lo_key, false, 0x1);
return NoFault;
}
Fault
ArmISA::authIB(ThreadContext *tc, uint64_t X, uint64_t Y, uint64_t* out)
{
/*
Returns a 64-bit value containing X, but replacing the pointer
authentication code field bits with the extension of the address bits.
The instruction checks a pointer
authentication code in the pointer authentication code field bits of X,
using the same algorithm and key as AddPACDA().
*/
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APIBKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APIBKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.enib : (bool)sc2.enib;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
{
enable = sc1.enib;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL2:
{
enable = sc2.enib;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL3:
{
enable = sc3.enib;
trapEL2 = false;
trapEL3 = false;
break;
}
default:
//unreachable
break;
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = auth(tc, el, X, Y, hi_key, lo_key, false, 0x2);
return NoFault;
}
Fault
ArmISA::addPACDA(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out)
{
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APDAKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APDAKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.enda : (bool)sc2.enda;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
{
enable = sc1.enda;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL2:
{
enable = sc2.enda;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL3:
{
enable = sc3.enda;
trapEL2 = false;
trapEL3 = false;
break;
}
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = addPAC(tc, el, X, Y, hi_key, lo_key, true);
return NoFault;
}
Fault
ArmISA::addPACDB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out)
{
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APDBKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APDBKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.endb : (bool)sc2.endb;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
enable = sc1.endb;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL2:
enable = sc2.endb;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL3:
enable = sc3.endb;
trapEL2 = false;
trapEL3 = false;
break;
default:
// unreachable
break;
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = addPAC(tc, el, X, Y, hi_key, lo_key, true);
return NoFault;
}
Fault
ArmISA::addPACGA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out)
{
bool trapEL2;
bool trapEL3;
uint64_t hi_key= tc->readMiscReg(MISCREG_APGAKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APGAKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCR sc3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == '0' || hcr.e2h == 0));
trapEL3 = have_el3 && sc3.api == 0;
break;
case EL1:
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && sc3.api == 0;
break;
case EL2:
trapEL2 = false;
trapEL3 = have_el3 && sc3.api == 0;
break;
case EL3:
trapEL2 = false;
trapEL3 = false;
break;
default:
//unreachable
break;
}
if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = QARMA::computePAC(X, Y, hi_key, lo_key) & 0xFFFFFFFF00000000;
return NoFault;
}
Fault
ArmISA::addPACIA(ThreadContext * tc, uint64_t X, uint64_t Y, uint64_t* out){
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APIAKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APIAKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.enia : (bool)sc2.enia;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
enable = sc1.enia;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL2:
enable = sc2.enia;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL3:
enable = sc3.enia;
trapEL2 = false;
trapEL3 = false;
break;
default:
//unreachable
break;
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = addPAC(tc, el, X, Y, hi_key, lo_key, false);
return NoFault;
}
Fault
ArmISA::addPACIB(ThreadContext* tc, uint64_t X, uint64_t Y, uint64_t* out){
bool trapEL2;
bool trapEL3;
bool enable;
uint64_t hi_key= tc->readMiscReg(MISCREG_APIBKeyHi_EL1);
uint64_t lo_key= tc->readMiscReg(MISCREG_APIBKeyLo_EL1);
ExceptionLevel el = currEL(tc);
SCTLR sc1 = tc->readMiscReg(MISCREG_SCTLR_EL1);
SCTLR sc2 = tc->readMiscReg(MISCREG_SCTLR_EL2);
SCTLR sc3 = tc->readMiscReg(MISCREG_SCTLR_EL3);
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
{
bool IsEL1Regime = s1TranslationRegime(tc, el) == EL1;
enable = IsEL1Regime ? (bool)sc1.enib : (bool)sc2.enib;
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
}
case EL1:
enable = sc1.enib;
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL2:
enable = sc2.enib;
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL3:
enable = sc3.enib;
trapEL2 = false;
trapEL3 = false;
break;
default:
// Unnaccessible
break;
}
if (!enable)
*out = X;
else if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = addPAC(tc, el, X, Y, hi_key, lo_key, false);
return NoFault;
}
Fault
ArmISA::stripPAC(ThreadContext* tc, uint64_t A, bool data, uint64_t* out){
bool trapEL2;
bool trapEL3;
uint64_t ptr;
ExceptionLevel el = currEL(tc);
bool tbi = calculateTBI(tc, el, A, data);
bool selbit = (bool) bits(A, 55);
int bottom_PAC_bit = calculateBottomPACBit(tc, el, selbit);
int top_bit = tbi ? 55 : 63;
uint32_t nbits = (top_bit+1) - bottom_PAC_bit;
uint64_t pacbits = ((uint64_t)0x1 << nbits) -1; // 2^n -1;
uint64_t mask = pacbits << bottom_PAC_bit; // creates mask
if (selbit) {
ptr = A | mask;
} else {
ptr = A & ~mask;
}
SCR scr3 = tc->readMiscReg(MISCREG_SCR_EL3);
HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool have_el3 = ArmSystem::haveEL(tc, EL3);
switch (el)
{
case EL0:
trapEL2 = (EL2Enabled(tc) && hcr.api == 0 &&
(hcr.tge == 0 || hcr.e2h == 0));
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL1:
trapEL2 = EL2Enabled(tc) && hcr.api == 0;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL2:
trapEL2 = false;
trapEL3 = have_el3 && scr3.api == 0;
break;
case EL3:
trapEL2 = false;
trapEL3 = false;
break;
default:
// Unnaccessible
break;
}
if (trapEL2)
return trapPACUse(tc, EL2);
else if (trapEL3)
return trapPACUse(tc, EL3);
else
*out = ptr;
return NoFault;
}

View File

@@ -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__

396
src/arch/arm/qarma.cc Normal file
View File

@@ -0,0 +1,396 @@
// -*- mode:c++ -*-
// Copyright (c) 2020 Metempsy Technology Consulting
// All rights reserved
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Jordi Vaquero
#include "arch/arm/qarma.hh"
#include "base/bitfield.hh"
using namespace QARMA;
using namespace std;
uint8_t
QARMA::rotCell(uint8_t incell, int amount)
{
uint8_t res = ((incell << amount) | (incell >> (4-amount)))& 0xF;
return res;
}
uint8_t
QARMA::tweakCellInvRot(uint8_t incell)
{
uint8_t outcell = 0x0;
outcell = incell << 1;
uint8_t t = 0x1 & (incell ^ (incell>>3));
outcell |= t;
return outcell & 0xF;
}
uint8_t
QARMA::tweakCellRot(uint8_t incell)
{
uint8_t outcell = 0x0;
outcell = incell >> 1;
uint8_t t = 0x1 & (incell ^ (incell>>1));
outcell |= t<<3;
return outcell & 0xF;
}
BIT64
QARMA::tweakInvShuffle(BIT64 indata)
{
BIT64 outdata = 0x0;
outdata.b0 = tweakCellInvRot(indata.b12);
outdata.b1 = indata.b13;
outdata.b2 = indata.b5;
outdata.b3 = indata.b6;
outdata.b4 = indata.b0;
outdata.b5 = indata.b1;
outdata.b6 = tweakCellInvRot(indata.b2);
outdata.b7 = indata.b3;
outdata.b8 = tweakCellInvRot(indata.b7);
outdata.b9 = tweakCellInvRot(indata.b15);
outdata.b10 = tweakCellInvRot(indata.b14);
outdata.b11 = tweakCellInvRot(indata.b4);
outdata.b12 = indata.b8;
outdata.b13 = indata.b9;
outdata.b14 = indata.b10;
outdata.b15 = tweakCellInvRot(indata.b11);
return outdata;
}
BIT64
QARMA::tweakShuffle(BIT64 indata)
{
BIT64 outdata = 0x0;
outdata.b0 = indata.b4;
outdata.b1 = indata.b5;
outdata.b2 = tweakCellRot(indata.b6);
outdata.b3 = indata.b7;
outdata.b4 = tweakCellRot(indata.b11);
outdata.b5 = indata.b2;
outdata.b6 = indata.b3;
outdata.b7 = tweakCellRot(indata.b8);
outdata.b8 = indata.b12;
outdata.b9 = indata.b13;
outdata.b10 = indata.b14;
outdata.b11 = tweakCellRot(indata.b15);
outdata.b12 = tweakCellRot(indata.b0);
outdata.b13 = indata.b1;
outdata.b14 = tweakCellRot(indata.b10);
outdata.b15 = tweakCellRot(indata.b9);
return outdata;
}
BIT64
QARMA::PACCellInvShuffle(BIT64 indata)
{
BIT64 outdata = 0x0;
outdata.b0 = indata.b3;
outdata.b1 = indata.b6;
outdata.b2 = indata.b12;
outdata.b3 = indata.b9;
outdata.b4 = indata.b14;
outdata.b5 = indata.b11;
outdata.b6 = indata.b1;
outdata.b7 = indata.b4;
outdata.b8 = indata.b8;
outdata.b9 = indata.b13;
outdata.b10 = indata.b7;
outdata.b11 = indata.b2;
outdata.b12 = indata.b5;
outdata.b13 = indata.b0;
outdata.b14 = indata.b10;
outdata.b15 = indata.b15;
return outdata;
}
BIT64
QARMA::PACCellShuffle(BIT64 indata)
{
BIT64 outdata = 0x0;
outdata.b0 = indata.b13;
outdata.b1 = indata.b6;
outdata.b2 = indata.b11;
outdata.b3 = indata.b0;
outdata.b4 = indata.b7;
outdata.b5 = indata.b12;
outdata.b6 = indata.b1;
outdata.b7 = indata.b10;
outdata.b8 = indata.b8;
outdata.b9 = indata.b3;
outdata.b10 = indata.b14;
outdata.b11 = indata.b5;
outdata.b12 = indata.b2;
outdata.b13 = indata.b9;
outdata.b14 = indata.b4;
outdata.b15 = indata.b15;
return outdata;
}
uint64_t
QARMA::PACInvSub(uint64_t tInput)
{
// This is a 4-bit substitution from the PRINCE-family cipher
uint64_t t_output = 0x0;
for (int i=15; i>=0; i--) {
t_output = t_output << 4;
uint8_t b = (tInput >> i*4 ) & 0xF;
switch ( b ) {
case 0x0:
t_output |= 0x5;
break;
case 0x1:
t_output |= 0xe;
break;
case 0x2:
t_output |= 0xd;
break;
case 0x3:
t_output |= 0x8;
break;
case 0x4:
t_output |= 0xa;
break;
case 0x5:
t_output |= 0xb;
break;
case 0x6:
t_output |= 0x1;
break;
case 0x7:
t_output |= 0x9;
break;
case 0x8:
t_output |= 0x2;
break;
case 0x9:
t_output |= 0x6;
break;
case 0xa:
t_output |= 0xf;
break;
case 0xb:
t_output |= 0x0;
break;
case 0xc:
t_output |= 0x4;
break;
case 0xd:
t_output |= 0xc;
break;
case 0xe:
t_output |= 0x7;
break;
case 0xf:
t_output |= 0x3;
break;
default:
//unreachable
break;
}
}
return t_output;
}
uint64_t
QARMA::PACSub(uint64_t tInput){
// This is a 4-bit substitution from the PRINCE-family cipher
uint64_t t_output = 0x0;
for (int i=15; i>=0; i--) {
t_output = t_output << 4;
uint8_t b = (tInput >> i*4 ) & 0xF;
switch ( b ) {
case 0x0:
t_output |= 0xb;
break;
case 0x1:
t_output |= 0x6;
break;
case 0x2:
t_output |= 0x8;
break;
case 0x3:
t_output |= 0xf;
break;
case 0x4:
t_output |= 0xc;
break;
case 0x5:
t_output |= 0x0;
break;
case 0x6:
t_output |= 0x9;
break;
case 0x7:
t_output |= 0xe;
break;
case 0x8:
t_output |= 0x3;
break;
case 0x9:
t_output |= 0x7;
break;
case 0xa:
t_output |= 0x4;
break;
case 0xb:
t_output |= 0x5;
break;
case 0xc:
t_output |= 0xd;
break;
case 0xd:
t_output |= 0x2;
break;
case 0xe:
t_output |= 0x1;
break;
case 0xf:
t_output |= 0xa;
break;
default:
//unreachable
break;
}
}
return t_output;
}
uint64_t
QARMA::PACMult(uint64_t tInput)
{
uint64_t t_output = 0;
for (int i=0;i<=3; i++) {
uint8_t b8 = (tInput >> (4*(i+8))) & 0xF;
uint8_t b4 = (tInput >> (4*(i+4))) & 0xF;
uint8_t b12 = (tInput >> (4*(i+12))) & 0xF;
uint8_t b0 = (tInput >> (4*(i))) & 0xF;
uint64_t t0 = rotCell(b8, 1) ^ rotCell(b4, 2);
t0 = t0 ^ rotCell(b0, 1);
uint64_t t1 = rotCell(b12, 1) ^ rotCell(b4, 1);
t1 = t1 ^ rotCell(b0, 2);
uint64_t t2 = rotCell(b12, 2) ^ rotCell(b8, 1);
t2 = t2 ^ rotCell(b0, 1);
uint64_t t3 = rotCell(b12, 1) ^ rotCell(b8, 2);
t3 = t3 ^ rotCell(b4, 1);
t_output |= (t3 << (4*i));
t_output |= (t2 << (4*(i+4)));
t_output |= (t1 << (4*(i+8)));
t_output |= (t0 << (4*(i+12)));
}
return t_output;
}
BIT64
QARMA::computePAC(BIT64 data, BIT64 modifier, BIT64 key0, BIT64 key1)
{
BIT64 workingval;
BIT64 runningmod;
BIT64 roundkey;
BIT64 modk0;
std::array<BIT64, 5> RC;
RC[0] = (BIT64) 0x0000000000000000;
RC[1] = (BIT64) 0x13198A2E03707344;
RC[2] = (BIT64) 0xA4093822299F31D0;
RC[3] = (BIT64) 0x082EFA98EC4E6C89;
RC[4] = (BIT64) 0x452821E638D01377;
const BIT64 alpha = 0xC0AC29B7C97C50DD;
//modk0 = key0<0>:key0<63:2>:
modk0 = (key0 & 0x1) << 63;
modk0 = modk0 | ((key0 & ~0x3) >> 1);
modk0 = modk0 | ((key0.b15>>3) ^ ((key0.b0 & 0x2)>>1));
runningmod = modifier;
workingval = data^key0;
for (int i=0; i<=4; i++) {
roundkey = key1 ^ runningmod;
workingval = workingval ^ roundkey;
workingval = workingval ^ RC[i];
if (i > 0) {
workingval = PACCellShuffle(workingval);
workingval = PACMult(workingval);
}
workingval = PACSub(workingval);
runningmod = tweakShuffle(runningmod);
}
roundkey = modk0 ^ runningmod;
workingval = workingval ^ roundkey;
workingval = PACCellShuffle(workingval);
workingval = PACMult(workingval);
workingval = PACSub(workingval);
workingval = PACCellShuffle(workingval);
workingval = PACMult(workingval);
workingval = key1 ^ workingval;
workingval = PACCellInvShuffle(workingval);
workingval = PACInvSub(workingval);
workingval = PACMult(workingval);
workingval = PACCellInvShuffle(workingval);
workingval = workingval ^ key0;
workingval = workingval ^ runningmod;
for (int i=0; i<=4; i++) {
workingval = PACInvSub(workingval);
if (i < 4) {
workingval = PACMult(workingval);
workingval = PACCellInvShuffle(workingval);
}
runningmod = tweakInvShuffle(runningmod);
roundkey = key1 ^ runningmod;
workingval = workingval ^ RC[4-i];
workingval = workingval ^ roundkey;
workingval = workingval ^ alpha;
}
workingval = workingval ^ modk0;
return workingval;
}

95
src/arch/arm/qarma.hh Normal file
View File

@@ -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__

View File

@@ -261,7 +261,8 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
currState->vaddr_tainted = currState->req->getVaddr();
if (currState->aarch64)
currState->vaddr = purifyTaggedAddr(currState->vaddr_tainted,
currState->tc, currState->el);
currState->tc, currState->el,
currState->mode==TLB::Execute);
else
currState->vaddr = currState->vaddr_tainted;

View File

@@ -535,7 +535,8 @@ TLB::translateSe(const RequestPtr &req, ThreadContext *tc, Mode mode,
Addr vaddr_tainted = req->getVaddr();
Addr vaddr = 0;
if (aarch64)
vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, (TCR)ttbcr,
mode==Execute);
else
vaddr = vaddr_tainted;
Request::Flags flags = req->getFlags();
@@ -761,7 +762,8 @@ TLB::checkPermissions64(TlbEntry *te, const RequestPtr &req, Mode mode,
}
Addr vaddr_tainted = req->getVaddr();
Addr vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
Addr vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, (TCR)ttbcr,
mode==Execute);
Request::Flags flags = req->getFlags();
bool is_fetch = (mode == Execute);
@@ -1131,7 +1133,8 @@ TLB::translateFs(const RequestPtr &req, ThreadContext *tc, Mode mode,
Addr vaddr_tainted = req->getVaddr();
Addr vaddr = 0;
if (aarch64)
vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, (TCR)ttbcr,
mode==Execute);
else
vaddr = vaddr_tainted;
Request::Flags flags = req->getFlags();
@@ -1454,7 +1457,8 @@ TLB::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode,
Addr vaddr = 0;
ExceptionLevel target_el = aarch64 ? aarch64EL : EL1;
if (aarch64) {
vaddr = purifyTaggedAddr(vaddr_tainted, tc, target_el, ttbcr);
vaddr = purifyTaggedAddr(vaddr_tainted, tc, target_el, (TCR)ttbcr,
mode==Execute);
} else {
vaddr = vaddr_tainted;
}

View File

@@ -620,6 +620,7 @@ namespace ArmISA
EC_TRAPPED_HCPTR = 0x7,
EC_TRAPPED_SIMD_FP = 0x7, // AArch64 alias
EC_TRAPPED_CP10_MRC_VMRS = 0x8,
EC_TRAPPED_PAC = 0x9,
EC_TRAPPED_BXJ = 0xA,
EC_TRAPPED_CP14_MCRR_MRRC = 0xC,
EC_ILLEGAL_INST = 0xE,

View File

@@ -286,6 +286,21 @@ HaveVirtHostExt(ThreadContext *tc)
return id_aa64mmfr1.vh;
}
ExceptionLevel
s1TranslationRegime(ThreadContext* tc, ExceptionLevel el)
{
SCR scr = tc->readMiscReg(MISCREG_SCR);
if (el != EL0)
return el;
else if (ArmSystem::haveEL(tc, EL3) && ELIs32(tc, EL3) && scr.ns == 0)
return EL3;
else if (ArmSystem::haveVirtualization(tc) && ELIsInHost(tc, el))
return EL2;
else
return EL1;
}
bool
HaveSecureEL2Ext(ThreadContext *tc)
{
@@ -413,69 +428,77 @@ badMode(ThreadContext *tc, OperatingMode mode)
return unknownMode(mode) || !ArmSystem::haveEL(tc, opModeToEL(mode));
}
int
computeAddrTop(ThreadContext *tc, bool selbit, bool isInstr,
TCR tcr, ExceptionLevel el)
{
bool tbi = false;
bool tbid = false;
ExceptionLevel regime = s1TranslationRegime(tc, el);
if (ELIs32(tc, regime)) {
return 31;
} else {
switch (regime) {
case EL1:
{
//TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
tbi = selbit? tcr.tbi1 : tcr.tbi0;
tbid = selbit? tcr.tbid1 : tcr.tbid0;
break;
}
case EL2:
{
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL2);
if (ArmSystem::haveVirtualization(tc) && ELIsInHost(tc, el)) {
tbi = selbit? tcr.tbi1 : tcr.tbi0;
tbid = selbit? tcr.tbid1 : tcr.tbid0;
} else {
tbi = tcr.tbi;
tbid = tcr.tbid;
}
break;
}
case EL3:
{
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL3);
tbi = tcr.tbi;
tbid = tcr.tbid;
break;
}
default:
break;
}
}
int res = (tbi && (!tbid || !isInstr))? 55: 63;
return res;
}
Addr
purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
TTBCR tcr)
TCR tcr, bool isInstr)
{
switch (el) {
case EL0:
case EL1:
if (bits(addr, 55, 48) == 0xFF && tcr.tbi1)
return addr | mask(63, 55);
else if (!bits(addr, 55, 48) && tcr.tbi0)
return bits(addr,55, 0);
break;
case EL2:
assert(ArmSystem::haveVirtualization(tc));
tcr = tc->readMiscReg(MISCREG_TCR_EL2);
if (tcr.tbi)
return addr & mask(56);
break;
case EL3:
assert(ArmSystem::haveSecurity(tc));
if (tcr.tbi)
return addr & mask(56);
break;
default:
panic("Invalid exception level");
break;
}
bool selbit = bits(addr, 55);
// TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
int topbit = computeAddrTop(tc, selbit, isInstr, tcr, el);
if (topbit == 63) {
return addr;
} else if (selbit && (el == EL1 || el == EL0 || ELIsInHost(tc, el))) {
uint64_t mask = ((uint64_t)0x1 << topbit) -1;
addr = addr | ~mask;
} else {
addr = bits(addr, topbit, 0);
}
return addr; // Nothing to do if this is not a tagged address
}
Addr
purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el)
purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
bool isInstr)
{
TTBCR tcr;
switch (el) {
case EL0:
case EL1:
tcr = tc->readMiscReg(MISCREG_TCR_EL1);
if (bits(addr, 55, 48) == 0xFF && tcr.tbi1)
return addr | mask(63, 55);
else if (!bits(addr, 55, 48) && tcr.tbi0)
return bits(addr,55, 0);
break;
case EL2:
assert(ArmSystem::haveVirtualization(tc));
tcr = tc->readMiscReg(MISCREG_TCR_EL2);
if (tcr.tbi)
return addr & mask(56);
break;
case EL3:
assert(ArmSystem::haveSecurity(tc));
tcr = tc->readMiscReg(MISCREG_TCR_EL3);
if (tcr.tbi)
return addr & mask(56);
break;
default:
panic("Invalid exception level");
break;
}
return addr; // Nothing to do if this is not a tagged address
TCR tcr = tc->readMiscReg(MISCREG_TCR_EL1);
return purifyTaggedAddr(addr, tc, el, tcr, isInstr);
}
Addr

View File

@@ -217,6 +217,8 @@ itState(CPSR psr)
return (uint8_t)it;
}
ExceptionLevel s1TranslationRegime(ThreadContext* tc, ExceptionLevel el);
/**
* Removes the tag from tagged addresses if that mode is enabled.
* @param addr The address to be purified.
@@ -225,8 +227,11 @@ itState(CPSR psr)
* @return The purified address.
*/
Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
TTBCR tcr);
Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el);
TCR tcr, bool isInstr);
Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el,
bool isInstr);
int computeAddrTop(ThreadContext *tc, bool selbit, bool isInstr,
TTBCR tcr, ExceptionLevel el);
static inline bool
inSecureState(SCR scr, CPSR cpsr)
@@ -247,13 +252,6 @@ inSecureState(SCR scr, CPSR cpsr)
bool inSecureState(ThreadContext *tc);
/**
* Return TRUE if an Exception level below EL3 is in Secure state.
* Differs from inSecureState in that it ignores the current EL
* or Mode in considering security state.
*/
inline bool isSecureBelowEL3(ThreadContext *tc);
bool longDescFormatInUse(ThreadContext *tc);
/** This helper function is either returing the value of