Added code to avoid most interrupt/trap cycles.

PiperOrigin-RevId: 716757966
Change-Id: I4ef6b8ee0fe03a230ebe76fa065ba6073322733c
diff --git a/cheriot/cheriot_state.cc b/cheriot/cheriot_state.cc
index cbbdc22..6caa2c0 100644
--- a/cheriot/cheriot_state.cc
+++ b/cheriot/cheriot_state.cc
@@ -49,6 +49,7 @@
 namespace cheriot {
 
 using EC = ::mpact::sim::riscv::ExceptionCode;
+using PB = ::mpact::sim::cheriot::CheriotRegister::PermissionBits;
 using ::mpact::sim::generic::operator*;  // NOLINT: used below (clang error).
 using ::mpact::sim::riscv::IsaExtension;
 using ::mpact::sim::riscv::RiscVCounterCsr;
@@ -683,6 +684,38 @@
   interrupt_info_list_.push_back(info);
 
   counter_interrupts_taken_.Increment(1);
+  // Check that executing the interrupt handler will not cause an interrupt. If
+  // it will, we need to halt instead. Also, verify that we are not trapping
+  // from the first instruction of the trap handler itself.
+  if ((epc == trap_target) || !pcc_->tag() ||
+      !pcc_->HasPermission(PB::kPermitExecute) ||
+      !pcc_->IsInBounds(trap_target, 4)) {
+    if (epc == trap_target) {
+      std::string trap_list;
+      int i = 0;
+      for (auto &info : interrupt_info_list_) {
+        absl::StrAppend(&trap_list, "    [", i++,
+                        "]: ", info.is_interrupt ? "Interrupt" : "Trap",
+                        " was taken", " at 0x",
+                        absl::Hex(info.epc, absl::kZeroPad8), " cause: 0x",
+                        absl::Hex(info.cause), " tval: 0x",
+                        absl::Hex(info.tval, absl::kZeroPad8), "\n");
+      }
+      LOG(FATAL) << absl::StrCat("Recursive trap at 0x", absl::Hex(epc), "\n",
+                                 trap_list, "\n");
+    } else {
+      LOG(FATAL) << absl::StrCat(
+          info.is_interrupt ? "Interrupt" : "Trap", " handler execution at 0x",
+          absl::Hex(trap_target),
+          " will cause an interrupt due to mtcc "
+          "value/tag/permissions/bounds violation!\n"
+          "mtcc: ",
+          pcc()->AsString(), "\n", "    ",
+          info.is_interrupt ? "Interrupt" : "Trap", " was taken at 0x",
+          absl::Hex(epc), " cause: 0x", absl::Hex(info.cause), " tval: 0x",
+          absl::Hex(info.tval), "\n");
+    }
+  }
 }
 
 // Called upon returning from an interrupt or exception.
diff --git a/cheriot/cheriot_top.cc b/cheriot/cheriot_top.cc
index f74fc76..798ccfe 100644
--- a/cheriot/cheriot_top.cc
+++ b/cheriot/cheriot_top.cc
@@ -210,16 +210,8 @@
 bool CheriotTop::ExecuteInstruction(Instruction *inst) {
   // Check that pcc has tag set.
   if (!pcc_->tag()) {
-    if (state_->mtcc()->tag()) {
-      state_->HandleCheriRegException(inst, inst->address(),
-                                      EC::kCapExTagViolation, pcc_);
-      return true;
-    }
-    // If the mtcc tag is not set, then we would get an infinite loop of
-    // exceptions. Better to exit.
-    LOG(ERROR) << absl::StrCat("Infinite exception loop detected at ",
-                               absl::Hex(inst->address()), " - halting");
-    RequestHalt(HaltReason::kSimulatorError, inst);
+    state_->HandleCheriRegException(inst, inst->address(),
+                                    EC::kCapExTagViolation, pcc_);
     return true;
   }
   // Check that pcc has execute permission.