Alioth Code Coverage

tdx.rs0.00%

1// Copyright 2026 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
15use std::arch::x86_64::CpuidResult;
16use std::collections::HashMap;
17use std::mem::MaybeUninit;
18
19use crate::arch::cpuid::CpuidIn;
20use crate::arch::tdx::TdAttr;
21use crate::hv::Result;
22use crate::hv::kvm::tdx::tdx_op;
23use crate::hv::kvm::vm::KvmVm;
24use crate::sys::kvm::{KvmCap, KvmCpuid2Flag, KvmCpuidEntry2, KvmHypercall};
25use crate::sys::tdx::{KvmTdxCapabilities, KvmTdxCmdId, KvmTdxInitVm};
26
27impl KvmVm {
28 pub fn tdx_init(&self) -> Result<()> {
29 let map_gpa_range = 1 << KvmHypercall::MAP_GPA_RANGE.raw();
30 self.vm.enable_cap(KvmCap::EXIT_HYPERCALL, map_gpa_range)?;
31 self.vm.enable_cap(KvmCap::X86_APIC_BUS_CYCLES_NS, 40)?;
32 Ok(())
33 }
34
35 fn tdx_get_capabilities(&self) -> Result<Box<KvmTdxCapabilities>> {
36 let mut caps: Box<KvmTdxCapabilities> =
37 Box::new(unsafe { MaybeUninit::zeroed().assume_init() });
38 caps.cpuid.nent = caps.cpuid.entries.len() as u32;
39 tdx_op(&self.vm.fd, KvmTdxCmdId::CAPABILITIES, 0, Some(&mut *caps))?;
40 Ok(caps)
41 }
42
43 pub fn tdx_init_vm(&self, attr: TdAttr, cpuids: &HashMap<CpuidIn, CpuidResult>) -> Result<()> {
44 let mut init: Box<KvmTdxInitVm> = Box::new(unsafe { MaybeUninit::zeroed().assume_init() });
45 init.attributes = attr;
46
47 let caps = self.tdx_get_capabilities()?;
48 let convert = |e: &KvmCpuidEntry2| {
49 let (mut in_, out) = From::from(*e);
50 if in_.index.is_none() {
51 in_.index = Some(0)
52 }
53 (in_, out)
54 };
55 let caps_cpuid = caps.cpuid.entries.iter().take(caps.cpuid.nent as usize);
56 let caps_cpuid: HashMap<_, _> = caps_cpuid.map(convert).collect();
57 for (in_, out) in cpuids {
58 let cap_cpuid_in = CpuidIn {
59 func: in_.func,
60 index: in_.index.or(Some(0)),
61 };
62 let Some(cap_out) = caps_cpuid.get(&cap_cpuid_in) else {
63 continue;
64 };
65
66 let entry = &mut init.cpuid.entries[init.cpuid.nent as usize];
67 entry.function = in_.func;
68 entry.index = in_.index.unwrap_or(0);
69 entry.flags = if in_.index.is_some() {
70 KvmCpuid2Flag::SIGNIFCANT_INDEX
71 } else {
72 KvmCpuid2Flag::empty()
73 };
74 entry.eax = out.eax & cap_out.eax;
75 entry.ebx = out.ebx & cap_out.ebx;
76 entry.ecx = out.ecx & cap_out.ecx;
77 entry.edx = out.edx & cap_out.edx;
78
79 init.cpuid.nent += 1;
80 }
81
82 tdx_op(&self.vm.fd, KvmTdxCmdId::INIT_VM, 0, Some(&mut *init))?;
83 Ok(())
84 }
85
86 pub fn tdx_finalize_vm(&self) -> Result<()> {
87 tdx_op::<()>(&self.vm.fd, KvmTdxCmdId::FINALIZE_VM, 0, None)
88 }
89}
90