lib/sys/src/kvm/vcpu.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const abi = @import("abi.zig");
  3 const run_exit = @import("exit.zig");
  4 const state = @import("state.zig");
  5 const types = @import("types.zig");
  6 
  7 pub const RunControls = struct {
  8     request_interrupt_window: bool = false,
  9     cr8: u64 = 0,
 10     apic_base: u64 = 0,
 11 };
 12 
 13 pub const RunStatus = struct {
 14     ready_for_interrupt_injection: bool,
 15     interrupts_enabled: bool,
 16     flags: u16,
 17     cr8: u64,
 18     apic_base: u64,
 19 };
 20 
 21 pub const Vcpu = struct {
 22     pub const descriptor_capacity: usize = 1;
 23     pub const mapping_capacity: usize = 1;
 24 
 25     operations: types.Operations,
 26     descriptor: types.Descriptor,
 27     mapping: []align(types.page_size) u8,
 28     extensions: types.Extensions,
 29     active: bool = true,
 30 
 31     pub fn deinit(self: *@This()) void {
 32         if (!self.active) return;
 33         std.debug.assert(self.descriptor >= 0);
 34         std.debug.assert(self.mapping.len >= abi.minimum_run_bytes);
 35         self.operations.unmap(self.mapping);
 36         self.operations.close(self.descriptor);
 37         self.active = false;
 38     }
 39 
 40     pub fn run(self: *@This()) (types.RunError || run_exit.DecodeError)!run_exit.Exit {
 41         if (!self.active) return error.Closed;
 42         std.debug.assert(self.mapping.len >= abi.minimum_run_bytes);
 43         switch (self.operations.control(self.descriptor, abi.request.run, 0)) {
 44             .value => {},
 45             .failure => |code| return runError(code),
 46         }
 47         return run_exit.decode(self.mapping);
 48     }
 49 
 50     pub fn setImmediateExit(self: *@This(), requested: bool) types.RunError!void {
 51         if (!self.active) return error.Closed;
 52         if (self.extensions.immediate_exit == 0) {
 53             return error.UnsupportedOperation;
 54         }
 55         std.debug.assert(self.mapping.len >= @sizeOf(abi.RunHeader));
 56         const header: *abi.RunHeader = @ptrCast(self.mapping.ptr);
 57         @atomicStore(u8, &header.immediate_exit, @intFromBool(requested), .monotonic);
 58     }
 59 
 60     pub fn setRunControls(self: *@This(), controls: RunControls) types.RunError!void {
 61         if (!self.active) return error.Closed;
 62         const header = self.runHeader();
 63         header.request_interrupt_window = @intFromBool(controls.request_interrupt_window);
 64         header.cr8 = controls.cr8;
 65         header.apic_base = controls.apic_base;
 66     }
 67 
 68     pub fn runStatus(self: *@This()) types.RunError!RunStatus {
 69         if (!self.active) return error.Closed;
 70         const header = self.runHeader();
 71         return .{
 72             .ready_for_interrupt_injection = header.ready_for_interrupt_injection != 0,
 73             .interrupts_enabled = header.interrupts_enabled != 0,
 74             .flags = header.flags,
 75             .cr8 = header.cr8,
 76             .apic_base = header.apic_base,
 77         };
 78     }
 79 
 80     pub fn capture(self: *@This(), parts: state.Parts) types.StateError!state.Fixed {
 81         if (!self.active) return error.Closed;
 82         if (!fixedStateSupported(parts, self.extensions)) return error.UnsupportedState;
 83         var result = std.mem.zeroes(state.Fixed);
 84         result.valid = parts;
 85         try self.captureBasic(parts, &result);
 86         try self.captureExtended(parts, &result);
 87         return result;
 88     }
 89 
 90     pub fn restore(self: *@This(), snapshot: *const state.Fixed) types.StateError!void {
 91         if (!self.active) return error.Closed;
 92         if (!fixedStateSupported(snapshot.valid, self.extensions)) {
 93             return error.UnsupportedState;
 94         }
 95         try self.restoreBasic(snapshot);
 96         try self.restoreExtended(snapshot);
 97     }
 98 
 99     pub fn readMsrs(self: *@This(), buffer: anytype) types.StateError!void {
100         if (!self.active) return error.Closed;
101         validateMsrBuffer(@TypeOf(buffer.*));
102         if (buffer.count > buffer.entries.len) return error.CapacityExceeded;
103         const result = types.controlRetry(
104             self.operations,
105             self.descriptor,
106             abi.request.get_msrs,
107             @intFromPtr(buffer),
108         );
109         try expectTransfer(result, buffer.count);
110     }
111 
112     pub fn writeMsrs(self: *@This(), buffer: anytype) types.StateError!void {
113         if (!self.active) return error.Closed;
114         validateMsrBuffer(@TypeOf(buffer.*));
115         if (buffer.count > buffer.entries.len) return error.CapacityExceeded;
116         const result = types.controlRetry(
117             self.operations,
118             self.descriptor,
119             abi.request.set_msrs,
120             @intFromPtr(buffer),
121         );
122         try expectTransfer(result, buffer.count);
123     }
124 
125     pub fn readCpuid(self: *@This(), buffer: anytype) types.StateError!void {
126         if (!self.active) return error.Closed;
127         if (self.extensions.extended_cpuid == 0) return error.UnsupportedState;
128         validateCpuidBuffer(@TypeOf(buffer.*));
129         if (buffer.count > buffer.entries.len) return error.CapacityExceeded;
130         try types.stateControl(
131             self.operations,
132             self.descriptor,
133             abi.request.get_cpuid,
134             @intFromPtr(buffer),
135         );
136     }
137 
138     pub fn writeCpuid(self: *@This(), buffer: anytype) types.StateError!void {
139         if (!self.active) return error.Closed;
140         if (self.extensions.extended_cpuid == 0) return error.UnsupportedState;
141         validateCpuidBuffer(@TypeOf(buffer.*));
142         if (buffer.count > buffer.entries.len) return error.CapacityExceeded;
143         try types.stateControl(
144             self.operations,
145             self.descriptor,
146             abi.request.set_cpuid,
147             @intFromPtr(buffer),
148         );
149     }
150 
151     fn captureBasic(
152         self: *@This(),
153         parts: state.Parts,
154         result: *state.Fixed,
155     ) types.StateError!void {
156         if (parts.registers) try self.get(abi.request.get_registers, &result.registers);
157         if (parts.special_registers) {
158             try self.get(abi.request.get_special_registers, &result.special_registers);
159         }
160         if (parts.fpu) try self.get(abi.request.get_fpu, &result.fpu);
161     }
162 
163     fn captureExtended(
164         self: *@This(),
165         parts: state.Parts,
166         result: *state.Fixed,
167     ) types.StateError!void {
168         if (parts.events) try self.get(abi.request.get_vcpu_events, &result.events);
169         if (parts.debug_registers) {
170             try self.get(abi.request.get_debug_registers, &result.debug_registers);
171         }
172         if (parts.xsave) try self.get(abi.request.get_xsave, &result.xsave);
173         if (parts.xcrs) try self.get(abi.request.get_xcrs, &result.xcrs);
174         if (parts.multiprocessor) {
175             try self.get(abi.request.get_mp_state, &result.multiprocessor);
176         }
177     }
178 
179     fn restoreBasic(self: *@This(), snapshot: *const state.Fixed) types.StateError!void {
180         if (snapshot.valid.special_registers) {
181             try self.set(abi.request.set_special_registers, &snapshot.special_registers);
182         }
183         if (snapshot.valid.registers) {
184             try self.set(abi.request.set_registers, &snapshot.registers);
185         }
186         if (snapshot.valid.fpu) try self.set(abi.request.set_fpu, &snapshot.fpu);
187     }
188 
189     fn restoreExtended(
190         self: *@This(),
191         snapshot: *const state.Fixed,
192     ) types.StateError!void {
193         if (snapshot.valid.events) {
194             try self.set(abi.request.set_vcpu_events, &snapshot.events);
195         }
196         if (snapshot.valid.debug_registers) {
197             try self.set(abi.request.set_debug_registers, &snapshot.debug_registers);
198         }
199         if (snapshot.valid.xsave) try self.set(abi.request.set_xsave, &snapshot.xsave);
200         if (snapshot.valid.xcrs) try self.set(abi.request.set_xcrs, &snapshot.xcrs);
201         if (snapshot.valid.multiprocessor) {
202             try self.set(abi.request.set_mp_state, &snapshot.multiprocessor);
203         }
204     }
205 
206     fn get(self: *@This(), request: u32, destination: anytype) types.StateError!void {
207         std.debug.assert(request != 0);
208         try types.stateControl(
209             self.operations,
210             self.descriptor,
211             request,
212             @intFromPtr(destination),
213         );
214     }
215 
216     fn set(self: *@This(), request: u32, source: anytype) types.StateError!void {
217         std.debug.assert(request != 0);
218         try types.stateControl(
219             self.operations,
220             self.descriptor,
221             request,
222             @intFromPtr(source),
223         );
224     }
225 
226     fn runHeader(self: *@This()) *abi.RunHeader {
227         std.debug.assert(self.mapping.len >= @sizeOf(abi.RunHeader));
228         return @ptrCast(self.mapping.ptr);
229     }
230 };
231 
232 fn runError(code: types.Errno) types.RunError {
233     return switch (code) {
234         .INTR => error.Interrupted,
235         .AGAIN => error.WouldBlock,
236         .ACCES, .PERM => error.AccessDenied,
237         .BADF, .NODEV => error.Closed,
238         .FAULT, .INVAL => error.InvalidRunState,
239         .NOSYS, .NOTTY, .OPNOTSUPP => error.UnsupportedOperation,
240         else => error.RunFailed,
241     };
242 }
243 
244 fn expectTransfer(result: types.RawResult, expected: u32) types.StateError!void {
245     switch (result) {
246         .value => |value| {
247             if (value != expected) return error.PartialTransfer;
248         },
249         .failure => |code| return switch (code) {
250             .ACCES, .PERM => error.AccessDenied,
251             .BADF, .NODEV => error.Closed,
252             .INVAL, .NOSYS, .NOTTY, .OPNOTSUPP => error.UnsupportedState,
253             else => error.StateFailed,
254         },
255     }
256 }
257 
258 fn fixedStateSupported(parts: state.Parts, extensions: types.Extensions) bool {
259     if (parts.events and extensions.vcpu_events == 0) return false;
260     if (parts.debug_registers and extensions.debug_registers == 0) return false;
261     if (parts.xsave and extensions.xsave == 0) return false;
262     if (parts.xcrs and extensions.xcrs == 0) return false;
263     if (parts.multiprocessor and extensions.multiprocessor_state == 0) return false;
264     return true;
265 }
266 
267 fn validateMsrBuffer(comptime Buffer: type) void {
268     comptime {
269         if (!@hasField(Buffer, "count") or !@hasField(Buffer, "entries")) {
270             @compileError("expected abi.MsrBuffer");
271         }
272         if (@FieldType(Buffer, "count") != u32) @compileError("invalid MSR count type");
273         if (@typeInfo(@FieldType(Buffer, "entries")).array.child != abi.MsrEntry) {
274             @compileError("invalid MSR entry type");
275         }
276         if (@offsetOf(Buffer, "entries") != @sizeOf(abi.MsrHeader)) {
277             @compileError("invalid MSR buffer layout");
278         }
279     }
280 }
281 
282 fn validateCpuidBuffer(comptime Buffer: type) void {
283     comptime {
284         if (!@hasField(Buffer, "count") or !@hasField(Buffer, "entries")) {
285             @compileError("expected abi.CpuidBuffer");
286         }
287         if (@FieldType(Buffer, "count") != u32) @compileError("invalid CPUID count type");
288         if (@typeInfo(@FieldType(Buffer, "entries")).array.child != abi.CpuidEntry) {
289             @compileError("invalid CPUID entry type");
290         }
291         if (@offsetOf(Buffer, "entries") != @sizeOf(abi.CpuidHeader)) {
292             @compileError("invalid CPUID buffer layout");
293         }
294     }
295 }