/*
- * Copyright (c) 2010, 2012-2014, 2016-2017 ARM Limited
+ * Copyright (c) 2010, 2012-2014, 2016-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
0x0d, // PermissionL1
0x0e, // PermissionL2
0x0f, // PermissionL3
- 0xff, // DebugEvent (INVALID)
+ 0x22, // DebugEvent
0x10, // SynchronousExternalAbort
0x30, // TLBConflictAbort
0x18, // SynchPtyErrOnMemoryAccess
// Fields: name, offset, cur{ELT,ELH}Offset, lowerEL{64,32}Offset, next mode,
// {ARM, Thumb, ARM_ELR, Thumb_ELR} PC offset, hyp trap,
// {A, F} disable, class, stat
-template<> ArmFault::FaultVals ArmFaultVals<Reset>::vals = {
+template<> ArmFault::FaultVals ArmFaultVals<Reset>::vals(
// Some dummy values (the reset vector has an IMPLEMENTATION DEFINED
// location in AArch64)
"Reset", 0x000, 0x000, 0x000, 0x000, 0x000, MODE_SVC,
- 0, 0, 0, 0, false, true, true, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<UndefinedInstruction>::vals = {
+ 0, 0, 0, 0, false, true, true, EC_UNKNOWN
+);
+template<> ArmFault::FaultVals ArmFaultVals<UndefinedInstruction>::vals(
"Undefined Instruction", 0x004, 0x000, 0x200, 0x400, 0x600, MODE_UNDEFINED,
- 4, 2, 0, 0, true, false, false, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<SupervisorCall>::vals = {
+ 4, 2, 0, 0, true, false, false, EC_UNKNOWN
+);
+template<> ArmFault::FaultVals ArmFaultVals<SupervisorCall>::vals(
"Supervisor Call", 0x008, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
- 4, 2, 4, 2, true, false, false, EC_SVC_TO_HYP, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorCall>::vals = {
+ 4, 2, 4, 2, true, false, false, EC_SVC_TO_HYP
+);
+template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorCall>::vals(
"Secure Monitor Call", 0x008, 0x000, 0x200, 0x400, 0x600, MODE_MON,
- 4, 4, 4, 4, false, true, true, EC_SMC_TO_HYP, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<HypervisorCall>::vals = {
+ 4, 4, 4, 4, false, true, true, EC_SMC_TO_HYP
+);
+template<> ArmFault::FaultVals ArmFaultVals<HypervisorCall>::vals(
"Hypervisor Call", 0x008, 0x000, 0x200, 0x400, 0x600, MODE_HYP,
- 4, 4, 4, 4, true, false, false, EC_HVC, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<PrefetchAbort>::vals = {
+ 4, 4, 4, 4, true, false, false, EC_HVC
+);
+template<> ArmFault::FaultVals ArmFaultVals<PrefetchAbort>::vals(
"Prefetch Abort", 0x00C, 0x000, 0x200, 0x400, 0x600, MODE_ABORT,
- 4, 4, 0, 0, true, true, false, EC_PREFETCH_ABORT_TO_HYP, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<DataAbort>::vals = {
+ 4, 4, 0, 0, true, true, false, EC_PREFETCH_ABORT_TO_HYP
+);
+template<> ArmFault::FaultVals ArmFaultVals<DataAbort>::vals(
"Data Abort", 0x010, 0x000, 0x200, 0x400, 0x600, MODE_ABORT,
- 8, 8, 0, 0, true, true, false, EC_DATA_ABORT_TO_HYP, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<VirtualDataAbort>::vals = {
+ 8, 8, 0, 0, true, true, false, EC_DATA_ABORT_TO_HYP
+);
+template<> ArmFault::FaultVals ArmFaultVals<VirtualDataAbort>::vals(
"Virtual Data Abort", 0x010, 0x000, 0x200, 0x400, 0x600, MODE_ABORT,
- 8, 8, 0, 0, true, true, false, EC_INVALID, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<HypervisorTrap>::vals = {
+ 8, 8, 0, 0, true, true, false, EC_INVALID
+);
+template<> ArmFault::FaultVals ArmFaultVals<HypervisorTrap>::vals(
// @todo: double check these values
"Hypervisor Trap", 0x014, 0x000, 0x200, 0x400, 0x600, MODE_HYP,
- 0, 0, 0, 0, false, false, false, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<Interrupt>::vals = {
+ 0, 0, 0, 0, false, false, false, EC_UNKNOWN
+);
+template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorTrap>::vals(
+ "Secure Monitor Trap", 0x004, 0x000, 0x200, 0x400, 0x600, MODE_MON,
+ 4, 2, 0, 0, false, false, false, EC_UNKNOWN
+);
+template<> ArmFault::FaultVals ArmFaultVals<Interrupt>::vals(
"IRQ", 0x018, 0x080, 0x280, 0x480, 0x680, MODE_IRQ,
- 4, 4, 0, 0, false, true, false, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<VirtualInterrupt>::vals = {
+ 4, 4, 0, 0, false, true, false, EC_UNKNOWN
+);
+template<> ArmFault::FaultVals ArmFaultVals<VirtualInterrupt>::vals(
"Virtual IRQ", 0x018, 0x080, 0x280, 0x480, 0x680, MODE_IRQ,
- 4, 4, 0, 0, false, true, false, EC_INVALID, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<FastInterrupt>::vals = {
+ 4, 4, 0, 0, false, true, false, EC_INVALID
+);
+template<> ArmFault::FaultVals ArmFaultVals<FastInterrupt>::vals(
"FIQ", 0x01C, 0x100, 0x300, 0x500, 0x700, MODE_FIQ,
- 4, 4, 0, 0, false, true, true, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<VirtualFastInterrupt>::vals = {
+ 4, 4, 0, 0, false, true, true, EC_UNKNOWN
+);
+template<> ArmFault::FaultVals ArmFaultVals<VirtualFastInterrupt>::vals(
"Virtual FIQ", 0x01C, 0x100, 0x300, 0x500, 0x700, MODE_FIQ,
- 4, 4, 0, 0, false, true, true, EC_INVALID, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<SupervisorTrap>::vals = {
+ 4, 4, 0, 0, false, true, true, EC_INVALID
+);
+template<> ArmFault::FaultVals ArmFaultVals<IllegalInstSetStateFault>::vals(
+ "Illegal Inst Set State Fault", 0x004, 0x000, 0x200, 0x400, 0x600, MODE_UNDEFINED,
+ 4, 2, 0, 0, true, false, false, EC_ILLEGAL_INST
+);
+template<> ArmFault::FaultVals ArmFaultVals<SupervisorTrap>::vals(
// Some dummy values (SupervisorTrap is AArch64-only)
"Supervisor Trap", 0x014, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
- 0, 0, 0, 0, false, false, false, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorTrap>::vals = {
- // Some dummy values (SecureMonitorTrap is AArch64-only)
- "Secure Monitor Trap", 0x014, 0x000, 0x200, 0x400, 0x600, MODE_MON,
- 0, 0, 0, 0, false, false, false, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<PCAlignmentFault>::vals = {
+ 0, 0, 0, 0, false, false, false, EC_UNKNOWN
+);
+template<> ArmFault::FaultVals ArmFaultVals<PCAlignmentFault>::vals(
// Some dummy values (PCAlignmentFault is AArch64-only)
"PC Alignment Fault", 0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
- 0, 0, 0, 0, true, false, false, EC_PC_ALIGNMENT, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<SPAlignmentFault>::vals = {
+ 0, 0, 0, 0, true, false, false, EC_PC_ALIGNMENT
+);
+template<> ArmFault::FaultVals ArmFaultVals<SPAlignmentFault>::vals(
// Some dummy values (SPAlignmentFault is AArch64-only)
"SP Alignment Fault", 0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
- 0, 0, 0, 0, true, false, false, EC_STACK_PTR_ALIGNMENT, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<SystemError>::vals = {
+ 0, 0, 0, 0, true, false, false, EC_STACK_PTR_ALIGNMENT
+);
+template<> ArmFault::FaultVals ArmFaultVals<SystemError>::vals(
// Some dummy values (SError is AArch64-only)
"SError", 0x000, 0x180, 0x380, 0x580, 0x780, MODE_SVC,
- 0, 0, 0, 0, false, true, true, EC_SERROR, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<SoftwareBreakpoint>::vals = {
+ 0, 0, 0, 0, false, true, true, EC_SERROR
+);
+template<> ArmFault::FaultVals ArmFaultVals<SoftwareBreakpoint>::vals(
// Some dummy values (SoftwareBreakpoint is AArch64-only)
"Software Breakpoint", 0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
- 0, 0, 0, 0, true, false, false, EC_SOFTWARE_BREAKPOINT, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals = {
+ 0, 0, 0, 0, true, false, false, EC_SOFTWARE_BREAKPOINT
+);
+template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals(
// Some dummy values
"ArmSev Flush", 0x000, 0x000, 0x000, 0x000, 0x000, MODE_SVC,
- 0, 0, 0, 0, false, true, true, EC_UNKNOWN, FaultStat()
-};
-template<> ArmFault::FaultVals ArmFaultVals<IllegalInstSetStateFault>::vals = {
- // Some dummy values (SPAlignmentFault is AArch64-only)
- "Illegal Inst Set State Fault", 0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
- 0, 0, 0, 0, true, false, false, EC_ILLEGAL_INST, FaultStat()
-};
+ 0, 0, 0, 0, false, true, true, EC_UNKNOWN
+);
Addr
ArmFault::getVector(ThreadContext *tc)
{
Addr base;
- // ARM ARM issue C B1.8.1
- bool haveSecurity = ArmSystem::haveSecurity(tc);
-
- // panic if SCTLR.VE because I have no idea what to do with vectored
- // interrupts
- SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
- assert(!sctlr.ve);
// Check for invalid modes
CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
- assert(haveSecurity || cpsr.mode != MODE_MON);
+ assert(ArmSystem::haveSecurity(tc) || cpsr.mode != MODE_MON);
assert(ArmSystem::haveVirtualization(tc) || cpsr.mode != MODE_HYP);
switch (cpsr.mode)
base = tc->readMiscReg(MISCREG_HVBAR);
break;
default:
+ SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
if (sctlr.v) {
base = HighVecs;
} else {
- base = haveSecurity ? tc->readMiscReg(MISCREG_VBAR) : 0;
+ base = ArmSystem::haveSecurity(tc) ?
+ tc->readMiscReg(MISCREG_VBAR) : 0;
}
break;
}
+
return base + offset(tc);
}
panic("Invalid target exception level");
break;
}
- return vbar + offset64();
+ return vbar + offset64(tc);
}
MiscRegIndex
uint32_t value;
uint32_t exc_class = (uint32_t) ec(tc);
uint32_t issVal = iss();
+
assert(!from64 || ArmSystem::highestELIs64(tc));
value = exc_class << 26;
}
void
-ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
+ArmFault::update(ThreadContext *tc)
{
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
- if (ArmSystem::highestELIs64(tc)) { // ARMv8
- // Determine source exception level and mode
- fromMode = (OperatingMode) (uint8_t) cpsr.mode;
- fromEL = opModeToEL(fromMode);
- if (opModeIs64(fromMode))
- from64 = true;
-
- // Determine target exception level
- if (ArmSystem::haveSecurity(tc) && routeToMonitor(tc))
- toEL = EL3;
- else if (ArmSystem::haveVirtualization(tc) && routeToHyp(tc))
- toEL = EL2;
- else
- toEL = opModeToEL(nextMode());
- if (fromEL > toEL)
- toEL = fromEL;
-
- if (toEL == ArmSystem::highestEL(tc) || ELIs64(tc, toEL)) {
- // Invoke exception handler in AArch64 state
- to64 = true;
- invoke64(tc, inst);
- return;
+ // Determine source exception level and mode
+ fromMode = (OperatingMode) (uint8_t) cpsr.mode;
+ fromEL = opModeToEL(fromMode);
+ if (opModeIs64(fromMode))
+ from64 = true;
+
+ // Determine target exception level (aarch64) or target execution
+ // mode (aarch32).
+ if (ArmSystem::haveSecurity(tc) && routeToMonitor(tc)) {
+ toMode = MODE_MON;
+ toEL = EL3;
+ } else if (ArmSystem::haveVirtualization(tc) && routeToHyp(tc)) {
+ toMode = MODE_HYP;
+ toEL = EL2;
+ hypRouted = true;
+ } else {
+ toMode = nextMode();
+ toEL = opModeToEL(toMode);
+ }
+
+ if (fromEL > toEL)
+ toEL = fromEL;
+
+ // Check for Set Priviledge Access Never, if PAN is supported
+ AA64MMFR1 mmfr1 = tc->readMiscReg(MISCREG_ID_AA64MMFR1_EL1);
+ if (mmfr1.pan) {
+ if (toEL == EL1) {
+ const SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL1);
+ span = !sctlr.span;
+ }
+
+ const HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR_EL2);
+ if (toEL == EL2 && hcr.e2h && hcr.tge) {
+ const SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL2);
+ span = !sctlr.span;
}
}
+ to64 = ELIs64(tc, toEL);
+
+ // The fault specific informations have been updated; it is
+ // now possible to use them inside the fault.
+ faultUpdated = true;
+}
+
+void
+ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
+{
+
+ // Update fault state informations, like the starting mode (aarch32)
+ // or EL (aarch64) and the ending mode or EL.
+ // From the update function we are also evaluating if the fault must
+ // be handled in AArch64 mode (to64).
+ update(tc);
+
+ if (to64) {
+ // Invoke exception handler in AArch64 state
+ invoke64(tc, inst);
+ return;
+ }
+
// ARMv7 (ARM ARM issue C B1.9)
bool have_security = ArmSystem::haveSecurity(tc);
- bool have_virtualization = ArmSystem::haveVirtualization(tc);
FaultBase::invoke(tc);
if (!FullSystem)
// if we have a valid instruction then use it to annotate this fault with
// extra information. This is used to generate the correct fault syndrome
// information
- if (inst) {
- ArmStaticInst *armInst = static_cast<ArmStaticInst *>(inst.get());
- armInst->annotateFault(this);
- }
-
- if (have_security && routeToMonitor(tc))
- cpsr.mode = MODE_MON;
- else if (have_virtualization && routeToHyp(tc))
- cpsr.mode = MODE_HYP;
- else
- cpsr.mode = nextMode();
+ ArmStaticInst *arm_inst M5_VAR_USED = instrAnnotate(inst);
// Ensure Secure state if initially in Monitor mode
if (have_security && saved_cpsr.mode == MODE_MON) {
}
}
+ CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+ cpsr.mode = toMode;
+
// some bits are set differently if we have been routed to hyp mode
if (cpsr.mode == MODE_HYP) {
SCTLR hsctlr = tc->readMiscReg(MISCREG_HSCTLR);
}
cpsr.it1 = cpsr.it2 = 0;
cpsr.j = 0;
+ cpsr.pan = span ? 1 : saved_cpsr.pan;
tc->setMiscReg(MISCREG_CPSR, cpsr);
// Make sure mailbox sets to one always
setSyndrome(tc, MISCREG_HSR);
break;
case MODE_HYP:
- assert(have_virtualization);
+ assert(ArmSystem::haveVirtualization(tc));
tc->setMiscReg(MISCREG_SPSR_HYP, saved_cpsr);
setSyndrome(tc, MISCREG_HSR);
break;
}
Addr newPc = getVector(tc);
- DPRINTF(Faults, "Invoking Fault:%s cpsr:%#x PC:%#x lr:%#x newVec: %#x\n",
- name(), cpsr, curPc, tc->readIntReg(INTREG_LR), newPc);
+ DPRINTF(Faults, "Invoking Fault:%s cpsr:%#x PC:%#x lr:%#x newVec: %#x "
+ "%s\n", name(), cpsr, curPc, tc->readIntReg(INTREG_LR),
+ newPc, arm_inst ? csprintf("inst: %#x", arm_inst->encoding()) :
+ std::string());
PCState pc(newPc);
pc.thumb(cpsr.t);
pc.nextThumb(pc.thumb());
pc.nextJazelle(pc.jazelle());
pc.aarch64(!cpsr.width);
pc.nextAArch64(!cpsr.width);
+ pc.illegalExec(false);
tc->pcState(pc);
}
spsr.q = 0;
spsr.it1 = 0;
spsr.j = 0;
- spsr.res0_23_22 = 0;
spsr.ge = 0;
spsr.it2 = 0;
spsr.t = 0;
spsr.it2 = it.top6;
spsr.it1 = it.bottom2;
// Force some bitfields to 0
- spsr.res0_23_22 = 0;
spsr.ss = 0;
}
tc->setMiscReg(spsr_idx, spsr);
ret_addr += spsr.t ? thumbPcElrOffset() : armPcElrOffset();
tc->setMiscReg(elr_idx, ret_addr);
+ Addr vec_address = getVector64(tc);
+
// Update process state
OperatingMode64 mode = 0;
mode.spX = 1;
cpsr.daif = 0xf;
cpsr.il = 0;
cpsr.ss = 0;
+ cpsr.pan = span ? 1 : spsr.pan;
tc->setMiscReg(MISCREG_CPSR, cpsr);
+ // If we have a valid instruction then use it to annotate this fault with
+ // extra information. This is used to generate the correct fault syndrome
+ // information
+ ArmStaticInst *arm_inst M5_VAR_USED = instrAnnotate(inst);
+
// Set PC to start of exception handler
- Addr new_pc = purifyTaggedAddr(getVector64(tc), tc, toEL);
+ Addr new_pc = purifyTaggedAddr(vec_address, tc, toEL);
DPRINTF(Faults, "Invoking Fault (AArch64 target EL):%s cpsr:%#x PC:%#x "
- "elr:%#x newVec: %#x\n", name(), cpsr, curr_pc, ret_addr, new_pc);
+ "elr:%#x newVec: %#x %s\n", name(), cpsr, curr_pc, ret_addr,
+ new_pc, arm_inst ? csprintf("inst: %#x", arm_inst->encoding()) :
+ std::string());
PCState pc(new_pc);
pc.aarch64(!cpsr.width);
pc.nextAArch64(!cpsr.width);
+ pc.illegalExec(false);
tc->pcState(pc);
- // If we have a valid instruction then use it to annotate this fault with
- // extra information. This is used to generate the correct fault syndrome
- // information
- if (inst)
- static_cast<ArmStaticInst *>(inst.get())->annotateFault(this);
// Save exception syndrome
if ((nextMode() != MODE_IRQ) && (nextMode() != MODE_FIQ))
setSyndrome(tc, getSyndromeReg64());
}
+ArmStaticInst *
+ArmFault::instrAnnotate(const StaticInstPtr &inst)
+{
+ if (inst) {
+ auto arm_inst = static_cast<ArmStaticInst *>(inst.get());
+ arm_inst->annotateFault(this);
+ return arm_inst;
+ } else {
+ return nullptr;
+ }
+}
+
+Addr
+Reset::getVector(ThreadContext *tc)
+{
+ Addr base;
+
+ // Check for invalid modes
+ CPSR M5_VAR_USED cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
+ assert(ArmSystem::haveSecurity(tc) || cpsr.mode != MODE_MON);
+ assert(ArmSystem::haveVirtualization(tc) || cpsr.mode != MODE_HYP);
+
+ // RVBAR is aliased (implemented as) MVBAR in gem5, since the two
+ // are mutually exclusive; there is no need to check here for
+ // which register to use since they hold the same value
+ base = tc->readMiscReg(MISCREG_MVBAR);
+
+ return base + offset(tc);
+}
+
void
Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
}
} else {
// Advance the PC to the IMPLEMENTATION DEFINED reset value
- PCState pc = ArmSystem::resetAddr64(tc);
+ PCState pc = ArmSystem::resetAddr(tc);
pc.aarch64(true);
pc.nextAArch64(true);
tc->pcState(pc);
// If the mnemonic isn't defined this has to be an unknown instruction.
assert(unknown || mnemonic != NULL);
+ auto arm_inst = static_cast<ArmStaticInst *>(inst.get());
if (disabled) {
panic("Attempted to execute disabled instruction "
- "'%s' (inst 0x%08x)", mnemonic, machInst);
+ "'%s' (inst 0x%08x)", mnemonic, arm_inst->encoding());
} else if (unknown) {
panic("Attempted to execute unknown instruction (inst 0x%08x)",
- machInst);
+ arm_inst->encoding());
} else {
panic("Attempted to execute unimplemented instruction "
- "'%s' (inst 0x%08x)", mnemonic, machInst);
+ "'%s' (inst 0x%08x)", mnemonic, arm_inst->encoding());
}
}
CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
// if in Hyp mode then stay in Hyp mode
- toHyp = scr.ns && (cpsr.mode == MODE_HYP);
+ toHyp = scr.ns && (currEL(tc) == EL2);
// if HCR.TGE is set to 1, take to Hyp mode through Hyp Trap vector
- toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (cpsr.mode == MODE_USER);
+ toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (currEL(tc) == EL0);
return toHyp;
}
uint32_t
UndefinedInstruction::iss() const
{
+
+ // If UndefinedInstruction is routed to hypervisor, iss field is 0.
+ if (hypRouted) {
+ return 0;
+ }
+
if (overrideEc == EC_INVALID)
return issRaw;
// As of now, there isn't a 32 bit thumb version of this instruction.
assert(!machInst.bigThumb);
- uint32_t callNum;
- CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
- OperatingMode mode = (OperatingMode)(uint8_t)cpsr.mode;
- if (opModeIs64(mode))
- callNum = tc->readIntReg(INTREG_X8);
- else
- callNum = tc->readIntReg(INTREG_R7);
Fault fault;
- tc->syscall(callNum, &fault);
+ tc->syscall(&fault);
// Advance the PC since that won't happen automatically.
PCState pc = tc->pcState();
// if in Hyp mode then stay in Hyp mode
toHyp = scr.ns && (cpsr.mode == MODE_HYP);
// if HCR.TGE is set to 1, take to Hyp mode through Hyp Trap vector
- toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (cpsr.mode == MODE_USER);
+ toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (currEL(tc) == EL0);
return toHyp;
}
ExceptionClass
UndefinedInstruction::ec(ThreadContext *tc) const
{
- return (overrideEc != EC_INVALID) ? overrideEc : vals.ec;
+ // If UndefinedInstruction is routed to hypervisor,
+ // HSR.EC field is 0.
+ if (hypRouted)
+ return EC_UNKNOWN;
+ else
+ return (overrideEc != EC_INVALID) ? overrideEc : vals.ec;
}
return isHypTrap ? 0x14 : vals.offset;
}
+template<class T>
+FaultOffset
+ArmFaultVals<T>::offset64(ThreadContext *tc)
+{
+ if (toEL == fromEL) {
+ if (opModeIsT(fromMode))
+ return vals.currELTOffset;
+ return vals.currELHOffset;
+ } else {
+ bool lower_32 = false;
+ if (toEL == EL3) {
+ if (!inSecureState(tc) && ArmSystem::haveEL(tc, EL2))
+ lower_32 = ELIs32(tc, EL2);
+ else
+ lower_32 = ELIs32(tc, EL1);
+ } else {
+ lower_32 = ELIs32(tc, static_cast<ExceptionLevel>(toEL - 1));
+ }
+
+ if (lower_32)
+ return vals.lowerEL32Offset;
+ return vals.lowerEL64Offset;
+ }
+}
+
// void
// SupervisorCall::setSyndrome64(ThreadContext *tc, MiscRegIndex esr_idx)
// {
return (from64 ? EC_SMC_64 : vals.ec);
}
+bool
+SupervisorTrap::routeToHyp(ThreadContext *tc) const
+{
+ bool toHyp = false;
+
+ SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3);
+ HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR_EL2);
+ CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
+
+ // if HCR.TGE is set to 1, take to Hyp mode through Hyp Trap vector
+ toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (currEL(tc) == EL0);
+ return toHyp;
+}
+
+uint32_t
+SupervisorTrap::iss() const
+{
+ // If SupervisorTrap is routed to hypervisor, iss field is 0.
+ if (hypRouted) {
+ return 0;
+ }
+ return issRaw;
+}
+
ExceptionClass
SupervisorTrap::ec(ThreadContext *tc) const
{
- return (overrideEc != EC_INVALID) ? overrideEc : vals.ec;
+ if (hypRouted)
+ return EC_UNKNOWN;
+ else
+ return (overrideEc != EC_INVALID) ? overrideEc : vals.ec;
}
ExceptionClass
}
// Get effective fault source encoding
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
- FSR fsr = getFsr(tc);
// source must be determined BEFORE invoking generic routines which will
// try to set hsr etc. and are based upon source!
ArmFaultVals<T>::invoke(tc, inst);
if (!this->to64) { // AArch32
+ FSR fsr = getFsr(tc);
if (cpsr.mode == MODE_HYP) {
tc->setMiscReg(T::HFarIndex, faultAddr);
} else if (stage2) {
}
template<class T>
-FSR
-AbortFault<T>::getFsr(ThreadContext *tc)
+void
+AbortFault<T>::setSyndrome(ThreadContext *tc, MiscRegIndex syndrome_reg)
+{
+ srcEncoded = getFaultStatusCode(tc);
+ if (srcEncoded == ArmFault::FaultSourceInvalid) {
+ panic("Invalid fault source\n");
+ }
+ ArmFault::setSyndrome(tc, syndrome_reg);
+}
+
+template<class T>
+uint8_t
+AbortFault<T>::getFaultStatusCode(ThreadContext *tc) const
{
- FSR fsr = 0;
- if (((CPSR) tc->readMiscRegNoEffect(MISCREG_CPSR)).width) {
+ panic_if(!this->faultUpdated,
+ "Trying to use un-updated ArmFault internal variables\n");
+
+ uint8_t fsc = 0;
+
+ if (!this->to64) {
// AArch32
assert(tranMethod != ArmFault::UnknownTran);
if (tranMethod == ArmFault::LpaeTran) {
- srcEncoded = ArmFault::longDescFaultSources[source];
- fsr.status = srcEncoded;
- fsr.lpae = 1;
+ fsc = ArmFault::longDescFaultSources[source];
} else {
- srcEncoded = ArmFault::shortDescFaultSources[source];
- fsr.fsLow = bits(srcEncoded, 3, 0);
- fsr.fsHigh = bits(srcEncoded, 4);
- fsr.domain = static_cast<uint8_t>(domain);
+ fsc = ArmFault::shortDescFaultSources[source];
}
- fsr.wnr = (write ? 1 : 0);
- fsr.ext = 0;
} else {
// AArch64
- srcEncoded = ArmFault::aarch64FaultSources[source];
+ fsc = ArmFault::aarch64FaultSources[source];
}
- if (srcEncoded == ArmFault::FaultSourceInvalid) {
- panic("Invalid fault source\n");
+
+ return fsc;
+}
+
+template<class T>
+FSR
+AbortFault<T>::getFsr(ThreadContext *tc) const
+{
+ FSR fsr = 0;
+
+ auto fsc = getFaultStatusCode(tc);
+
+ // AArch32
+ assert(tranMethod != ArmFault::UnknownTran);
+ if (tranMethod == ArmFault::LpaeTran) {
+ fsr.status = fsc;
+ fsr.lpae = 1;
+ } else {
+ fsr.fsLow = bits(fsc, 3, 0);
+ fsr.fsHigh = bits(fsc, 4);
+ fsr.domain = static_cast<uint8_t>(domain);
}
+
+ fsr.wnr = (write ? 1 : 0);
+ fsr.ext = 0;
+
return fsr;
}
(source < ArmFault::PermissionLL + 4));
}
+template<class T>
+bool
+AbortFault<T>::getFaultVAddr(Addr &va) const
+{
+ va = (stage2 ? OVAddr : faultAddr);
+ return true;
+}
+
ExceptionClass
PrefetchAbort::ec(ThreadContext *tc) const
{
SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR);
HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR);
- CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
HDCR hdcr = tc->readMiscRegNoEffect(MISCREG_HDCR);
// if in Hyp mode then stay in Hyp mode
- toHyp = scr.ns && (cpsr.mode == MODE_HYP);
+ toHyp = scr.ns && (currEL(tc) == EL2);
// otherwise, check whether to take to Hyp mode through Hyp Trap vector
toHyp |= (stage2 ||
- ( (source == DebugEvent) && hdcr.tde && (cpsr.mode != MODE_HYP)) ||
- ( (source == SynchronousExternalAbort) && hcr.tge && (cpsr.mode == MODE_USER))
- ) && !inSecureState(tc);
+ ((source == DebugEvent) && hdcr.tde && (currEL(tc) != EL2)) ||
+ ((source == SynchronousExternalAbort) && hcr.tge &&
+ (currEL(tc) == EL0))) && !inSecureState(tc);
return toHyp;
}
SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR);
HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR);
- CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
HDCR hdcr = tc->readMiscRegNoEffect(MISCREG_HDCR);
// if in Hyp mode then stay in Hyp mode
- toHyp = scr.ns && (cpsr.mode == MODE_HYP);
+ toHyp = scr.ns && (currEL(tc) == EL2);
// otherwise, check whether to take to Hyp mode through Hyp Trap vector
toHyp |= (stage2 ||
- ( (cpsr.mode != MODE_HYP) && ( ((source == AsynchronousExternalAbort) && hcr.amo) ||
- ((source == DebugEvent) && hdcr.tde) )
- ) ||
- ( (cpsr.mode == MODE_USER) && hcr.tge &&
- ((source == AlignmentFault) ||
- (source == SynchronousExternalAbort))
- )
- ) && !inSecureState(tc);
+ ((currEL(tc) != EL2) &&
+ (((source == AsynchronousExternalAbort) && hcr.amo) ||
+ ((source == DebugEvent) && hdcr.tde))) ||
+ ((currEL(tc) == EL0) && hcr.tge &&
+ ((source == AlignmentFault) ||
+ (source == SynchronousExternalAbort)))) && !inSecureState(tc);
return toHyp;
}
// Add on the data abort specific fields to the generic abort ISS value
val = AbortFault<DataAbort>::iss();
+
+ val |= cm << 8;
+
// ISS is valid if not caused by a stage 1 page table walk, and when taken
// to AArch64 only when directed to EL2
- if (!s1ptw && (!to64 || toEL == EL2)) {
+ if (!s1ptw && stage2 && (!to64 || toEL == EL2)) {
val |= isv << 24;
if (isv) {
val |= sas << 22;
isv = true;
ar = val;
break;
+ case CM:
+ cm = val;
+ break;
+ case OFA:
+ faultAddr = val;
+ break;
// Just ignore unknown ID's
default:
break;
tc->setMiscReg(getFaultAddrReg64(), faultPC);
}
+bool
+PCAlignmentFault::routeToHyp(ThreadContext *tc) const
+{
+ bool toHyp = false;
+
+ SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3);
+ HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR_EL2);
+ CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
+
+ // if HCR.TGE is set to 1, take to Hyp mode through Hyp Trap vector
+ toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (currEL(tc) == EL0);
+ return toHyp;
+}
+
SPAlignmentFault::SPAlignmentFault()
{}
bool
SoftwareBreakpoint::routeToHyp(ThreadContext *tc) const
{
- assert(from64);
-
const bool have_el2 = ArmSystem::haveVirtualization(tc);
const HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR_EL2);
(hcr.tge || mdcr.tde);
}
+ExceptionClass
+SoftwareBreakpoint::ec(ThreadContext *tc) const
+{
+ return from64 ? EC_SOFTWARE_BREAKPOINT_64 : vals.ec;
+}
+
void
ArmSev::invoke(ThreadContext *tc, const StaticInstPtr &inst) {
DPRINTF(Faults, "Invoking ArmSev Fault\n");
IllegalInstSetStateFault::IllegalInstSetStateFault()
{}
+bool
+getFaultVAddr(Fault fault, Addr &va)
+{
+ auto arm_fault = dynamic_cast<ArmFault *>(fault.get());
+
+ if (arm_fault) {
+ return arm_fault->getFaultVAddr(va);
+ } else {
+ auto pgt_fault = dynamic_cast<GenericPageTableFault *>(fault.get());
+ if (pgt_fault) {
+ va = pgt_fault->getFaultVAddr();
+ return true;
+ }
+
+ auto align_fault = dynamic_cast<GenericAlignmentFault *>(fault.get());
+ if (align_fault) {
+ va = align_fault->getFaultVAddr();
+ return true;
+ }
+
+ // Return false since it's not an address triggered exception
+ return false;
+ }
+}
} // namespace ArmISA