Adds information about exceptions/interrupts to interactive prompt.
Adds capability to break on interrupt and/or exceptions and their returns.
PiperOrigin-RevId: 663036503
Change-Id: Ie3b89c2375808528280c24a8a81f4307945183da
diff --git a/cheriot/BUILD b/cheriot/BUILD
index 8380337..15fce63 100644
--- a/cheriot/BUILD
+++ b/cheriot/BUILD
@@ -543,6 +543,7 @@
"@com_google_absl//absl/container:btree",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/functional:any_invocable",
+ "@com_google_absl//absl/log",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
@@ -550,6 +551,7 @@
"@com_google_mpact-riscv//riscv:stoull_wrapper",
"@com_google_mpact-sim//mpact/sim/generic:core",
"@com_google_mpact-sim//mpact/sim/generic:core_debug_interface",
+ "@com_google_mpact-sim//mpact/sim/generic:counters",
"@com_google_mpact-sim//mpact/sim/generic:debug_command_shell_interface",
"@com_google_mpact-sim//mpact/sim/generic:instruction",
"@com_google_mpact-sim//mpact/sim/generic:type_helpers",
diff --git a/cheriot/cheriot_state.cc b/cheriot/cheriot_state.cc
index 28edaec..e0c194d 100644
--- a/cheriot/cheriot_state.cc
+++ b/cheriot/cheriot_state.cc
@@ -241,7 +241,9 @@
util::AtomicMemoryOpInterface *atomic_memory)
: generic::ArchState(id),
tagged_memory_(memory),
- atomic_tagged_memory_(atomic_memory) {
+ atomic_tagged_memory_(atomic_memory),
+ counter_interrupts_taken_("interrupts_taken", 0),
+ counter_interrupt_returns_("interrupt_returns", 0) {
for (auto &[name, index] : std::vector<std::pair<std::string, unsigned>>{
{"c0", 0b0'00000}, {"c1", 0b0'00001}, {"c2", 0b0'00010},
{"c3", 0b0'00011}, {"c4", 0b0'00100}, {"c5", 0b0'00101},
@@ -258,6 +260,8 @@
{"mepcc", 0b1'11111}}) {
cap_index_map_.emplace(name, index);
}
+ CHECK_OK(AddCounter(&counter_interrupts_taken_));
+ CHECK_OK(AddCounter(&counter_interrupt_returns_));
// Create root capabilities and the special capability CSRs.
executable_root_ = new CheriotRegister(this, "executable_root");
executable_root_->ResetExecuteRoot();
@@ -604,8 +608,8 @@
void CheriotState::Trap(bool is_interrupt, uint64_t trap_value,
uint64_t exception_code, uint64_t epc,
const Instruction *inst) {
- // LOG(INFO) << "Trap: " << std::hex << is_interrupt << " " << trap_value << "
- // " << exception_code << " " << epc; Call the handler.
+ // LOG(INFO) << "Trap: " << std::hex << is_interrupt << " " << trap_value
+ // << " " << exception_code << " " << epc; // Call the handler.
if (on_trap_ != nullptr) {
bool res = on_trap_(is_interrupt, trap_value, exception_code, epc, inst);
// If the handler returns true, the trap has been handled. Just return.
@@ -651,6 +655,7 @@
set_branch(true);
// TODO(torerik): set next pc
mstatus_->Submit();
+ counter_interrupts_taken_.Increment(1);
}
// CheckForInterrupt is called whenever any relevant bits in the interrupt
@@ -682,7 +687,6 @@
Trap(/*is_interrupt*/ true, 0, *available_interrupt_code_, epc, nullptr);
// Clear pending interrupt.
is_interrupt_available_ = false;
- ++interrupt_handler_depth_;
available_interrupt_code_ = InterruptCode::kNone;
}
diff --git a/cheriot/cheriot_state.h b/cheriot/cheriot_state.h
index c736f71..b24f5e3 100644
--- a/cheriot/cheriot_state.h
+++ b/cheriot/cheriot_state.h
@@ -30,6 +30,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "mpact/sim/generic/arch_state.h"
+#include "mpact/sim/generic/counters.h"
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/generic/instruction.h"
#include "mpact/sim/generic/operand_interface.h"
@@ -60,6 +61,7 @@
using ::mpact::sim::generic::DataBuffer;
using ::mpact::sim::generic::Instruction;
using ::mpact::sim::generic::ReferenceCount;
+using ::mpact::sim::generic::SimpleCounter;
using ::mpact::sim::riscv::InterruptCode;
using ::mpact::sim::riscv::IsaExtension;
using ::mpact::sim::riscv::PrivilegeMode;
@@ -288,11 +290,23 @@
// Indicates that the program has returned from handling an interrupt. This
// decrements the interrupt handler depth and should be called by the
// implementations of mret, sret, and uret.
- void SignalReturnFromInterrupt() { --interrupt_handler_depth_; }
+ void SignalReturnFromInterrupt() { counter_interrupt_returns_.Increment(1); }
// Returns the depth of the interrupt handler currently being executed, or
// zero if no interrupt handler is being executed.
- int InterruptHandlerDepth() const { return interrupt_handler_depth_; }
+ int InterruptHandlerDepth() const {
+ return counter_interrupts_taken_.GetValue() -
+ counter_interrupt_returns_.GetValue();
+ }
+ // Returns the interrupt counters. This allows code to be connected to the
+ // counters when the value changes.
+ SimpleCounter<int64_t> *counter_interrupts_taken() {
+ return &counter_interrupts_taken_;
+ }
+
+ SimpleCounter<int64_t> *counter_interrupt_returns() {
+ return &counter_interrupt_returns_;
+ }
// Returns true if a capability register with the given base should be
// revoked.
@@ -434,7 +448,8 @@
CheriotVectorState *rv_vector_ = nullptr;
// For interrupt handling.
bool is_interrupt_available_ = false;
- int interrupt_handler_depth_ = 0;
+ SimpleCounter<int64_t> counter_interrupts_taken_;
+ SimpleCounter<int64_t> counter_interrupt_returns_;
InterruptCode available_interrupt_code_ = InterruptCode::kNone;
// By default, execute in machine mode.
PrivilegeMode privilege_mode_ = PrivilegeMode::kMachine;
diff --git a/cheriot/cheriot_top.cc b/cheriot/cheriot_top.cc
index 47002d3..14d1cbf 100644
--- a/cheriot/cheriot_top.cc
+++ b/cheriot/cheriot_top.cc
@@ -73,6 +73,7 @@
counter_pc_("pc", 0),
cap_reg_re_{
R"((\w+)\.(top|base|length|tag|permissions|object_type|reserved))"} {
+ CHECK_OK(AddChildComponent(*state_));
Initialize();
}
diff --git a/cheriot/debug_command_shell.cc b/cheriot/debug_command_shell.cc
index 43537b4..f174d56 100644
--- a/cheriot/debug_command_shell.cc
+++ b/cheriot/debug_command_shell.cc
@@ -17,6 +17,7 @@
#include <cstdint>
#include <cstring>
#include <fstream>
+#include <functional>
#include <istream>
#include <ostream>
#include <string>
@@ -24,6 +25,7 @@
#include <vector>
#include "absl/functional/any_invocable.h"
+#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
@@ -51,6 +53,59 @@
using HaltReason = ::mpact::sim::generic::CoreDebugInterface::HaltReason;
using ::mpact::sim::generic::operator*; // NOLINT: used below (clang error).
+DebugCommandShell::InterruptListener::InterruptListener(CoreAccess *core_access)
+ : core_access_(core_access),
+ top_(static_cast<CheriotTop *>(core_access->debug_interface)),
+ taken_listener_(std::bind_front(&InterruptListener::SetTakenValue, this)),
+ return_listener_(
+ std::bind_front(&InterruptListener::SetReturnValue, this)) {
+ top_->state()->counter_interrupts_taken()->AddListener(&taken_listener_);
+ top_->state()->counter_interrupt_returns()->AddListener(&return_listener_);
+}
+
+void DebugCommandShell::InterruptListener::SetReturnValue(int64_t value) {
+ if (interrupt_info_list_.empty()) {
+ LOG(ERROR) << "Interrupt stack is empty";
+ return;
+ }
+ auto info = interrupt_info_list_.front();
+ interrupt_info_list_.pop_front();
+ // If breakpoints are enabled, then request a halt of the appropriate type.
+ if (info.is_interrupt && interrupts_enabled_)
+ top_->RequestHalt(kInterruptReturn, nullptr);
+ if (!info.is_interrupt && exceptions_enabled_)
+ top_->RequestHalt(kExceptionReturn, nullptr);
+}
+
+void DebugCommandShell::InterruptListener::SetTakenValue(int64_t value) {
+ InterruptInfo info;
+ bool ok = true;
+ // Read the values of the interrupt registers.
+ auto res = core_access_->debug_interface->ReadRegister("mcause");
+ ok &= res.ok();
+ if (ok) info.cause = res.value();
+
+ res = core_access_->debug_interface->ReadRegister("mtval");
+ ok &= res.ok();
+ if (ok) info.tval = res.value();
+
+ res = core_access_->debug_interface->ReadRegister("mepcc");
+ ok &= res.ok();
+ if (ok) info.epc = res.value();
+
+ if (!ok) {
+ LOG(ERROR) << "Failed to read interrupt registers";
+ return;
+ }
+ info.is_interrupt = (info.cause & 0x8000'0000u) != 0;
+ // If breakpoints are enabled, the request a halt of the appropriate type.
+ if (info.is_interrupt && interrupts_enabled_)
+ top_->RequestHalt(kInterruptTaken, nullptr);
+ if (!info.is_interrupt && exceptions_enabled_)
+ top_->RequestHalt(kExceptionTaken, nullptr);
+ interrupt_info_list_.push_front(info);
+}
+
// The constructor initializes all the regular expressions and the help string.
DebugCommandShell::DebugCommandShell()
: quit_re_{R"(\s*quit\s*)"},
@@ -123,6 +178,9 @@
according to FORMAT. Default format is x32.
break [set] VALUE - set breakpoint at address VALUE.
break [set] SYMBOL - set breakpoint at value of SYMBOL.
+ '$exception' and '$interrupt are special
+ symbols to break upon entry to and return
+ from exception/interrupt handlers.
break set #<N> - reactivate breakpoint index N.
break #<N> - reactivate breakpoint index N.
break clear VALUE - clear breakpoint at address VALUE.
@@ -175,8 +233,15 @@
reg_vector_.push_back("mscratchc");
}
+DebugCommandShell::~DebugCommandShell() {
+ for (auto *listener : interrupt_listeners_) {
+ delete listener;
+ }
+}
+
void DebugCommandShell::AddCore(const CoreAccess &core_access) {
core_access_.push_back(core_access);
+ interrupt_listeners_.push_back(new InterruptListener(&core_access_.back()));
core_action_point_id_.push_back(0);
core_action_point_info_.emplace_back();
}
@@ -218,6 +283,19 @@
case *HaltReason::kDataWatchPoint:
absl::StrAppend(&prompt, "Stopped at data watchpoint\n");
break;
+ case InterruptListener::kInterruptTaken:
+ absl::StrAppend(&prompt, "Stopped at taken interrupt\n");
+ break;
+ case InterruptListener::kInterruptReturn:
+ absl::StrAppend(&prompt,
+ "Stopped at return from interrupt handler\n");
+ break;
+ case InterruptListener::kExceptionTaken:
+ absl::StrAppend(&prompt, "Stopped at exception\n");
+ break;
+ case InterruptListener::kExceptionReturn:
+ absl::StrAppend(&prompt, "Stopped at return exception handler\n");
+ break;
case *HaltReason::kProgramDone:
absl::StrAppend(&prompt, "Program done\n");
break;
@@ -252,6 +330,16 @@
}
absl::StrAppend(&prompt, "\n");
}
+ auto &info_list =
+ interrupt_listeners_[current_core_]->interrupt_info_list();
+ int count = 0;
+ for (auto iter = info_list.rbegin(); iter != info_list.rend(); ++iter) {
+ auto const &info = *iter;
+ absl::StrAppend(&prompt, "[", count++, "] ",
+ info.is_interrupt ? "interrupt" : "exception", " ",
+ info.is_interrupt ? GetInterruptDescription(info)
+ : GetExceptionDescription(info));
+ }
absl::StrAppend(&prompt, "[", current_core_, "] > ");
while (!command_streams_.empty()) {
auto ¤t_is = *command_streams_.back();
@@ -455,16 +543,31 @@
// break set VALUE | SYMBOL
if (std::string str_value;
- RE2::FullMatch(line_view, *set_break_re_, &str_value)) {
+ RE2::FullMatch(line_view, *set_break_re_, &str_value) ||
+ RE2::FullMatch(line_view, *set_break2_re_, &str_value)) {
if (str_value == "$branch") {
auto *cheriot_interface = reinterpret_cast<CheriotDebugInterface *>(
core_access_[current_core_].debug_interface);
cheriot_interface->SetBreakOnControlFlowChange(true);
continue;
+ } else if (str_value == "$exception") {
+ if (interrupt_listeners_[current_core_]->AreExceptionsEnabled()) {
+ os << "Break on exceptions are already enabled\n";
+ continue;
+ }
+ interrupt_listeners_[current_core_]->SetEnableExceptions(true);
+ continue;
+ } else if (str_value == "$interrupt") {
+ if (interrupt_listeners_[current_core_]->AreInterruptsEnabled()) {
+ os << "Break on interrupts are already enabled\n";
+ continue;
+ }
+ interrupt_listeners_[current_core_]->SetEnableInterrupts(true);
+ continue;
}
auto result = GetValueFromString(current_core_, str_value, /*radix=*/0);
if (!result.ok()) {
- os << absl::StrCat("Error: '", str_value, "' ",
+ os << absl::StrCat("Error: ?????? '", str_value, "' ",
result.status().message())
<< std::endl;
os.flush();
@@ -538,6 +641,8 @@
if (!status.ok()) {
os << absl::StrCat("Error: ", status.message(), "\n");
}
+ } else {
+ os << absl::StrCat("No such active breakpoint: #", index, "\n");
}
continue;
}
@@ -566,6 +671,20 @@
core_access_[current_core_].debug_interface);
cheriot_interface->SetBreakOnControlFlowChange(false);
continue;
+ } else if (str_value == "$exception") {
+ if (!interrupt_listeners_[current_core_]->AreExceptionsEnabled()) {
+ os << "Break on exceptions are already disabled\n";
+ continue;
+ }
+ interrupt_listeners_[current_core_]->SetEnableExceptions(false);
+ continue;
+ } else if (str_value == "$interrupt") {
+ if (!interrupt_listeners_[current_core_]->AreInterruptsEnabled()) {
+ os << "Break on interrupts are already disabled\n";
+ continue;
+ }
+ interrupt_listeners_[current_core_]->SetEnableInterrupts(false);
+ continue;
}
auto result = GetValueFromString(current_core_, str_value, /*radix=*/0);
if (!result.ok()) {
@@ -632,40 +751,6 @@
continue;
}
- // break SYMBOL | VALUE
- if (std::string str_value;
- RE2::FullMatch(line_view, *set_break2_re_, &str_value)) {
- if (str_value == "$branch") {
- auto *cheriot_interface = reinterpret_cast<CheriotDebugInterface *>(
- core_access_[current_core_].debug_interface);
- cheriot_interface->SetBreakOnControlFlowChange(true);
- continue;
- }
- auto result = GetValueFromString(current_core_, str_value, /*radix=*/0);
- if (!result.ok()) {
- os << absl::StrCat("Error: '", str_value, "' ",
- result.status().message())
- << std::endl;
- os.flush();
- continue;
- }
- auto cmd_result =
- core_access_[current_core_].debug_interface->SetSwBreakpoint(
- result.value());
- if (!cmd_result.ok()) {
- os << "Error: " << cmd_result.message() << std::endl;
- os.flush();
- continue;
- }
- core_access_[current_core_]
- .breakpoint_map[core_access_[current_core_].breakpoint_index++] =
- result.value();
- os << absl::StrCat("Breakpoint set at 0x",
- absl::Hex(result.value(), absl::PadSpec::kZeroPad8))
- << std::endl;
- continue;
- }
-
// watch set SYMBOL | VALUE <length> [r|w|rw]
if (std::string str_value, length_value, rw_value; RE2::FullMatch(
line_view, *set_watch_re_, &str_value, &length_value, &rw_value)) {
@@ -1457,11 +1542,9 @@
// inserted and return.
uint64_t bp_address = pcc + inst->size();
inst->DecRef();
- bool bp_set = false;
// See if there is a bp on that address already, if so, don't try to set
// another one.
if (!core_access_[current_core_].debug_interface->HasBreakpoint(bp_address)) {
- bp_set = true;
auto bp_set_res =
core_access_[current_core_].debug_interface->SetSwBreakpoint(
bp_address);
@@ -1684,6 +1767,159 @@
return absl::OkStatus();
}
+std::string DebugCommandShell::GetInterruptDescription(
+ const InterruptInfo &info) {
+ std::string output;
+ if (!info.is_interrupt) return output;
+ switch (info.cause & 0x7fff'ffff) {
+ case 0:
+ absl::StrAppend(&output, "User software interrupt");
+ break;
+ case 1:
+ absl::StrAppend(&output, "Supervisor software interrupt");
+ break;
+ case 3:
+ absl::StrAppend(&output, "Machine software interrupt");
+ break;
+ case 4:
+ absl::StrAppend(&output, "User timer interrupt");
+ break;
+ case 5:
+ absl::StrAppend(&output, "Supervisor timer interrupt");
+ break;
+ case 7:
+ absl::StrAppend(&output, "Machine timer interrupt");
+ break;
+ case 8:
+ absl::StrAppend(&output, "User external interrupt");
+ break;
+ case 9:
+ absl::StrAppend(&output, "Supervisor external interrupt");
+ break;
+ case 11:
+ absl::StrAppend(&output, "Machine external interrupt");
+ break;
+ default:
+ absl::StrAppend(&output, "Error - Unknown interrupt");
+ break;
+ }
+ absl::StrAppend(&output, "\n");
+ return output;
+}
+
+std::string DebugCommandShell::GetExceptionDescription(
+ const InterruptInfo &info) {
+ std::string output;
+ if (info.is_interrupt) return output;
+ absl::StrAppend(&output, " Exception taken at ", absl::Hex(info.epc), ": ");
+ switch (info.cause) {
+ case 0:
+ absl::StrAppend(&output, "Instruction address misaligned: ");
+ absl::StrAppend(&output, ": ", absl::Hex(info.tval));
+ break;
+ case 1:
+ absl::StrAppend(&output, "Instruction access fault");
+ break;
+ case 2:
+ absl::StrAppend(&output, "Illegal instruction");
+ absl::StrAppend(&output, " opcode: ", absl::Hex(info.tval));
+ break;
+ case 3:
+ absl::StrAppend(&output, "Breakpoint instruction");
+ break;
+ case 4:
+ absl::StrAppend(&output, "Load address misaligned");
+ absl::StrAppend(&output, ": ", absl::Hex(info.tval));
+ break;
+ case 5:
+ absl::StrAppend(&output, "Load access fault");
+ break;
+ case 6:
+ absl::StrAppend(&output, "Store/AMO address misaligned");
+ absl::StrAppend(&output, ": ", absl::Hex(info.tval));
+ break;
+ case 7:
+ absl::StrAppend(&output, "Store/AMO access fault");
+ break;
+ case 8:
+ absl::StrAppend(&output, "Environment call from U-mode");
+ break;
+ case 9:
+ absl::StrAppend(&output, "Environment call from S-mode");
+ break;
+ case 11:
+ absl::StrAppend(&output, "Environment call from M-mode");
+ break;
+ case 12:
+ absl::StrAppend(&output, "Instruction page fault");
+ absl::StrAppend(&output, ": ", absl::Hex(info.tval));
+ break;
+ case 13:
+ absl::StrAppend(&output, "Load page fault");
+ absl::StrAppend(&output, ": ", absl::Hex(info.tval));
+ break;
+ case 15:
+ absl::StrAppend(&output, "Store/AMO page fault");
+ absl::StrAppend(&output, ": ", absl::Hex(info.tval));
+ break;
+ case 0x1c: {
+ absl::StrAppend(&output, "CHERI exception");
+ switch (info.tval & 0x1f) {
+ case 0:
+ absl::StrAppend(&output, ": none??");
+ break;
+ case 1:
+ absl::StrAppend(&output, ": bounds violation");
+ break;
+ case 2:
+ absl::StrAppend(&output, ": tag violation");
+ break;
+ case 3:
+ absl::StrAppend(&output, ": seal violation");
+ break;
+ case 0x11:
+ absl::StrAppend(&output, ": PERMIT_EXECUTION violation");
+ break;
+ case 0x12:
+ absl::StrAppend(&output, ": PERMIT_LOAD violation");
+ break;
+ case 0x13:
+ absl::StrAppend(&output, ": PERMIT_STORE violation");
+ break;
+ case 0x15:
+ absl::StrAppend(&output, ": PERMIT_STORE_CAPABILITY violation");
+ break;
+ case 0x18:
+ absl::StrAppend(&output,
+ ": PERMIT_ACCESS_SYSTEM_REGISTERS violation");
+ break;
+ default:
+ absl::StrAppend(&output, ": unknown cause");
+ break;
+ }
+ int cap_indx = (info.tval >> 5) & 0x1f;
+ if (cap_indx < 16)
+ absl::StrAppend(&output, " c", cap_indx);
+ else if (cap_indx == 28)
+ absl::StrAppend(&output, " mtcc");
+ else if (cap_indx == 29)
+ absl::StrAppend(&output, " mtdc");
+ else if (cap_indx == 30)
+ absl::StrAppend(&output, " mscratchc");
+ else if (cap_indx == 31)
+ absl::StrAppend(&output, " mepcc");
+ else
+ absl::StrAppend(&output, " unknown capability");
+ break;
+ }
+ default:
+ absl::StrAppend(&output, "Error - Unknown trap");
+ break;
+ }
+ absl::StrAppend(&output, "\n");
+ return output;
+}
+
} // namespace cheriot
} // namespace sim
} // namespace mpact
diff --git a/cheriot/debug_command_shell.h b/cheriot/debug_command_shell.h
index 0a3b218..71fc7b0 100644
--- a/cheriot/debug_command_shell.h
+++ b/cheriot/debug_command_shell.h
@@ -19,11 +19,11 @@
#include <cstdint>
#include <deque>
-#include <fstream>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
+#include <utility>
#include <vector>
#include "absl/container/btree_map.h"
@@ -32,7 +32,11 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
+#include "cheriot/cheriot_top.h"
+#include "mpact/sim/generic/core_debug_interface.h"
+#include "mpact/sim/generic/counters_base.h"
#include "mpact/sim/generic/debug_command_shell_interface.h"
+#include "mpact/sim/generic/type_helpers.h"
#include "re2/re2.h"
namespace mpact::sim::generic {
@@ -43,14 +47,17 @@
namespace sim {
namespace cheriot {
+using ::mpact::sim::generic::CounterValueSetInterface;
using ::mpact::sim::generic::DebugCommandShellInterface;
+using HaltReason = ::mpact::sim::generic::CoreDebugInterface::HaltReason;
+using ::mpact::sim::generic::operator*; // NOLINT: used below (clang error).
// This class implements an interactive command shell for a set of cores
// simulated by the MPact simulator using the CoreDebugInterface.
class DebugCommandShell : public DebugCommandShellInterface {
public:
- // Default constructor is deleted.
DebugCommandShell();
+ ~DebugCommandShell() override;
// Add core access to the system. All cores must be added before calling Run.
void AddCore(const CoreAccess &core_access) override;
@@ -81,6 +88,67 @@
bool is_enabled;
};
+ // Struct to track interrupt/trap information.
+ struct InterruptInfo {
+ bool is_interrupt;
+ uint32_t cause;
+ uint32_t tval;
+ uint32_t epc;
+ };
+
+ // The interrupt listener class is used to track interrupts/exceptions and
+ // returns from interrupts/exceptions, so that breakpoints can be set on these
+ // events.
+ class InterruptListener {
+ public:
+ // Convenience class to provide listeners to the counters.
+ class Listener : public CounterValueSetInterface<int64_t> {
+ public:
+ explicit Listener(absl::AnyInvocable<void(int64_t)> callback)
+ : callback_(std::move(callback)) {}
+
+ private:
+ void SetValue(const int64_t &value) override { callback_(value); }
+ absl::AnyInvocable<void(int64_t)> callback_;
+ };
+
+ using InterruptInfoList = std::deque<InterruptInfo>;
+ static constexpr uint32_t kInterruptTaken =
+ *HaltReason::kUserSpecifiedMin + 1;
+ static constexpr uint32_t kInterruptReturn =
+ *HaltReason::kUserSpecifiedMin + 2;
+ static constexpr uint32_t kExceptionTaken =
+ *HaltReason::kUserSpecifiedMin + 3;
+ static constexpr uint32_t kExceptionReturn =
+ *HaltReason::kUserSpecifiedMin + 4;
+
+ explicit InterruptListener(CoreAccess *core_access);
+ void SetEnableExceptions(bool value) { exceptions_enabled_ = value; }
+ void SetEnableInterrupts(bool value) { interrupts_enabled_ = value; }
+ bool AreExceptionsEnabled() const { return exceptions_enabled_; }
+ bool AreInterruptsEnabled() const { return interrupts_enabled_; }
+
+ const InterruptInfoList &interrupt_info_list() const {
+ return interrupt_info_list_;
+ }
+
+ private:
+ void SetReturnValue(int64_t value);
+ void SetTakenValue(int64_t value);
+
+ CoreAccess *core_access_;
+ CheriotTop *top_;
+ bool interrupts_enabled_ = false;
+ bool exceptions_enabled_ = false;
+ InterruptInfoList interrupt_info_list_;
+ Listener taken_listener_;
+ Listener return_listener_;
+ };
+
+ // Helper method to get the interrupt description.
+ std::string GetInterruptDescription(const InterruptInfo &info);
+ std::string GetExceptionDescription(const InterruptInfo &info);
+
// Helper method for formatting single data buffer value.
std::string FormatSingleDbValue(generic::DataBuffer *db,
const std::string &format, int width,
@@ -194,6 +262,7 @@
std::deque<std::string> previous_commands_;
std::vector<absl::btree_map<int, ActionPointInfo>> core_action_point_info_;
std::vector<int> core_action_point_id_;
+ std::vector<InterruptListener *> interrupt_listeners_;
};
} // namespace cheriot
diff --git a/cheriot/riscv_cheriot_priv_instructions.cc b/cheriot/riscv_cheriot_priv_instructions.cc
index e729c5d..ee2b29b 100644
--- a/cheriot/riscv_cheriot_priv_instructions.cc
+++ b/cheriot/riscv_cheriot_priv_instructions.cc
@@ -36,8 +36,8 @@
// Set mstatus:mpie to 1.
mstatus->set_mpie(1);
mstatus->set_mpp(*PrivilegeMode::kMachine);
- state->SignalReturnFromInterrupt();
mstatus->Submit();
+ state->SignalReturnFromInterrupt();
}
void RiscVPrivWfi(const Instruction *inst) {