diff --git a/src/Makefile b/src/Makefile
index 5f66b62d7..2e608a827 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -350,7 +350,6 @@ LIBCARTESI_OBJS:= \
htif-factory.o \
shadow-state.o \
shadow-state-factory.o \
- shadow-pmas.o \
shadow-pmas-factory.o \
shadow-tlb.o \
shadow-tlb-factory.o \
diff --git a/src/device-state-access.h b/src/device-state-access.h
index fd810ab91..101cb0d9a 100644
--- a/src/device-state-access.h
+++ b/src/device-state-access.h
@@ -146,14 +146,6 @@ class device_state_access : public i_device_state_access {
bool do_write_memory(uint64_t paddr, const unsigned char *data, uint64_t length) override {
return m_a.write_memory(paddr, data, length);
}
-
- uint64_t do_read_pma_istart(int p) override {
- return m_a.read_pma_istart(p);
- }
-
- uint64_t do_read_pma_ilength(int p) override {
- return m_a.read_pma_ilength(p);
- }
};
} // namespace cartesi
diff --git a/src/find-pma-entry.h b/src/find-pma-entry.h
new file mode 100644
index 000000000..8022421c2
--- /dev/null
+++ b/src/find-pma-entry.h
@@ -0,0 +1,58 @@
+// Copyright Cartesi and individual authors (see AUTHORS)
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with this program (see COPYING). If not, see .
+//
+
+#ifndef FIND_PMA_ENTRY_H
+#define FIND_PMA_ENTRY_H
+
+#include "compiler-defines.h"
+#include
+
+namespace cartesi {
+
+/// \brief Returns PMAs entry where a word falls.
+/// \tparam T uint8_t, uint16_t, uint32_t, or uint64_t.
+/// \tparam STATE_ACCESS Class of machine state accessor object.
+/// \param a Machine state accessor object.
+/// \param paddr Target physical address of word.
+/// \returns PMA entry where word falls, or empty sentinel.
+template
+auto &find_pma_entry(STATE_ACCESS &a, uint64_t paddr) {
+ uint64_t index = 0;
+ while (true) {
+ auto &pma = a.read_pma_entry(index);
+ const auto length = pma.get_length();
+ // The pmas array always contain a sentinel.
+ // It is an entry with zero length.
+ // If we hit it, return it
+ if (unlikely(length == 0)) {
+ return pma;
+ }
+ // Otherwise, if we found an entry where the access fits, return it
+ // Note the "strange" order of arithmetic operations.
+ // This is to ensure there is no overflow.
+ // Since we know paddr >= start, there is no chance of overflow in the first subtraction.
+ // Since length is at least 4096 (an entire page), there is no chance of overflow in the second subtraction.
+ const auto start = pma.get_start();
+ if (paddr >= start && paddr - start <= length - sizeof(T)) {
+ return pma;
+ }
+ ++index;
+ }
+}
+
+} // namespace cartesi
+
+#endif // FIND_PMA_ENTRY_H
diff --git a/src/htif-factory.cpp b/src/htif-factory.cpp
index c48add943..151da7f09 100644
--- a/src/htif-factory.cpp
+++ b/src/htif-factory.cpp
@@ -32,7 +32,7 @@ static bool htif_peek(const pma_entry &pma, const machine & /*m*/, uint64_t page
return (page_offset % PMA_PAGE_SIZE) == 0 && page_offset < pma.get_length();
}
-pma_entry make_htif_pma_entry(uint64_t start, uint64_t length, htif_runtime_config *context) {
+pma_entry make_htif_pma_entry(uint64_t start, uint64_t length) {
const pma_entry::flags f{
true, // R
true, // W
@@ -41,7 +41,7 @@ pma_entry make_htif_pma_entry(uint64_t start, uint64_t length, htif_runtime_conf
false, // IW
PMA_ISTART_DID::HTIF // DID
};
- return make_device_pma_entry("HTIF device", start, length, htif_peek, &htif_driver, context).set_flags(f);
+ return make_device_pma_entry("HTIF device", start, length, htif_peek, &htif_driver).set_flags(f);
}
} // namespace cartesi
diff --git a/src/htif-factory.h b/src/htif-factory.h
index 97dde77c8..9a6807682 100644
--- a/src/htif-factory.h
+++ b/src/htif-factory.h
@@ -25,7 +25,7 @@
namespace cartesi {
/// \brief Creates a PMA entry for the HTIF device
-pma_entry make_htif_pma_entry(uint64_t start, uint64_t length, htif_runtime_config *context);
+pma_entry make_htif_pma_entry(uint64_t start, uint64_t length);
} // namespace cartesi
diff --git a/src/htif.cpp b/src/htif.cpp
index 24358d6d8..d6490a930 100644
--- a/src/htif.cpp
+++ b/src/htif.cpp
@@ -19,7 +19,6 @@
#include "htif.h"
#include "i-device-state-access.h"
#include "interpret.h"
-#include "machine-runtime-config.h"
#include "os.h"
#include "pma-driver.h"
@@ -89,17 +88,12 @@ static execute_status htif_yield(i_device_state_access *a, uint64_t cmd, uint64_
return status;
}
-static execute_status htif_console(htif_runtime_config *runtime_config, i_device_state_access *a, uint64_t cmd,
- uint64_t data) {
+static execute_status htif_console(i_device_state_access *a, uint64_t cmd, uint64_t data) {
// If console command is enabled, perform it and acknowledge
if (cmd < 64 && (((a->read_htif_iconsole() >> cmd) & 1) != 0)) {
if (cmd == HTIF_CONSOLE_CMD_PUTCHAR) {
const uint8_t ch = data & 0xff;
- // In microarchitecture runtime_config will always be nullptr,
- // therefore the HTIF runtime config is actually ignored.
- if ((runtime_config == nullptr) || !runtime_config->no_console_putchar) {
- os_putchar(ch);
- }
+ os_putchar(ch);
a->write_htif_fromhost(HTIF_BUILD(HTIF_DEV_CONSOLE, cmd, 0, 0));
} else if (cmd == HTIF_CONSOLE_CMD_GETCHAR) {
// In blockchain, this command will never be enabled as there is no way to input the same character
@@ -115,8 +109,7 @@ static execute_status htif_console(htif_runtime_config *runtime_config, i_device
return execute_status::success;
}
-static execute_status htif_write_tohost(htif_runtime_config *runtime_config, i_device_state_access *a,
- uint64_t tohost) {
+static execute_status htif_write_tohost(i_device_state_access *a, uint64_t tohost) {
// Decode tohost
const uint32_t device = HTIF_DEV_FIELD(tohost);
const uint32_t cmd = HTIF_CMD_FIELD(tohost);
@@ -128,7 +121,7 @@ static execute_status htif_write_tohost(htif_runtime_config *runtime_config, i_d
case HTIF_DEV_HALT:
return htif_halt(a, cmd, data);
case HTIF_DEV_CONSOLE:
- return htif_console(runtime_config, a, cmd, data);
+ return htif_console(a, cmd, data);
case HTIF_DEV_YIELD:
return htif_yield(a, cmd, data);
//??D Unknown HTIF devices are silently ignored
@@ -138,10 +131,8 @@ static execute_status htif_write_tohost(htif_runtime_config *runtime_config, i_d
}
/// \brief HTIF device write callback. See ::pma_write.
-static execute_status htif_write(void *context, i_device_state_access *a, uint64_t offset, uint64_t val,
+static execute_status htif_write(void * /*context*/, i_device_state_access *a, uint64_t offset, uint64_t val,
int log2_size) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- auto *runtime_config = reinterpret_cast(context);
// Our HTIF only supports 64-bit writes
if (log2_size != 3) {
return execute_status::failure;
@@ -150,7 +141,7 @@ static execute_status htif_write(void *context, i_device_state_access *a, uint64
// Only these 64-bit aligned offsets are valid
switch (offset) {
case htif_tohost_rel_addr:
- return htif_write_tohost(runtime_config, a, val);
+ return htif_write_tohost(a, val);
case htif_fromhost_rel_addr:
a->write_htif_fromhost(val);
return execute_status::success;
diff --git a/src/i-device-state-access.h b/src/i-device-state-access.h
index 184edda44..efdfaa06e 100644
--- a/src/i-device-state-access.h
+++ b/src/i-device-state-access.h
@@ -193,18 +193,6 @@ class i_device_state_access {
return do_write_memory(paddr, data, length);
}
- /// \brief Reads the istart field of a PMA entry
- /// \param p Index of PMA
- uint64_t read_pma_istart(int p) {
- return do_read_pma_istart(p);
- }
-
- /// \brief Reads the ilength field of a PMA entry
- /// \param p Index of PMA
- uint64_t read_pma_ilength(int p) {
- return do_read_pma_ilength(p);
- }
-
private:
virtual void do_set_mip(uint64_t mask) = 0;
virtual void do_reset_mip(uint64_t mask) = 0;
@@ -228,8 +216,6 @@ class i_device_state_access {
virtual uint64_t do_read_htif_iyield() = 0;
virtual bool do_read_memory(uint64_t paddr, unsigned char *data, uint64_t length) = 0;
virtual bool do_write_memory(uint64_t paddr, const unsigned char *data, uint64_t length) = 0;
- virtual uint64_t do_read_pma_istart(int p) = 0;
- virtual uint64_t do_read_pma_ilength(int p) = 0;
};
} // namespace cartesi
diff --git a/src/i-state-access.h b/src/i-state-access.h
index 6fbeb0de5..2d8345ff6 100644
--- a/src/i-state-access.h
+++ b/src/i-state-access.h
@@ -600,23 +600,10 @@ class i_state_access { // CRTP
return derived().do_poll_external_interrupts(mcycle, mcycle_max);
}
- /// \brief Reads PMA at a given index.
- /// \param pma PMA entry.
- /// \param i Index of PMA index.
- void read_pma(const PMA_ENTRY_TYPE &pma, int i) {
- return derived().do_read_pma(pma, i);
- }
-
- /// \brief Reads the istart field of a PMA entry
- /// \param p Index of PMA
- uint64_t read_pma_istart(int p) {
- return derived().do_read_pma_istart(p);
- }
-
- /// \brief Reads the ilength field of a PMA entry
- /// \param p Index of PMA
- uint64_t read_pma_ilength(int p) {
- return derived().do_read_pma_ilength(p);
+ /// \brief Reads PMA entry at a given index.
+ /// \param index Index of PMA
+ PMA_ENTRY_TYPE &read_pma_entry(uint64_t index) {
+ return derived().do_read_pma_entry(index);
}
/// \brief Reads a chunk of data from a memory PMA range.
@@ -665,32 +652,10 @@ class i_state_access { // CRTP
return derived().template do_write_memory_word(paddr, hpage, hoffset, val);
}
- /// \brief Obtain PMA entry covering a physical memory word
- /// \param paddr Target physical address.
- /// \returns Corresponding entry if found, or a sentinel entry
- /// for an empty range.
- /// \tparam T Type of word.
- template
- PMA_ENTRY_TYPE &find_pma_entry(uint64_t paddr) {
- return derived().template do_find_pma_entry(paddr);
- }
-
auto get_host_memory(PMA_ENTRY_TYPE &pma) {
return derived().do_get_host_memory(pma);
}
- PMA_ENTRY_TYPE &get_pma_entry(int index) {
- return derived().do_get_pma_entry(index);
- }
-
- auto read_device(PMA_ENTRY_TYPE &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) {
- return derived().do_read_device(pma, mcycle, offset, pval, log2_size);
- }
-
- auto write_device(PMA_ENTRY_TYPE &pma, uint64_t mcycle, uint64_t offset, uint64_t pval, int log2_size) {
- return derived().do_write_device(pma, mcycle, offset, pval, log2_size);
- }
-
/// \brief Try to translate a virtual address to a host pointer through the TLB.
/// \tparam ETYPE TLB entry type.
/// \tparam T Type of word that would be read with the pointer.
diff --git a/src/i-uarch-state-access.h b/src/i-uarch-state-access.h
index ef51c63d4..5905f0907 100644
--- a/src/i-uarch-state-access.h
+++ b/src/i-uarch-state-access.h
@@ -95,11 +95,6 @@ class i_uarch_state_access { // CRTP
return derived().do_write_word(paddr, data);
}
- template
- pma_entry &find_pma_entry(uint64_t paddr) {
- return derived().template do_find_pma_entry(paddr);
- }
-
/// \brief Resets uarch to pristine state
void reset_state() {
return derived().do_reset_state();
diff --git a/src/interpret.cpp b/src/interpret.cpp
index 72d66d736..fc02d88ba 100644
--- a/src/interpret.cpp
+++ b/src/interpret.cpp
@@ -102,6 +102,7 @@
/// https://gcc.gnu.org/onlinedocs/gcc-7.3.0/gcc/Arrays-and-pointers-implementation.html#Arrays-and-pointers-implementation
/// \}
+#include "find-pma-entry.h"
#include "interpret.h"
#include "meta.h"
#include "riscv-constants.h"
@@ -837,7 +838,7 @@ static NO_INLINE std::pair read_virtual_memory_slow(STATE_ACCESS
vaddr);
return {false, pc};
}
- auto &pma = a.template find_pma_entry(paddr);
+ auto &pma = find_pma_entry(a, paddr);
if (likely(pma.get_istart_R())) {
if (likely(pma.get_istart_M())) {
unsigned char *hpage = a.template replace_tlb_entry(vaddr, paddr, pma);
@@ -848,8 +849,11 @@ static NO_INLINE std::pair read_virtual_memory_slow(STATE_ACCESS
if (likely(pma.get_istart_IO())) {
const uint64_t offset = paddr - pma.get_start();
uint64_t val{};
+ device_state_access da(a, mcycle);
// If we do not know how to read, we treat this as a PMA violation
- if (likely(a.read_device(pma, mcycle, offset, &val, log2_size::value))) {
+ const bool status = pma.get_device_noexcept().get_driver()->read(pma.get_device_noexcept().get_context(),
+ &da, offset, &val, log2_size::value);
+ if (likely(status)) {
*pval = static_cast(val);
// device logs its own state accesses
return {true, pc};
@@ -913,7 +917,7 @@ static NO_INLINE std::pair write_virtual_memory_slow(S
pc = raise_exception(a, pc, MCAUSE_STORE_AMO_PAGE_FAULT, vaddr);
return {execute_status::failure, pc};
}
- auto &pma = a.template find_pma_entry(paddr);
+ auto &pma = find_pma_entry(a, paddr);
if (likely(pma.get_istart_W())) {
if (likely(pma.get_istart_M())) {
unsigned char *hpage = a.template replace_tlb_entry(vaddr, paddr, pma);
@@ -923,8 +927,9 @@ static NO_INLINE std::pair write_virtual_memory_slow(S
}
if (likely(pma.get_istart_IO())) {
const uint64_t offset = paddr - pma.get_start();
- auto status =
- a.write_device(pma, mcycle, offset, static_cast(static_cast(val64)), log2_size::value);
+ device_state_access da(a, mcycle);
+ auto status = pma.get_device_noexcept().get_driver()->write(pma.get_device_noexcept().get_context(), &da,
+ offset, static_cast(static_cast(val64)), log2_size::value);
// If we do not know how to write, we treat this as a PMA violation
if (likely(status != execute_status::failure)) {
return {status, pc};
@@ -5397,7 +5402,7 @@ static FORCE_INLINE fetch_status fetch_translate_pc_slow(STATE_ACCESS &a, uint64
return fetch_status::exception;
}
// Walk memory map to find the range that contains the physical address
- auto &pma = a.template find_pma_entry(paddr);
+ auto &pma = find_pma_entry(a, paddr);
// We only execute directly from RAM (as in "random access memory")
// If the range is not memory or not executable, this as a PMA violation
if (unlikely(!pma.get_istart_M() || !pma.get_istart_X())) {
diff --git a/src/machine.cpp b/src/machine.cpp
index 6c6eca5bb..9adc9f115 100644
--- a/src/machine.cpp
+++ b/src/machine.cpp
@@ -31,7 +31,6 @@
#include
#include
-#include
#include "access-log.h"
#include "bracket-note.h"
@@ -49,9 +48,9 @@
#include "pma-constants.h"
#include "pma-defines.h"
#include "pma.h"
-#include "record-state-access.h"
+#include "record-send-cmio-state-access.h"
#include "record-step-state-access.h"
-#include "replay-state-access.h"
+#include "replay-send-cmio-state-access.h"
#include "replay-step-state-access.h"
#include "riscv-constants.h"
#include "send-cmio-response.h"
@@ -86,7 +85,6 @@
namespace cartesi {
using namespace std::string_literals;
-using namespace boost::adaptors;
const pma_entry::flags machine::m_ram_flags{
true, // R
@@ -394,7 +392,7 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) : m_c
register_pma_entry(make_cmio_rx_buffer_pma_entry(m_c.cmio));
// Register HTIF device
- register_pma_entry(make_htif_pma_entry(PMA_HTIF_START, PMA_HTIF_LENGTH, &m_r.htif));
+ register_pma_entry(make_htif_pma_entry(PMA_HTIF_START, PMA_HTIF_LENGTH));
// Copy HTIF state to from config to machine
write_reg(reg::htif_tohost, m_c.htif.tohost);
@@ -426,8 +424,14 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) : m_c
// Register state shadow device
register_pma_entry(make_shadow_state_pma_entry(PMA_SHADOW_STATE_START, PMA_SHADOW_STATE_LENGTH));
- // Register pma board shadow device
- register_pma_entry(make_shadow_pmas_pma_entry(PMA_SHADOW_PMAS_START, PMA_SHADOW_PMAS_LENGTH));
+ // Register memory range that holds shadow PMA state, keep pointer to populate later
+ shadow_pmas_state *shadow_pmas = nullptr;
+ {
+ auto shadow_pmas_pma_entry = make_shadow_pmas_pma_entry(PMA_SHADOW_PMAS_START, PMA_SHADOW_PMAS_LENGTH);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ shadow_pmas = reinterpret_cast(shadow_pmas_pma_entry.get_memory().get_host_memory());
+ register_pma_entry(std::move(shadow_pmas_pma_entry));
+ }
// Initialize VirtIO devices
if (!m_c.virtio.empty()) {
@@ -489,21 +493,30 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) : m_c
dtb_init(m_c, dtb.get_memory().get_host_memory(), PMA_DTB_LENGTH);
}
- // Add sentinel to PMA vector
+ // Include machine PMAs in set considered by the Merkle tree.
+ for (auto &pma : m_s.pmas) {
+ m_merkle_pmas.push_back(&pma);
+ }
+
+ // Last, add empty sentinels until we reach capacity (need at least one sentinel)
register_pma_entry(make_empty_pma_entry("sentinel"s, 0, 0));
- // Initialize the vector of the pmas used by the merkle tree to compute hashes.
- // First, add the pmas visible to the big machine, except the sentinel
- for (auto &pma : m_s.pmas | sliced(0, m_s.pmas.size() - 1)) {
- m_pmas.push_back(&pma);
+ // NOLINTNEXTLINE(readability-static-accessed-through-instance)
+ if (m_s.pmas.capacity() != PMA_MAX) {
+ throw std::logic_error{"PMAs array must be able to hold PMA_MAX entries"};
+ }
+ while (m_s.pmas.size() < PMA_MAX) {
+ register_pma_entry(make_empty_pma_entry("sentinel"s, 0, 0));
}
- // Second, push uarch pmas that are visible only to the microarchitecture interpreter
- m_pmas.push_back(&m_uarch.get_state().shadow_state);
- m_pmas.push_back(&m_uarch.get_state().ram);
+ // Populate shadow PMAs
+ populate_shadow_pmas_state(m_s.pmas, shadow_pmas);
- // Last, add sentinel
- m_pmas.push_back(&m_s.empty_pma);
+ // Include uarch PMAs in set considered by Merkle tree
+ m_merkle_pmas.push_back(&m_uarch.get_state().shadow_state);
+ m_merkle_pmas.push_back(&m_uarch.get_state().ram);
+ // Last, add sentinel PMA
+ m_merkle_pmas.push_back(&m_s.empty_pma);
// Initialize TLB device
// this must be done after all PMA entries are already registered, so we can lookup page addresses
@@ -532,9 +545,10 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) : m_c
}
os_open_tty();
}
+ os_silence_putchar(m_r.htif.no_console_putchar);
// Initialize memory range descriptions returned by get_memory_ranges method
- for (auto *pma : m_pmas) {
+ for (const auto *pma : m_merkle_pmas) {
if (pma->get_length() != 0) {
m_mrds.push_back(machine_memory_range_descr{pma->get_start(), pma->get_length(), pma->get_description()});
}
@@ -622,11 +636,9 @@ const machine_runtime_config &machine::get_runtime_config() const {
/// \brief Changes the machine runtime config.
void machine::set_runtime_config(const machine_runtime_config &r) {
- if (r.htif.no_console_putchar != m_r.htif.no_console_putchar) {
- throw std::runtime_error{"cannot change htif runtime configuration"};
- }
m_r = r;
m_s.soft_yield = m_r.soft_yield;
+ os_silence_putchar(r.htif.no_console_putchar);
}
machine_config machine::get_serialization_config() const {
@@ -1733,7 +1745,7 @@ bool machine::update_merkle_tree() const {
mark_write_tlb_dirty_pages();
// Now go over all PMAs and updating the Merkle tree
m_t.begin_update();
- for (const auto &pma : m_pmas) {
+ for (const auto &pma : m_merkle_pmas) {
auto peek = pma->get_peek();
// Each PMA has a number of pages
auto pages_in_range = (pma->get_length() + PMA_PAGE_SIZE - 1) / PMA_PAGE_SIZE;
@@ -1805,7 +1817,7 @@ bool machine::update_merkle_tree_page(uint64_t address) {
"PMA and machine_merkle_tree page sizes must match");
// Align address to beginning of page
address &= ~(PMA_PAGE_SIZE - 1);
- pma_entry &pma = find_pma_entry(m_pmas, address, sizeof(uint64_t));
+ pma_entry &pma = find_pma_entry(m_merkle_pmas, address, sizeof(uint64_t));
const uint64_t page_start_in_range = address - pma.get_start();
machine_merkle_tree::hasher_type h;
auto scratch = unique_calloc(PMA_PAGE_SIZE, std::nothrow_t{});
@@ -1885,7 +1897,7 @@ machine_merkle_tree::proof_type machine::get_proof(uint64_t address, int log2_si
// or entirely outside it.
if (log2_size < machine_merkle_tree::get_log2_page_size()) {
const uint64_t length = UINT64_C(1) << log2_size;
- const pma_entry &pma = find_pma_entry(m_pmas, address, length);
+ const pma_entry &pma = find_pma_entry(m_merkle_pmas, address, length);
auto scratch = unique_calloc(PMA_PAGE_SIZE);
const unsigned char *page_data = nullptr;
// If the PMA range is empty, we know the desired range is
@@ -1920,7 +1932,7 @@ void machine::read_memory(uint64_t address, unsigned char *data, uint64_t length
if (data == nullptr) {
throw std::invalid_argument{"invalid data buffer"};
}
- const pma_entry &pma = find_pma_entry(m_pmas, address, length);
+ const pma_entry &pma = find_pma_entry(m_merkle_pmas, address, length);
if (pma.get_istart_M()) {
memcpy(data, pma.get_memory().get_host_memory() + (address - pma.get_start()), length);
return;
@@ -1972,7 +1984,7 @@ void machine::write_memory(uint64_t address, const unsigned char *data, uint64_t
if (data == nullptr) {
throw std::invalid_argument{"invalid data buffer"};
}
- pma_entry &pma = find_pma_entry(m_pmas, address, length);
+ pma_entry &pma = find_pma_entry(m_merkle_pmas, address, length);
if (!pma.get_istart_M() || pma.get_istart_E()) {
throw std::invalid_argument{"address range not entirely in memory PMA"};
}
@@ -1983,7 +1995,7 @@ void machine::fill_memory(uint64_t address, uint8_t data, uint64_t length) {
if (length == 0) {
return;
}
- pma_entry &pma = find_pma_entry(m_pmas, address, length);
+ pma_entry &pma = find_pma_entry(m_merkle_pmas, address, length);
if (!pma.get_istart_M() || pma.get_istart_E()) {
throw std::invalid_argument{"address range not entirely in memory PMA"};
}
@@ -2099,7 +2111,7 @@ access_log machine::log_send_cmio_response(uint16_t reason, const unsigned char
hash_type root_hash_before;
get_root_hash(root_hash_before);
// Call send_cmio_response with the recording state accessor
- record_state_access a(*this, log_type);
+ record_send_cmio_state_access a(*this, log_type);
a.push_bracket(bracket_type::begin, "send cmio response");
cartesi::send_cmio_response(a, reason, data, length);
a.push_bracket(bracket_type::end, "send cmio response");
@@ -2119,7 +2131,7 @@ void machine::verify_send_cmio_response(uint16_t reason, const unsigned char *da
}
// Verify all intermediate state transitions
- replay_state_access a(log, root_hash_before);
+ replay_send_cmio_state_access a(log, root_hash_before);
cartesi::send_cmio_response(a, reason, data, length);
a.finish();
diff --git a/src/machine.h b/src/machine.h
index 2c500d33c..c7bb5f705 100644
--- a/src/machine.h
+++ b/src/machine.h
@@ -64,13 +64,13 @@ class machine final {
// not constantly going through the extra indirection. We
// should test this.
- mutable machine_state m_s; ///< Opaque machine state
- mutable machine_merkle_tree m_t; ///< Merkle tree of state
- std::vector m_pmas; ///< List of all pmas used to compute the machine hash: big machine and uarch
- machine_config m_c; ///< Copy of initialization config
- uarch_machine m_uarch; ///< Microarchitecture machine
- machine_runtime_config m_r; ///< Copy of initialization runtime config
- machine_memory_range_descrs m_mrds; ///< List of memory ranges returned by get_memory_ranges().
+ mutable machine_state m_s; ///< Opaque machine state
+ mutable machine_merkle_tree m_t; ///< Merkle tree of state
+ std::vector m_merkle_pmas; ///< PMAs considered by the Merkle tree: from big machine and uarch
+ machine_config m_c; ///< Copy of initialization config
+ uarch_machine m_uarch; ///< Microarchitecture machine
+ machine_runtime_config m_r; ///< Copy of initialization runtime config
+ machine_memory_range_descrs m_mrds; ///< List of memory ranges returned by get_memory_ranges().
boost::container::static_vector, VIRTIO_MAX> m_vdevs; ///< Array of VirtIO devices
diff --git a/src/os.cpp b/src/os.cpp
index e05316995..44d1ac527 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -120,6 +120,7 @@ using namespace std::string_literals;
struct tty_state {
bool initialized{false};
bool resize_pending{false};
+ bool silence_putchar{false};
std::array buf{}; // Characters in console input buffer
intptr_t buf_pos{};
intptr_t buf_len{};
@@ -135,12 +136,23 @@ struct tty_state {
};
/// Returns pointer to the global TTY state
-static tty_state *get_state() {
+static tty_state *get_tty_state() {
static tty_state data;
return &data;
}
#endif // HAVE_TTY
+/// \brief putchar global state
+struct putchar_state {
+ bool silence;
+};
+
+/// Returns pointer to the global TTY state
+static putchar_state *get_putchar_state() {
+ static putchar_state data;
+ return &data;
+}
+
#ifdef HAVE_TERMIOS
static int new_ttyfd(const char *path) {
int fd{};
@@ -176,7 +188,7 @@ static int get_ttyfd() {
#ifdef HAVE_SIGACTION
/// \brief Signal raised whenever TTY size changes
static void os_SIGWINCH_handler(int /*sig*/) {
- auto *s = get_state();
+ auto *s = get_tty_state();
if (!s->initialized) {
return;
}
@@ -225,7 +237,7 @@ bool os_update_tty_size([[maybe_unused]] tty_state *s) {
void os_open_tty() {
#ifdef HAVE_TTY
- auto *s = get_state();
+ auto *s = get_tty_state();
if (s->initialized) {
// Already initialized
return;
@@ -332,7 +344,7 @@ void os_open_tty() {
void os_close_tty() {
#ifdef HAVE_TTY
#ifdef HAVE_TERMIOS
- auto *s = get_state();
+ auto *s = get_tty_state();
if (s->ttyfd >= 0) { // Restore old mode
tcsetattr(s->ttyfd, TCSANOW, &s->oldtty);
close(s->ttyfd);
@@ -340,7 +352,7 @@ void os_close_tty() {
}
#elif defined(_WIN32)
- auto *s = get_state();
+ auto *s = get_tty_state();
if (s->hStdin) {
SetConsoleMode(s->hStdin, s->dwOldStdinMode);
s->hStdin = NULL;
@@ -351,7 +363,7 @@ void os_close_tty() {
}
void os_get_tty_size(uint16_t *pwidth, uint16_t *pheight) {
- auto *s = get_state();
+ auto *s = get_tty_state();
if (!s->initialized) {
// fallback values
*pwidth = TTY_DEFAULT_COLS;
@@ -370,7 +382,7 @@ void os_get_tty_size(uint16_t *pwidth, uint16_t *pheight) {
void os_prepare_tty_select([[maybe_unused]] select_fd_sets *fds) {
#ifdef HAVE_TTY
- auto *s = get_state();
+ auto *s = get_tty_state();
// Ignore if TTY is not initialized or stdin was closed
if (!s->initialized) {
return;
@@ -387,7 +399,7 @@ void os_prepare_tty_select([[maybe_unused]] select_fd_sets *fds) {
}
bool os_poll_selected_tty([[maybe_unused]] int select_ret, [[maybe_unused]] select_fd_sets *fds) {
- auto *s = get_state();
+ auto *s = get_tty_state();
if (!s->initialized) { // We can't poll when TTY is not initialized
return false;
}
@@ -444,7 +456,7 @@ bool os_poll_selected_tty([[maybe_unused]] int select_ret, [[maybe_unused]] sele
bool os_poll_tty(uint64_t timeout_us) {
#ifdef _WIN32
- auto *s = get_state();
+ auto *s = get_tty_state();
if (!s->initialized) { // We can't poll when TTY is not initialized
return false;
}
@@ -468,7 +480,7 @@ bool os_poll_tty(uint64_t timeout_us) {
int os_getchar() {
#ifdef HAVE_TTY
- auto *s = get_state();
+ auto *s = get_tty_state();
if (!s->initialized) {
return -1;
}
@@ -501,9 +513,18 @@ static void fputc_with_line_buffering(uint8_t ch) {
}
}
+void os_silence_putchar(bool yes) {
+ auto *ps = get_putchar_state();
+ ps->silence = yes;
+}
+
void os_putchar(uint8_t ch) {
+ auto *ps = get_putchar_state();
+ if (ps->silence) {
+ return;
+ }
#ifdef HAVE_TTY
- auto *s = get_state();
+ auto *s = get_tty_state();
if (!s->initialized) {
// Write through fputc(), so we can take advantage of buffering.
fputc_with_line_buffering(ch);
@@ -520,6 +541,10 @@ void os_putchar(uint8_t ch) {
}
void os_putchars(const uint8_t *data, size_t len) {
+ auto *ps = get_putchar_state();
+ if (ps->silence) {
+ return;
+ }
for (size_t i = 0; i < len; ++i) {
os_putchar(data[i]);
}
diff --git a/src/os.h b/src/os.h
index ffb41ea21..dbca15543 100644
--- a/src/os.h
+++ b/src/os.h
@@ -86,6 +86,10 @@ void os_putchar(uint8_t ch);
/// \param len Length of buffer.
void os_putchars(const uint8_t *data, size_t len);
+/// \brief Silences putchar (and putchars) output
+/// \param yes If true, putchar is silenced
+void os_silence_putchar(bool yes);
+
/// \brief Creates a new directory
int os_mkdir(const char *path, int mode);
diff --git a/src/record-state-access.h b/src/record-send-cmio-state-access.h
similarity index 93%
rename from src/record-state-access.h
rename to src/record-send-cmio-state-access.h
index 7df3b90b2..aee38f5ad 100644
--- a/src/record-state-access.h
+++ b/src/record-send-cmio-state-access.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef RECORD_STATE_ACCESS_H
-#define RECORD_STATE_ACCESS_H
+#ifndef RECORD_SEND_CMIO_STATE_ACCESS_H
+#define RECORD_SEND_CMIO_STATE_ACCESS_H
/// \file
/// \brief State access implementation that records state accesses to an access log.
@@ -38,10 +38,10 @@
namespace cartesi {
-/// \class record_state_access
-/// \details This ....
-/// access to the machine state. No logs are kept.
-class record_state_access : public i_state_access {
+/// \class record_send_cmio_state_access
+/// \details This records all state accesses that happen during the execution of
+/// a machine::send_cmio_response() function call
+class record_send_cmio_state_access : public i_state_access {
using hasher_type = machine_merkle_tree::hasher_type;
using hash_type = machine_merkle_tree::hash_type;
// NOLINTBEGIN(cppcoreguidelines-avoid-const-or-ref-data-members)
@@ -58,7 +58,7 @@ class record_state_access : public i_state_access(log_type)) {
@@ -66,15 +66,15 @@ class record_state_access : public i_state_access get_log() const {
@@ -193,7 +193,7 @@ class record_state_access : public i_state_access;
+ friend i_state_access;
void do_push_bracket(bracket_type &type, const char *text) {
m_log->push_bracket(type, text);
diff --git a/src/record-step-state-access.h b/src/record-step-state-access.h
index cdfe85864..eb70b926f 100644
--- a/src/record-step-state-access.h
+++ b/src/record-step-state-access.h
@@ -588,28 +588,6 @@ class record_step_state_access : public i_state_access= 0 && i < (int) PMA_MAX);
- touch_page(shadow_pmas_get_pma_abs_addr(i));
- const auto &pmas = m_m.get_pmas();
- uint64_t istart = 0;
- if (i >= 0 && i < static_cast(pmas.size())) {
- istart = pmas[i].get_istart();
- }
- return istart;
- }
-
- uint64_t do_read_pma_ilength(int i) const {
- assert(i >= 0 && i < (int) PMA_MAX);
- touch_page(shadow_pmas_get_pma_abs_addr(i));
- const auto &pmas = m_m.get_pmas();
- uint64_t ilength = 0;
- if (i >= 0 && i < static_cast(pmas.size())) {
- ilength = pmas[i].get_ilength();
- }
- return ilength;
- }
-
template
void do_read_memory_word(uint64_t paddr, const unsigned char *hpage, uint64_t hoffset, T *pval) const {
(void) paddr;
@@ -641,56 +619,15 @@ class record_step_state_access : public i_state_access
- pma_entry &do_find_pma_entry(uint64_t paddr) {
- int i = 0;
- while (true) {
- touch_page(shadow_pmas_get_pma_abs_addr(i));
- auto &pma = m_m.get_state().pmas[i];
- // The pmas array always contain a sentinel. It is an entry with
- // zero length. If we hit it, return it
- if (pma.get_length() == 0) {
- return pma;
- }
- // Otherwise, if we found an entry where the access fits, return it
- // Note the "strange" order of arithmetic operations.
- // This is to ensure there is no overflow.
- // Since we know paddr >= start, there is no chance of overflow
- // in the first subtraction.
- // Since length is at least 4096 (an entire page), there is no
- // chance of overflow in the second subtraction.
- if (paddr >= pma.get_start() && paddr - pma.get_start() <= pma.get_length() - sizeof(T)) {
- return pma;
- }
- i++;
- }
- }
-
static unsigned char *do_get_host_memory(pma_entry &pma) {
return pma.get_memory_noexcept().get_host_memory();
}
- pma_entry &do_get_pma_entry(int index) {
- auto &pmas = m_m.get_state().pmas;
- const auto last_pma_index = static_cast(pmas.size()) - 1;
- if (index >= last_pma_index) {
- touch_page(shadow_pmas_get_pma_abs_addr(last_pma_index));
- return pmas[last_pma_index];
- }
+ pma_entry &do_read_pma_entry(uint64_t index) {
+ assert(index < PMA_MAX);
touch_page(shadow_pmas_get_pma_abs_addr(index));
- return pmas[index];
- }
-
- bool do_read_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) {
- device_state_access da(*this, mcycle);
- return pma.get_device_noexcept().get_driver()->read(pma.get_device_noexcept().get_context(), &da, offset, pval,
- log2_size);
- }
-
- execute_status do_write_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) {
- device_state_access da(*this, mcycle);
- return pma.get_device_noexcept().get_driver()->write(pma.get_device_noexcept().get_context(), &da, offset, val,
- log2_size);
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions)
+ return m_m.get_state().pmas[static_cast(index)];
}
template
@@ -756,7 +693,7 @@ class record_step_state_access : public i_state_access(tlbce.pma_index));
+ pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
}
}
@@ -782,7 +719,7 @@ class record_step_state_access : public i_state_access(tlbce.pma_index));
+ pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
} else {
tlbhe.vaddr_page = TLB_INVALID_PAGE;
diff --git a/src/replay-state-access.h b/src/replay-send-cmio-state-access.h
similarity index 95%
rename from src/replay-state-access.h
rename to src/replay-send-cmio-state-access.h
index 43c28cb35..56cc135be 100644
--- a/src/replay-state-access.h
+++ b/src/replay-send-cmio-state-access.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef REPLAY_STATE_ACCESS_H
-#define REPLAY_STATE_ACCESS_H
+#ifndef REPLAY_SEND_CMIO_STATE_ACCESS_H
+#define REPLAY_SEND_CMIO_STATE_ACCESS_H
/// \file
/// \brief State access implementation that replays recorded state accesses
@@ -41,8 +41,8 @@
namespace cartesi {
-/// \brief Allows replaying a uarch reset operation from an access log.
-class replay_state_access : public i_state_access {
+/// \brief Allows replaying a machine::send_cmio_response() from an access log.
+class replay_send_cmio_state_access : public i_state_access {
using tree_type = machine_merkle_tree;
using hash_type = tree_type::hash_type;
using hasher_type = tree_type::hasher_type;
@@ -61,7 +61,7 @@ class replay_state_access : public i_state_access;
+ friend i_state_access;
std::string access_to_report() const {
auto index = m_next_access + 1;
diff --git a/src/replay-step-state-access.h b/src/replay-step-state-access.h
index 786414951..39637095a 100644
--- a/src/replay-step-state-access.h
+++ b/src/replay-step-state-access.h
@@ -42,6 +42,8 @@ namespace cartesi {
// \file this code is designed to be compiled for a free-standing environment.
// Environment-specific functions have the prefix "interop_" and are declared in "replay-step-state-access-interop.h"
+//??D can we merge this calss with uarch_pma_entry in uarch/uarch-machine-state-access.h ?
+//??D maybe implement base class in pma.h and subclass here if there is some minor difference?
class mock_pma_entry final {
public:
struct flags {
@@ -57,29 +59,57 @@ class mock_pma_entry final {
};
private:
- int m_pma_index;
+ uint64_t m_pma_index;
uint64_t m_start;
uint64_t m_length;
flags m_flags;
- const pma_driver *m_device_driver;
- void *m_device_context;
+ const pma_driver *m_driver{nullptr};
+
+ static constexpr flags split_flags(uint64_t istart) {
+ flags f{};
+ f.M = ((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0;
+ f.IO = ((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0;
+ f.E = ((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0;
+ f.R = ((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0;
+ f.W = ((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0;
+ f.X = ((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0;
+ f.IR = ((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0;
+ f.IW = ((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0;
+ f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT);
+ return f;
+ }
public:
- mock_pma_entry(int pma_index, uint64_t start, uint64_t length, flags flags, const pma_driver *pma_driver = nullptr,
- void *device_context = nullptr) :
+ mock_pma_entry(uint64_t pma_index, uint64_t istart, uint64_t ilength) :
m_pma_index{pma_index},
- m_start{start},
- m_length{length},
- m_flags{flags},
- m_device_driver{pma_driver},
- m_device_context{device_context} {}
-
- mock_pma_entry() :
- mock_pma_entry(-1, 0, 0, {false, false, true, false, false, false, false, false, PMA_ISTART_DID{}}) {
- ;
+ m_start{istart & PMA_ISTART_START_MASK},
+ m_length{ilength},
+ m_flags{split_flags(istart)} {
+ if (m_flags.IO) {
+ switch (m_flags.DID) {
+ case PMA_ISTART_DID::shadow_state:
+ m_driver = &shadow_state_driver;
+ break;
+ case PMA_ISTART_DID::shadow_TLB:
+ m_driver = &shadow_tlb_driver;
+ break;
+ case PMA_ISTART_DID::CLINT:
+ m_driver = &clint_driver;
+ break;
+ case PMA_ISTART_DID::PLIC:
+ m_driver = &plic_driver;
+ break;
+ case PMA_ISTART_DID::HTIF:
+ m_driver = &htif_driver;
+ break;
+ default:
+ interop_throw_runtime_error("unsupported device in build_mock_pma_entry");
+ break;
+ }
+ }
}
- int get_index() const {
+ uint64_t get_index() const {
return m_pma_index;
}
@@ -123,12 +153,16 @@ class mock_pma_entry final {
return m_flags.IR;
}
- const pma_driver *get_device_driver() {
- return m_device_driver;
+ const auto *get_driver() const {
+ return m_driver;
}
- void *get_device_context() {
- return m_device_context;
+ const auto &get_device_noexcept() const {
+ return *this;
+ }
+
+ static void *get_context() {
+ return nullptr;
}
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
@@ -820,11 +854,11 @@ class replay_step_state_access : public i_state_access(shadow_pmas_get_pma_abs_addr(i));
}
- uint64_t do_read_pma_ilength(int i) {
+ uint64_t read_pma_ilength(uint64_t i) {
return raw_read_memory(shadow_pmas_get_pma_abs_addr(i) + sizeof(uint64_t));
}
@@ -858,28 +892,17 @@ class replay_step_state_access : public i_state_access
- mock_pma_entry &do_find_pma_entry(uint64_t paddr) {
- for (size_t i = 0; i < m_pmas.size(); i++) {
- auto &pma = get_pma_entry(static_cast(i));
- if (pma.get_istart_E()) {
- return pma;
- }
- if (paddr >= pma.get_start() && paddr - pma.get_start() <= pma.get_length() - sizeof(T)) {
- return pma;
- }
- }
- interop_throw_runtime_error("do_find_pma_entry failed to find address");
- }
-
- mock_pma_entry &do_get_pma_entry(int index) {
+ mock_pma_entry &do_read_pma_entry(uint64_t index) {
+ assert(index < PMA_MAX);
const uint64_t istart = read_pma_istart(index);
const uint64_t ilength = read_pma_ilength(index);
- if (!m_pmas[index]) {
- m_pmas[index] = build_mock_pma_entry(index, istart, ilength);
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions)
+ const int i = static_cast(index);
+ if (!m_pmas[i]) {
+ m_pmas[i] = mock_pma_entry(index, istart, ilength);
}
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
- return m_pmas[index].value();
+ return m_pmas[i].value();
}
unsigned char *do_get_host_memory(mock_pma_entry &pma) { // NOLINT(readability-convert-member-functions-to-static)
@@ -887,64 +910,6 @@ class replay_step_state_access : public i_state_accessread(pma.get_device_context(), &da, offset, pval, log2_size);
- }
-
- execute_status do_write_device(mock_pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) {
- device_state_access da(*this, mcycle);
- return pma.get_device_driver()->write(pma.get_device_context(), &da, offset, val, log2_size);
- }
-
- // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
- mock_pma_entry build_mock_pma_entry(int index, uint64_t istart, uint64_t ilength) {
- uint64_t start{};
- mock_pma_entry::flags flags{};
- split_istart(istart, start, flags);
- const pma_driver *driver = nullptr;
- void *device_ctx = nullptr;
- if (flags.IO) {
- switch (flags.DID) {
- case PMA_ISTART_DID::shadow_state:
- driver = &shadow_state_driver;
- break;
- case PMA_ISTART_DID::shadow_pmas:
- driver = &shadow_pmas_driver;
- break;
- case PMA_ISTART_DID::shadow_TLB:
- driver = &shadow_tlb_driver;
- break;
- case PMA_ISTART_DID::CLINT:
- driver = &clint_driver;
- break;
- case PMA_ISTART_DID::PLIC:
- driver = &plic_driver;
- break;
- case PMA_ISTART_DID::HTIF:
- driver = &htif_driver;
- break;
- default:
- interop_throw_runtime_error("Unsupported device in build_mock_pma_entry");
- break;
- }
- }
- return mock_pma_entry{index, start, ilength, flags, driver, device_ctx};
- }
-
- static constexpr void split_istart(uint64_t istart, uint64_t &start, mock_pma_entry::flags &f) {
- f.M = ((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0;
- f.IO = ((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0;
- f.E = ((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0;
- f.R = ((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0;
- f.W = ((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0;
- f.X = ((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0;
- f.IR = ((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0;
- f.IW = ((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0;
- f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT);
- start = istart & PMA_ISTART_START_MASK;
- }
-
template
volatile tlb_hot_entry &do_get_tlb_hot_entry(uint64_t eidx) {
auto addr = tlb_get_entry_hot_abs_addr(eidx);
@@ -1007,7 +972,7 @@ class replay_step_state_access : public i_state_access(eidx);
if constexpr (ETYPE == TLB_WRITE) {
if (tlbhe.vaddr_page != TLB_INVALID_PAGE) {
- mock_pma_entry &pma = do_get_pma_entry(static_cast(tlbce.pma_index));
+ mock_pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
}
}
@@ -1020,7 +985,7 @@ class replay_step_state_access : public i_state_access(hpage) - vaddr_page;
tlbce.paddr_page = paddr_page;
- tlbce.pma_index = static_cast(pma.get_index());
+ tlbce.pma_index = pma.get_index();
return hpage;
}
@@ -1032,7 +997,7 @@ class replay_step_state_access : public i_state_access(eidx);
- mock_pma_entry &pma = do_get_pma_entry(static_cast(tlbce.pma_index));
+ mock_pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
} else {
tlbhe.vaddr_page = TLB_INVALID_PAGE;
diff --git a/src/send-cmio-response.cpp b/src/send-cmio-response.cpp
index 48567e92d..121c48e08 100644
--- a/src/send-cmio-response.cpp
+++ b/src/send-cmio-response.cpp
@@ -19,8 +19,8 @@
// NOLINTBEGIN(google-readability-casting,misc-const-correctness,modernize-use-auto,hicpp-use-auto)
-#include "record-state-access.h"
-#include "replay-state-access.h"
+#include "record-send-cmio-state-access.h"
+#include "replay-send-cmio-state-access.h"
#include "state-access.h"
#include "send-cmio-response.h"
@@ -64,10 +64,12 @@ void send_cmio_response(STATE_ACCESS &a, uint16 reason, bytes data, uint32 dataL
template void send_cmio_response(state_access &a, uint16_t reason, const unsigned char *data, uint32 length);
// Explicit instantiation for record_state_access
-template void send_cmio_response(record_state_access &a, uint16_t reason, const unsigned char *data, uint32 length);
+template void send_cmio_response(record_send_cmio_state_access &a, uint16_t reason, const unsigned char *data,
+ uint32 length);
// Explicit instantiation for replay_state_access
-template void send_cmio_response(replay_state_access &a, uint16_t reason, const unsigned char *data, uint32 length);
+template void send_cmio_response(replay_send_cmio_state_access &a, uint16_t reason, const unsigned char *data,
+ uint32 length);
} // namespace cartesi
// NOLINTEND(google-readability-casting,misc-const-correctness,modernize-use-auto,hicpp-use-auto)
diff --git a/src/shadow-pmas-factory.cpp b/src/shadow-pmas-factory.cpp
index 116b5be86..51b146afb 100644
--- a/src/shadow-pmas-factory.cpp
+++ b/src/shadow-pmas-factory.cpp
@@ -26,32 +26,6 @@
namespace cartesi {
-static bool shadow_pmas_peek(const pma_entry & /*pma*/, const machine &m, uint64_t page_offset,
- const unsigned char **page_data, unsigned char *scratch) {
- static_assert(sizeof(shadow_pmas) <= PMA_PAGE_SIZE);
-
- // There is only one page: 0
- if (page_offset != 0) {
- *page_data = nullptr;
- return false;
- }
-
- // Clear page
- memset(scratch, 0, PMA_PAGE_SIZE);
-
- // The page will reflect the pma_board structure
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- auto *b = reinterpret_cast(scratch);
- int i = 0;
- for (const auto &pma : m.get_pmas()) {
- b->pmas[i].start = pma.get_istart();
- b->pmas[i].length = pma.get_ilength();
- ++i;
- }
- *page_data = scratch;
- return true;
-}
-
pma_entry make_shadow_pmas_pma_entry(uint64_t start, uint64_t length) {
const pma_entry::flags f{
true, // R
@@ -61,8 +35,7 @@ pma_entry make_shadow_pmas_pma_entry(uint64_t start, uint64_t length) {
false, // IW
PMA_ISTART_DID::shadow_pmas // DID
};
- return make_device_pma_entry("shadow PMAs device", start, length, shadow_pmas_peek, &shadow_pmas_driver)
- .set_flags(f);
+ return make_callocd_memory_pma_entry("shadow PMAs", start, length).set_flags(f);
}
} // namespace cartesi
diff --git a/src/shadow-pmas-factory.h b/src/shadow-pmas-factory.h
index 8ec2b0d9d..35514872f 100644
--- a/src/shadow-pmas-factory.h
+++ b/src/shadow-pmas-factory.h
@@ -23,11 +23,23 @@
/// \brief Shadow device.
#include "pma.h"
+#include "shadow-pmas.h"
namespace cartesi {
pma_entry make_shadow_pmas_pma_entry(uint64_t start, uint64_t length);
+template
+void populate_shadow_pmas_state(const PMAS &pmas, shadow_pmas_state *shadow) {
+ static_assert(PMA_SHADOW_PMAS_LENGTH >= sizeof(shadow_pmas_state), "shadow PMAs length is too small");
+ unsigned index = 0;
+ for (const auto &pma : pmas) {
+ shadow->pmas[index].istart = pma.get_istart();
+ shadow->pmas[index].ilength = pma.get_ilength();
+ ++index;
+ }
+}
+
} // namespace cartesi
#endif
diff --git a/src/shadow-pmas.cpp b/src/shadow-pmas.cpp
deleted file mode 100644
index f35fcab3f..000000000
--- a/src/shadow-pmas.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright Cartesi and individual authors (see AUTHORS)
-// SPDX-License-Identifier: LGPL-3.0-or-later
-//
-// This program is free software: you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License as published by the Free
-// Software Foundation, either version 3 of the License, or (at your option) any
-// later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License along
-// with this program (see COPYING). If not, see .
-//
-
-#include "shadow-pmas.h"
-#include "i-device-state-access.h"
-#include "pma-constants.h"
-#include "pma-driver.h"
-
-#include
-#include
-
-namespace cartesi {
-
-/// \brief Shadow device read callback. See ::pma_read.
-static bool shadow_pmas_read(void * /*context*/, i_device_state_access *a, uint64_t offset, uint64_t *pval,
- int log2_size) {
- static_assert(offsetof(shadow_pmas, pmas) == 0, "Unexpected offswet of PMA board");
- static_assert(sizeof(shadow_pma_entry) == 2 * sizeof(uint64_t), "Unexpected size of shadow PMA entry");
- static_assert(sizeof(shadow_pmas) == PMA_MAX * sizeof(shadow_pma_entry), "Unexpected size of Shadow PMA array ");
-
- // Our shadow only supports aligned 64-bit reads
- if (((offset & 7) != 0) || log2_size != 3) {
- return false;
- }
- if (offset < sizeof(shadow_pmas)) {
- offset >>= 3;
- const int p = static_cast(offset >> 1);
- if ((offset & 1) != 0) {
- *pval = a->read_pma_ilength(p);
- } else {
- *pval = a->read_pma_istart(p);
- }
- return true;
- }
- return false;
-}
-
-const pma_driver shadow_pmas_driver = {"SHADOW PMAS", shadow_pmas_read, device_write_error};
-
-} // namespace cartesi
diff --git a/src/shadow-pmas.h b/src/shadow-pmas.h
index a0c79e4a0..1aa7656da 100644
--- a/src/shadow-pmas.h
+++ b/src/shadow-pmas.h
@@ -32,27 +32,24 @@ namespace cartesi {
/// \brief Shadow memory layout
struct PACKED shadow_pma_entry {
- uint64_t start;
- uint64_t length;
+ uint64_t istart;
+ uint64_t ilength;
};
-struct PACKED shadow_pmas {
+struct PACKED shadow_pmas_state {
shadow_pma_entry pmas[PMA_MAX];
};
-/// \brief Global instance of the pma board shadow device driver.
-extern const pma_driver shadow_pmas_driver;
-
/// \brief Obtains the relative address of a PMA entry in shadow memory.
/// \param p Index of desired shadow PMA entry, in 0..31.
/// \returns The address.
-static inline uint64_t shadow_pmas_get_pma_rel_addr(int p) {
- assert(p >= 0 && p < (int) PMA_MAX);
+static inline uint64_t shadow_pmas_get_pma_rel_addr(uint64_t p) {
+ assert(p < (int) PMA_MAX);
return p * sizeof(shadow_pma_entry);
}
/// \brief Obtains the absolute address of a PMA entry in shadow memory.
-static inline uint64_t shadow_pmas_get_pma_abs_addr(int p) {
+static inline uint64_t shadow_pmas_get_pma_abs_addr(uint64_t p) {
return PMA_SHADOW_PMAS_START + shadow_pmas_get_pma_rel_addr(p);
}
diff --git a/src/state-access.h b/src/state-access.h
index c7fc808ce..fd2a5cd60 100644
--- a/src/state-access.h
+++ b/src/state-access.h
@@ -458,26 +458,6 @@ class state_access : public i_state_access {
return {mcycle, interrupt_raised};
}
- uint64_t do_read_pma_istart(int i) const {
- assert(i >= 0 && i < (int) PMA_MAX);
- const auto &pmas = m_m.get_pmas();
- uint64_t istart = 0;
- if (i >= 0 && i < static_cast(pmas.size())) {
- istart = pmas[i].get_istart();
- }
- return istart;
- }
-
- uint64_t do_read_pma_ilength(int i) const {
- assert(i >= 0 && i < (int) PMA_MAX);
- const auto &pmas = m_m.get_pmas();
- uint64_t ilength = 0;
- if (i >= 0 && i < static_cast(pmas.size())) {
- ilength = pmas[i].get_ilength();
- }
- return ilength;
- }
-
template
void do_read_memory_word(uint64_t /*paddr*/, const unsigned char *hpage, uint64_t hoffset, T *pval) const {
*pval = aliased_aligned_read(hpage + hoffset);
@@ -510,52 +490,14 @@ class state_access : public i_state_access {
}
}
- template
- pma_entry &do_find_pma_entry(uint64_t paddr) {
- int i = 0;
- while (true) {
- auto &pma = m_m.get_state().pmas[i];
- // The pmas array always contain a sentinel. It is an entry with
- // zero length. If we hit it, return it
- if (pma.get_length() == 0) {
- return pma;
- }
- // Otherwise, if we found an entry where the access fits, return it
- // Note the "strange" order of arithmetic operations.
- // This is to ensure there is no overflow.
- // Since we know paddr >= start, there is no chance of overflow
- // in the first subtraction.
- // Since length is at least 4096 (an entire page), there is no
- // chance of overflow in the second subtraction.
- if (paddr >= pma.get_start() && paddr - pma.get_start() <= pma.get_length() - sizeof(T)) {
- return pma;
- }
- i++;
- }
- }
-
static unsigned char *do_get_host_memory(pma_entry &pma) {
return pma.get_memory_noexcept().get_host_memory();
}
- pma_entry &do_get_pma_entry(int index) {
- auto &pmas = m_m.get_state().pmas;
- if (index >= static_cast(pmas.size())) {
- return pmas[pmas.size() - 1];
- }
- return pmas[index];
- }
-
- bool do_read_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) {
- device_state_access da(*this, mcycle);
- return pma.get_device_noexcept().get_driver()->read(pma.get_device_noexcept().get_context(), &da, offset, pval,
- log2_size);
- }
-
- execute_status do_write_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) {
- device_state_access da(*this, mcycle);
- return pma.get_device_noexcept().get_driver()->write(pma.get_device_noexcept().get_context(), &da, offset, val,
- log2_size);
+ pma_entry &do_read_pma_entry(uint64_t index) {
+ assert(index < PMA_MAX);
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions)
+ return m_m.get_state().pmas[static_cast(index)];
}
template
@@ -601,7 +543,7 @@ class state_access : public i_state_access {
// Mark page that was on TLB as dirty so we know to update the Merkle tree
if constexpr (ETYPE == TLB_WRITE) {
if (tlbhe.vaddr_page != TLB_INVALID_PAGE) {
- pma_entry &pma = do_get_pma_entry(static_cast(tlbce.pma_index));
+ pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
}
}
@@ -623,7 +565,7 @@ class state_access : public i_state_access {
if (tlbhe.vaddr_page != TLB_INVALID_PAGE) {
tlbhe.vaddr_page = TLB_INVALID_PAGE;
const tlb_cold_entry &tlbce = m_m.get_state().tlb.cold[ETYPE][eidx];
- pma_entry &pma = do_get_pma_entry(static_cast(tlbce.pma_index));
+ pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
} else {
tlbhe.vaddr_page = TLB_INVALID_PAGE;
diff --git a/src/translate-virtual-address.h b/src/translate-virtual-address.h
index fe0811dc4..ecbecf867 100644
--- a/src/translate-virtual-address.h
+++ b/src/translate-virtual-address.h
@@ -46,6 +46,7 @@
#include
#include "compiler-defines.h"
+#include "find-pma-entry.h"
#include "riscv-constants.h"
namespace cartesi {
@@ -58,7 +59,7 @@ namespace cartesi {
/// \returns True if succeeded, false otherwise.
template
static inline bool write_ram_uint64(STATE_ACCESS &a, uint64_t paddr, uint64_t val) {
- auto &pma = a.template find_pma_entry(paddr);
+ auto &pma = find_pma_entry(a, paddr);
if (unlikely(!pma.get_istart_M() || !pma.get_istart_W())) {
return false;
}
@@ -80,7 +81,7 @@ static inline bool write_ram_uint64(STATE_ACCESS &a, uint64_t paddr, uint64_t va
/// \returns True if succeeded, false otherwise.
template
static inline bool read_ram_uint64(STATE_ACCESS &a, uint64_t paddr, uint64_t *pval) {
- auto &pma = a.template find_pma_entry(paddr);
+ auto &pma = find_pma_entry(a, paddr);
if (unlikely(!pma.get_istart_M() || !pma.get_istart_R())) {
return false;
}
diff --git a/tests/lua/cartesi-machine-tests.lua b/tests/lua/cartesi-machine-tests.lua
index 7478d3bfa..dbb7c6fe9 100755
--- a/tests/lua/cartesi-machine-tests.lua
+++ b/tests/lua/cartesi-machine-tests.lua
@@ -291,7 +291,7 @@ local riscv_tests = {
{ "translate_vaddr.bin", 343 },
{ "htif_invalid_ops.bin", 109 },
{ "clint_ops.bin", 133 },
- { "shadow_ops.bin", 114 },
+ { "shadow_ops.bin", 80 },
{ "compressed.bin", 410 },
}
diff --git a/tests/machine/src/shadow_ops.S b/tests/machine/src/shadow_ops.S
index e3c0666af..530f36547 100644
--- a/tests/machine/src/shadow_ops.S
+++ b/tests/machine/src/shadow_ops.S
@@ -32,9 +32,11 @@
#define MCAUSE_STORE_AMO_ACCESS_FAULT 0x7
#define MCAUSE_LOAD_ACCESS_FAULT 0x5
-#define SHADOWS_PMA_LAST_ENTRY_START (31*16)
-#define SHADOWS_PMA_LAST_ENTRY_LENGTH (31*16+8)
+#define SHADOWS_PMA_LAST_ENTRY_ISTART (31*16)
+#define SHADOWS_PMA_LAST_ENTRY_ILENGTH (31*16+8)
#define SHADOWS_PMA_TOTAL_SIZE (32*16)
+#define EMPTY_PMA_ISTART (4)
+#define EMPTY_PMA_ILENGTH (0)
// Section with code
.section .text.init
@@ -47,33 +49,17 @@ _start:
// We are allowed to read the shadow PMAs
li t0, PMA_SHADOW_PMAS_START_DEF;
- ld t1, SHADOWS_PMA_LAST_ENTRY_START(t0);
- bnez t1, fail;
- ld t1, SHADOWS_PMA_LAST_ENTRY_LENGTH(t0);
- bnez t1, fail;
+ ld t1, SHADOWS_PMA_LAST_ENTRY_ISTART(t0);
+ li t2, EMPTY_PMA_ISTART
+ bne t1, t2, fail;
+ ld t1, SHADOWS_PMA_LAST_ENTRY_ILENGTH(t0);
+ li t2, EMPTY_PMA_ILENGTH
+ bne t1, t2, fail;
// Set the exception handler to skip instructions
la t0, skip_insn_trap;
csrw mtvec, t0;
- // Attempt to load a non 8-bytes value from the shadow PMAs
- expect_trap(MCAUSE_LOAD_ACCESS_FAULT,
- li t0, PMA_SHADOW_PMAS_START_DEF;
- lw t1, 0(t0);
- )
-
- // Attempt to load from a misaligned shadow PMAs offset
- expect_trap(MCAUSE_LOAD_ACCESS_FAULT,
- li t0, PMA_SHADOW_PMAS_START_DEF;
- lb t1, 1(t0);
- )
-
- // Attempt to load a PMA entry out of bounds from shadow PMAs
- expect_trap(MCAUSE_LOAD_ACCESS_FAULT,
- li t0, PMA_SHADOW_PMAS_START_DEF;
- ld t1, SHADOWS_PMA_TOTAL_SIZE(t0);
- )
-
// Attempt to load a value from the shadow state
expect_trap(MCAUSE_LOAD_ACCESS_FAULT,
li t0, PMA_SHADOW_STATE_START_DEF;
diff --git a/uarch/Makefile b/uarch/Makefile
index cd80e391c..67cfeadcb 100644
--- a/uarch/Makefile
+++ b/uarch/Makefile
@@ -69,7 +69,6 @@ EMULATOR_SOURCES=\
shadow-tlb.cpp \
shadow-state.cpp \
shadow-uarch-state.cpp \
- shadow-pmas.cpp \
plic.cpp \
clint.cpp
diff --git a/uarch/uarch-machine-state-access.h b/uarch/uarch-machine-state-access.h
index 1b9455099..da9d20e23 100644
--- a/uarch/uarch-machine-state-access.h
+++ b/uarch/uarch-machine-state-access.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef uarch_machine_state_access_H
-#define uarch_machine_state_access_H
+#ifndef UARCH_MACHINE_STATE_ACCESS_H
+#define UARCH_MACHINE_STATE_ACCESS_H
#include "uarch-runtime.h" // must be included first, because of assert
@@ -50,6 +50,8 @@ static void raw_write_memory(uint64_t paddr, T val) {
*p = val;
}
+//??D can we merge this class with the mock_pma_entry in src/replay-step-state-access.h ?
+//??D maybe implement base class in pma.h and subclass here if there is some minor difference?
class uarch_pma_entry final {
public:
struct flags {
@@ -65,28 +67,61 @@ class uarch_pma_entry final {
};
private:
- int m_pma_index{-1};
- uint64_t m_start{};
- uint64_t m_length{};
+
+ uint64_t m_pma_index;
+ uint64_t m_start;
+ uint64_t m_length;
flags m_flags;
- const pma_driver *m_device_driver{};
- void *m_device_context{};
+ const pma_driver *m_driver{nullptr};
+
+ static constexpr flags split_flags(uint64_t istart) {
+ flags f{};
+ f.M = (((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0);
+ f.IO = (((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0);
+ f.E = (((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0);
+ f.R = (((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0);
+ f.W = (((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0);
+ f.X = (((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0);
+ f.IR = (((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0);
+ f.IW = (((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0);
+ f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT);
+ return f;
+ }
public:
- uarch_pma_entry(int pma_index, uint64_t start, uint64_t length, flags flags,
- const pma_driver *pma_driver = nullptr, void *device_context = nullptr) :
- m_pma_index{pma_index},
- m_start{start},
- m_length{length},
- m_flags{flags},
- m_device_driver{pma_driver},
- m_device_context{device_context} {}
- uarch_pma_entry() : uarch_pma_entry(-1, 0, 0, {false, false, true /* empty */}) {
- ;
+ uarch_pma_entry(uint64_t pma_index, uint64_t istart, uint64_t ilength) :
+ m_pma_index{pma_index},
+ m_start{istart & PMA_ISTART_START_MASK},
+ m_length{ilength},
+ m_flags{split_flags(istart)},
+ m_driver{nullptr} {
+ if (m_flags.IO) {
+ switch (m_flags.DID) {
+ case PMA_ISTART_DID::shadow_state:
+ m_driver = &shadow_state_driver;
+ break;
+ case PMA_ISTART_DID::shadow_TLB:
+ m_driver = &shadow_tlb_driver;
+ break;
+ case PMA_ISTART_DID::CLINT:
+ m_driver = &clint_driver;
+ break;
+ case PMA_ISTART_DID::PLIC:
+ m_driver = &plic_driver;
+ break;
+ case PMA_ISTART_DID::HTIF:
+ m_driver = &htif_driver;
+ break;
+ default:
+ // Other unsupported device in uarch (eg. VirtIO)
+ abort();
+ break;
+ }
+ }
}
- int get_index() const {
+ uint64_t get_index() const {
return m_pma_index;
}
@@ -130,12 +165,16 @@ class uarch_pma_entry final {
return m_flags.IR;
}
- const pma_driver *get_device_driver() {
- return m_device_driver;
+ const pma_driver *get_driver() const {
+ return m_driver;
}
- void *get_device_context() {
- return m_device_context;
+ const auto &get_device_noexcept() const {
+ return *this;
+ }
+
+ static void *get_context() {
+ return nullptr;
}
void mark_dirty_page(uint64_t /*address_in_range*/) {
@@ -501,11 +540,11 @@ class uarch_machine_state_access : public i_state_access(shadow_pmas_get_pma_abs_addr(i));
}
- uint64_t do_read_pma_ilength(int i) {
+ uint64_t read_pma_ilength(int i) {
return raw_read_memory(shadow_pmas_get_pma_abs_addr(i) + sizeof(uint64_t));
}
@@ -531,92 +570,22 @@ class uarch_machine_state_access : public i_state_access
- uarch_pma_entry &do_find_pma_entry(uint64_t paddr) {
- for (unsigned int i = 0; i < m_pmas.size(); i++) {
- auto &pma = get_pma_entry(static_cast(i));
- if (pma.get_istart_E()) {
- return pma;
- }
- if (paddr >= pma.get_start() && paddr - pma.get_start() <= pma.get_length() - sizeof(T)) {
- return pma;
- }
- }
- abort();
- }
-
- uarch_pma_entry &do_get_pma_entry(int index) {
+ uarch_pma_entry &do_read_pma_entry(uint64_t index) {
const uint64_t istart = read_pma_istart(index);
const uint64_t ilength = read_pma_ilength(index);
- if (!m_pmas[index]) {
- m_pmas[index] = build_uarch_pma_entry(index, istart, ilength);
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions)
+ int i = static_cast(index);
+ if (!m_pmas[i]) {
+ m_pmas[i] = uarch_pma_entry{index, istart, ilength};
}
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
- return m_pmas[index].value();
+ return m_pmas[i].value();
}
unsigned char *do_get_host_memory(uarch_pma_entry &/*pma*/) {
return nullptr;
}
- bool do_read_device(uarch_pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) {
- device_state_access da(*this, mcycle);
- return pma.get_device_driver()->read(pma.get_device_context(), &da, offset, pval, log2_size);
- }
-
- execute_status do_write_device(uarch_pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) {
- device_state_access da(*this, mcycle);
- return pma.get_device_driver()->write(pma.get_device_context(), &da, offset, val, log2_size);
- }
-
- uarch_pma_entry build_uarch_pma_entry(int index, uint64_t istart, uint64_t ilength) {
- uint64_t start = 0;
- uarch_pma_entry::flags flags;
- split_istart(istart, start, flags);
- const pma_driver *driver = nullptr;
- void *device_ctx = nullptr;
- if (flags.IO) {
- switch (flags.DID) {
- case PMA_ISTART_DID::shadow_state:
- driver = &shadow_state_driver;
- break;
- case PMA_ISTART_DID::shadow_pmas:
- driver = &shadow_pmas_driver;
- break;
- case PMA_ISTART_DID::shadow_TLB:
- driver = &shadow_tlb_driver;
- break;
- case PMA_ISTART_DID::CLINT:
- driver = &clint_driver;
- break;
- case PMA_ISTART_DID::PLIC:
- driver = &plic_driver;
- break;
- case PMA_ISTART_DID::HTIF:
- driver = &htif_driver;
- break;
- default:
- // Other unsupported device in uarch (eg. VirtIO)
- abort();
- break;
- }
- }
- return uarch_pma_entry{index, start, ilength, flags, driver, device_ctx};
- }
-
- static constexpr void split_istart(uint64_t istart, uint64_t &start, uarch_pma_entry::flags &f) {
- f.M = (((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0);
- f.IO = (((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0);
- f.E = (((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0);
- f.R = (((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0);
- f.W = (((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0);
- f.X = (((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0);
- f.IR = (((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0);
- f.IW = (((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0);
- f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT);
- start = istart & PMA_ISTART_START_MASK;
- }
-
template
volatile tlb_hot_entry& do_get_tlb_hot_entry(uint64_t eidx) {
// Volatile is used, so the compiler does not optimize out, or do of order writes.
@@ -680,7 +649,7 @@ class uarch_machine_state_access : public i_state_access(tlbce.pma_index));
+ uarch_pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
}
}
@@ -709,7 +678,7 @@ class uarch_machine_state_access : public i_state_access(eidx);
- uarch_pma_entry &pma = do_get_pma_entry(static_cast(tlbce.pma_index));
+ uarch_pma_entry &pma = do_read_pma_entry(tlbce.pma_index);
pma.mark_dirty_page(tlbce.paddr_page - pma.get_start());
} else {
tlbhe.vaddr_page = TLB_INVALID_PAGE;