Alioth Code Coverage

vcpu_x86_64.rs0.00%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod tdx;
16
17use std::arch::x86_64::CpuidResult;
18use std::collections::HashMap;
19use std::iter::zip;
20use std::os::fd::{FromRawFd, OwnedFd};
21
22use snafu::ResultExt;
23
24use crate::arch::cpuid::CpuidIn;
25use crate::arch::reg::{DtReg, DtRegVal, Reg, SReg, SegAccess, SegReg, SegRegVal};
26use crate::hv::kvm::kvm_error;
27use crate::hv::kvm::vcpu::KvmVcpu;
28use crate::hv::kvm::vm::KvmVm;
29use crate::hv::{Error, Result, error};
30use crate::sys::kvm::{
31 KVM_MAX_CPUID_ENTRIES, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2, KvmMsrEntry, KvmMsrs, KvmRegs,
32 MAX_IO_MSRS, kvm_create_vcpu, kvm_get_regs, kvm_get_sregs, kvm_get_sregs2, kvm_kvmclock_ctrl,
33 kvm_set_cpuid2, kvm_set_msrs, kvm_set_regs, kvm_set_sregs, kvm_set_sregs2,
34};
35
36#[derive(Debug)]
37pub struct VcpuArch {
38 pub io_index: usize,
39}
40
41impl VcpuArch {
42 pub fn new(_id: u64) -> Self {
43 Self { io_index: 0 }
44 }
45}
46
47macro_rules! set_kvm_sreg {
48 ($kvm_sregs:ident, $sreg:ident, $val:expr) => {
49 match $sreg {
50 SReg::Cr0 => $kvm_sregs.cr0 = $val,
51 SReg::Cr2 => $kvm_sregs.cr2 = $val,
52 SReg::Cr3 => $kvm_sregs.cr3 = $val,
53 SReg::Cr4 => $kvm_sregs.cr4 = $val,
54 SReg::Cr8 => $kvm_sregs.cr8 = $val,
55 SReg::Efer => $kvm_sregs.efer = $val,
56 SReg::ApicBase => $kvm_sregs.apic_base = $val,
57 }
58 };
59}
60
61macro_rules! set_kvm_dt_reg {
62 ($kvm_sregs:ident, $dt_reg:ident, $val:expr) => {
63 let target = match $dt_reg {
64 DtReg::Idtr => &mut $kvm_sregs.idt,
65 DtReg::Gdtr => &mut $kvm_sregs.gdt,
66 };
67 target.limit = $val.limit;
68 target.base = $val.base;
69 };
70}
71
72macro_rules! set_kvm_seg_reg {
73 ($kvm_sregs:ident, $seg_reg:ident, $val:expr) => {
74 let target = match $seg_reg {
75 SegReg::Cs => &mut $kvm_sregs.cs,
76 SegReg::Ds => &mut $kvm_sregs.ds,
77 SegReg::Es => &mut $kvm_sregs.es,
78 SegReg::Fs => &mut $kvm_sregs.fs,
79 SegReg::Gs => &mut $kvm_sregs.gs,
80 SegReg::Ss => &mut $kvm_sregs.ss,
81 SegReg::Tr => &mut $kvm_sregs.tr,
82 SegReg::Ldtr => &mut $kvm_sregs.ldt,
83 };
84 target.selector = $val.selector;
85 target.base = $val.base;
86 target.limit = $val.limit;
87 target.type_ = $val.access.seg_type() as u8;
88 target.s = $val.access.s_code_data() as u8;
89 target.dpl = $val.access.priv_level() as u8;
90 target.present = $val.access.present() as u8;
91 target.avl = $val.access.available() as u8;
92 target.db = $val.access.db_size_32() as u8;
93 target.g = $val.access.granularity() as u8;
94 target.l = $val.access.l_64bit() as u8;
95 target.unusable = $val.access.unusable() as u8;
96 };
97}
98
99macro_rules! get_kvm_sreg {
100 ($kvm_sregs:ident, $sreg:ident) => {
101 match $sreg {
102 SReg::Cr0 => $kvm_sregs.cr0,
103 SReg::Cr2 => $kvm_sregs.cr2,
104 SReg::Cr3 => $kvm_sregs.cr3,
105 SReg::Cr4 => $kvm_sregs.cr4,
106 SReg::Cr8 => $kvm_sregs.cr8,
107 SReg::Efer => $kvm_sregs.efer,
108 SReg::ApicBase => $kvm_sregs.apic_base,
109 }
110 };
111}
112
113macro_rules! get_kvm_dt_reg {
114 ($kvm_sregs:ident, $dt_reg:ident) => {{
115 let target = match $dt_reg {
116 DtReg::Idtr => $kvm_sregs.idt,
117 DtReg::Gdtr => $kvm_sregs.gdt,
118 };
119 DtRegVal {
120 limit: target.limit,
121 base: target.base,
122 }
123 }};
124}
125
126macro_rules! get_kvm_seg_reg {
127 ($kvm_sregs:ident, $seg_reg:ident) => {{
128 let kvm_segment = match $seg_reg {
129 SegReg::Cs => $kvm_sregs.cs,
130 SegReg::Ds => $kvm_sregs.ds,
131 SegReg::Es => $kvm_sregs.es,
132 SegReg::Fs => $kvm_sregs.fs,
133 SegReg::Gs => $kvm_sregs.gs,
134 SegReg::Ss => $kvm_sregs.ss,
135 SegReg::Tr => $kvm_sregs.tr,
136 SegReg::Ldtr => $kvm_sregs.ldt,
137 };
138 let access = (kvm_segment.unusable as u32) << 16
139 | (kvm_segment.g as u32) << 15
140 | (kvm_segment.db as u32) << 14
141 | (kvm_segment.l as u32) << 13
142 | (kvm_segment.avl as u32) << 12
143 | (kvm_segment.present as u32) << 7
144 | (kvm_segment.dpl as u32) << 5
145 | (kvm_segment.s as u32) << 4
146 | (kvm_segment.type_ as u32);
147 SegRegVal {
148 selector: kvm_segment.selector,
149 base: kvm_segment.base,
150 limit: kvm_segment.limit,
151 access: SegAccess(access),
152 }
153 }};
154}
155
156impl KvmVcpu {
157 pub fn create_vcpu(vm: &KvmVm, _: u16, identity: u64) -> Result<OwnedFd> {
158 let apic_id = identity as u32;
159 let fd = unsafe { kvm_create_vcpu(&vm.vm.fd, apic_id) }.context(error::CreateVcpu)?;
160 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
161 }
162
163 pub fn kvmclock_ctrl(&mut self) -> Result<()> {
164 unsafe { kvm_kvmclock_ctrl(&self.fd) }.context(kvm_error::KvmClockCtrl)?;
165 Ok(())
166 }
167
168 fn get_kvm_regs(&self) -> Result<KvmRegs> {
169 let kvm_regs = unsafe { kvm_get_regs(&self.fd) }.context(error::VcpuReg)?;
170 Ok(kvm_regs)
171 }
172
173 fn set_kvm_regs(&self, kvm_regs: &KvmRegs) -> Result<()> {
174 unsafe { kvm_set_regs(&self.fd, kvm_regs) }.context(error::VcpuReg)?;
175 Ok(())
176 }
177
178 pub fn kvm_set_regs(&self, vals: &[(Reg, u64)]) -> Result<()> {
179 let mut kvm_regs = self.get_kvm_regs()?;
180 for (reg, val) in vals {
181 match reg {
182 Reg::Rax => kvm_regs.rax = *val,
183 Reg::Rbx => kvm_regs.rbx = *val,
184 Reg::Rcx => kvm_regs.rcx = *val,
185 Reg::Rdx => kvm_regs.rdx = *val,
186 Reg::Rsi => kvm_regs.rsi = *val,
187 Reg::Rdi => kvm_regs.rdi = *val,
188 Reg::Rsp => kvm_regs.rsp = *val,
189 Reg::Rbp => kvm_regs.rbp = *val,
190 Reg::R8 => kvm_regs.r8 = *val,
191 Reg::R9 => kvm_regs.r9 = *val,
192 Reg::R10 => kvm_regs.r10 = *val,
193 Reg::R11 => kvm_regs.r11 = *val,
194 Reg::R12 => kvm_regs.r12 = *val,
195 Reg::R13 => kvm_regs.r13 = *val,
196 Reg::R14 => kvm_regs.r14 = *val,
197 Reg::R15 => kvm_regs.r15 = *val,
198 Reg::Rip => kvm_regs.rip = *val,
199 Reg::Rflags => kvm_regs.rflags = *val,
200 }
201 }
202 self.set_kvm_regs(&kvm_regs)
203 }
204
205 pub fn kvm_get_reg(&self, reg: Reg) -> Result<u64> {
206 let kvm_regs = self.get_kvm_regs()?;
207 let val = match reg {
208 Reg::Rax => kvm_regs.rax,
209 Reg::Rbx => kvm_regs.rbx,
210 Reg::Rcx => kvm_regs.rcx,
211 Reg::Rdx => kvm_regs.rdx,
212 Reg::Rsi => kvm_regs.rsi,
213 Reg::Rdi => kvm_regs.rdi,
214 Reg::Rsp => kvm_regs.rsp,
215 Reg::Rbp => kvm_regs.rbp,
216 Reg::R8 => kvm_regs.r8,
217 Reg::R9 => kvm_regs.r9,
218 Reg::R10 => kvm_regs.r10,
219 Reg::R11 => kvm_regs.r11,
220 Reg::R12 => kvm_regs.r12,
221 Reg::R13 => kvm_regs.r13,
222 Reg::R14 => kvm_regs.r14,
223 Reg::R15 => kvm_regs.r15,
224 Reg::Rip => kvm_regs.rip,
225 Reg::Rflags => kvm_regs.rflags,
226 };
227 Ok(val)
228 }
229
230 pub fn kvm_set_sregs2(
231 &mut self,
232 sregs: &[(SReg, u64)],
233 seg_regs: &[(SegReg, SegRegVal)],
234 dt_regs: &[(DtReg, DtRegVal)],
235 ) -> Result<(), Error> {
236 let mut kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;
237 for (reg, val) in sregs {
238 set_kvm_sreg!(kvm_sregs2, reg, *val)
239 }
240 for (reg, val) in dt_regs {
241 set_kvm_dt_reg!(kvm_sregs2, reg, val);
242 }
243 for (reg, val) in seg_regs {
244 set_kvm_seg_reg!(kvm_sregs2, reg, val);
245 }
246 unsafe { kvm_set_sregs2(&self.fd, &kvm_sregs2) }.context(error::VcpuReg)?;
247 Ok(())
248 }
249
250 pub fn kvm_get_dt_reg2(&self, reg: DtReg) -> Result<DtRegVal> {
251 let kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;
252 let val = get_kvm_dt_reg!(kvm_sregs2, reg);
253 Ok(val)
254 }
255
256 pub fn kvm_get_seg_reg2(&self, reg: SegReg) -> Result<SegRegVal> {
257 let kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;
258 let val = get_kvm_seg_reg!(kvm_sregs2, reg);
259 Ok(val)
260 }
261
262 pub fn kvm_get_sreg2(&self, reg: SReg) -> Result<u64> {
263 let kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;
264 let val = get_kvm_sreg!(kvm_sregs2, reg);
265 Ok(val)
266 }
267
268 pub fn kvm_set_sregs(
269 &mut self,
270 sregs: &[(SReg, u64)],
271 seg_regs: &[(SegReg, SegRegVal)],
272 dt_regs: &[(DtReg, DtRegVal)],
273 ) -> Result<(), Error> {
274 let mut kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;
275 for (reg, val) in sregs {
276 set_kvm_sreg!(kvm_sregs, reg, *val)
277 }
278 for (reg, val) in dt_regs {
279 set_kvm_dt_reg!(kvm_sregs, reg, val);
280 }
281 for (reg, val) in seg_regs {
282 set_kvm_seg_reg!(kvm_sregs, reg, val);
283 }
284 unsafe { kvm_set_sregs(&self.fd, &kvm_sregs) }.context(error::VcpuReg)?;
285 Ok(())
286 }
287
288 pub fn kvm_get_dt_reg(&self, reg: DtReg) -> Result<DtRegVal> {
289 let kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;
290 let val = get_kvm_dt_reg!(kvm_sregs, reg);
291 Ok(val)
292 }
293
294 pub fn kvm_get_seg_reg(&self, reg: SegReg) -> Result<SegRegVal> {
295 let kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;
296 let val = get_kvm_seg_reg!(kvm_sregs, reg);
297 Ok(val)
298 }
299
300 pub fn kvm_get_sreg(&self, reg: SReg) -> Result<u64> {
301 let kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;
302 let val = get_kvm_sreg!(kvm_sregs, reg);
303 Ok(val)
304 }
305
306 pub fn kvm_set_cpuids(&mut self, cpuids: &HashMap<CpuidIn, CpuidResult>) -> Result<(), Error> {
307 if cpuids.len() > KVM_MAX_CPUID_ENTRIES {
308 return kvm_error::CpuidTableTooLong.fail()?;
309 }
310 let mut kvm_cpuid2 = KvmCpuid2 {
311 nent: cpuids.len() as u32,
312 padding: 0,
313 entries: [KvmCpuidEntry2::default(); KVM_MAX_CPUID_ENTRIES],
314 };
315 for ((in_, out), entry) in zip(cpuids, &mut kvm_cpuid2.entries) {
316 entry.eax = out.eax;
317 entry.ebx = out.ebx;
318 entry.ecx = out.ecx;
319 entry.edx = out.edx;
320 entry.function = in_.func;
321 if let Some(index) = in_.index {
322 entry.index = index;
323 entry.flags = KvmCpuid2Flag::SIGNIFCANT_INDEX;
324 } else {
325 entry.flags = KvmCpuid2Flag::empty();
326 }
327 }
328 unsafe { kvm_set_cpuid2(&self.fd, &kvm_cpuid2) }.context(error::GuestCpuid)?;
329 Ok(())
330 }
331
332 pub fn kvm_set_msrs(&mut self, msrs: &[(u32, u64)]) -> Result<()> {
333 let mut kvm_msrs = KvmMsrs {
334 nmsrs: msrs.len() as u32,
335 _pad: 0,
336 entries: [KvmMsrEntry::default(); MAX_IO_MSRS],
337 };
338 for (i, (index, data)) in msrs.iter().enumerate() {
339 kvm_msrs.entries[i].index = *index;
340 kvm_msrs.entries[i].data = *data;
341 }
342 unsafe { kvm_set_msrs(&self.fd, &kvm_msrs) }.context(error::GuestMsr)?;
343 Ok(())
344 }
345}
346
347#[cfg(test)]
348#[path = "vcpu_x86_64_test.rs"]
349mod tests;
350