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::tdx::tdx_op;23
use crate::hv::kvm::vm::KvmVm;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
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_INDEX71
} 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