summaryrefslogtreecommitdiff
path: root/src/arch/arm/insts/misc64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/arm/insts/misc64.cc')
-rw-r--r--src/arch/arm/insts/misc64.cc226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/arch/arm/insts/misc64.cc b/src/arch/arm/insts/misc64.cc
index 5bdf6cb94..b2761e76c 100644
--- a/src/arch/arm/insts/misc64.cc
+++ b/src/arch/arm/insts/misc64.cc
@@ -81,6 +81,232 @@ UnknownOp64::generateDisassembly(Addr pc, const SymbolTable *symtab) const
return csprintf("%-10s (inst %#08x)", "unknown", machInst & mask(32));
}
+Fault
+MiscRegOp64::trap(ThreadContext *tc, MiscRegIndex misc_reg,
+ ExceptionLevel el, uint32_t immediate) const
+{
+ bool is_vfp_neon = false;
+
+ // Check for traps to supervisor (FP/SIMD regs)
+ if (el <= EL1 && checkEL1Trap(tc, misc_reg, el)) {
+
+ return std::make_shared<SupervisorTrap>(machInst, 0x1E00000,
+ EC_TRAPPED_SIMD_FP);
+ }
+
+ // Check for traps to hypervisor
+ if ((ArmSystem::haveVirtualization(tc) && el <= EL2) &&
+ checkEL2Trap(tc, misc_reg, el, &is_vfp_neon)) {
+
+ return std::make_shared<HypervisorTrap>(
+ machInst, is_vfp_neon ? 0x1E00000 : immediate,
+ is_vfp_neon ? EC_TRAPPED_SIMD_FP : EC_TRAPPED_MSR_MRS_64);
+ }
+
+ // Check for traps to secure monitor
+ if ((ArmSystem::haveSecurity(tc) && el <= EL3) &&
+ checkEL3Trap(tc, misc_reg, el, &is_vfp_neon)) {
+
+ return std::make_shared<SecureMonitorTrap>(
+ machInst,
+ is_vfp_neon ? 0x1E00000 : immediate,
+ is_vfp_neon ? EC_TRAPPED_SIMD_FP : EC_TRAPPED_MSR_MRS_64);
+ }
+
+ return NoFault;
+}
+
+bool
+MiscRegOp64::checkEL1Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
+ ExceptionLevel el) const
+{
+ const CPACR cpacr = tc->readMiscReg(MISCREG_CPACR_EL1);
+
+ bool trap_to_sup = false;
+ switch (misc_reg) {
+ case MISCREG_FPCR:
+ case MISCREG_FPSR:
+ case MISCREG_FPEXC32_EL2:
+ if ((el == EL0 && cpacr.fpen != 0x3) ||
+ (el == EL1 && !(cpacr.fpen & 0x1)))
+ trap_to_sup = true;
+ break;
+ default:
+ break;
+ }
+ return trap_to_sup;
+}
+
+bool
+MiscRegOp64::checkEL2Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
+ ExceptionLevel el, bool * is_vfp_neon) const
+{
+ const CPTR cptr = tc->readMiscReg(MISCREG_CPTR_EL2);
+ const HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
+ const SCR scr = tc->readMiscReg(MISCREG_SCR_EL3);
+ const CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+
+ bool trap_to_hyp = false;
+ *is_vfp_neon = false;
+
+ if (!inSecureState(scr, cpsr) && (el != EL2)) {
+ switch (misc_reg) {
+ // FP/SIMD regs
+ case MISCREG_FPCR:
+ case MISCREG_FPSR:
+ case MISCREG_FPEXC32_EL2:
+ trap_to_hyp = cptr.tfp;
+ *is_vfp_neon = true;
+ break;
+ // CPACR
+ case MISCREG_CPACR_EL1:
+ trap_to_hyp = cptr.tcpac && el == EL1;
+ break;
+ // Virtual memory control regs
+ case MISCREG_SCTLR_EL1:
+ case MISCREG_TTBR0_EL1:
+ case MISCREG_TTBR1_EL1:
+ case MISCREG_TCR_EL1:
+ case MISCREG_ESR_EL1:
+ case MISCREG_FAR_EL1:
+ case MISCREG_AFSR0_EL1:
+ case MISCREG_AFSR1_EL1:
+ case MISCREG_MAIR_EL1:
+ case MISCREG_AMAIR_EL1:
+ case MISCREG_CONTEXTIDR_EL1:
+ trap_to_hyp =
+ ((hcr.trvm && miscRead) || (hcr.tvm && !miscRead)) &&
+ el == EL1;
+ break;
+ // TLB maintenance instructions
+ case MISCREG_TLBI_VMALLE1:
+ case MISCREG_TLBI_VAE1_Xt:
+ case MISCREG_TLBI_ASIDE1_Xt:
+ case MISCREG_TLBI_VAAE1_Xt:
+ case MISCREG_TLBI_VALE1_Xt:
+ case MISCREG_TLBI_VAALE1_Xt:
+ case MISCREG_TLBI_VMALLE1IS:
+ case MISCREG_TLBI_VAE1IS_Xt:
+ case MISCREG_TLBI_ASIDE1IS_Xt:
+ case MISCREG_TLBI_VAAE1IS_Xt:
+ case MISCREG_TLBI_VALE1IS_Xt:
+ case MISCREG_TLBI_VAALE1IS_Xt:
+ trap_to_hyp = hcr.ttlb && el == EL1;
+ break;
+ // Cache maintenance instructions to the point of unification
+ case MISCREG_IC_IVAU_Xt:
+ case MISCREG_ICIALLU:
+ case MISCREG_ICIALLUIS:
+ case MISCREG_DC_CVAU_Xt:
+ trap_to_hyp = hcr.tpu && el <= EL1;
+ break;
+ // Data/Unified cache maintenance instructions to the
+ // point of coherency
+ case MISCREG_DC_IVAC_Xt:
+ case MISCREG_DC_CIVAC_Xt:
+ case MISCREG_DC_CVAC_Xt:
+ trap_to_hyp = hcr.tpc && el <= EL1;
+ break;
+ // Data/Unified cache maintenance instructions by set/way
+ case MISCREG_DC_ISW_Xt:
+ case MISCREG_DC_CSW_Xt:
+ case MISCREG_DC_CISW_Xt:
+ trap_to_hyp = hcr.tsw && el == EL1;
+ break;
+ // ACTLR
+ case MISCREG_ACTLR_EL1:
+ trap_to_hyp = hcr.tacr && el == EL1;
+ break;
+
+ // @todo: Trap implementation-dependent functionality based on
+ // hcr.tidcp
+
+ // ID regs, group 3
+ case MISCREG_ID_PFR0_EL1:
+ case MISCREG_ID_PFR1_EL1:
+ case MISCREG_ID_DFR0_EL1:
+ case MISCREG_ID_AFR0_EL1:
+ case MISCREG_ID_MMFR0_EL1:
+ case MISCREG_ID_MMFR1_EL1:
+ case MISCREG_ID_MMFR2_EL1:
+ case MISCREG_ID_MMFR3_EL1:
+ case MISCREG_ID_ISAR0_EL1:
+ case MISCREG_ID_ISAR1_EL1:
+ case MISCREG_ID_ISAR2_EL1:
+ case MISCREG_ID_ISAR3_EL1:
+ case MISCREG_ID_ISAR4_EL1:
+ case MISCREG_ID_ISAR5_EL1:
+ case MISCREG_MVFR0_EL1:
+ case MISCREG_MVFR1_EL1:
+ case MISCREG_MVFR2_EL1:
+ case MISCREG_ID_AA64PFR0_EL1:
+ case MISCREG_ID_AA64PFR1_EL1:
+ case MISCREG_ID_AA64DFR0_EL1:
+ case MISCREG_ID_AA64DFR1_EL1:
+ case MISCREG_ID_AA64ISAR0_EL1:
+ case MISCREG_ID_AA64ISAR1_EL1:
+ case MISCREG_ID_AA64MMFR0_EL1:
+ case MISCREG_ID_AA64MMFR1_EL1:
+ case MISCREG_ID_AA64MMFR2_EL1:
+ case MISCREG_ID_AA64AFR0_EL1:
+ case MISCREG_ID_AA64AFR1_EL1:
+ assert(miscRead);
+ trap_to_hyp = hcr.tid3 && el == EL1;
+ break;
+ // ID regs, group 2
+ case MISCREG_CTR_EL0:
+ case MISCREG_CCSIDR_EL1:
+ case MISCREG_CLIDR_EL1:
+ case MISCREG_CSSELR_EL1:
+ trap_to_hyp = hcr.tid2 && el <= EL1;
+ break;
+ // ID regs, group 1
+ case MISCREG_AIDR_EL1:
+ case MISCREG_REVIDR_EL1:
+ assert(miscRead);
+ trap_to_hyp = hcr.tid1 && el == EL1;
+ break;
+ default:
+ break;
+ }
+ }
+ return trap_to_hyp;
+}
+
+bool
+MiscRegOp64::checkEL3Trap(ThreadContext *tc, const MiscRegIndex misc_reg,
+ ExceptionLevel el, bool * is_vfp_neon) const
+{
+ const CPTR cptr = tc->readMiscReg(MISCREG_CPTR_EL3);
+
+ bool trap_to_mon = false;
+ *is_vfp_neon = false;
+
+ switch (misc_reg) {
+ // FP/SIMD regs
+ case MISCREG_FPCR:
+ case MISCREG_FPSR:
+ case MISCREG_FPEXC32_EL2:
+ trap_to_mon = cptr.tfp;
+ *is_vfp_neon = true;
+ break;
+ // CPACR, CPTR
+ case MISCREG_CPACR_EL1:
+ if (el == EL1 || el == EL2) {
+ trap_to_mon = cptr.tcpac;
+ }
+ break;
+ case MISCREG_CPTR_EL2:
+ if (el == EL2) {
+ trap_to_mon = cptr.tcpac;
+ }
+ break;
+ default:
+ break;
+ }
+ return trap_to_mon;
+}
+
std::string
MiscRegRegImmOp64::generateDisassembly(
Addr pc, const SymbolTable *symtab) const