| // 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 |
| // |
| // http://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 MPACT_CHERIOT_CHERIOT_IBEX_HW_REVOKER_H_ |
| #define MPACT_CHERIOT_CHERIOT_IBEX_HW_REVOKER_H_ |
| |
| #include <cstdint> |
| |
| #include "cheriot/cheriot_register.h" |
| #include "mpact/sim/generic/counters_base.h" |
| #include "mpact/sim/generic/data_buffer.h" |
| #include "mpact/sim/generic/instruction.h" |
| #include "mpact/sim/generic/ref_count.h" |
| #include "mpact/sim/util/memory/memory_interface.h" |
| #include "mpact/sim/util/memory/tagged_memory_interface.h" |
| #include "riscv//riscv_plic.h" |
| |
| // This file contains the class declaration for the model of the Ibex HW |
| // revoker for Cheriot. The HW revoker is a module that is used to invalidate |
| // (or revoke the validity of) capabilities pointing to a freed portion of heap |
| // memory. It is controlled by a set of memory mapped registers. |
| // |
| // The HW revoker is implemented as a counter value set object. It is bound |
| // to a counter that is incremented whenever an instruction is executed, and, |
| // when active, performs an action every 'period' number of increments |
| // (configurable). |
| // |
| // The HW revoker is programmed using a memory interface. It supports non-vector |
| // loads and stores only. |
| // |
| // The HW revoker is described in more detail in the following documents: |
| // https://lowrisc.github.io/sonata-system/doc/ip/revoker.html |
| // https://github.com/microsoft/cheriot-safe/blob/main/src/msft_cheri_subsystem/msftDvIp_mmreg.sv |
| |
| namespace mpact { |
| namespace sim { |
| namespace cheriot { |
| |
| using ::mpact::sim::generic::CounterValueSetInterface; |
| using ::mpact::sim::generic::DataBuffer; |
| using ::mpact::sim::generic::DataBufferFactory; |
| using ::mpact::sim::generic::Instruction; |
| using ::mpact::sim::generic::ReferenceCount; |
| using ::mpact::sim::riscv::RiscVPlic; |
| using ::mpact::sim::riscv::RiscVPlicIrqInterface; |
| using ::mpact::sim::util::MemoryInterface; |
| using ::mpact::sim::util::TaggedMemoryInterface; |
| |
| class CheriotIbexHWRevoker : public CounterValueSetInterface<uint64_t>, |
| public TaggedMemoryInterface { |
| public: |
| static constexpr uint32_t kStartAddressOffset = 0x0000; |
| static constexpr uint32_t kEndAddressOffset = 0x0004; |
| static constexpr uint32_t kGoOffset = 0x0008; |
| static constexpr uint32_t kEpochOffset = 0x000c; |
| static constexpr uint32_t kStatusOffset = 0x0010; |
| static constexpr uint32_t kInterruptEnableOffset = 0x0014; |
| |
| CheriotIbexHWRevoker() = delete; |
| CheriotIbexHWRevoker(const CheriotIbexHWRevoker &) = delete; |
| CheriotIbexHWRevoker &operator=(const CheriotIbexHWRevoker &) = delete; |
| CheriotIbexHWRevoker(RiscVPlicIrqInterface *plic_irq, uint64_t heap_base, |
| uint64_t heap_size, TaggedMemoryInterface *heap_memory, |
| uint64_t revocation_bits_base, |
| MemoryInterface *revocation_memory); |
| CheriotIbexHWRevoker(uint64_t heap_base, uint64_t heap_size, |
| TaggedMemoryInterface *heap_memory, |
| uint64_t revocation_bits_base, |
| MemoryInterface *revocation_memory); |
| ~CheriotIbexHWRevoker(); |
| // Resets the interrupt controller. |
| void Reset(); |
| // CounterValueSetInterface override. This is called when the value of the |
| // bound counter is modified. |
| void SetValue(const uint64_t &val) override; |
| |
| // MemoryInterface overrides. |
| // Non-vector load method. |
| void Load(uint64_t address, DataBuffer *db, DataBuffer *tags, |
| Instruction *inst, ReferenceCount *context) override; |
| void Load(uint64_t address, DataBuffer *db, Instruction *inst, |
| ReferenceCount *context) override; |
| // Vector load method - this is stubbed out. |
| void Load(DataBuffer *address_db, DataBuffer *mask_db, int el_size, |
| DataBuffer *db, Instruction *inst, |
| ReferenceCount *context) override; |
| // Non-vector store method. |
| void Store(uint64_t address, DataBuffer *db, DataBuffer *tags) override; |
| void Store(uint64_t address, DataBuffer *dbs) override; |
| // Vector store method - this is stubbed out. |
| void Store(DataBuffer *address, DataBuffer *mask, int el_size, |
| DataBuffer *db) override; |
| |
| // Getters & setters. |
| void set_plic_irq(RiscVPlicIrqInterface *plic_irq) { plic_irq_ = plic_irq; } |
| int period() const { return period_; } |
| void set_period(int period) { period_ = period; } |
| int cap_count() const { return cap_count_; } |
| void set_cap_count(int cap_count) { cap_count_ = cap_count; } |
| uint64_t revocation_bits_base() const { return revocation_bits_base_; } |
| void set_revocation_bits_base(uint64_t revocation_bits_base) { |
| revocation_bits_base_ = revocation_bits_base; |
| } |
| |
| private: |
| // MMR read/write methods. |
| uint32_t Read(uint32_t offset); |
| void Write(uint32_t offset, uint32_t value); |
| void WriteGo(); |
| // Perform an iteration of revocation. |
| void Revoke(); |
| void ProcessCapability(uint64_t address); |
| bool MustRevoke(uint64_t address); |
| void SetInterrupt(bool value); |
| // The number of times SetValue is called before triggering a revocation |
| // operation. |
| int period_ = 1; |
| // Tracker for the number of times SetValue is called. |
| int num_calls_ = 0; |
| // The max number of capabilities to revoke in a single operation. |
| int cap_count_ = 0; |
| // Current capability index. |
| uint64_t current_cap_ = 0; |
| // Sweep in progress. |
| bool sweep_in_progress_ = false; |
| RiscVPlicIrqInterface *plic_irq_ = nullptr; |
| // Heap range. |
| uint64_t heap_base_ = 0; |
| uint64_t heap_max_ = 0; |
| // Memory interface to use for the tagged heap. |
| TaggedMemoryInterface *heap_memory_ = nullptr; |
| // Memory interface to use for the revocation bits. |
| MemoryInterface *revocation_memory_ = nullptr; |
| // Data buffers. |
| DataBuffer *db_ = nullptr; |
| DataBuffer *tag_db_ = nullptr; |
| // Capability register. |
| CheriotRegister *cap_reg_ = nullptr; |
| // Base address of the revocation bits. |
| uint64_t revocation_bits_base_ = 0; |
| // DB factory. |
| DataBufferFactory db_factory_; |
| |
| // MMRs |
| uint64_t start_address_ = 0; |
| uint64_t end_address_ = 0; |
| uint32_t go_ = 0; |
| uint32_t epoch_ = 0; |
| uint32_t interrupt_enable_ = 0; |
| uint32_t interrupt_status_ = 0; |
| }; |
| |
| } // namespace cheriot |
| } // namespace sim |
| } // namespace mpact |
| |
| #endif // MPACT_CHERIOT_CHERIOT_IBEX_HW_REVOKER_H_ |