tdx.rs0.00%
1
// Copyright 2026 Google LLC2
//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 at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// 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 and13
// limitations under the License.14
15
use std::arch::x86_64::CpuidResult;16
use std::collections::HashMap;17
use std::mem::MaybeUninit;18
19
use crate::arch::cpuid::CpuidIn;20
use crate::arch::tdx::TdAttr;21
use crate::hv::Result;22
use crate::hv::kvm::vm::KvmVm;23
use crate::hv::kvm::x86_64::tdx::tdx_op;24
use crate::sys::kvm::{KvmCap, KvmCpuid2Flag, KvmCpuidEntry2, KvmHypercall};25
use crate::sys::tdx::{KvmTdxCapabilities, KvmTdxCmdId, KvmTdxInitVm};26
27
impl 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
// Work around the missing SIGNIFICANT_INDEX flag in KVM_TDX_CAPABILITIES51
// (https://lore.kernel.org/all/20260223214336.722463-1-changyuanl@google.com/).52
// Until this is fixed upstream, explicitly retain the index value from the53
// KvmCpuidEntry2 struct.54
in_.index = Some(e.index);55
(in_, out)56
};57
let caps_cpuid = caps.cpuid.entries.iter().take(caps.cpuid.nent as usize);58
let caps_cpuid: HashMap<_, _> = caps_cpuid.map(convert).collect();59
for (in_, out) in cpuids {60
let cap_cpuid_in = CpuidIn {61
func: in_.func,62
// Fall back to index 0 to work around the missing SIGNIFICANT_INDEX63
// flag in KVM_TDX_CAPABILITIES.64
index: in_.index.or(Some(0)),65
};66
let Some(cap_out) = caps_cpuid.get(&cap_cpuid_in) else {67
continue;68
};69
70
let entry = &mut init.cpuid.entries[init.cpuid.nent as usize];71
entry.function = in_.func;72
entry.index = in_.index.unwrap_or(0);73
entry.flags = if in_.index.is_some() {74
KvmCpuid2Flag::SIGNIFCANT_INDEX75
} else {76
KvmCpuid2Flag::empty()77
};78
entry.eax = out.eax & cap_out.eax;79
entry.ebx = out.ebx & cap_out.ebx;80
entry.ecx = out.ecx & cap_out.ecx;81
entry.edx = out.edx & cap_out.edx;82
83
init.cpuid.nent += 1;84
}85
86
tdx_op(&self.vm.fd, KvmTdxCmdId::INIT_VM, 0, Some(&mut *init))?;87
Ok(())88
}89
90
pub fn tdx_finalize_vm(&self) -> Result<()> {91
tdx_op::<()>(&self.vm.fd, KvmTdxCmdId::FINALIZE_VM, 0, None)92
}93
}94