vm_x86_64.rs30.00%
1
// Copyright 2024 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
mod sev;16
mod tdx;17
18
use std::os::fd::{FromRawFd, OwnedFd};19
use std::path::Path;20
21
use snafu::ResultExt;22
23
use crate::arch::intr::{MsiAddrHi, MsiAddrLo};24
use crate::arch::ioapic::NUM_PINS;25
use crate::hv::kvm::sev::SevFd;26
use crate::hv::kvm::{KvmVm, kvm_error};27
use crate::hv::{Coco, Kvm, Result, VmConfig, error};28
use crate::sys::kvm::{29
KvmCap, KvmCreateGuestMemfd, KvmVmType, KvmX2apicApiFlag, kvm_create_guest_memfd,30
kvm_set_identity_map_addr, kvm_set_tss_addr,31
};32
33
pub fn translate_msi_addr(addr_lo: u32, addr_hi: u32) -> (u32, u32) {5x34
let mut addr_lo = MsiAddrLo(addr_lo);5x35
let mut addr_hi = MsiAddrHi(addr_hi);5x36
if addr_lo.virt_dest_id_hi() == 0 || addr_lo.remappable() || addr_hi.dest_id_hi() != 0 {5x37
return (addr_lo.0, addr_hi.0);4x38
}1x39
40
addr_hi.set_dest_id_hi(addr_lo.virt_dest_id_hi() as u32);1x41
addr_lo.set_virt_dest_id_hi(0);1x42
(addr_lo.0, addr_hi.0)1x43
}5x44
45
#[derive(Debug, Default)]46
pub struct VmArch {47
pub sev_fd: Option<SevFd>,48
}49
50
impl VmArch {51
pub fn new(kvm: &Kvm, config: &VmConfig) -> Result<Self> {52
let Some(coco) = &config.coco else {53
return Ok(VmArch::default());54
};55
match coco {56
Coco::AmdSev { .. } | Coco::AmdSnp { .. } => {57
let default_dev = Path::new("/dev/sev");58
let dev_sev = kvm.config.dev_sev.as_deref().unwrap_or(default_dev);59
let fd = SevFd::new(dev_sev)?;60
Ok(VmArch { sev_fd: Some(fd) })61
}62
Coco::IntelTdx { .. } => Ok(VmArch::default()),63
}64
}65
}66
67
impl KvmVm {68
pub fn determine_vm_type(config: &VmConfig) -> KvmVmType {4x69
let Some(coco) = &config.coco else {4x70
return KvmVmType::DEFAULT;1x71
};72
match coco {3x73
Coco::AmdSev { .. } => KvmVmType::DEFAULT,1x74
Coco::AmdSnp { .. } => KvmVmType::SNP,1x75
Coco::IntelTdx { .. } => KvmVmType::TDX,1x76
}77
}4x78
79
pub fn create_guest_memfd(config: &VmConfig, fd: &OwnedFd) -> Result<Option<OwnedFd>> {80
let Some(coco) = &config.coco else {81
return Ok(None);82
};83
if !matches!(coco, Coco::AmdSnp { .. } | Coco::IntelTdx { .. }) {84
return Ok(None);85
}86
let mut gmem = KvmCreateGuestMemfd {87
size: 1 << 48,88
..Default::default()89
};90
let fd = unsafe { kvm_create_guest_memfd(fd, &mut gmem) }.context(kvm_error::GuestMemfd)?;91
Ok(Some(unsafe { OwnedFd::from_raw_fd(fd) }))92
}93
94
pub fn init(&self, config: &VmConfig) -> Result<()> {95
let x2apic_caps =96
KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK;97
if let Err(e) = self.vm.enable_cap(KvmCap::X2APIC_API, x2apic_caps.bits()) {98
log::error!("Failed to enable KVM_CAP_X2APIC_API: {e:?}");99
}100
self.vm.enable_cap(KvmCap::SPLIT_IRQCHIP, NUM_PINS as u64)?;101
// TODO should be in parameters102
unsafe { kvm_set_tss_addr(&self.vm.fd, 0xf000_0000) }.context(error::SetVmParam)?;103
unsafe { kvm_set_identity_map_addr(&self.vm.fd, &0xf000_3000) }104
.context(error::SetVmParam)?;105
106
if let Some(coco) = &config.coco {107
match coco {108
Coco::AmdSev { policy } => self.sev_init(*policy),109
Coco::AmdSnp { .. } => self.snp_init(),110
Coco::IntelTdx { .. } => self.tdx_init(),111
}?;112
}113
114
Ok(())115
}116
}117
118
#[cfg(test)]119
#[path = "vm_x86_64_test.rs"]120
mod test;121