/*
- * Copyright (c) 2010, 2012-2014, 2016-2018 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
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
// 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);
- }
+ 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.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
}
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());
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);
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(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)
{
// 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;
}
// 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;
}
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 && (cpsr.el == EL0);
+ toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (currEL(tc) == EL0);
return toHyp;
}
(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;
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 && (cpsr.el == EL0);
+ toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (currEL(tc) == EL0);
return toHyp;
}
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