aboutsummaryrefslogtreecommitdiffstats
path: root/liblfvm/vm_config.ccm
blob: cd155761ec105cfa4d9d0740b712b4e862293a94 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
 * This source code is released into the public domain.
 */

module;

#include <cstdint>
#include <expected>
#include <string>
#include <system_error>
#include <utility>

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<void, nihil::error>
	{
		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<void, nihil::error>
	{
		// Due to limitations in UCL, memory size can't be larger
		// than std::int64_t.
		if (std::cmp_greater(new_value,
				     std::numeric_limits<std::int64_t>::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<vm_config, nihil::error>;
	
	// 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<vm_config, nihil::error>
{
	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<void, nihil::error>;

} // namespace lfvm