diff --git a/README.md b/README.md index e4b44d1..753d758 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # 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. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 605f0ed..63e524e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,7 @@ add_executable(tv2hv + # KVM code + hv/kvm/accelerant.cpp # utility code utils/error.cpp diff --git a/src/hv/kvm/accelerant.cpp b/src/hv/kvm/accelerant.cpp new file mode 100644 index 0000000..559ca08 --- /dev/null +++ b/src/hv/kvm/accelerant.cpp @@ -0,0 +1,19 @@ +#include +#include + +#include + +namespace hv::kvm { + + util::Ref Accelerant::create() { + auto fd = util::UniqueFd{open("/dev/kvm", O_RDWR|O_CLOEXEC)}; + if(!fd) + util::throwError(util::Error::systemError()); + + return util::Ref(new Accelerant(std::move(fd))); + } + + Accelerant::Accelerant(util::UniqueFd&& fd) + : deviceFd(std::move(fd)) { + } +} diff --git a/src/hv/kvm/accelerant.hpp b/src/hv/kvm/accelerant.hpp new file mode 100644 index 0000000..94e3a03 --- /dev/null +++ b/src/hv/kvm/accelerant.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +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 create(); + + /// Create a VM instance. + util::Ref createVM(); + }; + +} // namespace kvm diff --git a/src/hv/kvm/cpu.hpp b/src/hv/kvm/cpu.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/kvm/vm.hpp b/src/kvm/vm.hpp deleted file mode 100644 index 8964db9..0000000 --- a/src/kvm/vm.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -namespace kvm { - - class CPU; - - class VM { - /// The primary vCPU. - util::Ref vcpu; - - public: - /// Creates a new VM instance. - static util::ErrorOr> create(); - - // TODO: more stuff - }; - -} // namespace kvm diff --git a/src/main.cpp b/src/main.cpp index 49207c4..d77ca41 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,14 @@ - +#include +#include "utils/error.hpp" 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; } diff --git a/src/utils/error.cpp b/src/utils/error.cpp index 17b4443..fada60a 100644 --- a/src/utils/error.cpp +++ b/src/utils/error.cpp @@ -13,4 +13,9 @@ namespace util { return Error::format("System error: {}", std::string_view(pStr)); } + + void throwError(const Error& error) { + throw ErrorException(error); + } + } // namespace util diff --git a/src/utils/error.hpp b/src/utils/error.hpp index 5eb8d94..af8008b 100644 --- a/src/utils/error.hpp +++ b/src/utils/error.hpp @@ -26,38 +26,19 @@ namespace util { const char* message() const { return msg.c_str(); } }; - /// A type which can store either an error or a value. - template - class ErrorOr { - std::variant variant; + /// An exception which wraps an error. + class ErrorException : std::exception { + Error error; + public: + explicit ErrorException(const Error& error) + : error(error) {} - public: - constexpr ErrorOr(const Error& error) : variant(error) {} - - constexpr ErrorOr(const T& value) : variant(value) {} - - bool isValue() const { return std::holds_alternative(variant); } - - bool isError() const { return std::holds_alternative(variant); } - - const Error& err() const { return std::get(variant); } - - T& value() { return std::get(variant); } - - T& value() const { return std::get(variant); } + const char* what() const noexcept override { + return error.message(); + } }; - template <> - class ErrorOr { - std::optional error; - - public: - ErrorOr() = default; - ErrorOr(const Error& error) : error(error) {} - - bool isError() const { return error.has_value(); } - - const Error& err() const { return error.value(); } - }; + /// Utility function to throw an error. + void throwError(const Error& error); } // namespace util diff --git a/src/utils/types.hpp b/src/utils/types.hpp index 2b493dc..d74dc33 100644 --- a/src/utils/types.hpp +++ b/src/utils/types.hpp @@ -1,7 +1,6 @@ //! Core types and includes #pragma once -#include #include #include #include diff --git a/src/utils/unique_fd.hpp b/src/utils/unique_fd.hpp new file mode 100644 index 0000000..a64c628 --- /dev/null +++ b/src/utils/unique_fd.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +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; + } + + }; + +}