Skip to content

Commit

Permalink
feat!: add VirtIO configs to C/Lua APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Jan 19, 2024
1 parent 2097ada commit 83f72e1
Show file tree
Hide file tree
Showing 7 changed files with 429 additions and 54 deletions.
148 changes: 148 additions & 0 deletions src/clua-machine-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,16 @@ static void push_cm_memory_range_config(lua_State *L, const cm_memory_range_conf
clua_setbooleanfield(L, m->shared, "shared", -1);
}

/// \brief Pushes cm_virtio_hostfwd_config to the Lua stack
/// \param L Lua state.
/// \param m VirtIO host forward config to be pushed.
static void push_cm_virtio_hostfwd_config(lua_State *L, const cm_virtio_hostfwd_config *m) {
lua_newtable(L);
clua_setbooleanfield(L, m->is_udp, "is_udp", -1);
clua_setintegerfield(L, m->host_port, "host_port", -1);
clua_setintegerfield(L, m->guest_port, "guest_port", -1);
}

/// \brief Pushes cm_rollup_config to the Lua stack
/// \param L Lua state.
/// \param r Rollup config to be pushed.
Expand Down Expand Up @@ -913,6 +923,57 @@ static void push_cm_flash_drive_configs(lua_State *L, const cm_memory_range_conf
}
}

/// \brief Pushes cm_virtio_hostfwd_configs to the Lua stack
/// \param L Lua state.
/// \param virtio_hostfwds VirtIO host forward configuration array to be pushed.
static void push_cm_virtio_hostfwd_configs(lua_State *L, const cm_virtio_hostfwd_config_array *virtio_hostfwds) {
lua_newtable(L);
for (size_t j = 0; j < virtio_hostfwds->count; ++j) {
push_cm_virtio_hostfwd_config(L, &virtio_hostfwds->entry[j]);
lua_rawseti(L, -2, static_cast<lua_Integer>(j) + 1);
}
}

/// \brief Pushes cm_virtio_device_config to the Lua stack
/// \param L Lua state.
/// \param m VirtIO device config to be pushed.
static void push_cm_virtio_device_config(lua_State *L, const cm_virtio_device_config *v) {
lua_newtable(L);
switch (v->type) {
case CM_VIRTIO_DEVICE_CONSOLE:
clua_setstringfield(L, "console", "type", -1);
break;
case CM_VIRTIO_DEVICE_P9FS:
clua_setstringfield(L, "p9fs", "type", -1);
clua_setstringfield(L, v->device.p9fs.tag, "tag", -1);
clua_setstringfield(L, v->device.p9fs.host_directory, "host_directory", -1);
break;
case CM_VIRTIO_DEVICE_NET_USER:
clua_setstringfield(L, "net-user", "type", -1);
push_cm_virtio_hostfwd_configs(L, &v->device.net_user.hostfwd);
lua_setfield(L, -2, "hostfwd");
break;
case CM_VIRTIO_DEVICE_NET_TUNTAP:
clua_setstringfield(L, "net-tuntap", "type", -1);
clua_setstringfield(L, v->device.net_tuntap.iface, "iface", -1);
break;
default:
luaL_error(L, "invalid virtio device config type");
break;
}
}

/// \brief Pushes cm_virtio_config_array to the Lua stack
/// \param L Lua state.
/// \param virtio VirtIO configuration array to be pushed.
static void push_cm_virtio_configs(lua_State *L, const cm_virtio_config_array *virtio) {
lua_newtable(L);
for (size_t j = 0; j < virtio->count; ++j) {
push_cm_virtio_device_config(L, &virtio->entry[j]);
lua_rawseti(L, -2, static_cast<lua_Integer>(j) + 1);
}
}

/// \brief Pushes a cm_uarch_ram_config to the Lua stack
/// \param L Lua state.
/// \param r microarchitecture RAM configuration to be pushed.
Expand Down Expand Up @@ -964,6 +1025,8 @@ void clua_push_cm_machine_config(lua_State *L, const cm_machine_config *c) {
lua_setfield(L, -2, "plic"); // config
push_cm_flash_drive_configs(L, &c->flash_drive); // config flash_drive
lua_setfield(L, -2, "flash_drive"); // config
push_cm_virtio_configs(L, &c->virtio); // config virtio
lua_setfield(L, -2, "virtio"); // config
push_cm_ram_config(L, &c->ram); // config ram
lua_setfield(L, -2, "ram"); // config
push_cm_dtb_config(L, &c->dtb); // config dtb
Expand Down Expand Up @@ -1030,6 +1093,17 @@ cm_memory_range_config *clua_check_cm_memory_range_config(lua_State *L, int tabi
return m;
}

cm_virtio_hostfwd_config *clua_check_cm_virtio_hostfwd_config(lua_State *L, int tabidx, const char *what,
cm_virtio_hostfwd_config *m) {
if (!lua_istable(L, tabidx)) {
luaL_error(L, "%s virtio hostfwd not a table", what);
}
m->is_udp = opt_boolean_field(L, tabidx, "is_udp");
m->guest_port = check_uint_field(L, tabidx, "guest_port");
m->host_port = check_uint_field(L, tabidx, "host_port");
return m;
}

/// \brief Loads rollup config from Lua to cm_rollup_config
/// \param L Lua state
/// \param tabidx Config stack index
Expand Down Expand Up @@ -1082,6 +1156,79 @@ static void check_cm_flash_drive_configs(lua_State *L, int tabidx, cm_memory_ran
lua_pop(L, 1);
}

/// \brief Loads a C api VirtIO host forward configs from a Lua machine config
/// \param L Lua state
/// \param tabidx Machine config stack index
/// \param fs Receives allocated array of VirtIO host forward configs
static void check_cm_virtio_hostfwd_configs(lua_State *L, int tabidx, cm_virtio_hostfwd_config_array *hostfwds) {
memset(hostfwds, 0, sizeof(cm_virtio_hostfwd_config_array));
if (!opt_table_field(L, tabidx, "hostfwd")) {
return;
}
auto virtio_hostfwd_table_idx = lua_gettop(L);
const size_t count = luaL_len(L, virtio_hostfwd_table_idx);
if (count > CM_VIRTIO_HOSTFWD_CONFIGS_MAX_SIZE) {
luaL_error(L, "too many host forwards (expected max %d, got %d)", CM_VIRTIO_HOSTFWD_CONFIGS_MAX_SIZE,
static_cast<int>(hostfwds->count));
}
hostfwds->count = count;
hostfwds->entry = new cm_virtio_hostfwd_config[count]{};
for (unsigned i = 1; i <= hostfwds->count; ++i) {
lua_geti(L, virtio_hostfwd_table_idx, i);
clua_check_cm_virtio_hostfwd_config(L, -1, "hostfwd", &hostfwds->entry[i - 1]);
lua_pop(L, 1);
}
lua_pop(L, 1);
}

cm_virtio_device_config *clua_check_cm_virtio_device_config(lua_State *L, int tabidx, cm_virtio_device_config *m) {
if (!lua_istable(L, tabidx)) {
luaL_error(L, "virtio device not a table");
}
const std::string type = check_string_field(L, tabidx, "type");
if (type == "console") {
m->type = CM_VIRTIO_DEVICE_CONSOLE;
} else if (type == "p9fs") {
m->type = CM_VIRTIO_DEVICE_P9FS;
m->device.p9fs.tag = opt_copy_string_field(L, tabidx, "tag");
m->device.p9fs.host_directory = opt_copy_string_field(L, tabidx, "host_directory");
} else if (type == "net-user") {
m->type = CM_VIRTIO_DEVICE_NET_USER;
check_cm_virtio_hostfwd_configs(L, tabidx, &m->device.net_user.hostfwd);
} else if (type == "net-tuntap") {
m->type = CM_VIRTIO_DEVICE_NET_TUNTAP;
m->device.net_tuntap.iface = opt_copy_string_field(L, tabidx, "iface");
} else {
luaL_error(L, "invalid virtio device type '%s'", type.c_str());
}
return m;
}

/// \brief Loads a C api virtio configs from a Lua machine config
/// \param L Lua state
/// \param tabidx Machine config stack index
/// \param virtio Receives allocated array of virtio configs
static void check_cm_virtio_configs(lua_State *L, int tabidx, cm_virtio_config_array *virtio) {
memset(virtio, 0, sizeof(cm_virtio_config_array));
if (!opt_table_field(L, tabidx, "virtio")) {
return;
}
auto virtio_table_idx = lua_gettop(L);
const size_t count = luaL_len(L, virtio_table_idx);
if (count > CM_VIRTIO_CONFIGS_MAX_SIZE) {
luaL_error(L, "too many virtio devices (expected max %d, got %d)", CM_VIRTIO_CONFIGS_MAX_SIZE,
static_cast<int>(virtio->count));
}
virtio->count = count;
virtio->entry = new cm_virtio_device_config[count]{};
for (unsigned i = 1; i <= virtio->count; ++i) {
lua_geti(L, virtio_table_idx, i);
clua_check_cm_virtio_device_config(L, -1, &virtio->entry[i - 1]);
lua_pop(L, 1);
}
lua_pop(L, 1);
}

/// \brief Loads processor config from a Lua to C api machine config
/// \param L Lua state
/// \param tabidx Config stack index
Expand Down Expand Up @@ -1294,6 +1441,7 @@ cm_machine_config *clua_check_cm_machine_config(lua_State *L, int tabidx, int ct
check_cm_uarch_config(L, tabidx, &config->uarch);
check_cm_rollup_config(L, tabidx, &config->rollup);
check_cm_flash_drive_configs(L, tabidx, &config->flash_drive);
check_cm_virtio_configs(L, tabidx, &config->virtio);
managed.release();
lua_pop(L, 1); //??DD I don't think lua_pop can throw, but we should check
return config;
Expand Down
23 changes: 1 addition & 22 deletions src/dtb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,7 @@ void dtb_init(const machine_config &c, unsigned char *dtb_start, uint64_t dtb_le
fdt.prop_u32_list<2>("interrupts-extended", {INTC_PHANDLE, X_HOST});
fdt.end_node();
}
if (c.htif.console_getchar) { // virtio console
const uint32_t virtio_idx = 0;
const uint64_t virtio_paddr = PMA_FIRST_VIRTIO_START + virtio_idx * PMA_VIRTIO_LENGTH;
const uint32_t plic_irq_id = virtio_idx + 1;
fdt.begin_node_num("virtio", virtio_paddr);
fdt.prop_string("compatible", "virtio,mmio");
fdt.prop_u64_list<2>("reg", {virtio_paddr, PMA_VIRTIO_LENGTH});
fdt.prop_u32_list<2>("interrupts-extended", {PLIC_PHANDLE, plic_irq_id});
fdt.end_node();
}
if (c.htif.console_getchar) { // virtio 9p
const uint32_t virtio_idx = 1;
const uint64_t virtio_paddr = PMA_FIRST_VIRTIO_START + virtio_idx * PMA_VIRTIO_LENGTH;
const uint32_t plic_irq_id = virtio_idx + 1;
fdt.begin_node_num("virtio", virtio_paddr);
fdt.prop_string("compatible", "virtio,mmio");
fdt.prop_u64_list<2>("reg", {virtio_paddr, PMA_VIRTIO_LENGTH});
fdt.prop_u32_list<2>("interrupts-extended", {PLIC_PHANDLE, plic_irq_id});
fdt.end_node();
}
if (c.htif.console_getchar) { // virtio net
const uint32_t virtio_idx = 2;
for (uint32_t virtio_idx = 0; virtio_idx < c.virtio.size(); ++virtio_idx) { // virtio
const uint64_t virtio_paddr = PMA_FIRST_VIRTIO_START + virtio_idx * PMA_VIRTIO_LENGTH;
const uint32_t plic_irq_id = virtio_idx + 1;
fdt.begin_node_num("virtio", virtio_paddr);
Expand Down
125 changes: 125 additions & 0 deletions src/machine-c-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <regex>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>

#include "i-virtual-machine.h"
#include "machine-c-api-internal.h"
Expand Down Expand Up @@ -220,6 +222,94 @@ static cm_memory_range_config convert_to_c(const cartesi::memory_range_config &c
return new_c_memory_range_config;
}

// ----------------------------------------------
// VirtIO host forward configuration conversion functions
// ----------------------------------------------
static cartesi::virtio_hostfwd_config convert_from_c(const cm_virtio_hostfwd_config *c_config) {
if (c_config == nullptr) {
throw std::invalid_argument("invalid memory range configuration");
}
cartesi::virtio_hostfwd_config new_cpp_virtio_hostfwd_config{c_config->is_udp, c_config->host_port,
c_config->guest_port};
return new_cpp_virtio_hostfwd_config;
}

static cm_virtio_hostfwd_config convert_to_c(const cartesi::virtio_hostfwd_config &cpp_config) {
cm_virtio_hostfwd_config new_c_virtio_hostfwd_config{};
new_c_virtio_hostfwd_config.is_udp = cpp_config.is_udp;
new_c_virtio_hostfwd_config.guest_port = cpp_config.guest_port;
new_c_virtio_hostfwd_config.host_port = cpp_config.host_port;
return new_c_virtio_hostfwd_config;
}

// ----------------------------------------------
// VirtIO device configuration conversion functions
// ----------------------------------------------
static cartesi::virtio_device_config convert_from_c(const cm_virtio_device_config *c_config) {
if (c_config == nullptr) {
throw std::invalid_argument("invalid virtio device configuration");
}
switch (c_config->type) {
case CM_VIRTIO_DEVICE_CONSOLE:
return cartesi::virtio_console_config{};
case CM_VIRTIO_DEVICE_P9FS: {
cartesi::virtio_p9fs_config new_cpp_virtio_device_config{};
new_cpp_virtio_device_config.tag = null_to_empty(c_config->device.p9fs.tag);
new_cpp_virtio_device_config.host_directory = null_to_empty(c_config->device.p9fs.host_directory);
return new_cpp_virtio_device_config;
}
case CM_VIRTIO_DEVICE_NET_USER: {
cartesi::virtio_net_user_config new_cpp_virtio_device_config{};
for (size_t i = 0; i < c_config->device.net_user.hostfwd.count; ++i) {
new_cpp_virtio_device_config.hostfwd.push_back(
convert_from_c(&(c_config->device.net_user.hostfwd.entry[i])));
}
return new_cpp_virtio_device_config;
}
case CM_VIRTIO_DEVICE_NET_TUNTAP: {
cartesi::virtio_net_tuntap_config new_cpp_virtio_device_config{};
new_cpp_virtio_device_config.iface = null_to_empty(c_config->device.net_tuntap.iface);
return new_cpp_virtio_device_config;
}
default:
throw std::invalid_argument("invalid virtio device configuration");
}
}

static cm_virtio_device_config convert_to_c(const cartesi::virtio_device_config &cpp_config) {
return std::visit(
[](const auto &cpp_virtio_device_config) -> cm_virtio_device_config {
using T = std::decay_t<decltype(cpp_virtio_device_config)>;
cm_virtio_device_config new_c_virtio_device_config{};
if constexpr (std::is_same_v<T, cartesi::virtio_console_config>) {
new_c_virtio_device_config.type = CM_VIRTIO_DEVICE_CONSOLE;
} else if constexpr (std::is_same_v<T, cartesi::virtio_p9fs_config>) {
new_c_virtio_device_config.type = CM_VIRTIO_DEVICE_P9FS;
new_c_virtio_device_config.device.p9fs.tag = convert_to_c(cpp_virtio_device_config.tag);
new_c_virtio_device_config.device.p9fs.host_directory =
convert_to_c(cpp_virtio_device_config.host_directory);
} else if constexpr (std::is_same_v<T, cartesi::virtio_net_user_config>) {
cm_virtio_hostfwd_config_array new_c_hostfdw;
new_c_hostfdw.count = cpp_virtio_device_config.hostfwd.size();
new_c_hostfdw.entry = new cm_virtio_hostfwd_config[new_c_hostfdw.count];
memset(new_c_hostfdw.entry, 0, sizeof(cm_virtio_hostfwd_config) * new_c_hostfdw.count);
for (size_t i = 0; i < new_c_hostfdw.count; ++i) {
new_c_hostfdw.entry[i] = convert_to_c(cpp_virtio_device_config.hostfwd[i]);
}

new_c_virtio_device_config.type = CM_VIRTIO_DEVICE_NET_USER;
new_c_virtio_device_config.device.net_user.hostfwd = new_c_hostfdw;
} else if constexpr (std::is_same_v<T, cartesi::virtio_net_tuntap_config>) {
new_c_virtio_device_config.type = CM_VIRTIO_DEVICE_NET_TUNTAP;
new_c_virtio_device_config.device.net_tuntap.iface = convert_to_c(cpp_virtio_device_config.iface);
} else {
throw std::invalid_argument("invalid virtio device configuration");
}
return new_c_virtio_device_config;
},
cpp_config);
}

// ----------------------------------------------
// TLB configuration conversion functions
// ----------------------------------------------
Expand Down Expand Up @@ -411,6 +501,10 @@ cartesi::machine_config convert_from_c(const cm_machine_config *c_config) {
new_cpp_machine_config.flash_drive.push_back(convert_from_c(&(c_config->flash_drive.entry[i])));
}

for (size_t i = 0; i < c_config->virtio.count; ++i) {
new_cpp_machine_config.virtio.push_back(convert_from_c(&(c_config->virtio.entry[i])));
}

return new_cpp_machine_config;
}

Expand All @@ -425,12 +519,23 @@ cm_memory_range_config_array convert_to_c(const cartesi::flash_drive_configs &fl
return new_flash_drive;
}

cm_virtio_config_array convert_to_c(const cartesi::virtio_configs &virtio) {
cm_virtio_config_array new_virtio;
new_virtio.count = virtio.size();
new_virtio.entry = new cm_virtio_device_config[virtio.size()]{};
for (size_t i = 0; i < new_virtio.count; ++i) {
new_virtio.entry[i] = convert_to_c(virtio[i]);
}
return new_virtio;
}

cm_machine_config *convert_to_c(const cartesi::machine_config &cpp_config) {
auto *new_machine_config = new cm_machine_config{};
new_machine_config->processor = convert_to_c(cpp_config.processor);
new_machine_config->ram = convert_to_c(cpp_config.ram);
new_machine_config->dtb = convert_to_c(cpp_config.dtb);
new_machine_config->flash_drive = convert_to_c(cpp_config.flash_drive);
new_machine_config->virtio = convert_to_c(cpp_config.virtio);
new_machine_config->tlb = convert_to_c(cpp_config.tlb);
new_machine_config->clint = convert_to_c(cpp_config.clint);
new_machine_config->plic = convert_to_c(cpp_config.plic);
Expand Down Expand Up @@ -765,6 +870,26 @@ void cm_delete_machine_config(const cm_machine_config *config) {
delete[] config->flash_drive.entry[i].image_filename;
}
delete[] config->flash_drive.entry;

for (size_t i = 0; i < config->virtio.count; ++i) {
const cm_virtio_device_config &entry = config->virtio.entry[i];
switch (entry.type) {
case CM_VIRTIO_DEVICE_NET_USER:
delete[] entry.device.net_user.hostfwd.entry;
break;
case CM_VIRTIO_DEVICE_P9FS:
delete[] entry.device.p9fs.tag;
delete[] entry.device.p9fs.host_directory;
break;
case CM_VIRTIO_DEVICE_NET_TUNTAP:
delete[] entry.device.net_tuntap.iface;
break;
default:
break;
}
}
delete[] config->virtio.entry;

delete[] config->dtb.image_filename;
delete[] config->dtb.bootargs;
delete[] config->dtb.init;
Expand Down
Loading

0 comments on commit 83f72e1

Please sign in to comment.