/* * This source code is released into the public domain. */ module; #include #include #include #include #include import nihil; export module liblfvm:vm_config; namespace lfvm { /* * Represents the configuration for a virtual machine. */ export struct vm_config { // The virtual machine name. auto name(this vm_config const &self) -> std::string_view { return self.m_name; } // The virtual machine UUID. // Default: a random UUID. auto uuid(this vm_config const &self) -> nihil::uuid { return self.m_uuid; } auto uuid(this vm_config &self, nihil::uuid const &new_value) -> void { self.m_uuid = new_value; } // How many virtual CPUs the VM will have. Default is 1. // TODO: support the full bhyve CPU topology here. auto ncpus(this vm_config const &self) -> unsigned { return self.c_flag; } [[nodiscard]] auto ncpus(this vm_config &self, unsigned new_value) -> std::expected { if (new_value == 0) return std::unexpected(nihil::error( std::errc::invalid_argument)); self.c_flag = new_value; return {}; } // How much memory to allocate to the guest. // Default is 256MB. auto memory_size(this vm_config const &self) -> std::uint64_t { return self.m_flag; } [[nodiscard]] auto memory_size(this vm_config &self, std::uint64_t new_value) -> std::expected { // Due to limitations in UCL, memory size can't be larger // than std::int64_t. if (std::cmp_greater(new_value, std::numeric_limits::max())) return std::unexpected(nihil::error( std::errc::value_too_large)); if (new_value == 0) return std::unexpected(nihil::error( std::errc::invalid_argument)); self.m_flag = new_value; return {}; } // Whether to destroy this vm_config when the guest powers off. // Defaults to true. auto destroy_on_poweroff(this vm_config const &self) -> bool { return self.D_flag; } auto destroy_on_poweroff(this vm_config &self, bool new_value) -> void { self.D_flag = new_value; } // Whether to wire guest memory. // Defaults to false. auto wire_memory(this vm_config const &self) -> bool { return self.S_flag; } auto wire_memory(this vm_config &self, bool new_value) -> void { self.S_flag = new_value; } // Whether to include memory in core files. // Defaults to false. auto include_memory_in_core(this vm_config const &self) -> bool { return self.C_flag; } auto include_memory_in_core(this vm_config &self, bool new_value) -> void { self.C_flag = new_value; } // Whether to yield when the guest issues a HLT instruction. // Defaults to true. auto yield_on_halt(this vm_config const &self) -> bool { return self.H_flag; } auto yield_on_halt(this vm_config &self, bool new_value) -> void { self.H_flag = new_value; } // Whether to exit when the guest issues a PAUSE instruction. // Defaults to true. auto exit_on_pause(this vm_config const &self) -> bool { return self.P_flag; } auto exit_on_pause(this vm_config &self, bool new_value) -> void { self.P_flag = new_value; } // Whether the RTC keeps UTC time. // Defaults to true. auto rtc_is_utc(this vm_config const &self) -> bool { return self.u_flag; } auto rtc_is_utc(this vm_config &self, bool new_value) -> void { self.u_flag = new_value; } private: friend auto make_vm_config(std::string_view name) -> std::expected; // Create a new, empty configuration. vm_config(std::string_view name) : m_name(name) { } std::string m_name; nihil::uuid m_uuid = nihil::random_uuid(); unsigned c_flag = 1; // number of CPUs std::uint64_t m_flag = 256 * 1024 * 1024; // guest memory size bool C_flag = false; // include memory in core dumps bool D_flag = true; // destroy VM on poweroff bool H_flag = true; // yield on HLT bool P_flag = true; // exit on PAUSE bool S_flag = false; // wire guest memory bool u_flag = true; // RTC is UTC }; /* * Create a new VM config for the given VM. */ export [[nodiscard]] auto make_vm_config(std::string_view name) -> std::expected { if (name.empty()) return std::unexpected(nihil::error( "name may not be empty")); return vm_config(name); } /* * Set a VM option from a text string, e.g. "memory=4g". */ export [[nodiscard]] auto set_vm_option(vm_config &vm, std::string_view option) -> std::expected; } // namespace lfvm