Alioth Code Coverage

vm_x86_64.rs30.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 sev;
16mod tdx;
17
18use std::os::fd::{FromRawFd, OwnedFd};
19use std::path::Path;
20
21use snafu::ResultExt;
22
23use crate::arch::intr::{MsiAddrHi, MsiAddrLo};
24use crate::arch::ioapic::NUM_PINS;
25use crate::hv::kvm::sev::SevFd;
26use crate::hv::kvm::{KvmVm, kvm_error};
27use crate::hv::{Coco, Kvm, Result, VmConfig, error};
28use crate::sys::kvm::{
29 KvmCap, KvmCreateGuestMemfd, KvmVmType, KvmX2apicApiFlag, kvm_create_guest_memfd,
30 kvm_set_identity_map_addr, kvm_set_tss_addr,
31};
32
33pub fn translate_msi_addr(addr_lo: u32, addr_hi: u32) -> (u32, u32) {5x
34 let mut addr_lo = MsiAddrLo(addr_lo);5x
35 let mut addr_hi = MsiAddrHi(addr_hi);5x
36 if addr_lo.virt_dest_id_hi() == 0 || addr_lo.remappable() || addr_hi.dest_id_hi() != 0 {5x
37 return (addr_lo.0, addr_hi.0);4x
38 }1x
39
40 addr_hi.set_dest_id_hi(addr_lo.virt_dest_id_hi() as u32);1x
41 addr_lo.set_virt_dest_id_hi(0);1x
42 (addr_lo.0, addr_hi.0)1x
43}5x
44
45#[derive(Debug, Default)]
46pub struct VmArch {
47 pub sev_fd: Option<SevFd>,
48}
49
50impl 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
67impl KvmVm {
68 pub fn determine_vm_type(config: &VmConfig) -> KvmVmType {4x
69 let Some(coco) = &config.coco else {4x
70 return KvmVmType::DEFAULT;1x
71 };
72 match coco {3x
73 Coco::AmdSev { .. } => KvmVmType::DEFAULT,1x
74 Coco::AmdSnp { .. } => KvmVmType::SNP,1x
75 Coco::IntelTdx { .. } => KvmVmType::TDX,1x
76 }
77 }4x
78
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 parameters
102 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"]
120mod test;
121