Skip to content

Commit

Permalink
feat: allow running machines directly from mmaped backing files
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Oct 11, 2024
1 parent 4a3040d commit d03411e
Show file tree
Hide file tree
Showing 16 changed files with 635 additions and 424 deletions.
1 change: 1 addition & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ LIBCARTESI_OBJS:= \
virtio-net-carrier-slirp.o \
dtb.o \
os.o \
os-mmap.o \
htif.o \
htif-factory.o \
shadow-state.o \
Expand Down
2 changes: 2 additions & 0 deletions src/json-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, machine_runtime_con
ju_get_opt_field(j[key], "skip_root_hash_store"s, value.skip_root_hash_store, path + to_string(key) + "/");
ju_get_opt_field(j[key], "skip_version_check"s, value.skip_version_check, path + to_string(key) + "/");
ju_get_opt_field(j[key], "soft_yield"s, value.soft_yield, path + to_string(key) + "/");
ju_get_opt_field(j[key], "backing_storage"s, value.backing_storage, path + to_string(key) + "/");
}

template void ju_get_opt_field<uint64_t>(const nlohmann::json &j, const uint64_t &key, machine_runtime_config &value,
Expand Down Expand Up @@ -1971,6 +1972,7 @@ void to_json(nlohmann::json &j, const machine_runtime_config &runtime) {
{"skip_root_hash_store", runtime.skip_root_hash_store},
{"skip_version_check", runtime.skip_version_check},
{"soft_yield", runtime.soft_yield},
{"backing_storage", runtime.backing_storage},
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/machine-runtime-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define MACHINE_RUNTIME_CONFIG_H

#include <cstdint>
#include <string>

/// \file
/// \brief Runtime configuration for machines.
Expand All @@ -42,6 +43,7 @@ struct machine_runtime_config {
bool skip_root_hash_store{};
bool skip_version_check{};
bool soft_yield{};
std::string backing_storage{};
};

/// \brief CONCURRENCY constants
Expand Down
91 changes: 40 additions & 51 deletions src/machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,39 +108,6 @@ const pma_entry::flags machine::m_cmio_tx_buffer_flags{
PMA_ISTART_DID::cmio_tx_buffer // DID
};

pma_entry machine::make_memory_range_pma_entry(const std::string &description, const memory_range_config &c) {
if (c.image_filename.empty()) {
return make_callocd_memory_pma_entry(description, c.start, c.length);
}
return make_mmapd_memory_pma_entry(description, c.start, c.length, c.image_filename, c.shared);
}

pma_entry machine::make_flash_drive_pma_entry(const std::string &description, const memory_range_config &c) {
return make_memory_range_pma_entry(description, c).set_flags(m_flash_drive_flags);
}

pma_entry machine::make_cmio_rx_buffer_pma_entry(const cmio_config &c) {
const auto description = "cmio rx buffer memory range"s;
if (!c.rx_buffer.image_filename.empty()) {
return make_mmapd_memory_pma_entry(description, PMA_CMIO_RX_BUFFER_START, PMA_CMIO_RX_BUFFER_LENGTH,
c.rx_buffer.image_filename, c.rx_buffer.shared)
.set_flags(m_cmio_rx_buffer_flags);
}
return make_callocd_memory_pma_entry(description, PMA_CMIO_RX_BUFFER_START, PMA_CMIO_RX_BUFFER_LENGTH)
.set_flags(m_cmio_rx_buffer_flags);
}

pma_entry machine::make_cmio_tx_buffer_pma_entry(const cmio_config &c) {
const auto description = "cmio tx buffer memory range"s;
if (!c.tx_buffer.image_filename.empty()) {
return make_mmapd_memory_pma_entry(description, PMA_CMIO_TX_BUFFER_START, PMA_CMIO_TX_BUFFER_LENGTH,
c.tx_buffer.image_filename, c.tx_buffer.shared)
.set_flags(m_cmio_tx_buffer_flags);
}
return make_callocd_memory_pma_entry(description, PMA_CMIO_TX_BUFFER_START, PMA_CMIO_TX_BUFFER_LENGTH)
.set_flags(m_cmio_tx_buffer_flags);
}

pma_entry &machine::register_pma_entry(pma_entry &&pma) {
if (m_s.pmas.capacity() <= m_s.pmas.size()) { // NOLINT(readability-static-accessed-through-instance)
throw std::runtime_error{"too many PMAs when adding "s + pma.get_description()};
Expand Down Expand Up @@ -199,7 +166,9 @@ void machine::replace_memory_range(const memory_range_config &range) {
throw std::invalid_argument{"attempt to replace a protected range "s + pma.get_description()};
}
// replace range preserving original flags
pma = make_memory_range_pma_entry(pma.get_description(), range).set_flags(pma.get_flags());
pma = make_mmapd_memory_pma_entry(pma.get_description(), range.start, range.length, range.image_filename,
range.shared)
.set_flags(pma.get_flags());
return;
}
}
Expand Down Expand Up @@ -322,19 +291,22 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) :
write_reg(reg::iflags, m_c.processor.iflags);
write_reg(reg::iunrep, m_c.processor.iunrep);

// Register RAM
if (m_c.ram.image_filename.empty()) {
register_pma_entry(make_callocd_memory_pma_entry("RAM"s, PMA_RAM_START, m_c.ram.length).set_flags(m_ram_flags));
} else {
register_pma_entry(make_callocd_memory_pma_entry("RAM"s, PMA_RAM_START, m_c.ram.length, m_c.ram.image_filename)
.set_flags(m_ram_flags));
// TODO(edubart): handle case when backing storage is the same dir
// TODO(edubart): remove directory + files on failure
if (!m_r.backing_storage.empty()) {
os_mkdir(m_r.backing_storage.c_str(), 0700);
}

// Register uarch PMAs
m_uarch.register_pmas(m_r);

// Register RAM
register_pma_entry(make_memory_range_pma_entry("RAM"s, m_ram_flags, PMA_RAM_START, m_c.ram.length,
m_c.ram.image_filename, false, m_r));

// Register DTB
pma_entry &dtb = register_pma_entry((m_c.dtb.image_filename.empty() ?
make_callocd_memory_pma_entry("DTB"s, PMA_DTB_START, PMA_DTB_LENGTH) :
make_callocd_memory_pma_entry("DTB"s, PMA_DTB_START, PMA_DTB_LENGTH, m_c.dtb.image_filename))
.set_flags(m_dtb_flags));
pma_entry &dtb = register_pma_entry(make_memory_range_pma_entry("DTB"s, m_dtb_flags, PMA_DTB_START, PMA_DTB_LENGTH,
m_c.dtb.image_filename, false, m_r));

// Register all flash drives
int i = 0;
Expand All @@ -360,13 +332,18 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) :
}
f.length = length;
}
register_pma_entry(make_flash_drive_pma_entry(flash_description, f));
register_pma_entry(make_memory_range_pma_entry(flash_description, m_flash_drive_flags, f.start, f.length,
f.image_filename, f.shared, m_r));
i++;
}

// Register cmio memory ranges
register_pma_entry(make_cmio_tx_buffer_pma_entry(m_c.cmio));
register_pma_entry(make_cmio_rx_buffer_pma_entry(m_c.cmio));
register_pma_entry(
make_memory_range_pma_entry("cmio tx buffer memory range"s, m_cmio_tx_buffer_flags, PMA_CMIO_TX_BUFFER_START,
PMA_CMIO_TX_BUFFER_LENGTH, m_c.cmio.tx_buffer.image_filename, m_c.cmio.tx_buffer.shared, m_r));
register_pma_entry(
make_memory_range_pma_entry("cmio rx buffer memory range"s, m_cmio_rx_buffer_flags, PMA_CMIO_RX_BUFFER_START,
PMA_CMIO_RX_BUFFER_LENGTH, m_c.cmio.rx_buffer.image_filename, m_c.cmio.rx_buffer.shared, m_r));

// Register HTIF device
register_pma_entry(make_htif_pma_entry(PMA_HTIF_START, PMA_HTIF_LENGTH, &m_r.htif));
Expand Down Expand Up @@ -485,7 +462,7 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) :
if (!m_c.tlb.image_filename.empty()) {
// Create a temporary PMA entry just to load TLB contents from an image file
pma_entry tlb_image_pma = make_mmapd_memory_pma_entry("shadow TLB device"s, PMA_SHADOW_TLB_START,
PMA_SHADOW_TLB_LENGTH, m_c.tlb.image_filename, false);
PMA_SHADOW_TLB_LENGTH, m_c.tlb.image_filename);
unsigned char *hmem = tlb_image_pma.get_memory().get_host_memory();
for (uint64_t i = 0; i < PMA_TLB_SIZE; ++i) {
load_tlb_entry<TLB_CODE>(*this, i, hmem);
Expand Down Expand Up @@ -771,9 +748,8 @@ static void store_hash(const machine::hash_type &h, const std::string &dir) {
}

void machine::store(const std::string &dir) const {
if (os_mkdir(dir.c_str(), 0700)) {
throw std::system_error{errno, std::generic_category(), "error creating directory '"s + dir + "'"s};
}
// TODO(edubart): handle the case of saving to backing storage
os_mkdir(dir.c_str(), 0700);
if (!m_r.skip_root_hash_store) {
if (!update_merkle_tree()) {
throw std::runtime_error{"error updating Merkle tree"};
Expand All @@ -789,6 +765,19 @@ void machine::store(const std::string &dir) const {

// NOLINTNEXTLINE(modernize-use-equals-default)
machine::~machine() {
if (!m_r.backing_storage.empty()) {
try {
// TODO(edubart): save root hash?
// TODO(edubart): make tlb a memory PMA?
store_device_pma(*this, find_pma_entry<uint64_t>(PMA_SHADOW_TLB_START), m_r.backing_storage);
auto c = get_serialization_config();
c.store(m_r.backing_storage);
} catch (std::exception &e) {
// Silently fail
(void) fprintf(stderr, "unable to save backing storage machine config: %s\n", e.what());
}
}

// Cleanup TTY if console input was enabled
if (m_c.htif.console_getchar || has_virtio_console()) {
os_close_tty();
Expand Down
22 changes: 0 additions & 22 deletions src/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,28 +77,6 @@ class machine final {
/// \returns Reference to corresponding entry in machine state.
pma_entry &register_pma_entry(pma_entry &&pma);

/// \brief Creates a new PMA entry reflecting a memory range configuration.
/// \param description Informative description of PMA entry for use in error messages
/// \param c Memory range configuration.
/// \returns New PMA entry (with default flags).
static pma_entry make_memory_range_pma_entry(const std::string &description, const memory_range_config &c);

/// \brief Creates a new flash drive PMA entry.
/// \param description Informative description of PMA entry for use in error messages
/// \param c Memory range configuration.
/// \returns New PMA entry with flash drive flags already set.
static pma_entry make_flash_drive_pma_entry(const std::string &description, const memory_range_config &c);

/// \brief Creates a new cmio rx buffer PMA entry.
// \param c Optional cmio configuration
/// \returns New PMA entry with rx buffer flags already set.
static pma_entry make_cmio_rx_buffer_pma_entry(const cmio_config &cmio_config);

/// \brief Creates a new cmio tx buffer PMA entry.
// \param c Optional cmio configuration
/// \returns New PMA entry with tx buffer flags already set.
static pma_entry make_cmio_tx_buffer_pma_entry(const cmio_config &cmio_config);

/// \brief Saves PMAs into files for serialization
/// \param config Machine config to be stored
/// \param directory Directory where PMAs will be stored
Expand Down
4 changes: 4 additions & 0 deletions src/os-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
#define HAVE_MMAP
#endif

#if !defined(NO_FLOCK) && !defined(_WIN32) && !defined(__wasi__)
#define HAVE_FLOCK
#endif

#if !defined(NO_MKDIR)
#define HAVE_MKDIR
#endif
Expand Down
Loading

0 comments on commit d03411e

Please sign in to comment.