Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplifications to the state access mechanism #303

Merged
merged 4 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
8 changes: 0 additions & 8 deletions src/device-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 58 additions & 0 deletions src/find-pma-entry.h
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
//

#ifndef FIND_PMA_ENTRY_H
#define FIND_PMA_ENTRY_H

#include "compiler-defines.h"
#include <cstdint>

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 <typename T, typename STATE_ACCESS>
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
4 changes: 2 additions & 2 deletions src/htif-factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
2 changes: 1 addition & 1 deletion src/htif-factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
21 changes: 6 additions & 15 deletions src/htif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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<htif_runtime_config *>(context);
// Our HTIF only supports 64-bit writes
if (log2_size != 3) {
return execute_status::failure;
Expand All @@ -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;
Expand Down
14 changes: 0 additions & 14 deletions src/i-device-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
43 changes: 4 additions & 39 deletions src/i-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -665,32 +652,10 @@ class i_state_access { // CRTP
return derived().template do_write_memory_word<T>(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 <typename T>
PMA_ENTRY_TYPE &find_pma_entry(uint64_t paddr) {
return derived().template do_find_pma_entry<T>(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.
Expand Down
5 changes: 0 additions & 5 deletions src/i-uarch-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,6 @@ class i_uarch_state_access { // CRTP
return derived().do_write_word(paddr, data);
}

template <typename T>
pma_entry &find_pma_entry(uint64_t paddr) {
return derived().template do_find_pma_entry<T>(paddr);
}

/// \brief Resets uarch to pristine state
void reset_state() {
return derived().do_reset_state();
Expand Down
17 changes: 11 additions & 6 deletions src/interpret.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -837,7 +838,7 @@ static NO_INLINE std::pair<bool, uint64_t> read_virtual_memory_slow(STATE_ACCESS
vaddr);
return {false, pc};
}
auto &pma = a.template find_pma_entry<T>(paddr);
auto &pma = find_pma_entry<T>(a, paddr);
if (likely(pma.get_istart_R())) {
if (likely(pma.get_istart_M())) {
unsigned char *hpage = a.template replace_tlb_entry<TLB_READ>(vaddr, paddr, pma);
Expand All @@ -848,8 +849,11 @@ static NO_INLINE std::pair<bool, uint64_t> 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<U>::value))) {
const bool status = pma.get_device_noexcept().get_driver()->read(pma.get_device_noexcept().get_context(),
&da, offset, &val, log2_size<U>::value);
if (likely(status)) {
*pval = static_cast<T>(val);
// device logs its own state accesses
return {true, pc};
Expand Down Expand Up @@ -913,7 +917,7 @@ static NO_INLINE std::pair<execute_status, uint64_t> 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<T>(paddr);
auto &pma = find_pma_entry<T>(a, paddr);
if (likely(pma.get_istart_W())) {
if (likely(pma.get_istart_M())) {
unsigned char *hpage = a.template replace_tlb_entry<TLB_WRITE>(vaddr, paddr, pma);
Expand All @@ -923,8 +927,9 @@ static NO_INLINE std::pair<execute_status, uint64_t> 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<U>(static_cast<T>(val64)), log2_size<U>::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<U>(static_cast<T>(val64)), log2_size<U>::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};
Expand Down Expand Up @@ -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<uint16_t>(paddr);
auto &pma = find_pma_entry<uint16_t>(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())) {
Expand Down
Loading
Loading