//src/hv/kvm: Begin implementing the acclerant API

The files were moved to be a little bit nicer directory-structure wise.

Errors are now thrown via exceptions. I initially wanted to do
no-exceptions, but doing so will be kind of annoying with third party
libraries and in general, so the shift to exceptions is a Good Thing.
This commit is contained in:
2026-02-15 15:25:35 -05:00
parent d34a6058fb
commit f545235e30
11 changed files with 117 additions and 52 deletions

View File

@@ -1,3 +1,5 @@
# tv2hv # tv2hv
this is a very experimental project to emulate a MSN TV 2 (RCA RM4100) box. this is a very experimental project to emulate a MSN TV 2 (RCA RM4100) box. Currently hilariously linux only, due to the usage of KVM.
At a later time, other hypervisor APIs and platforms may be considered.

View File

@@ -1,5 +1,7 @@
add_executable(tv2hv add_executable(tv2hv
# KVM code
hv/kvm/accelerant.cpp
# utility code # utility code
utils/error.cpp utils/error.cpp

19
src/hv/kvm/accelerant.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include <hv/kvm/accelerant.hpp>
#include <utils/unique_fd.hpp>
#include <sys/file.h>
namespace hv::kvm {
util::Ref<Accelerant> Accelerant::create() {
auto fd = util::UniqueFd{open("/dev/kvm", O_RDWR|O_CLOEXEC)};
if(!fd)
util::throwError(util::Error::systemError());
return util::Ref<Accelerant>(new Accelerant(std::move(fd)));
}
Accelerant::Accelerant(util::UniqueFd&& fd)
: deviceFd(std::move(fd)) {
}
}

26
src/hv/kvm/accelerant.hpp Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include <utils/error.hpp>
#include <utils/types.hpp>
#include <utils/unique_fd.hpp>
namespace hv::kvm {
class VM;
class Accelerant {
/// The fd of the KVM device.
util::UniqueFd deviceFd;
Accelerant(util::UniqueFd&& fd);
public:
/// Creates a new instance of the accelerant.
static util::Ref<Accelerant> create();
/// Create a VM instance.
util::Ref<VM> createVM();
};
} // namespace kvm

0
src/hv/kvm/cpu.hpp Normal file
View File

View File

@@ -1,19 +0,0 @@
#include <utils/error.hpp>
#include <utils/types.hpp>
namespace kvm {
class CPU;
class VM {
/// The primary vCPU.
util::Ref<CPU> vcpu;
public:
/// Creates a new VM instance.
static util::ErrorOr<util::Ref<VM>> create();
// TODO: more stuff
};
} // namespace kvm

View File

@@ -1,4 +1,14 @@
#include <hv/kvm/accelerant.hpp>
#include "utils/error.hpp"
int main(int argc, char** argv) { int main(int argc, char** argv) {
try {
auto accelerant = hv::kvm::Accelerant::create();
printf("Created KVM accelerant\n");
} catch(util::ErrorException& error) {
printf("Error creating KVM Accelerant: %s\n", error.what());
}
return 0;
} }

View File

@@ -13,4 +13,9 @@ namespace util {
return Error::format("System error: {}", std::string_view(pStr)); return Error::format("System error: {}", std::string_view(pStr));
} }
void throwError(const Error& error) {
throw ErrorException(error);
}
} // namespace util } // namespace util

View File

@@ -26,38 +26,19 @@ namespace util {
const char* message() const { return msg.c_str(); } const char* message() const { return msg.c_str(); }
}; };
/// A type which can store either an error or a value. /// An exception which wraps an error.
template <class T> class ErrorException : std::exception {
class ErrorOr { Error error;
std::variant<Error, T> variant; public:
explicit ErrorException(const Error& error)
: error(error) {}
public: const char* what() const noexcept override {
constexpr ErrorOr(const Error& error) : variant(error) {} return error.message();
}
constexpr ErrorOr(const T& value) : variant(value) {}
bool isValue() const { return std::holds_alternative<T>(variant); }
bool isError() const { return std::holds_alternative<Error>(variant); }
const Error& err() const { return std::get<Error>(variant); }
T& value() { return std::get<T>(variant); }
T& value() const { return std::get<T>(variant); }
}; };
template <> /// Utility function to throw an error.
class ErrorOr<void> { void throwError(const Error& error);
std::optional<Error> error;
public:
ErrorOr() = default;
ErrorOr(const Error& error) : error(error) {}
bool isError() const { return error.has_value(); }
const Error& err() const { return error.value(); }
};
} // namespace util } // namespace util

View File

@@ -1,7 +1,6 @@
//! Core types and includes //! Core types and includes
#pragma once #pragma once
#include <base/assert.hpp>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <span> #include <span>

40
src/utils/unique_fd.hpp Normal file
View File

@@ -0,0 +1,40 @@
#pragma once
#include <unistd.h>
namespace util {
/// A wrapper over a file descriptor which
/// cleanly manages the lifetime of it.
class UniqueFd {
int fd;
public:
explicit UniqueFd(int fd) {
reset(fd);
}
~UniqueFd() {
reset();
}
UniqueFd(const UniqueFd&) = delete;
UniqueFd(UniqueFd&& mv) {
fd = mv.fd;
mv.fd = -1;
}
int get() const { return fd; }
operator bool() const {
return fd != -1;
}
void reset(int newFd = -1) {
if(fd != -1)
close(fd);
fd = newFd;
}
};
}