blob: fd09220867c8cad8a5cca5c9a7be75a418514db2 [file]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_MPACT_RISCV_RISCV_PMP_H_
#define THIRD_PARTY_MPACT_RISCV_RISCV_PMP_H_
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include "mpact/sim/generic/arch_state.h"
#include "mpact/sim/generic/type_helpers.h"
#include "riscv/riscv_csr.h"
// This file defines the RiscV Physical Memory Protection management class. For
// now, this class only creates the CSRs and does not model the actual PMP
// functionality. In the future, these classes may be extended to model the
// actual PMP functionality.
//
// The CSRs are created internal to the class, and therefore are owned, and
// subsequently destructed by the destructor. This is done so that in the future
// it is easier to replace the CSRs with new PMP specific CSR classes that will
// be able to (re)configure PMP checking upon CSR writes.
namespace mpact::sim::riscv {
using ::mpact::sim::generic::operator*; // NOLINT: used below (clang error).
using ::mpact::sim::generic::ArchState;
enum class PmpCfgBits {
kRead = 1 << 0,
kWrite = 1 << 1,
kExecute = 1 << 2,
kAtomic = 3 << 3,
kNone = 3 << 5,
kLock = 1 << 8,
};
class RiscVPmp {
public:
explicit RiscVPmp(ArchState* state) : state_(state) {}
RiscVPmp(const RiscVPmp&) = delete;
RiscVPmp& operator=(const RiscVPmp&) = delete;
template <typename T, typename E>
void CreatePmpCsrs(RiscVCsrSet* csr_set);
virtual ~RiscVPmp() {
for (auto* pmp_cfg : pmp_cfg_) delete pmp_cfg;
for (auto* pmp_addr : pmp_addr_) delete pmp_addr;
}
private:
ArchState* state_;
RiscVCsrInterface* pmp_addr_[16];
RiscVCsrInterface* pmp_cfg_[4];
};
template <typename T, typename E>
void RiscVPmp::CreatePmpCsrs(RiscVCsrSet* csr_set) {
// Create the PMP configuration registers. Each configuration register
// contains XLEN/8 configuration entries for a total of 16 configuration
// entries. In the case of XLEN=64, there are only two configuration registers
// pmp_cfg_[0] and pmp_cfg_[2].
pmp_cfg_[0] = new RiscVSimpleCsr<T>("pmpcfg0", *E::kPmpCfg0, state_);
pmp_cfg_[1] = sizeof(T) == 8
? nullptr
: new RiscVSimpleCsr<T>("pmpcfg1", *E::kPmpCfg1, state_);
pmp_cfg_[2] = new RiscVSimpleCsr<T>("pmpcfg2", *E::kPmpCfg2, state_);
pmp_cfg_[3] = sizeof(T) == 8
? nullptr
: new RiscVSimpleCsr<T>("pmpcfg3", *E::kPmpCfg3, state_);
for (auto* pmp_cfg : pmp_cfg_) {
if (pmp_cfg == nullptr) continue;
auto status = csr_set->AddCsr(pmp_cfg);
if (!status.ok()) {
LOG(ERROR) << absl::StrCat("Failed to add PMP configuration register: '",
pmp_cfg->name(), "': ", status.message());
}
}
// Create the 16 PMP address registers.
pmp_addr_[0] = new RiscVSimpleCsr<T>("pmpaddr0", *E::kPmpAddr0, state_);
pmp_addr_[1] = new RiscVSimpleCsr<T>("pmpaddr1", *E::kPmpAddr1, state_);
pmp_addr_[2] = new RiscVSimpleCsr<T>("pmpaddr2", *E::kPmpAddr2, state_);
pmp_addr_[3] = new RiscVSimpleCsr<T>("pmpaddr3", *E::kPmpAddr3, state_);
pmp_addr_[4] = new RiscVSimpleCsr<T>("pmpaddr4", *E::kPmpAddr4, state_);
pmp_addr_[5] = new RiscVSimpleCsr<T>("pmpaddr5", *E::kPmpAddr5, state_);
pmp_addr_[6] = new RiscVSimpleCsr<T>("pmpaddr6", *E::kPmpAddr6, state_);
pmp_addr_[7] = new RiscVSimpleCsr<T>("pmpaddr7", *E::kPmpAddr7, state_);
pmp_addr_[8] = new RiscVSimpleCsr<T>("pmpaddr8", *E::kPmpAddr8, state_);
pmp_addr_[9] = new RiscVSimpleCsr<T>("pmpaddr9", *E::kPmpAddr9, state_);
pmp_addr_[10] = new RiscVSimpleCsr<T>("pmpaddr10", *E::kPmpAddr10, state_);
pmp_addr_[11] = new RiscVSimpleCsr<T>("pmpaddr11", *E::kPmpAddr11, state_);
pmp_addr_[12] = new RiscVSimpleCsr<T>("pmpaddr12", *E::kPmpAddr12, state_);
pmp_addr_[13] = new RiscVSimpleCsr<T>("pmpaddr13", *E::kPmpAddr13, state_);
pmp_addr_[14] = new RiscVSimpleCsr<T>("pmpaddr14", *E::kPmpAddr14, state_);
pmp_addr_[15] = new RiscVSimpleCsr<T>("pmpaddr15", *E::kPmpAddr15, state_);
for (auto* pmp_addr : pmp_addr_) {
auto status = csr_set->AddCsr(pmp_addr);
if (!status.ok()) {
LOG(ERROR) << absl::StrCat("Failed to add PMP address register: '",
pmp_addr->name(), "': ", status.message());
}
}
}
} // namespace mpact::sim::riscv
#endif // THIRD_PARTY_MPACT_RISCV_RISCV_PMP_H_