Allows setting a core version from command line and renode properties.
The version is specified as an integer, with 100 = 1.00, 150 = 1.50, etc.
Behavior of jal/jalr are changed for core versions greater than 100 (default).
In higher versions, when the destination register is not "ra", then an
unsealed return capability is returned as opposed to a sealed one.
PiperOrigin-RevId: 702487323
Change-Id: I856b7bcf0b1fb6da694486d6de8d0dde41de7029
diff --git a/cheriot/BUILD b/cheriot/BUILD
index 365d1c2..b574d8d 100644
--- a/cheriot/BUILD
+++ b/cheriot/BUILD
@@ -47,6 +47,11 @@
values = {"cpu": "aarch64"},
)
+config_setting(
+ name = "darwin_aarch64_cpu",
+ values = {"cpu": "darwin_arm64"},
+)
+
mpact_isa_decoder(
name = "riscv_cheriot_isa",
src = "riscv_cheriot.isa",
@@ -266,12 +271,16 @@
"riscv_cheriot_vector_reduction_instructions.h",
"riscv_cheriot_vector_unary_instructions.h",
],
- copts = [
- "-O3",
- "-ffp-model=strict",
- ] + select({
- "darwin_arm64_cpu": [],
- "//conditions:default": ["-fprotect-parens"],
+ copts = select({
+ "darwin_aarch64_cpu": [
+ "-O3",
+ "-ffp-model=strict",
+ ],
+ "//conditions:default": [
+ "-O3",
+ "-ffp-model=strict",
+ "-fprotect-parens",
+ ],
}),
deps = [
":cheriot_state",
@@ -304,12 +313,16 @@
"riscv_cheriot_vector_fp_reduction_instructions.h",
"riscv_cheriot_vector_fp_unary_instructions.h",
],
- copts = [
- "-O3",
- "-ffp-model=strict",
- ] + select({
- "darwin_arm64_cpu": [],
- "//conditions:default": ["-fprotect-parens"],
+ copts = select({
+ "darwin_aarch64_cpu": [
+ "-O3",
+ "-ffp-model=strict",
+ ],
+ "//conditions:default": [
+ "-O3",
+ "-ffp-model=strict",
+ "-fprotect-parens",
+ ],
}),
deps = [
":cheriot_state",
diff --git a/cheriot/cheriot_register.cc b/cheriot/cheriot_register.cc
index d964e33..9ab85ef 100644
--- a/cheriot/cheriot_register.cc
+++ b/cheriot/cheriot_register.cc
@@ -315,11 +315,11 @@
if (is_null_ || !tag()) return false;
if (HasPermission(kPermitExecute)) {
- return (object_type() == kSentry) ||
- (object_type() == kInterruptEnablingSentry) ||
- (object_type() == kInterruptDisablingSentry) ||
- (object_type() == kInterruptEnablingReturnSentry) ||
- (object_type() == kInterruptDisablingReturnSentry) ||
+ return (object_type() == kInterruptInheritingSentry) ||
+ (object_type() == kInterruptEnablingForwardSentry) ||
+ (object_type() == kInterruptDisablingForwardSentry) ||
+ (object_type() == kInterruptEnablingBackwardSentry) ||
+ (object_type() == kInterruptDisablingBackwardSentry) ||
(object_type() == kSealedExecutable6) ||
(object_type() == kSealedExecutable7);
} else {
@@ -357,11 +357,11 @@
if (status.ok()) {
if (HasPermission(PermissionBits::kPermitExecute)) {
switch (obj_type) {
- case kSentry:
- case kInterruptEnablingSentry:
- case kInterruptDisablingSentry:
- case kInterruptEnablingReturnSentry:
- case kInterruptDisablingReturnSentry:
+ case kInterruptInheritingSentry:
+ case kInterruptEnablingForwardSentry:
+ case kInterruptDisablingForwardSentry:
+ case kInterruptEnablingBackwardSentry:
+ case kInterruptDisablingBackwardSentry:
case kSealedExecutable6:
case kSealedExecutable7:
// The sealing type is ok.
@@ -433,13 +433,13 @@
}
bool CheriotRegister::IsSentry() const {
- return !is_null_ && (object_type() >= kSentry) &&
- (object_type() <= kInterruptEnablingReturnSentry);
+ return !is_null_ && (object_type() >= kInterruptInheritingSentry) &&
+ (object_type() <= kInterruptEnablingBackwardSentry);
}
bool CheriotRegister::IsBackwardSentry() const {
- return !is_null_ && ((object_type() == kInterruptEnablingReturnSentry) ||
- (object_type() == kInterruptDisablingReturnSentry));
+ return !is_null_ && ((object_type() == kInterruptEnablingBackwardSentry) ||
+ (object_type() == kInterruptDisablingBackwardSentry));
}
void CheriotRegister::CopyFrom(const CheriotRegister &other) {
diff --git a/cheriot/cheriot_register.h b/cheriot/cheriot_register.h
index c62ddbb..647b58c 100644
--- a/cheriot/cheriot_register.h
+++ b/cheriot/cheriot_register.h
@@ -69,11 +69,11 @@
// Special object types.
enum ObjectType : uint32_t {
kUnsealed = 0,
- kSentry = 1,
- kInterruptDisablingSentry = 2,
- kInterruptEnablingSentry = 3,
- kInterruptDisablingReturnSentry = 4,
- kInterruptEnablingReturnSentry = 5,
+ kInterruptInheritingSentry = 1,
+ kInterruptDisablingForwardSentry = 2,
+ kInterruptEnablingForwardSentry = 3,
+ kInterruptDisablingBackwardSentry = 4,
+ kInterruptEnablingBackwardSentry = 5,
kSealedExecutable6 = 6,
kSealedExecutable7 = 7,
kReserved8 = 8,
diff --git a/cheriot/cheriot_renode.cc b/cheriot/cheriot_renode.cc
index 4ab981b..5269cf7 100644
--- a/cheriot/cheriot_renode.cc
+++ b/cheriot/cheriot_renode.cc
@@ -109,6 +109,8 @@
constexpr std::string_view kBaseName = "Mpact.Cheriot";
constexpr std::string_view kRvvName = "Mpact.CheriotRvv";
constexpr std::string_view kRvvFpName = "Mpact.CheriotRvvFp";
+// Core version.
+constexpr std::string_view kCoreVersion = "coreVersion";
CheriotRenode::CheriotRenode(std::string name, MemoryInterface *renode_sysbus)
: name_(name), renode_sysbus_(renode_sysbus) {}
@@ -151,7 +153,7 @@
std::fstream proto_file(proto_file_name.c_str(), std::ios_base::out);
std::string serialized;
if (!proto_file.good() || !google::protobuf::TextFormat::PrintToString(
- *component_proto.get(), &serialized)) {
+ *component_proto, &serialized)) {
LOG(ERROR) << "Failed to write proto to file";
} else {
proto_file << serialized;
@@ -388,6 +390,8 @@
do_inst_profile = value != 0;
} else if (name == kMemProfile) {
mem_profiler_->set_is_enabled(value != 0);
+ } else if (name == kCoreVersion) {
+ cheriot_state_->set_core_version(value);
} else {
LOG(ERROR) << "Unknown config name: " << name << " "
<< config_values[i];
diff --git a/cheriot/cheriot_state.h b/cheriot/cheriot_state.h
index 6045039..2b082b9 100644
--- a/cheriot/cheriot_state.h
+++ b/cheriot/cheriot_state.h
@@ -169,6 +169,7 @@
class CheriotState : public generic::ArchState {
public:
+ static constexpr int kVersion0Dot5 = 50;
static int constexpr kCapRegQueueSizeMask = 0x11;
static constexpr uint32_t kCheriExceptionCode = 0x1c;
static constexpr char kCregPrefix[] = "c";
@@ -323,6 +324,9 @@
bool MustRevoke(uint32_t address) const;
// Accessors.
+ // Core version.
+ int core_version() const { return core_version_; }
+ void set_core_version(int version) { core_version_ = version; }
// Returns true if an interrupt is available for the core to take or false
// otherwise.
inline bool is_interrupt_available() const { return is_interrupt_available_; }
@@ -431,6 +435,9 @@
private:
InterruptCode PickInterrupt(uint32_t interrupts);
+ // Core version. Expressed as an integer where as version * 100. Thus
+ // version 1.0 is 100, and 1.5 is 150. Default is 0.5 (or 50).
+ int core_version_ = kVersion0Dot5;
// A map from register name to entry in the mtval register.
absl::flat_hash_map<std::string, uint32_t> cap_index_map_;
// These are root capabilities
diff --git a/cheriot/mpact_cheriot.cc b/cheriot/mpact_cheriot.cc
index ced488d..ef14699 100644
--- a/cheriot/mpact_cheriot.cc
+++ b/cheriot/mpact_cheriot.cc
@@ -81,6 +81,8 @@
using ::mpact::sim::util::InstructionProfiler;
using ::mpact::sim::util::TaggedMemoryUseProfiler;
+// Flat to specify core version.
+ABSL_FLAG(int, core_version, 100, "Core version");
// Flags for specifying interactive mode.
ABSL_FLAG(bool, i, false, "Interactive mode");
ABSL_FLAG(bool, interactive, false, "Interactive mode");
@@ -278,6 +280,7 @@
}
CheriotState cheriot_state("CherIoT", data_memory,
static_cast<AtomicMemoryOpInterface *>(router));
+ cheriot_state.set_core_version(absl::GetFlag(FLAGS_core_version));
DecoderInterface *decoder = nullptr;
if (absl::GetFlag(FLAGS_rvv_fp)) {
@@ -604,7 +607,7 @@
std::fstream proto_file(proto_file_name.c_str(), std::ios_base::out);
std::string serialized;
if (!proto_file.good() || !google::protobuf::TextFormat::PrintToString(
- *component_proto.get(), &serialized)) {
+ *component_proto, &serialized)) {
LOG(ERROR) << "Failed to write proto to file";
} else {
proto_file << serialized;
diff --git a/cheriot/riscv_cheriot.bin_fmt b/cheriot/riscv_cheriot.bin_fmt
index 0d2cdf2..9a9fdf2 100644
--- a/cheriot/riscv_cheriot.bin_fmt
+++ b/cheriot/riscv_cheriot.bin_fmt
@@ -225,7 +225,8 @@
cheriot_gettype : R2Type : func7 == 0x7f, func5 == 0x01, func3 == 0, opcode == 0x5b;
cheriot_incaddr : RType : func7 == 0x11, func3 == 0, opcode == 0x5b;
cheriot_incaddrimm : IType : func3 == 0x1, opcode == 0x5b;
- cheriot_jal : JType : rd != 0, opcode == 0x6f;
+ cheriot_jal : JType : rd > 1, opcode == 0x6f;
+ cheriot_jal_cra : JType : rd == 1, opcode == 0x6f;
cheriot_j : JType : rd == 0, opcode == 0x6f;
// For jalr and jr, need to differentiate when the destination (jalr) or the
// source (jr) designates the cra register.
@@ -487,7 +488,7 @@
cswsp : CSS: func3 == 0b110, op == 0b10;
cscsp : CSS: func3 == 0b111, op == 0b10;
cheriot_cj : CJ : func3 == 0b101, op == 0b01;
- cheriot_cjal : CJ : func3 == 0b001, op == 0b01;
+ cheriot_cjal_cra : CJ : func3 == 0b001, op == 0b01;
cheriot_cjr : CR : func4 == 0b1000, rs1 > 1, rs2 == 0, op == 0b10;
cheriot_cjr_cra : CR : func4 == 0b1000, rs1 == 1, rs2 == 0, op == 0b10;
cheriot_cjalr_cra : CR : func4 == 0b1001, rs1 != 0, rs2 == 0, op == 0b10;
diff --git a/cheriot/riscv_cheriot.isa b/cheriot/riscv_cheriot.isa
index 3dbf475..1af2abe 100644
--- a/cheriot/riscv_cheriot.isa
+++ b/cheriot/riscv_cheriot.isa
@@ -205,6 +205,9 @@
cheriot_incaddrimm{: cs1, I_imm12 : cd},
disasm: "cincoffset", "%cd, %cs1, 0x%(I_imm12:08x)",
semfunc: "&CheriotCIncAddr";
+ cheriot_jal_cra{: J_imm20 : cd},
+ disasm: "cjal", "%cd, 0x%(J_imm20:08x)",
+ semfunc: "&CheriotCJalCra";
cheriot_jal{: J_imm20 : cd},
disasm: "cjal", "%cd, 0x%(J_imm20:08x)",
semfunc: "&CheriotCJal";
@@ -522,6 +525,9 @@
cheriot_cjal{: I_cj_imm11, x0 : x1},
disasm: "c.jal", "%(@+I_cj_imm11:08x)",
semfunc: "&CheriotCJal";
+ cheriot_cjal_cra{: I_cj_imm11, x0 : x1},
+ disasm: "c.jal", "%(@+I_cj_imm11:08x)",
+ semfunc: "&CheriotCJalCra";
cheriot_cjr{: crs1, x0 :},
disasm: "c.jr", "%crs1",
semfunc: "&CheriotCJr";
diff --git a/cheriot/riscv_cheriot_instructions.cc b/cheriot/riscv_cheriot_instructions.cc
index 1bf26e0..06d20a1 100644
--- a/cheriot/riscv_cheriot_instructions.cc
+++ b/cheriot/riscv_cheriot_instructions.cc
@@ -200,9 +200,31 @@
cd->CopyFrom(*pcc);
cd->set_address(instruction->address() + instruction->size());
bool interrupt_enable = state->mstatus()->mie();
+ if (state->core_version() == CheriotState::kVersion0Dot5) {
+ (void)cd->Seal(*state->sealing_root(),
+ interrupt_enable
+ ? CapReg::kInterruptEnablingBackwardSentry
+ : CapReg::kInterruptDisablingBackwardSentry);
+ }
+ // Update pcc.
+ pcc->set_address(new_pc);
+ state->set_branch(true);
+}
+
+void CheriotCJalCra(const Instruction *instruction) {
+ auto *state = static_cast<CheriotState *>(instruction->state());
+ auto offset = generic::GetInstructionSource<uint32_t>(instruction, 0);
+ uint64_t new_pc = offset + instruction->address();
+ auto *pcc = state->pcc();
+ if (!CheriotCJChecks(instruction, new_pc, pcc)) return;
+ // Update link register.
+ auto *cd = GetCapDest(instruction, 0);
+ cd->CopyFrom(*pcc);
+ cd->set_address(instruction->address() + instruction->size());
+ bool interrupt_enable = state->mstatus()->mie();
(void)cd->Seal(*state->sealing_root(),
- interrupt_enable ? CapReg::kInterruptEnablingReturnSentry
- : CapReg::kInterruptDisablingReturnSentry);
+ interrupt_enable ? CapReg::kInterruptEnablingBackwardSentry
+ : CapReg::kInterruptDisablingBackwardSentry);
// Update pcc.
pcc->set_address(new_pc);
state->set_branch(true);
@@ -233,11 +255,12 @@
ok |= !has_dest && uses_ra && cs1->IsBackwardSentry();
ok |= !has_dest && !uses_ra &&
((cs1->object_type() == CapReg::kUnsealed) ||
- (cs1->object_type() == CapReg::kSentry));
- ok |= has_dest && ((cs1->object_type() == CapReg::kUnsealed) ||
- (cs1->object_type() == CapReg::kSentry));
+ (cs1->object_type() == CapReg::kInterruptInheritingSentry));
+ ok |=
+ has_dest && ((cs1->object_type() == CapReg::kUnsealed) ||
+ (cs1->object_type() == CapReg::kInterruptInheritingSentry));
ok |= has_dest && uses_ra && (cs1->object_type() >= CapReg::kUnsealed) &&
- (cs1->object_type() <= CapReg::kInterruptEnablingSentry);
+ (cs1->object_type() <= CapReg::kInterruptEnablingForwardSentry);
if ((cs1->IsSealed() && offset != 0) || !ok) {
state->HandleCheriRegException(instruction, instruction->address(),
EC::kCapExSealViolation, cs1);
@@ -275,23 +298,25 @@
state->temp_reg()->set_address(instruction->address() +
instruction->size());
bool interrupt_enable = (mstatus->GetUint32() & 0b1000) != 0;
- auto status = state->temp_reg()->Seal(
- *state->sealing_root(), interrupt_enable
- ? CapReg::kInterruptEnablingReturnSentry
- : CapReg::kInterruptDisablingReturnSentry);
- if (!status.ok()) {
- LOG(ERROR) << "Failed to seal: " << status;
- return;
+ if ((state->core_version() == CheriotState::kVersion0Dot5) || uses_ra) {
+ auto status = state->temp_reg()->Seal(
+ *state->sealing_root(),
+ interrupt_enable ? CapReg::kInterruptEnablingBackwardSentry
+ : CapReg::kInterruptDisablingBackwardSentry);
+ if (!status.ok()) {
+ LOG(ERROR) << "Failed to seal: " << status;
+ return;
+ }
}
}
// Update pcc.
pcc->CopyFrom(*cs1);
// If the new pcc is a sentry, unseal and set/clear mie accordingly.
if (pcc->IsSentry()) {
- if (pcc->object_type() != CapReg::kSentry) {
+ if (pcc->object_type() != CapReg::kInterruptInheritingSentry) {
bool interrupt_enable =
- (pcc->object_type() == CapReg::kInterruptEnablingSentry) ||
- (pcc->object_type() == CapReg::kInterruptEnablingReturnSentry);
+ (pcc->object_type() == CapReg::kInterruptEnablingForwardSentry) ||
+ (pcc->object_type() == CapReg::kInterruptEnablingBackwardSentry);
mstatus->set_mie(interrupt_enable);
mstatus->Submit();
}
@@ -490,9 +515,9 @@
uint32_t object_type = cs2->address();
bool permitted_otype = false;
switch (object_type) {
- case CapReg::kSentry:
- case CapReg::kInterruptDisablingSentry:
- case CapReg::kInterruptEnablingSentry:
+ case CapReg::kInterruptInheritingSentry:
+ case CapReg::kInterruptDisablingForwardSentry:
+ case CapReg::kInterruptEnablingForwardSentry:
case CapReg::kSealedExecutable6:
case CapReg::kSealedExecutable7:
permitted_otype = cs1->HasPermission(CapReg::kPermitExecute);
diff --git a/cheriot/riscv_cheriot_instructions.h b/cheriot/riscv_cheriot_instructions.h
index ec59f87..8988908 100644
--- a/cheriot/riscv_cheriot_instructions.h
+++ b/cheriot/riscv_cheriot_instructions.h
@@ -72,6 +72,7 @@
// This instruction takes 1 source (an offset), and one destination (the link
// capability). The pcc is implied.
void CheriotCJal(const Instruction *instruction);
+void CheriotCJalCra(const Instruction *instruction);
// This instruction takes 1 source (an offset). The pcc is implied.
void CheriotCJ(const Instruction *instruction);
// This instruction takes 2 sources and one destination operand. Source 0 is the
diff --git a/cheriot/test/BUILD b/cheriot/test/BUILD
index 3616d1d..42440bb 100644
--- a/cheriot/test/BUILD
+++ b/cheriot/test/BUILD
@@ -21,6 +21,11 @@
values = {"cpu": "darwin_arm64"},
)
+config_setting(
+ name = "darwin_aarch64_cpu",
+ values = {"cpu": "darwin_arm64"},
+)
+
cc_test(
name = "cheriot_register_test",
size = "small",
@@ -413,11 +418,12 @@
srcs = [
"riscv_cheriot_vector_fp_unary_instructions_test.cc",
],
- copts = [
- "-ffp-model=strict",
- ] + select({
- "darwin_arm64_cpu": [],
- "//conditions:default": ["-fprotect-parens"],
+ copts = select({
+ "darwin_aarch64_cpu": ["-ffp-model=strict"],
+ "//conditions:default": [
+ "-ffp-model=strict",
+ "-fprotect-parens",
+ ],
}),
deps = [
":riscv_cheriot_vector_fp_test_utilities",
@@ -443,11 +449,12 @@
srcs = [
"riscv_cheriot_vector_fp_instructions_test.cc",
],
- copts = [
- "-ffp-model=strict",
- ] + select({
- "darwin_arm64_cpu": [],
- "//conditions:default": ["-fprotect-parens"],
+ copts = select({
+ "darwin_aarch64_cpu": ["-ffp-model=strict"],
+ "//conditions:default": [
+ "-ffp-model=strict",
+ "-fprotect-parens",
+ ],
}),
deps = [
":riscv_cheriot_vector_fp_test_utilities",
@@ -473,11 +480,12 @@
srcs = [
"riscv_cheriot_vector_fp_compare_instructions_test.cc",
],
- copts = [
- "-ffp-model=strict",
- ] + select({
- "darwin_arm64_cpu": [],
- "//conditions:default": ["-fprotect-parens"],
+ copts = select({
+ "darwin_aarch64_cpu": ["-ffp-model=strict"],
+ "//conditions:default": [
+ "-ffp-model=strict",
+ "-fprotect-parens",
+ ],
}),
deps = [
":riscv_cheriot_vector_fp_test_utilities",
@@ -500,11 +508,12 @@
srcs = [
"riscv_cheriot_vector_fp_reduction_instructions_test.cc",
],
- copts = [
- "-ffp-model=strict",
- ] + select({
- "darwin_arm64_cpu": [],
- "//conditions:default": ["-fprotect-parens"],
+ copts = select({
+ "darwin_aarch64_cpu": ["-ffp-model=strict"],
+ "//conditions:default": [
+ "-ffp-model=strict",
+ "-fprotect-parens",
+ ],
}),
deps = [
":riscv_cheriot_vector_fp_test_utilities",
diff --git a/cheriot/test/cheriot_register_test.cc b/cheriot/test/cheriot_register_test.cc
index 2753ffd..262dd30 100644
--- a/cheriot/test/cheriot_register_test.cc
+++ b/cheriot/test/cheriot_register_test.cc
@@ -346,11 +346,11 @@
cap_reg()->ResetExecuteRoot();
auto status = cap_reg()->Seal(*seal_cap_reg, i);
// If the object type is out of range for data, expect failure.
- if ((i == ObjectType::kSentry) ||
- (i == ObjectType::kInterruptDisablingSentry) ||
- (i == ObjectType::kInterruptEnablingSentry) ||
- (i == ObjectType::kInterruptDisablingReturnSentry) ||
- (i == ObjectType::kInterruptEnablingReturnSentry) ||
+ if ((i == ObjectType::kInterruptInheritingSentry) ||
+ (i == ObjectType::kInterruptDisablingForwardSentry) ||
+ (i == ObjectType::kInterruptEnablingForwardSentry) ||
+ (i == ObjectType::kInterruptDisablingBackwardSentry) ||
+ (i == ObjectType::kInterruptEnablingBackwardSentry) ||
(i == ObjectType::kSealedExecutable6) ||
(i == ObjectType::kSealedExecutable7)) {
EXPECT_TRUE(status.ok()) << status.message();
@@ -373,7 +373,9 @@
// Try with a sealing root with cleared tag.
seal_cap_reg->ResetSealingRoot();
seal_cap_reg->Invalidate();
- EXPECT_FALSE(cap_reg()->Seal(*seal_cap_reg, ObjectType::kSentry).ok());
+ EXPECT_FALSE(cap_reg()
+ ->Seal(*seal_cap_reg, ObjectType::kInterruptInheritingSentry)
+ .ok());
cap_reg()->ResetExecuteRoot();
seal_cap_reg->ResetSealingRoot();
// Seal the sealing capability. This should succeed.
@@ -388,7 +390,8 @@
seal_cap_reg->ResetSealingRoot();
seal_cap_reg->ClearPermissions(PermissionBits::kPermitSeal);
cap_reg()->ResetExecuteRoot();
- status = cap_reg()->Seal(*seal_cap_reg, ObjectType::kSentry);
+ status =
+ cap_reg()->Seal(*seal_cap_reg, ObjectType::kInterruptInheritingSentry);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), absl::StatusCode::kPermissionDenied);
EXPECT_THAT(status.message(),
@@ -396,15 +399,18 @@
// Try sealing a null capability.
seal_cap_reg->ResetSealingRoot();
cap_reg()->ResetNull();
- status = cap_reg()->Seal(*seal_cap_reg, ObjectType::kSentry);
+ status =
+ cap_reg()->Seal(*seal_cap_reg, ObjectType::kInterruptInheritingSentry);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(status.message(),
testing::HasSubstr("Target is not a valid capability"));
// Try sealing twice.
cap_reg()->ResetExecuteRoot();
- CHECK_OK(cap_reg()->Seal(*seal_cap_reg, ObjectType::kSentry));
- status = cap_reg()->Seal(*seal_cap_reg, ObjectType::kSentry);
+ CHECK_OK(
+ cap_reg()->Seal(*seal_cap_reg, ObjectType::kInterruptInheritingSentry));
+ status =
+ cap_reg()->Seal(*seal_cap_reg, ObjectType::kInterruptInheritingSentry);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(status.message(),
diff --git a/cheriot/test/riscv_cheriot_encoding_test.cc b/cheriot/test/riscv_cheriot_encoding_test.cc
index 4cc6346..8b58730 100644
--- a/cheriot/test/riscv_cheriot_encoding_test.cc
+++ b/cheriot/test/riscv_cheriot_encoding_test.cc
@@ -158,7 +158,7 @@
constexpr uint32_t kCsd = 0b111'000'000'00'000'00;
// constexpr uint32_t kCdsd = 0b101'000'000'00'000'00;
constexpr uint32_t kCheriotCj = 0b101'00000000000'01;
-constexpr uint32_t kCheriotCjal = 0b001'00000000000'01;
+constexpr uint32_t kCheriotCjalCra = 0b001'00000000000'01;
constexpr uint32_t kCheriotCjr = 0b100'0'00000'00000'10;
constexpr uint32_t kCheriotCjalr = 0b100'1'00000'00000'10;
constexpr uint32_t kCbeqz = 0b110'000'000'00000'01;
@@ -206,6 +206,7 @@
};
constexpr int kRdValue = 1;
+constexpr int kNonRaValue = 2;
static uint32_t SetRd(uint32_t iword, uint32_t rdval) {
return (iword | ((rdval & 0x1f) << 7));
@@ -248,6 +249,9 @@
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kLui);
enc_->ParseInstruction(SetRd(kCheriotJal, kRdValue));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
+ OpcodeEnum::kCheriotJalCra);
+ enc_->ParseInstruction(SetRd(kCheriotJal, kNonRaValue));
+ EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
OpcodeEnum::kCheriotJal);
enc_->ParseInstruction(SetRd(kCheriotJalr, kRdValue));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
@@ -445,9 +449,9 @@
enc_->ParseInstruction(kCheriotCj);
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
OpcodeEnum::kCheriotCj);
- enc_->ParseInstruction(kCheriotCjal);
+ enc_->ParseInstruction(kCheriotCjalCra);
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kCheriotCjal);
+ OpcodeEnum::kCheriotCjalCra);
enc_->ParseInstruction(Set16Rd(kCheriotCjr, 1));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
OpcodeEnum::kCheriotCjrCra);
@@ -543,6 +547,9 @@
OpcodeEnum::kCheriotIncaddrimm);
enc_->ParseInstruction(SetRd(kCheriotJal, kRdValue));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
+ OpcodeEnum::kCheriotJalCra);
+ enc_->ParseInstruction(SetRd(kCheriotJal, kNonRaValue));
+ EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
OpcodeEnum::kCheriotJal);
enc_->ParseInstruction(SetRd(kCheriotJalr, kRdValue));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
diff --git a/cheriot/test/riscv_cheriot_instructions_test.cc b/cheriot/test/riscv_cheriot_instructions_test.cc
index 0173b83..3271a58 100644
--- a/cheriot/test/riscv_cheriot_instructions_test.cc
+++ b/cheriot/test/riscv_cheriot_instructions_test.cc
@@ -64,6 +64,8 @@
using ::mpact::sim::cheriot::CheriotCGetType;
using ::mpact::sim::cheriot::CheriotCIncAddr;
using ::mpact::sim::cheriot::CheriotCJal;
+using ::mpact::sim::cheriot::CheriotCJalCra;
+using ::mpact::sim::cheriot::CheriotCJalr;
using ::mpact::sim::cheriot::CheriotCJalrCra;
using ::mpact::sim::cheriot::CheriotCLc;
using ::mpact::sim::cheriot::CheriotCLcChild;
@@ -98,6 +100,8 @@
constexpr int kDataSeal10 = 10;
constexpr int kInstSizeNormal = 4;
+constexpr int kVersion1Dot0 = 100;
+
// Test fixture.
class RiscVCheriotInstructionsTest : public ::testing::Test {
protected:
@@ -544,8 +548,8 @@
}
// Jump and link - no traps.
-TEST_F(RiscVCheriotInstructionsTest, CJal) {
- inst()->set_semantic_function(&CheriotCJal);
+TEST_F(RiscVCheriotInstructionsTest, CJalCra) {
+ inst()->set_semantic_function(&CheriotCJalCra);
AppendCapabilityOperands(inst(), {kC1}, {kC3});
state()->pcc()->set_address(inst()->address());
c1_reg()->set_address(0x200);
@@ -558,7 +562,7 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(c3_reg()->tag());
EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptEnablingReturnSentry);
+ EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptEnablingBackwardSentry);
EXPECT_TRUE(state()->pcc()->tag());
// Set interrupt enable to false.
state()->mstatus()->set_mie(0);
@@ -570,13 +574,13 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(c3_reg()->tag());
EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptDisablingReturnSentry);
+ EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptDisablingBackwardSentry);
EXPECT_TRUE(state()->pcc()->tag());
}
// Jump and link - out of bounds error.
-TEST_F(RiscVCheriotInstructionsTest, CJalOutOfBounds) {
- inst()->set_semantic_function(&CheriotCJal);
+TEST_F(RiscVCheriotInstructionsTest, CJalCraOutOfBounds) {
+ inst()->set_semantic_function(&CheriotCJalCra);
AppendCapabilityOperands(inst(), {kC1}, {kC3});
state()->pcc()->set_address(inst()->address());
c1_reg()->set_address(0x200);
@@ -590,8 +594,8 @@
// Jump and link - misaligned (jumping to 2 byte aligned address with no
// compact instructions).
-TEST_F(RiscVCheriotInstructionsTest, CJalMisaligned) {
- inst()->set_semantic_function(&CheriotCJal);
+TEST_F(RiscVCheriotInstructionsTest, CJalCraMisaligned) {
+ inst()->set_semantic_function(&CheriotCJalCra);
AppendCapabilityOperands(inst(), {kC1}, {kC3});
state()->pcc()->set_address(inst()->address());
state()->misa()->Set(state()->misa()->AsUint64() & ~*ISA::kCompressed);
@@ -608,8 +612,67 @@
EXPECT_EQ(inst(), trap_inst());
}
+// Jump and link - rd != ra.
+TEST_F(RiscVCheriotInstructionsTest, CJalNonCra) {
+ inst()->set_semantic_function(&CheriotCJal);
+ AppendCapabilityOperands(inst(), {kC1}, {kC3});
+ state()->pcc()->set_address(inst()->address());
+ c1_reg()->set_address(0x200);
+ // Set interrupt enable to true.
+ state()->mstatus()->set_mie(1);
+ state()->mstatus()->Submit();
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(c3_reg()->tag());
+ EXPECT_TRUE(c3_reg()->IsSentry());
+ EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptEnablingBackwardSentry);
+ EXPECT_TRUE(state()->pcc()->tag());
+
+ // Set interrupt enable to false.
+ state()->mstatus()->set_mie(0);
+ state()->mstatus()->Submit();
+ state()->pcc()->set_address(inst()->address());
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(c3_reg()->tag());
+ EXPECT_TRUE(c3_reg()->IsSentry());
+ EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptDisablingBackwardSentry);
+ EXPECT_TRUE(state()->pcc()->tag());
+
+ // Now set core version to 1.0 - this behavior should return an unsealed
+ // capability.
+ state()->set_core_version(kVersion1Dot0);
+ // Set interrupt enable to true.
+ state()->mstatus()->set_mie(1);
+ state()->mstatus()->Submit();
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(c3_reg()->tag());
+ EXPECT_FALSE(c3_reg()->IsSentry());
+ EXPECT_EQ(c3_reg()->object_type(), OT::kUnsealed);
+ EXPECT_TRUE(state()->pcc()->tag());
+
+ // Set interrupt enable to false.
+ state()->mstatus()->set_mie(0);
+ state()->mstatus()->Submit();
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(c3_reg()->tag());
+ EXPECT_FALSE(c3_reg()->IsSentry());
+ EXPECT_EQ(c3_reg()->object_type(), OT::kUnsealed);
+ EXPECT_TRUE(state()->pcc()->tag());
+}
+
// Jump and link register (capability) indirect - no traps, unsealed source.
-TEST_F(RiscVCheriotInstructionsTest, CJalr) {
+TEST_F(RiscVCheriotInstructionsTest, CJalrCra) {
inst()->set_semantic_function(&CheriotCJalrCra);
AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
@@ -628,7 +691,7 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(cra_reg()->tag());
EXPECT_TRUE(cra_reg()->IsSentry());
- EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptEnablingReturnSentry);
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptEnablingBackwardSentry);
EXPECT_TRUE(state()->pcc()->tag());
// Set interrupt enable to false.
state()->mstatus()->set_mie(0);
@@ -640,12 +703,77 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(cra_reg()->tag());
EXPECT_TRUE(cra_reg()->IsSentry());
- EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptDisablingReturnSentry);
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptDisablingBackwardSentry);
+ EXPECT_TRUE(state()->pcc()->tag());
+}
+
+// Jump and link register (capability) indirect - no traps, unsealed source.
+// Non cra register used for destination.
+TEST_F(RiscVCheriotInstructionsTest, CJalr) {
+ inst()->set_semantic_function(&CheriotCJalr);
+ AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
+ state()->pcc()->set_address(inst()->address());
+ // Set up the destination capability.
+ c1_reg()->ResetExecuteRoot();
+ c1_reg()->set_address(kInstAddress + 0x100);
+ c1_reg()->SetBounds(kInstAddress, 0x400);
+ // Set offset.
+ c2_reg()->set_address(0x100);
+ // Set interrupt enable to true.
+ state()->mstatus()->set_mie(1);
+ state()->mstatus()->Submit();
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_TRUE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptEnablingBackwardSentry);
+ EXPECT_TRUE(state()->pcc()->tag());
+ // Set interrupt enable to false.
+ state()->mstatus()->set_mie(0);
+ state()->mstatus()->Submit();
+ state()->pcc()->set_address(inst()->address());
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_TRUE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptDisablingBackwardSentry);
+ EXPECT_TRUE(state()->pcc()->tag());
+
+ // Set core version to 1.0 - this behavior should return an unsealed
+ // capability.
+ state()->set_core_version(kVersion1Dot0);
+
+ // Set interrupt enable to true.
+ state()->mstatus()->set_mie(1);
+ state()->mstatus()->Submit();
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_FALSE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kUnsealed);
+ EXPECT_TRUE(state()->pcc()->tag());
+ // Set interrupt enable to false.
+ state()->mstatus()->set_mie(0);
+ state()->mstatus()->Submit();
+ state()->pcc()->set_address(inst()->address());
+ inst()->Execute(nullptr);
+ EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
+ << " value: " << trap_value();
+ EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_FALSE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kUnsealed);
EXPECT_TRUE(state()->pcc()->tag());
}
// Jump and link register (capability) indirect - no traps, sentry.
-TEST_F(RiscVCheriotInstructionsTest, CJalrSentry) {
+TEST_F(RiscVCheriotInstructionsTest, CJalrCraSentry) {
inst()->set_semantic_function(&CheriotCJalrCra);
AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
@@ -654,7 +782,7 @@
c1_reg()->set_address(kInstAddress + 0x200);
c1_reg()->SetBounds(kInstAddress, 0x400);
(void)c1_reg()->Seal(*(state()->sealing_root()),
- OT::kInterruptEnablingSentry);
+ OT::kInterruptEnablingForwardSentry);
// Set offset to zero (because c1_reg is sealed).
c2_reg()->set_address(0);
// Set interrupt enable to false.
@@ -667,14 +795,14 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(cra_reg()->tag());
EXPECT_TRUE(cra_reg()->IsSentry());
- EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptDisablingReturnSentry);
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptDisablingBackwardSentry);
EXPECT_TRUE(state()->pcc()->tag());
// Set up the destination capability.
c1_reg()->ResetExecuteRoot();
c1_reg()->SetBounds(kInstAddress, 0x400);
c1_reg()->set_address(kInstAddress + 0x200);
(void)c1_reg()->Seal(*(state()->sealing_root()),
- OT::kInterruptDisablingSentry);
+ OT::kInterruptDisablingForwardSentry);
// Set interrupt enable to true.
state()->mstatus()->set_mie(1);
state()->mstatus()->Submit();
@@ -686,12 +814,12 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(cra_reg()->tag());
EXPECT_TRUE(cra_reg()->IsSentry());
- EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptEnablingReturnSentry);
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptEnablingBackwardSentry);
EXPECT_TRUE(state()->pcc()->tag());
}
// Verify an unset tag generates a tag violation exception.
-TEST_F(RiscVCheriotInstructionsTest, CJalrTagViolation) {
+TEST_F(RiscVCheriotInstructionsTest, CJalrCraTagViolation) {
inst()->set_semantic_function(&CheriotCJalrCra);
AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
@@ -718,7 +846,7 @@
// For a jalr with a sentry, the immediate has to be zero or it will cause
// an exception. Make sure the exception happens.
-TEST_F(RiscVCheriotInstructionsTest, CJalrSentryNonZeroImmediate) {
+TEST_F(RiscVCheriotInstructionsTest, CJalrCraSentryNonZeroImmediate) {
inst()->set_semantic_function(&CheriotCJalrCra);
AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
@@ -727,7 +855,7 @@
c1_reg()->set_address(kInstAddress + 0x200);
c1_reg()->SetBounds(kInstAddress, 0x400);
(void)c1_reg()->Seal(*(state()->sealing_root()),
- OT::kInterruptEnablingSentry);
+ OT::kInterruptEnablingForwardSentry);
// Set offset to non-zero - should cause an exception.
c2_reg()->set_address(0x100);
inst()->Execute(nullptr);
@@ -745,7 +873,7 @@
// If the source capability does not have execute permission, there should
// be an exception.
-TEST_F(RiscVCheriotInstructionsTest, CJalrExecuteViolation) {
+TEST_F(RiscVCheriotInstructionsTest, CJalrCraExecuteViolation) {
inst()->set_semantic_function(&CheriotCJalrCra);
AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
@@ -773,7 +901,7 @@
// If the architecture does not have compact instructions, then misaligned
// access on two byte boundary should cause an exception.
-TEST_F(RiscVCheriotInstructionsTest, CJalrAlignmentViolation) {
+TEST_F(RiscVCheriotInstructionsTest, CJalrCraAlignmentViolation) {
inst()->set_semantic_function(&CheriotCJalrCra);
AppendCapabilityOperands(inst(), {kC1, kC2}, {kC3});
state()->pcc()->set_address(inst()->address());
@@ -1228,7 +1356,7 @@
c1_reg()->set_address(kMemAddress);
c2_reg()->set_address(0x200);
c3_reg()->ResetExecuteRoot();
- c3_reg()->set_object_type(CheriotRegister::kInterruptDisablingReturnSentry);
+ c3_reg()->set_object_type(CheriotRegister::kInterruptDisablingBackwardSentry);
c3_reg()->ClearPermissions(PB::kPermitGlobal);
EXPECT_TRUE(c3_reg()->IsBackwardSentry());
inst()->Execute(nullptr);
@@ -1245,7 +1373,7 @@
// Now with global flag on the stored capability.
c3_reg()->ResetExecuteRoot();
- c3_reg()->set_object_type(CheriotRegister::kInterruptDisablingReturnSentry);
+ c3_reg()->set_object_type(CheriotRegister::kInterruptDisablingBackwardSentry);
EXPECT_TRUE(c3_reg()->IsBackwardSentry());
inst()->Execute(nullptr);
EXPECT_FALSE(trap_taken());
@@ -1321,8 +1449,9 @@
inst()->Execute(nullptr);
EXPECT_EQ(c3_reg()->object_type(), o_type & 0b111);
// For executable object types the tag should be true.
- if ((o_type == OT::kSentry) || (o_type == OT::kInterruptDisablingSentry) ||
- (o_type == OT::kInterruptEnablingSentry) ||
+ if ((o_type == OT::kInterruptInheritingSentry) ||
+ (o_type == OT::kInterruptDisablingForwardSentry) ||
+ (o_type == OT::kInterruptEnablingForwardSentry) ||
(o_type == OT::kSealedExecutable6) ||
(o_type == OT::kSealedExecutable7)) {
EXPECT_TRUE(c3_reg()->tag());