syscall_emul: [patch 13/22] add system call retry capability
[gem5.git] / src / arch / arm / faults.cc
index 6c1992dd6039040ee8ced98c0fe9fcd0a0e536b5..740d71d02a83f6044b1f6ffff573e80371f79fba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012-2014 ARM Limited
+ * Copyright (c) 2010, 2012-2014, 2016 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  */
 
 #include "arch/arm/faults.hh"
+
+#include "arch/arm/insts/static_inst.hh"
 #include "arch/arm/system.hh"
 #include "arch/arm/utility.hh"
-#include "arch/arm/insts/static_inst.hh"
 #include "base/compiler.hh"
 #include "base/trace.hh"
 #include "cpu/base.hh"
@@ -338,11 +339,10 @@ ArmFault::getVector64(ThreadContext *tc)
         assert(ArmSystem::haveSecurity(tc));
         vbar = tc->readMiscReg(MISCREG_VBAR_EL3);
         break;
-      // @todo: uncomment this to enable Virtualization
-      // case EL2:
-      //   assert(ArmSystem::haveVirtualization(tc));
-      //   vbar = tc->readMiscReg(MISCREG_VBAR_EL2);
-      //   break;
+      case EL2:
+        assert(ArmSystem::haveVirtualization(tc));
+        vbar = tc->readMiscReg(MISCREG_VBAR_EL2);
+        break;
       case EL1:
         vbar = tc->readMiscReg(MISCREG_VBAR_EL1);
         break;
@@ -426,7 +426,7 @@ ArmFault::setSyndrome(ThreadContext *tc, MiscRegIndex syndrome_reg)
 }
 
 void
-ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
+ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
 
@@ -440,6 +440,8 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
         // 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)
@@ -587,7 +589,7 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
 }
 
 void
-ArmFault::invoke64(ThreadContext *tc, StaticInstPtr inst)
+ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst)
 {
     // Determine actual misc. register indices for ELR_ELx and SPSR_ELx
     MiscRegIndex elr_idx, spsr_idx;
@@ -596,12 +598,11 @@ ArmFault::invoke64(ThreadContext *tc, StaticInstPtr inst)
         elr_idx = MISCREG_ELR_EL1;
         spsr_idx = MISCREG_SPSR_EL1;
         break;
-      // @todo: uncomment this to enable Virtualization
-      // case EL2:
-      //   assert(ArmSystem::haveVirtualization());
-      //   elr_idx = MISCREG_ELR_EL2;
-      //   spsr_idx = MISCREG_SPSR_EL2;
-      //   break;
+      case EL2:
+        assert(ArmSystem::haveVirtualization(tc));
+        elr_idx = MISCREG_ELR_EL2;
+        spsr_idx = MISCREG_SPSR_EL2;
+        break;
       case EL3:
         assert(ArmSystem::haveSecurity(tc));
         elr_idx = MISCREG_ELR_EL3;
@@ -678,10 +679,10 @@ ArmFault::invoke64(ThreadContext *tc, StaticInstPtr inst)
 }
 
 void
-Reset::invoke(ThreadContext *tc, StaticInstPtr inst)
+Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     if (FullSystem) {
-        tc->getCpuPtr()->clearInterrupts();
+        tc->getCpuPtr()->clearInterrupts(tc->threadId());
         tc->clearArchRegs();
     }
     if (!ArmSystem::highestELIs64(tc)) {
@@ -706,7 +707,7 @@ Reset::invoke(ThreadContext *tc, StaticInstPtr inst)
 }
 
 void
-UndefinedInstruction::invoke(ThreadContext *tc, StaticInstPtr inst)
+UndefinedInstruction::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     if (FullSystem) {
         ArmFault::invoke(tc, inst);
@@ -767,7 +768,7 @@ UndefinedInstruction::iss() const
 }
 
 void
-SupervisorCall::invoke(ThreadContext *tc, StaticInstPtr inst)
+SupervisorCall::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     if (FullSystem) {
         ArmFault::invoke(tc, inst);
@@ -783,7 +784,8 @@ SupervisorCall::invoke(ThreadContext *tc, StaticInstPtr inst)
         callNum = tc->readIntReg(INTREG_X8);
     else
         callNum = tc->readIntReg(INTREG_R7);
-    tc->syscall(callNum);
+    Fault fault;
+    tc->syscall(callNum, &fault);
 
     // Advance the PC since that won't happen automatically.
     PCState pc = tc->pcState();
@@ -842,6 +844,12 @@ HypervisorCall::HypervisorCall(ExtMachInst _machInst, uint32_t _imm) :
         ArmFaultVals<HypervisorCall>(_machInst, _imm)
 {}
 
+ExceptionClass
+HypervisorCall::ec(ThreadContext *tc) const
+{
+    return from64 ? EC_HVC_64 : vals.ec;
+}
+
 ExceptionClass
 HypervisorTrap::ec(ThreadContext *tc) const
 {
@@ -884,7 +892,7 @@ ArmFaultVals<T>::offset(ThreadContext *tc)
 // }
 
 void
-SecureMonitorCall::invoke(ThreadContext *tc, StaticInstPtr inst)
+SecureMonitorCall::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     if (FullSystem) {
         ArmFault::invoke(tc, inst);
@@ -913,7 +921,7 @@ SecureMonitorTrap::ec(ThreadContext *tc) const
 
 template<class T>
 void
-AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst)
+AbortFault<T>::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     if (tranMethod == ArmFault::UnknownTran) {
         tranMethod = longDescFormatInUse(tc) ? ArmFault::LpaeTran
@@ -938,7 +946,7 @@ AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst)
     }
 
     if (source == ArmFault::AsynchronousExternalAbort) {
-        tc->getCpuPtr()->clearInterrupt(INT_ABT, 0);
+        tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
     }
     // Get effective fault source encoding
     CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
@@ -948,7 +956,7 @@ AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst)
     // try to set hsr etc. and are based upon source!
     ArmFaultVals<T>::invoke(tc, inst);
 
-    if (cpsr.width) {  // AArch32
+    if (!this->to64) {  // AArch32
         if (cpsr.mode == MODE_HYP) {
             tc->setMiscReg(T::HFarIndex, faultAddr);
         } else if (stage2) {
@@ -963,7 +971,17 @@ AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst)
     } else {  // AArch64
         // Set the FAR register.  Nothing else to do if we are in AArch64 state
         // because the syndrome register has already been set inside invoke64()
-        tc->setMiscReg(AbortFault<T>::getFaultAddrReg64(), faultAddr);
+        if (stage2) {
+            // stage 2 fault, set HPFAR_EL2 to the faulting IPA
+            // and FAR_EL2 to the Original VA
+            tc->setMiscReg(AbortFault<T>::getFaultAddrReg64(), OVAddr);
+            tc->setMiscReg(MISCREG_HPFAR_EL2, bits(faultAddr, 47, 12) << 4);
+
+            DPRINTF(Faults, "Abort Fault (Stage 2) VA: 0x%x IPA: 0x%x\n",
+                    OVAddr, faultAddr);
+        } else {
+            tc->setMiscReg(AbortFault<T>::getFaultAddrReg64(), faultAddr);
+        }
     }
 }
 
@@ -1110,7 +1128,7 @@ PrefetchAbort::routeToHyp(ThreadContext *tc) const
     toHyp |= (stage2 ||
                 ( (source ==               DebugEvent) && hdcr.tde && (cpsr.mode !=  MODE_HYP)) ||
                 ( (source == SynchronousExternalAbort) && hcr.tge  && (cpsr.mode == MODE_USER))
-             ) && !inSecureState(scr, cpsr);
+             ) && !inSecureState(tc);
     return toHyp;
 }
 
@@ -1120,8 +1138,8 @@ DataAbort::ec(ThreadContext *tc) const
     if (to64) {
         // AArch64
         if (source == ArmFault::AsynchronousExternalAbort) {
-            panic("Asynchronous External Abort should be handled with \
-                    SystemErrors (SErrors)!");
+            panic("Asynchronous External Abort should be handled with "
+                    "SystemErrors (SErrors)!");
         }
         if (toEL == fromEL)
             return EC_DATA_ABORT_CURR_EL;
@@ -1176,7 +1194,7 @@ DataAbort::routeToHyp(ThreadContext *tc) const
                   ((source == AlignmentFault)            ||
                    (source == SynchronousExternalAbort))
                 )
-             ) && !inSecureState(scr, cpsr);
+             ) && !inSecureState(tc);
     return toHyp;
 }
 
@@ -1237,7 +1255,7 @@ DataAbort::annotate(AnnotationIDs id, uint64_t val)
 }
 
 void
-VirtualDataAbort::invoke(ThreadContext *tc, StaticInstPtr inst)
+VirtualDataAbort::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     AbortFault<VirtualDataAbort>::invoke(tc, inst);
     HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR);
@@ -1266,7 +1284,7 @@ Interrupt::routeToHyp(ThreadContext *tc) const
     HCR  hcr  = tc->readMiscRegNoEffect(MISCREG_HCR);
     CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
     // Determine whether IRQs are routed to Hyp mode.
-    toHyp = (!scr.irq && hcr.imo && !inSecureState(scr, cpsr)) ||
+    toHyp = (!scr.irq && hcr.imo && !inSecureState(tc)) ||
             (cpsr.mode == MODE_HYP);
     return toHyp;
 }
@@ -1305,7 +1323,7 @@ FastInterrupt::routeToHyp(ThreadContext *tc) const
     HCR  hcr  = tc->readMiscRegNoEffect(MISCREG_HCR);
     CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
     // Determine whether IRQs are routed to Hyp mode.
-    toHyp = (!scr.fiq && hcr.fmo && !inSecureState(scr, cpsr)) ||
+    toHyp = (!scr.fiq && hcr.fmo && !inSecureState(tc)) ||
             (cpsr.mode == MODE_HYP);
     return toHyp;
 }
@@ -1336,7 +1354,7 @@ VirtualFastInterrupt::VirtualFastInterrupt()
 {}
 
 void
-PCAlignmentFault::invoke(ThreadContext *tc, StaticInstPtr inst)
+PCAlignmentFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     ArmFaultVals<PCAlignmentFault>::invoke(tc, inst);
     assert(from64);
@@ -1351,9 +1369,9 @@ SystemError::SystemError()
 {}
 
 void
-SystemError::invoke(ThreadContext *tc, StaticInstPtr inst)
+SystemError::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
-    tc->getCpuPtr()->clearInterrupt(INT_ABT, 0);
+    tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
     ArmFault::invoke(tc, inst);
 }
 
@@ -1374,15 +1392,14 @@ SystemError::routeToHyp(ThreadContext *tc) const
 
     SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3);
     HCR hcr  = tc->readMiscRegNoEffect(MISCREG_HCR);
-    CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR);
 
-    toHyp = (!scr.ea && hcr.amo && !inSecureState(scr, cpsr)) ||
-            (!scr.ea && !scr.rw && !hcr.amo && !inSecureState(scr,cpsr));
+    toHyp = (!scr.ea && hcr.amo && !inSecureState(tc)) ||
+            (!scr.ea && !scr.rw && !hcr.amo && !inSecureState(tc));
     return toHyp;
 }
 
 void
-FlushPipe::invoke(ThreadContext *tc, StaticInstPtr inst) {
+FlushPipe::invoke(ThreadContext *tc, const StaticInstPtr &inst) {
     DPRINTF(Faults, "Invoking FlushPipe Fault\n");
 
     // Set the PC to the next instruction of the faulting instruction.
@@ -1395,7 +1412,7 @@ FlushPipe::invoke(ThreadContext *tc, StaticInstPtr inst) {
 }
 
 void
-ArmSev::invoke(ThreadContext *tc, StaticInstPtr inst) {
+ArmSev::invoke(ThreadContext *tc, const StaticInstPtr &inst) {
     DPRINTF(Faults, "Invoking ArmSev Fault\n");
     if (!FullSystem)
         return;
@@ -1404,7 +1421,7 @@ ArmSev::invoke(ThreadContext *tc, StaticInstPtr inst) {
     // SEV execution and let pipeline continue as pcState is still
     // valid.
     tc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
-    tc->getCpuPtr()->clearInterrupt(INT_SEV, 0);
+    tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_SEV, 0);
 }
 
 // Instantiate all the templates to make the linker happy