1 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 2 // 3 // Copyright © 2020, Microsoft Corporation 4 // 5 6 use std::any::Any; 7 use std::collections::HashMap; 8 #[cfg(feature = "sev_snp")] 9 use std::num::NonZeroUsize; 10 use std::sync::{Arc, RwLock}; 11 12 #[cfg(feature = "sev_snp")] 13 use arc_swap::ArcSwap; 14 use mshv_bindings::*; 15 use mshv_ioctls::{set_registers_64, InterruptRequest, Mshv, NoDatamatch, VcpuFd, VmFd, VmType}; 16 use vfio_ioctls::VfioDeviceFd; 17 use vm::DataMatch; 18 #[cfg(feature = "sev_snp")] 19 use vm_memory::bitmap::AtomicBitmap; 20 21 use crate::arch::emulator::PlatformEmulator; 22 #[cfg(target_arch = "x86_64")] 23 use crate::arch::x86::emulator::Emulator; 24 use crate::mshv::emulator::MshvEmulatorContext; 25 use crate::vm::{self, InterruptSourceConfig, VmOps}; 26 use crate::{cpu, hypervisor, vec_with_array_field, HypervisorType}; 27 #[cfg(feature = "sev_snp")] 28 mod snp_constants; 29 // x86_64 dependencies 30 #[cfg(target_arch = "x86_64")] 31 pub mod x86_64; 32 #[cfg(target_arch = "x86_64")] 33 use std::fs::File; 34 use std::os::unix::io::AsRawFd; 35 36 #[cfg(feature = "sev_snp")] 37 use igvm_defs::IGVM_VHS_SNP_ID_BLOCK; 38 #[cfg(feature = "sev_snp")] 39 use snp_constants::*; 40 use vmm_sys_util::eventfd::EventFd; 41 #[cfg(target_arch = "x86_64")] 42 pub use x86_64::*; 43 #[cfg(target_arch = "x86_64")] 44 pub use x86_64::{emulator, VcpuMshvState}; 45 /// 46 /// Export generically-named wrappers of mshv-bindings for Unix-based platforms 47 /// 48 pub use { 49 mshv_bindings::mshv_create_device as CreateDevice, 50 mshv_bindings::mshv_device_attr as DeviceAttr, mshv_ioctls, mshv_ioctls::DeviceFd, 51 }; 52 53 #[cfg(target_arch = "x86_64")] 54 use crate::arch::x86::{CpuIdEntry, FpuState, MsrEntry}; 55 #[cfg(target_arch = "x86_64")] 56 use crate::ClockData; 57 use crate::{ 58 CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion, 59 USER_MEMORY_REGION_ADJUSTABLE, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, 60 USER_MEMORY_REGION_WRITE, 61 }; 62 63 pub const PAGE_SHIFT: usize = 12; 64 65 impl From<mshv_user_mem_region> for UserMemoryRegion { 66 fn from(region: mshv_user_mem_region) -> Self { 67 let mut flags: u32 = USER_MEMORY_REGION_READ | USER_MEMORY_REGION_ADJUSTABLE; 68 if region.flags & (1 << MSHV_SET_MEM_BIT_WRITABLE) != 0 { 69 flags |= USER_MEMORY_REGION_WRITE; 70 } 71 if region.flags & (1 << MSHV_SET_MEM_BIT_EXECUTABLE) != 0 { 72 flags |= USER_MEMORY_REGION_EXECUTE; 73 } 74 75 UserMemoryRegion { 76 guest_phys_addr: (region.guest_pfn << PAGE_SHIFT as u64) 77 + (region.userspace_addr & ((1 << PAGE_SHIFT) - 1)), 78 memory_size: region.size, 79 userspace_addr: region.userspace_addr, 80 flags, 81 ..Default::default() 82 } 83 } 84 } 85 86 #[cfg(target_arch = "x86_64")] 87 impl From<MshvClockData> for ClockData { 88 fn from(d: MshvClockData) -> Self { 89 ClockData::Mshv(d) 90 } 91 } 92 93 #[cfg(target_arch = "x86_64")] 94 impl From<ClockData> for MshvClockData { 95 fn from(ms: ClockData) -> Self { 96 match ms { 97 ClockData::Mshv(s) => s, 98 /* Needed in case other hypervisors are enabled */ 99 #[allow(unreachable_patterns)] 100 _ => unreachable!("MSHV clock data is not valid"), 101 } 102 } 103 } 104 105 impl From<UserMemoryRegion> for mshv_user_mem_region { 106 fn from(region: UserMemoryRegion) -> Self { 107 let mut flags: u8 = 0; 108 if region.flags & USER_MEMORY_REGION_WRITE != 0 { 109 flags |= 1 << MSHV_SET_MEM_BIT_WRITABLE; 110 } 111 if region.flags & USER_MEMORY_REGION_EXECUTE != 0 { 112 flags |= 1 << MSHV_SET_MEM_BIT_EXECUTABLE; 113 } 114 115 mshv_user_mem_region { 116 guest_pfn: region.guest_phys_addr >> PAGE_SHIFT, 117 size: region.memory_size, 118 userspace_addr: region.userspace_addr, 119 flags, 120 ..Default::default() 121 } 122 } 123 } 124 125 impl From<mshv_ioctls::IoEventAddress> for IoEventAddress { 126 fn from(a: mshv_ioctls::IoEventAddress) -> Self { 127 match a { 128 mshv_ioctls::IoEventAddress::Pio(x) => Self::Pio(x), 129 mshv_ioctls::IoEventAddress::Mmio(x) => Self::Mmio(x), 130 } 131 } 132 } 133 134 impl From<IoEventAddress> for mshv_ioctls::IoEventAddress { 135 fn from(a: IoEventAddress) -> Self { 136 match a { 137 IoEventAddress::Pio(x) => Self::Pio(x), 138 IoEventAddress::Mmio(x) => Self::Mmio(x), 139 } 140 } 141 } 142 143 impl From<VcpuMshvState> for CpuState { 144 fn from(s: VcpuMshvState) -> Self { 145 CpuState::Mshv(s) 146 } 147 } 148 149 impl From<CpuState> for VcpuMshvState { 150 fn from(s: CpuState) -> Self { 151 match s { 152 CpuState::Mshv(s) => s, 153 /* Needed in case other hypervisors are enabled */ 154 #[allow(unreachable_patterns)] 155 _ => panic!("CpuState is not valid"), 156 } 157 } 158 } 159 160 impl From<mshv_bindings::StandardRegisters> for crate::StandardRegisters { 161 fn from(s: mshv_bindings::StandardRegisters) -> Self { 162 crate::StandardRegisters::Mshv(s) 163 } 164 } 165 166 impl From<crate::StandardRegisters> for mshv_bindings::StandardRegisters { 167 fn from(e: crate::StandardRegisters) -> Self { 168 match e { 169 crate::StandardRegisters::Mshv(e) => e, 170 /* Needed in case other hypervisors are enabled */ 171 #[allow(unreachable_patterns)] 172 _ => panic!("StandardRegisters are not valid"), 173 } 174 } 175 } 176 177 impl From<mshv_user_irq_entry> for IrqRoutingEntry { 178 fn from(s: mshv_user_irq_entry) -> Self { 179 IrqRoutingEntry::Mshv(s) 180 } 181 } 182 183 impl From<IrqRoutingEntry> for mshv_user_irq_entry { 184 fn from(e: IrqRoutingEntry) -> Self { 185 match e { 186 IrqRoutingEntry::Mshv(e) => e, 187 /* Needed in case other hypervisors are enabled */ 188 #[allow(unreachable_patterns)] 189 _ => panic!("IrqRoutingEntry is not valid"), 190 } 191 } 192 } 193 194 struct MshvDirtyLogSlot { 195 guest_pfn: u64, 196 memory_size: u64, 197 } 198 199 /// Wrapper over mshv system ioctls. 200 pub struct MshvHypervisor { 201 mshv: Mshv, 202 } 203 204 impl MshvHypervisor { 205 #[cfg(target_arch = "x86_64")] 206 /// 207 /// Retrieve the list of MSRs supported by MSHV. 208 /// 209 fn get_msr_list(&self) -> hypervisor::Result<MsrList> { 210 self.mshv 211 .get_msr_index_list() 212 .map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into())) 213 } 214 215 fn create_vm_with_type_and_memory_int( 216 &self, 217 vm_type: u64, 218 #[cfg(feature = "sev_snp")] _mem_size: Option<u64>, 219 ) -> hypervisor::Result<Arc<dyn crate::Vm>> { 220 let mshv_vm_type: VmType = match VmType::try_from(vm_type) { 221 Ok(vm_type) => vm_type, 222 Err(_) => return Err(hypervisor::HypervisorError::UnsupportedVmType()), 223 }; 224 let fd: VmFd; 225 loop { 226 match self.mshv.create_vm_with_type(mshv_vm_type) { 227 Ok(res) => fd = res, 228 Err(e) => { 229 if e.errno() == libc::EINTR { 230 // If the error returned is EINTR, which means the 231 // ioctl has been interrupted, we have to retry as 232 // this can't be considered as a regular error. 233 continue; 234 } else { 235 return Err(hypervisor::HypervisorError::VmCreate(e.into())); 236 } 237 } 238 } 239 break; 240 } 241 242 // Set additional partition property for SEV-SNP partition. 243 #[cfg(target_arch = "x86_64")] 244 if mshv_vm_type == VmType::Snp { 245 let snp_policy = snp::get_default_snp_guest_policy(); 246 let vmgexit_offloads = snp::get_default_vmgexit_offload_features(); 247 // SAFETY: access union fields 248 unsafe { 249 debug!( 250 "Setting the partition isolation policy as: 0x{:x}", 251 snp_policy.as_uint64 252 ); 253 fd.set_partition_property( 254 hv_partition_property_code_HV_PARTITION_PROPERTY_ISOLATION_POLICY, 255 snp_policy.as_uint64, 256 ) 257 .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?; 258 debug!( 259 "Setting the partition property to enable VMGEXIT offloads as : 0x{:x}", 260 vmgexit_offloads.as_uint64 261 ); 262 fd.set_partition_property( 263 hv_partition_property_code_HV_PARTITION_PROPERTY_SEV_VMGEXIT_OFFLOADS, 264 vmgexit_offloads.as_uint64, 265 ) 266 .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?; 267 } 268 } 269 270 // Default Microsoft Hypervisor behavior for unimplemented MSR is to 271 // send a fault to the guest if it tries to access it. It is possible 272 // to override this behavior with a more suitable option i.e., ignore 273 // writes from the guest and return zero in attempt to read unimplemented 274 // MSR. 275 #[cfg(target_arch = "x86_64")] 276 fd.set_partition_property( 277 hv_partition_property_code_HV_PARTITION_PROPERTY_UNIMPLEMENTED_MSR_ACTION, 278 hv_unimplemented_msr_action_HV_UNIMPLEMENTED_MSR_ACTION_IGNORE_WRITE_READ_ZERO as u64, 279 ) 280 .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?; 281 282 // Always create a frozen partition 283 fd.set_partition_property( 284 hv_partition_property_code_HV_PARTITION_PROPERTY_TIME_FREEZE, 285 1u64, 286 ) 287 .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?; 288 289 let vm_fd = Arc::new(fd); 290 291 #[cfg(target_arch = "x86_64")] 292 { 293 let msr_list = self.get_msr_list()?; 294 let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize; 295 let mut msrs: Vec<MsrEntry> = vec![ 296 MsrEntry { 297 ..Default::default() 298 }; 299 num_msrs 300 ]; 301 let indices = msr_list.as_slice(); 302 for (pos, index) in indices.iter().enumerate() { 303 msrs[pos].index = *index; 304 } 305 306 Ok(Arc::new(MshvVm { 307 fd: vm_fd, 308 msrs, 309 dirty_log_slots: Arc::new(RwLock::new(HashMap::new())), 310 #[cfg(feature = "sev_snp")] 311 sev_snp_enabled: mshv_vm_type == VmType::Snp, 312 #[cfg(feature = "sev_snp")] 313 host_access_pages: ArcSwap::new( 314 AtomicBitmap::new( 315 _mem_size.unwrap_or_default() as usize, 316 NonZeroUsize::new(HV_PAGE_SIZE).unwrap(), 317 ) 318 .into(), 319 ), 320 })) 321 } 322 323 #[cfg(target_arch = "aarch64")] 324 { 325 Ok(Arc::new(MshvVm { 326 fd: vm_fd, 327 dirty_log_slots: Arc::new(RwLock::new(HashMap::new())), 328 })) 329 } 330 } 331 } 332 333 impl MshvHypervisor { 334 /// Create a hypervisor based on Mshv 335 #[allow(clippy::new_ret_no_self)] 336 pub fn new() -> hypervisor::Result<Arc<dyn hypervisor::Hypervisor>> { 337 let mshv_obj = 338 Mshv::new().map_err(|e| hypervisor::HypervisorError::HypervisorCreate(e.into()))?; 339 Ok(Arc::new(MshvHypervisor { mshv: mshv_obj })) 340 } 341 /// Check if the hypervisor is available 342 pub fn is_available() -> hypervisor::Result<bool> { 343 match std::fs::metadata("/dev/mshv") { 344 Ok(_) => Ok(true), 345 Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false), 346 Err(err) => Err(hypervisor::HypervisorError::HypervisorAvailableCheck( 347 err.into(), 348 )), 349 } 350 } 351 } 352 353 /// Implementation of Hypervisor trait for Mshv 354 /// 355 /// # Examples 356 /// 357 /// ``` 358 /// use hypervisor::mshv::MshvHypervisor; 359 /// use std::sync::Arc; 360 /// let mshv = MshvHypervisor::new().unwrap(); 361 /// let hypervisor = Arc::new(mshv); 362 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 363 /// ``` 364 impl hypervisor::Hypervisor for MshvHypervisor { 365 /// 366 /// Returns the type of the hypervisor 367 /// 368 fn hypervisor_type(&self) -> HypervisorType { 369 HypervisorType::Mshv 370 } 371 372 /// 373 /// Create a Vm of a specific type using the underlying hypervisor, passing memory size 374 /// Return a hypervisor-agnostic Vm trait object 375 /// 376 /// # Examples 377 /// 378 /// ``` 379 /// use hypervisor::kvm::KvmHypervisor; 380 /// use hypervisor::kvm::KvmVm; 381 /// let hypervisor = KvmHypervisor::new().unwrap(); 382 /// let vm = hypervisor.create_vm_with_type(0, 512*1024*1024).unwrap(); 383 /// ``` 384 fn create_vm_with_type_and_memory( 385 &self, 386 vm_type: u64, 387 #[cfg(feature = "sev_snp")] _mem_size: u64, 388 ) -> hypervisor::Result<Arc<dyn vm::Vm>> { 389 self.create_vm_with_type_and_memory_int( 390 vm_type, 391 #[cfg(feature = "sev_snp")] 392 Some(_mem_size), 393 ) 394 } 395 396 fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn crate::Vm>> { 397 self.create_vm_with_type_and_memory_int( 398 vm_type, 399 #[cfg(feature = "sev_snp")] 400 None, 401 ) 402 } 403 404 /// Create a mshv vm object and return the object as Vm trait object 405 /// 406 /// # Examples 407 /// 408 /// ``` 409 /// # extern crate hypervisor; 410 /// use hypervisor::mshv::MshvHypervisor; 411 /// use hypervisor::mshv::MshvVm; 412 /// let hypervisor = MshvHypervisor::new().unwrap(); 413 /// let vm = hypervisor.create_vm().unwrap(); 414 /// ``` 415 fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> { 416 let vm_type = 0; 417 self.create_vm_with_type(vm_type) 418 } 419 #[cfg(target_arch = "x86_64")] 420 /// 421 /// Get the supported CpuID 422 /// 423 fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> { 424 let mut cpuid = Vec::new(); 425 let functions: [u32; 2] = [0x1, 0xb]; 426 427 for function in functions { 428 cpuid.push(CpuIdEntry { 429 function, 430 ..Default::default() 431 }); 432 } 433 Ok(cpuid) 434 } 435 436 /// Get maximum number of vCPUs 437 fn get_max_vcpus(&self) -> u32 { 438 // TODO: Using HV_MAXIMUM_PROCESSORS would be better 439 // but the ioctl API is limited to u8 440 256 441 } 442 443 fn get_guest_debug_hw_bps(&self) -> usize { 444 0 445 } 446 } 447 448 #[cfg(feature = "sev_snp")] 449 struct Ghcb(*mut svm_ghcb_base); 450 451 #[cfg(feature = "sev_snp")] 452 // SAFETY: struct is based on GHCB page in the hypervisor, 453 // safe to Send across threads 454 unsafe impl Send for Ghcb {} 455 456 #[cfg(feature = "sev_snp")] 457 // SAFETY: struct is based on GHCB page in the hypervisor, 458 // safe to Sync across threads as this is only required for Vcpu trait 459 // functionally not used anyway 460 unsafe impl Sync for Ghcb {} 461 462 /// Vcpu struct for Microsoft Hypervisor 463 pub struct MshvVcpu { 464 fd: VcpuFd, 465 vp_index: u8, 466 #[cfg(target_arch = "x86_64")] 467 cpuid: Vec<CpuIdEntry>, 468 #[cfg(target_arch = "x86_64")] 469 msrs: Vec<MsrEntry>, 470 vm_ops: Option<Arc<dyn vm::VmOps>>, 471 vm_fd: Arc<VmFd>, 472 #[cfg(feature = "sev_snp")] 473 ghcb: Option<Ghcb>, 474 #[cfg(feature = "sev_snp")] 475 host_access_pages: ArcSwap<AtomicBitmap>, 476 } 477 478 /// Implementation of Vcpu trait for Microsoft Hypervisor 479 /// 480 /// # Examples 481 /// 482 /// ``` 483 /// use hypervisor::mshv::MshvHypervisor; 484 /// use std::sync::Arc; 485 /// let mshv = MshvHypervisor::new().unwrap(); 486 /// let hypervisor = Arc::new(mshv); 487 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 488 /// let vcpu = vm.create_vcpu(0, None).unwrap(); 489 /// ``` 490 impl cpu::Vcpu for MshvVcpu { 491 /// 492 /// Returns StandardRegisters with default value set 493 /// 494 #[cfg(target_arch = "x86_64")] 495 fn create_standard_regs(&self) -> crate::StandardRegisters { 496 mshv_bindings::StandardRegisters::default().into() 497 } 498 #[cfg(target_arch = "x86_64")] 499 /// 500 /// Returns the vCPU general purpose registers. 501 /// 502 fn get_regs(&self) -> cpu::Result<crate::StandardRegisters> { 503 Ok(self 504 .fd 505 .get_regs() 506 .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))? 507 .into()) 508 } 509 510 #[cfg(target_arch = "x86_64")] 511 /// 512 /// Sets the vCPU general purpose registers. 513 /// 514 fn set_regs(&self, regs: &crate::StandardRegisters) -> cpu::Result<()> { 515 let regs = (*regs).into(); 516 self.fd 517 .set_regs(®s) 518 .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into())) 519 } 520 521 #[cfg(target_arch = "x86_64")] 522 /// 523 /// Returns the vCPU special registers. 524 /// 525 fn get_sregs(&self) -> cpu::Result<crate::arch::x86::SpecialRegisters> { 526 Ok(self 527 .fd 528 .get_sregs() 529 .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))? 530 .into()) 531 } 532 533 #[cfg(target_arch = "x86_64")] 534 /// 535 /// Sets the vCPU special registers. 536 /// 537 fn set_sregs(&self, sregs: &crate::arch::x86::SpecialRegisters) -> cpu::Result<()> { 538 let sregs = (*sregs).into(); 539 self.fd 540 .set_sregs(&sregs) 541 .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into())) 542 } 543 544 #[cfg(target_arch = "x86_64")] 545 /// 546 /// Returns the floating point state (FPU) from the vCPU. 547 /// 548 fn get_fpu(&self) -> cpu::Result<FpuState> { 549 Ok(self 550 .fd 551 .get_fpu() 552 .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))? 553 .into()) 554 } 555 556 #[cfg(target_arch = "x86_64")] 557 /// 558 /// Set the floating point state (FPU) of a vCPU. 559 /// 560 fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> { 561 let fpu: mshv_bindings::FloatingPointUnit = (*fpu).clone().into(); 562 self.fd 563 .set_fpu(&fpu) 564 .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into())) 565 } 566 567 #[cfg(target_arch = "x86_64")] 568 /// 569 /// Returns the model-specific registers (MSR) for this vCPU. 570 /// 571 fn get_msrs(&self, msrs: &mut Vec<MsrEntry>) -> cpu::Result<usize> { 572 let mshv_msrs: Vec<msr_entry> = msrs.iter().map(|e| (*e).into()).collect(); 573 let mut mshv_msrs = MsrEntries::from_entries(&mshv_msrs).unwrap(); 574 let succ = self 575 .fd 576 .get_msrs(&mut mshv_msrs) 577 .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))?; 578 579 msrs[..succ].copy_from_slice( 580 &mshv_msrs.as_slice()[..succ] 581 .iter() 582 .map(|e| (*e).into()) 583 .collect::<Vec<MsrEntry>>(), 584 ); 585 586 Ok(succ) 587 } 588 589 #[cfg(target_arch = "x86_64")] 590 /// 591 /// Setup the model-specific registers (MSR) for this vCPU. 592 /// Returns the number of MSR entries actually written. 593 /// 594 fn set_msrs(&self, msrs: &[MsrEntry]) -> cpu::Result<usize> { 595 let mshv_msrs: Vec<msr_entry> = msrs.iter().map(|e| (*e).into()).collect(); 596 let mshv_msrs = MsrEntries::from_entries(&mshv_msrs).unwrap(); 597 self.fd 598 .set_msrs(&mshv_msrs) 599 .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into())) 600 } 601 602 #[cfg(target_arch = "x86_64")] 603 /// 604 /// X86 specific call to enable HyperV SynIC 605 /// 606 fn enable_hyperv_synic(&self) -> cpu::Result<()> { 607 /* We always have SynIC enabled on MSHV */ 608 Ok(()) 609 } 610 611 #[allow(non_upper_case_globals)] 612 fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> { 613 match self.fd.run() { 614 Ok(x) => match x.header.message_type { 615 hv_message_type_HVMSG_X64_HALT => { 616 debug!("HALT"); 617 Ok(cpu::VmExit::Reset) 618 } 619 hv_message_type_HVMSG_UNRECOVERABLE_EXCEPTION => { 620 warn!("TRIPLE FAULT"); 621 Ok(cpu::VmExit::Shutdown) 622 } 623 #[cfg(target_arch = "x86_64")] 624 hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => { 625 let info = x.to_ioport_info().unwrap(); 626 let access_info = info.access_info; 627 // SAFETY: access_info is valid, otherwise we won't be here 628 let len = unsafe { access_info.__bindgen_anon_1.access_size() } as usize; 629 let is_write = info.header.intercept_access_type == 1; 630 let port = info.port_number; 631 let mut data: [u8; 4] = [0; 4]; 632 let mut ret_rax = info.rax; 633 634 /* 635 * XXX: Ignore QEMU fw_cfg (0x5xx) and debug console (0x402) ports. 636 * 637 * Cloud Hypervisor doesn't support fw_cfg at the moment. It does support 0x402 638 * under the "fwdebug" feature flag. But that feature is not enabled by default 639 * and is considered legacy. 640 * 641 * OVMF unconditionally pokes these IO ports with string IO. 642 * 643 * Instead of trying to implement string IO support now which does not do much 644 * now, skip those ports explicitly to avoid panicking. 645 * 646 * Proper string IO support can be added once we gain the ability to translate 647 * guest virtual addresses to guest physical addresses on MSHV. 648 */ 649 match port { 650 0x402 | 0x510 | 0x511 | 0x514 => { 651 let insn_len = info.header.instruction_length() as u64; 652 653 /* Advance RIP and update RAX */ 654 let arr_reg_name_value = [ 655 ( 656 hv_register_name_HV_X64_REGISTER_RIP, 657 info.header.rip + insn_len, 658 ), 659 (hv_register_name_HV_X64_REGISTER_RAX, ret_rax), 660 ]; 661 set_registers_64!(self.fd, arr_reg_name_value) 662 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 663 return Ok(cpu::VmExit::Ignore); 664 } 665 _ => {} 666 } 667 668 assert!( 669 // SAFETY: access_info is valid, otherwise we won't be here 670 (unsafe { access_info.__bindgen_anon_1.string_op() } != 1), 671 "String IN/OUT not supported" 672 ); 673 assert!( 674 // SAFETY: access_info is valid, otherwise we won't be here 675 (unsafe { access_info.__bindgen_anon_1.rep_prefix() } != 1), 676 "Rep IN/OUT not supported" 677 ); 678 679 if is_write { 680 let data = (info.rax as u32).to_le_bytes(); 681 if let Some(vm_ops) = &self.vm_ops { 682 vm_ops 683 .pio_write(port.into(), &data[0..len]) 684 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 685 } 686 } else { 687 if let Some(vm_ops) = &self.vm_ops { 688 vm_ops 689 .pio_read(port.into(), &mut data[0..len]) 690 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 691 } 692 693 let v = u32::from_le_bytes(data); 694 /* Preserve high bits in EAX but clear out high bits in RAX */ 695 let mask = 0xffffffff >> (32 - len * 8); 696 let eax = (info.rax as u32 & !mask) | (v & mask); 697 ret_rax = eax as u64; 698 } 699 700 let insn_len = info.header.instruction_length() as u64; 701 702 /* Advance RIP and update RAX */ 703 let arr_reg_name_value = [ 704 ( 705 hv_register_name_HV_X64_REGISTER_RIP, 706 info.header.rip + insn_len, 707 ), 708 (hv_register_name_HV_X64_REGISTER_RAX, ret_rax), 709 ]; 710 set_registers_64!(self.fd, arr_reg_name_value) 711 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 712 Ok(cpu::VmExit::Ignore) 713 } 714 #[cfg(target_arch = "x86_64")] 715 msg_type @ (hv_message_type_HVMSG_UNMAPPED_GPA 716 | hv_message_type_HVMSG_GPA_INTERCEPT) => { 717 let info = x.to_memory_info().unwrap(); 718 let insn_len = info.instruction_byte_count as usize; 719 let gva = info.guest_virtual_address; 720 let gpa = info.guest_physical_address; 721 722 debug!("Exit ({:?}) GVA {:x} GPA {:x}", msg_type, gva, gpa); 723 724 let mut context = MshvEmulatorContext { 725 vcpu: self, 726 map: (gva, gpa), 727 }; 728 729 // Create a new emulator. 730 let mut emul = Emulator::new(&mut context); 731 732 // Emulate the trapped instruction, and only the first one. 733 let new_state = emul 734 .emulate_first_insn( 735 self.vp_index as usize, 736 &info.instruction_bytes[..insn_len], 737 ) 738 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 739 740 // Set CPU state back. 741 context 742 .set_cpu_state(self.vp_index as usize, new_state) 743 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 744 745 Ok(cpu::VmExit::Ignore) 746 } 747 #[cfg(feature = "sev_snp")] 748 hv_message_type_HVMSG_GPA_ATTRIBUTE_INTERCEPT => { 749 let info = x.to_gpa_attribute_info().unwrap(); 750 let host_vis = info.__bindgen_anon_1.host_visibility(); 751 if host_vis >= HV_MAP_GPA_READABLE | HV_MAP_GPA_WRITABLE { 752 warn!("Ignored attribute intercept with full host visibility"); 753 return Ok(cpu::VmExit::Ignore); 754 } 755 756 let num_ranges = info.__bindgen_anon_1.range_count(); 757 assert!(num_ranges >= 1); 758 if num_ranges > 1 { 759 return Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( 760 "Unhandled VCPU exit(GPA_ATTRIBUTE_INTERCEPT): Expected num_ranges to be 1 but found num_ranges {:?}", 761 num_ranges 762 ))); 763 } 764 765 // TODO: we could also deny the request with HvCallCompleteIntercept 766 let mut gpas = Vec::new(); 767 let ranges = info.ranges; 768 let (gfn_start, gfn_count) = snp::parse_gpa_range(ranges[0]).unwrap(); 769 debug!( 770 "Releasing pages: gfn_start: {:x?}, gfn_count: {:?}", 771 gfn_start, gfn_count 772 ); 773 let gpa_start = gfn_start * HV_PAGE_SIZE as u64; 774 for i in 0..gfn_count { 775 gpas.push(gpa_start + i * HV_PAGE_SIZE as u64); 776 } 777 778 let mut gpa_list = 779 vec_with_array_field::<mshv_modify_gpa_host_access, u64>(gpas.len()); 780 gpa_list[0].page_count = gpas.len() as u64; 781 gpa_list[0].flags = 0; 782 if host_vis & HV_MAP_GPA_READABLE != 0 { 783 gpa_list[0].flags |= 1 << MSHV_GPA_HOST_ACCESS_BIT_READABLE; 784 } 785 if host_vis & HV_MAP_GPA_WRITABLE != 0 { 786 gpa_list[0].flags |= 1 << MSHV_GPA_HOST_ACCESS_BIT_WRITABLE; 787 } 788 789 // SAFETY: gpa_list initialized with gpas.len() and now it is being turned into 790 // gpas_slice with gpas.len() again. It is guaranteed to be large enough to hold 791 // everything from gpas. 792 unsafe { 793 let gpas_slice: &mut [u64] = 794 gpa_list[0].guest_pfns.as_mut_slice(gpas.len()); 795 gpas_slice.copy_from_slice(gpas.as_slice()); 796 } 797 798 self.vm_fd 799 .modify_gpa_host_access(&gpa_list[0]) 800 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(anyhow!( 801 "Unhandled VCPU exit: attribute intercept - couldn't modify host access {}", e 802 )))?; 803 // Guest is revoking the shared access, so we need to update the bitmap 804 self.host_access_pages.rcu(|_bitmap| { 805 let bm = self.host_access_pages.load().as_ref().clone(); 806 bm.reset_addr_range(gpa_start as usize, gfn_count as usize); 807 bm 808 }); 809 Ok(cpu::VmExit::Ignore) 810 } 811 #[cfg(target_arch = "x86_64")] 812 hv_message_type_HVMSG_UNACCEPTED_GPA => { 813 let info = x.to_memory_info().unwrap(); 814 let gva = info.guest_virtual_address; 815 let gpa = info.guest_physical_address; 816 817 Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( 818 "Unhandled VCPU exit: Unaccepted GPA({:x}) found at GVA({:x})", 819 gpa, 820 gva, 821 ))) 822 } 823 #[cfg(target_arch = "x86_64")] 824 hv_message_type_HVMSG_X64_CPUID_INTERCEPT => { 825 let info = x.to_cpuid_info().unwrap(); 826 debug!("cpuid eax: {:x}", { info.rax }); 827 Ok(cpu::VmExit::Ignore) 828 } 829 #[cfg(target_arch = "x86_64")] 830 hv_message_type_HVMSG_X64_MSR_INTERCEPT => { 831 let info = x.to_msr_info().unwrap(); 832 if info.header.intercept_access_type == 0 { 833 debug!("msr read: {:x}", { info.msr_number }); 834 } else { 835 debug!("msr write: {:x}", { info.msr_number }); 836 } 837 Ok(cpu::VmExit::Ignore) 838 } 839 #[cfg(target_arch = "x86_64")] 840 hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT => { 841 //TODO: Handler for VMCALL here. 842 let info = x.to_exception_info().unwrap(); 843 debug!("Exception Info {:?}", { info.exception_vector }); 844 Ok(cpu::VmExit::Ignore) 845 } 846 #[cfg(target_arch = "x86_64")] 847 hv_message_type_HVMSG_X64_APIC_EOI => { 848 let info = x.to_apic_eoi_info().unwrap(); 849 // The kernel should dispatch the EOI to the correct thread. 850 // Check the VP index is the same as the one we have. 851 assert!(info.vp_index == self.vp_index as u32); 852 // The interrupt vector in info is u32, but x86 only supports 256 vectors. 853 // There is no good way to recover from this if the hypervisor messes around. 854 // Just unwrap. 855 Ok(cpu::VmExit::IoapicEoi( 856 info.interrupt_vector.try_into().unwrap(), 857 )) 858 } 859 #[cfg(feature = "sev_snp")] 860 hv_message_type_HVMSG_X64_SEV_VMGEXIT_INTERCEPT => { 861 let info = x.to_vmg_intercept_info().unwrap(); 862 let ghcb_data = info.ghcb_msr >> GHCB_INFO_BIT_WIDTH; 863 let ghcb_msr = svm_ghcb_msr { 864 as_uint64: info.ghcb_msr, 865 }; 866 // Safe to use unwrap, for sev_snp guest we already have the 867 // GHCB pointer wrapped in the option, otherwise this place is not reached. 868 let ghcb = self.ghcb.as_ref().unwrap().0; 869 870 // SAFETY: Accessing a union element from bindgen generated bindings. 871 let ghcb_op = unsafe { ghcb_msr.__bindgen_anon_2.ghcb_info() as u32 }; 872 // Sanity check on the header fields before handling other operations. 873 assert!(info.header.intercept_access_type == HV_INTERCEPT_ACCESS_EXECUTE as u8); 874 875 match ghcb_op { 876 GHCB_INFO_HYP_FEATURE_REQUEST => { 877 // Pre-condition: GHCB data must be zero 878 assert!(ghcb_data == 0); 879 let mut ghcb_response = GHCB_INFO_HYP_FEATURE_RESPONSE as u64; 880 // Indicate support for basic SEV-SNP features 881 ghcb_response |= 882 (GHCB_HYP_FEATURE_SEV_SNP << GHCB_INFO_BIT_WIDTH) as u64; 883 // Indicate support for SEV-SNP AP creation 884 ghcb_response |= (GHCB_HYP_FEATURE_SEV_SNP_AP_CREATION 885 << GHCB_INFO_BIT_WIDTH) 886 as u64; 887 debug!( 888 "GHCB_INFO_HYP_FEATURE_REQUEST: Supported features: {:0x}", 889 ghcb_response 890 ); 891 let arr_reg_name_value = 892 [(hv_register_name_HV_X64_REGISTER_GHCB, ghcb_response)]; 893 set_registers_64!(self.fd, arr_reg_name_value) 894 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 895 } 896 GHCB_INFO_REGISTER_REQUEST => { 897 let mut ghcb_gpa = hv_x64_register_sev_ghcb::default(); 898 899 // Disable the previously used GHCB page. 900 self.disable_prev_ghcb_page()?; 901 902 // SAFETY: Accessing a union element from bindgen generated bindings. 903 unsafe { 904 ghcb_gpa.__bindgen_anon_1.set_enabled(1); 905 ghcb_gpa 906 .__bindgen_anon_1 907 .set_page_number(ghcb_msr.__bindgen_anon_2.gpa_page_number()); 908 } 909 // SAFETY: Accessing a union element from bindgen generated bindings. 910 let reg_name_value = unsafe { 911 [( 912 hv_register_name_HV_X64_REGISTER_SEV_GHCB_GPA, 913 ghcb_gpa.as_uint64, 914 )] 915 }; 916 917 set_registers_64!(self.fd, reg_name_value) 918 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 919 920 let mut resp_ghcb_msr = svm_ghcb_msr::default(); 921 // SAFETY: Accessing a union element from bindgen generated bindings. 922 unsafe { 923 resp_ghcb_msr 924 .__bindgen_anon_2 925 .set_ghcb_info(GHCB_INFO_REGISTER_RESPONSE as u64); 926 resp_ghcb_msr.__bindgen_anon_2.set_gpa_page_number( 927 ghcb_msr.__bindgen_anon_2.gpa_page_number(), 928 ); 929 debug!("GHCB GPA is {:x}", ghcb_gpa.as_uint64); 930 } 931 // SAFETY: Accessing a union element from bindgen generated bindings. 932 let reg_name_value = unsafe { 933 [( 934 hv_register_name_HV_X64_REGISTER_GHCB, 935 resp_ghcb_msr.as_uint64, 936 )] 937 }; 938 939 set_registers_64!(self.fd, reg_name_value) 940 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 941 } 942 GHCB_INFO_SEV_INFO_REQUEST => { 943 let sev_cpuid_function = 0x8000_001F; 944 let cpu_leaf = self 945 .fd 946 .get_cpuid_values(sev_cpuid_function, 0, 0, 0) 947 .unwrap(); 948 let ebx = cpu_leaf[1]; 949 // First 6-byte of EBX represents page table encryption bit number 950 let pbit_encryption = (ebx & 0x3f) as u8; 951 let mut ghcb_response = GHCB_INFO_SEV_INFO_RESPONSE as u64; 952 953 // GHCBData[63:48] specifies the maximum GHCB protocol version supported 954 ghcb_response |= (GHCB_PROTOCOL_VERSION_MAX as u64) << 48; 955 // GHCBData[47:32] specifies the minimum GHCB protocol version supported 956 ghcb_response |= (GHCB_PROTOCOL_VERSION_MIN as u64) << 32; 957 // GHCBData[31:24] specifies the SEV page table encryption bit number. 958 ghcb_response |= (pbit_encryption as u64) << 24; 959 960 let arr_reg_name_value = 961 [(hv_register_name_HV_X64_REGISTER_GHCB, ghcb_response)]; 962 set_registers_64!(self.fd, arr_reg_name_value) 963 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 964 } 965 GHCB_INFO_NORMAL => { 966 let exit_code = 967 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_code as u32; 968 969 match exit_code { 970 SVM_EXITCODE_HV_DOORBELL_PAGE => { 971 let exit_info1 = 972 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32; 973 match exit_info1 { 974 SVM_NAE_HV_DOORBELL_PAGE_GET_PREFERRED => { 975 // Hypervisor does not have any preference for doorbell GPA. 976 let preferred_doorbell_gpa: u64 = 0xFFFFFFFFFFFFFFFF; 977 set_svm_field_u64_ptr!( 978 ghcb, 979 exit_info2, 980 preferred_doorbell_gpa 981 ); 982 } 983 SVM_NAE_HV_DOORBELL_PAGE_SET => { 984 let exit_info2 = info 985 .__bindgen_anon_2 986 .__bindgen_anon_1 987 .sw_exit_info2; 988 let mut ghcb_doorbell_gpa = 989 hv_x64_register_sev_hv_doorbell::default(); 990 // SAFETY: Accessing a union element from bindgen generated bindings. 991 unsafe { 992 ghcb_doorbell_gpa.__bindgen_anon_1.set_enabled(1); 993 ghcb_doorbell_gpa 994 .__bindgen_anon_1 995 .set_page_number(exit_info2 >> PAGE_SHIFT); 996 } 997 // SAFETY: Accessing a union element from bindgen generated bindings. 998 let reg_names = unsafe { 999 [( 1000 hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA, 1001 ghcb_doorbell_gpa.as_uint64, 1002 )] 1003 }; 1004 set_registers_64!(self.fd, reg_names).map_err(|e| { 1005 cpu::HypervisorCpuError::SetRegister(e.into()) 1006 })?; 1007 1008 set_svm_field_u64_ptr!(ghcb, exit_info2, exit_info2); 1009 1010 // Clear the SW_EXIT_INFO1 register to indicate no error 1011 self.clear_swexit_info1()?; 1012 } 1013 SVM_NAE_HV_DOORBELL_PAGE_QUERY => { 1014 let mut reg_assocs = [ hv_register_assoc { 1015 name: hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA, 1016 ..Default::default() 1017 } ]; 1018 self.fd.get_reg(&mut reg_assocs).unwrap(); 1019 // SAFETY: Accessing a union element from bindgen generated bindings. 1020 let doorbell_gpa = unsafe { reg_assocs[0].value.reg64 }; 1021 1022 set_svm_field_u64_ptr!(ghcb, exit_info2, doorbell_gpa); 1023 1024 // Clear the SW_EXIT_INFO1 register to indicate no error 1025 self.clear_swexit_info1()?; 1026 } 1027 SVM_NAE_HV_DOORBELL_PAGE_CLEAR => { 1028 set_svm_field_u64_ptr!(ghcb, exit_info2, 0); 1029 } 1030 _ => { 1031 panic!( 1032 "SVM_EXITCODE_HV_DOORBELL_PAGE: Unhandled exit code: {:0x}", 1033 exit_info1 1034 ); 1035 } 1036 } 1037 } 1038 SVM_EXITCODE_IOIO_PROT => { 1039 let exit_info1 = 1040 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32; 1041 let port_info = hv_sev_vmgexit_port_info { 1042 as_uint32: exit_info1, 1043 }; 1044 1045 let port = 1046 // SAFETY: Accessing a union element from bindgen generated bindings. 1047 unsafe { port_info.__bindgen_anon_1.intercepted_port() }; 1048 let mut len = 4; 1049 // SAFETY: Accessing a union element from bindgen generated bindings. 1050 unsafe { 1051 if port_info.__bindgen_anon_1.operand_size_16bit() == 1 { 1052 len = 2; 1053 } else if port_info.__bindgen_anon_1.operand_size_8bit() 1054 == 1 1055 { 1056 len = 1; 1057 } 1058 } 1059 let is_write = 1060 // SAFETY: Accessing a union element from bindgen generated bindings. 1061 unsafe { port_info.__bindgen_anon_1.access_type() == 0 }; 1062 // SAFETY: Accessing the field from a mapped address 1063 let mut data = unsafe { (*ghcb).rax.to_le_bytes() }; 1064 1065 if is_write { 1066 if let Some(vm_ops) = &self.vm_ops { 1067 vm_ops.pio_write(port.into(), &data[..len]).map_err( 1068 |e| cpu::HypervisorCpuError::RunVcpu(e.into()), 1069 )?; 1070 } 1071 } else { 1072 if let Some(vm_ops) = &self.vm_ops { 1073 vm_ops 1074 .pio_read(port.into(), &mut data[..len]) 1075 .map_err(|e| { 1076 cpu::HypervisorCpuError::RunVcpu(e.into()) 1077 })?; 1078 } 1079 set_svm_field_u64_ptr!(ghcb, rax, u64::from_le_bytes(data)); 1080 } 1081 1082 // Clear the SW_EXIT_INFO1 register to indicate no error 1083 self.clear_swexit_info1()?; 1084 } 1085 SVM_EXITCODE_MMIO_READ => { 1086 let src_gpa = 1087 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1; 1088 let data_len = 1089 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2 1090 as usize; 1091 // Sanity check to make sure data len is within supported range. 1092 assert!(data_len <= 0x8); 1093 1094 let mut data: Vec<u8> = vec![0; data_len]; 1095 if let Some(vm_ops) = &self.vm_ops { 1096 vm_ops.mmio_read(src_gpa, &mut data).map_err(|e| { 1097 cpu::HypervisorCpuError::RunVcpu(e.into()) 1098 })?; 1099 } 1100 // Copy the data to the shared buffer of the GHCB page 1101 let mut buffer_data = [0; 8]; 1102 buffer_data[..data_len].copy_from_slice(&data[..data_len]); 1103 // SAFETY: Updating the value of mapped area 1104 unsafe { (*ghcb).shared[0] = u64::from_le_bytes(buffer_data) }; 1105 1106 // Clear the SW_EXIT_INFO1 register to indicate no error 1107 self.clear_swexit_info1()?; 1108 } 1109 SVM_EXITCODE_MMIO_WRITE => { 1110 let dst_gpa = 1111 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1; 1112 let data_len = 1113 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2 1114 as usize; 1115 // Sanity check to make sure data len is within supported range. 1116 assert!(data_len <= 0x8); 1117 1118 let mut data = vec![0; data_len]; 1119 // SAFETY: Accessing data from a mapped address 1120 let bytes_shared_ghcb = 1121 unsafe { (*ghcb).shared[0].to_le_bytes() }; 1122 data.copy_from_slice(&bytes_shared_ghcb[..data_len]); 1123 1124 if let Some(vm_ops) = &self.vm_ops { 1125 vm_ops.mmio_write(dst_gpa, &data).map_err(|e| { 1126 cpu::HypervisorCpuError::RunVcpu(e.into()) 1127 })?; 1128 } 1129 1130 // Clear the SW_EXIT_INFO1 register to indicate no error 1131 self.clear_swexit_info1()?; 1132 } 1133 SVM_EXITCODE_SNP_GUEST_REQUEST 1134 | SVM_EXITCODE_SNP_EXTENDED_GUEST_REQUEST => { 1135 if exit_code == SVM_EXITCODE_SNP_EXTENDED_GUEST_REQUEST { 1136 info!("Fetching extended guest request is not supported"); 1137 // We don't support extended guest request, so we just write empty data. 1138 // This matches the behavior of KVM in Linux 6.11. 1139 1140 // Read RBX from the GHCB. 1141 // SAFETY: Accessing data from a mapped address 1142 let data_gpa = unsafe { (*ghcb).rax }; 1143 // SAFETY: Accessing data from a mapped address 1144 let data_npages = unsafe { (*ghcb).rbx }; 1145 1146 if data_npages > 0 { 1147 // The certificates are terminated by 24 zero bytes. 1148 // TODO: Need to check if data_gpa is the address of the shared buffer in the GHCB page 1149 // in that case we should clear the shared buffer(24 bytes) 1150 self.gpa_write(data_gpa, &[0; 24])?; 1151 } 1152 } 1153 1154 let req_gpa = 1155 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1; 1156 let rsp_gpa = 1157 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2; 1158 1159 let mshv_psp_req = 1160 mshv_issue_psp_guest_request { req_gpa, rsp_gpa }; 1161 self.vm_fd 1162 .psp_issue_guest_request(&mshv_psp_req) 1163 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 1164 1165 debug!( 1166 "SNP guest request: req_gpa {:0x} rsp_gpa {:0x}", 1167 req_gpa, rsp_gpa 1168 ); 1169 1170 set_svm_field_u64_ptr!(ghcb, exit_info2, 0); 1171 } 1172 SVM_EXITCODE_SNP_AP_CREATION => { 1173 let vmsa_gpa = 1174 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2; 1175 let apic_id = 1176 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 >> 32; 1177 debug!( 1178 "SNP AP CREATE REQUEST with VMSA GPA {:0x}, and APIC ID {:?}", 1179 vmsa_gpa, apic_id 1180 ); 1181 1182 let mshv_ap_create_req = mshv_sev_snp_ap_create { 1183 vp_id: apic_id, 1184 vmsa_gpa, 1185 }; 1186 self.vm_fd 1187 .sev_snp_ap_create(&mshv_ap_create_req) 1188 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 1189 1190 // Clear the SW_EXIT_INFO1 register to indicate no error 1191 self.clear_swexit_info1()?; 1192 } 1193 _ => panic!( 1194 "GHCB_INFO_NORMAL: Unhandled exit code: {:0x}", 1195 exit_code 1196 ), 1197 } 1198 } 1199 _ => panic!("Unsupported VMGEXIT operation: {:0x}", ghcb_op), 1200 } 1201 1202 Ok(cpu::VmExit::Ignore) 1203 } 1204 exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( 1205 "Unhandled VCPU exit {:?}", 1206 exit 1207 ))), 1208 }, 1209 1210 Err(e) => match e.errno() { 1211 libc::EAGAIN | libc::EINTR => Ok(cpu::VmExit::Ignore), 1212 _ => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( 1213 "VCPU error {:?}", 1214 e 1215 ))), 1216 }, 1217 } 1218 } 1219 1220 #[cfg(target_arch = "aarch64")] 1221 fn init_pmu(&self, irq: u32) -> cpu::Result<()> { 1222 unimplemented!() 1223 } 1224 1225 #[cfg(target_arch = "aarch64")] 1226 fn has_pmu_support(&self) -> bool { 1227 unimplemented!() 1228 } 1229 1230 #[cfg(target_arch = "aarch64")] 1231 fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> { 1232 unimplemented!() 1233 } 1234 1235 #[cfg(target_arch = "aarch64")] 1236 fn get_sys_reg(&self, sys_reg: u32) -> cpu::Result<u64> { 1237 unimplemented!() 1238 } 1239 1240 #[cfg(target_arch = "aarch64")] 1241 fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> { 1242 unimplemented!() 1243 } 1244 1245 #[cfg(target_arch = "aarch64")] 1246 fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> { 1247 unimplemented!() 1248 } 1249 1250 #[cfg(target_arch = "aarch64")] 1251 fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> { 1252 unimplemented!() 1253 } 1254 1255 #[cfg(target_arch = "aarch64")] 1256 fn get_regs(&self) -> cpu::Result<StandardRegisters> { 1257 unimplemented!() 1258 } 1259 1260 #[cfg(target_arch = "x86_64")] 1261 /// 1262 /// X86 specific call to setup the CPUID registers. 1263 /// 1264 fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> cpu::Result<()> { 1265 let cpuid: Vec<mshv_bindings::hv_cpuid_entry> = cpuid.iter().map(|e| (*e).into()).collect(); 1266 let mshv_cpuid = <CpuId>::from_entries(&cpuid) 1267 .map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?; 1268 1269 self.fd 1270 .register_intercept_result_cpuid(&mshv_cpuid) 1271 .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into())) 1272 } 1273 1274 #[cfg(target_arch = "x86_64")] 1275 /// 1276 /// X86 specific call to retrieve the CPUID registers. 1277 /// 1278 fn get_cpuid2(&self, _num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> { 1279 Ok(self.cpuid.clone()) 1280 } 1281 1282 #[cfg(target_arch = "x86_64")] 1283 /// 1284 /// X86 specific call to retrieve cpuid leaf 1285 /// 1286 fn get_cpuid_values( 1287 &self, 1288 function: u32, 1289 index: u32, 1290 xfem: u64, 1291 xss: u64, 1292 ) -> cpu::Result<[u32; 4]> { 1293 self.fd 1294 .get_cpuid_values(function, index, xfem, xss) 1295 .map_err(|e| cpu::HypervisorCpuError::GetCpuidVales(e.into())) 1296 } 1297 1298 #[cfg(target_arch = "x86_64")] 1299 /// 1300 /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 1301 /// 1302 fn get_lapic(&self) -> cpu::Result<crate::arch::x86::LapicState> { 1303 Ok(self 1304 .fd 1305 .get_lapic() 1306 .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))? 1307 .into()) 1308 } 1309 1310 #[cfg(target_arch = "x86_64")] 1311 /// 1312 /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 1313 /// 1314 fn set_lapic(&self, lapic: &crate::arch::x86::LapicState) -> cpu::Result<()> { 1315 let lapic: mshv_bindings::LapicState = (*lapic).clone().into(); 1316 self.fd 1317 .set_lapic(&lapic) 1318 .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into())) 1319 } 1320 1321 /// 1322 /// Returns the vcpu's current "multiprocessing state". 1323 /// 1324 fn get_mp_state(&self) -> cpu::Result<MpState> { 1325 Ok(MpState::Mshv) 1326 } 1327 1328 /// 1329 /// Sets the vcpu's current "multiprocessing state". 1330 /// 1331 fn set_mp_state(&self, _mp_state: MpState) -> cpu::Result<()> { 1332 Ok(()) 1333 } 1334 1335 #[cfg(target_arch = "x86_64")] 1336 /// 1337 /// Set CPU state for x86_64 guest. 1338 /// 1339 fn set_state(&self, state: &CpuState) -> cpu::Result<()> { 1340 let mut state: VcpuMshvState = state.clone().into(); 1341 self.set_msrs(&state.msrs)?; 1342 self.set_vcpu_events(&state.vcpu_events)?; 1343 self.set_regs(&state.regs.into())?; 1344 self.set_sregs(&state.sregs.into())?; 1345 self.set_fpu(&state.fpu)?; 1346 self.set_xcrs(&state.xcrs)?; 1347 // These registers are global and needed to be set only for first VCPU 1348 // as Microsoft Hypervisor allows setting this register for only one VCPU 1349 if self.vp_index == 0 { 1350 self.fd 1351 .set_misc_regs(&state.misc) 1352 .map_err(|e| cpu::HypervisorCpuError::SetMiscRegs(e.into()))? 1353 } 1354 self.fd 1355 .set_debug_regs(&state.dbg) 1356 .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?; 1357 self.fd 1358 .set_all_vp_state_components(&mut state.vp_states) 1359 .map_err(|e| cpu::HypervisorCpuError::SetAllVpStateComponents(e.into()))?; 1360 Ok(()) 1361 } 1362 1363 #[cfg(target_arch = "aarch64")] 1364 /// 1365 /// Set CPU state for aarch64 guest. 1366 /// 1367 fn set_state(&self, state: &CpuState) -> cpu::Result<()> { 1368 unimplemented!() 1369 } 1370 1371 #[cfg(target_arch = "x86_64")] 1372 /// 1373 /// Get CPU State for x86_64 guest 1374 /// 1375 fn state(&self) -> cpu::Result<CpuState> { 1376 let regs = self.get_regs()?; 1377 let sregs = self.get_sregs()?; 1378 let xcrs = self.get_xcrs()?; 1379 let fpu = self.get_fpu()?; 1380 let vcpu_events = self.get_vcpu_events()?; 1381 let mut msrs = self.msrs.clone(); 1382 self.get_msrs(&mut msrs)?; 1383 let misc = self 1384 .fd 1385 .get_misc_regs() 1386 .map_err(|e| cpu::HypervisorCpuError::GetMiscRegs(e.into()))?; 1387 let dbg = self 1388 .fd 1389 .get_debug_regs() 1390 .map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?; 1391 let vp_states = self 1392 .fd 1393 .get_all_vp_state_components() 1394 .map_err(|e| cpu::HypervisorCpuError::GetAllVpStateComponents(e.into()))?; 1395 1396 Ok(VcpuMshvState { 1397 msrs, 1398 vcpu_events, 1399 regs: regs.into(), 1400 sregs: sregs.into(), 1401 fpu, 1402 xcrs, 1403 dbg, 1404 misc, 1405 vp_states, 1406 } 1407 .into()) 1408 } 1409 1410 #[cfg(target_arch = "aarch64")] 1411 /// 1412 /// Get CPU state for aarch64 guest. 1413 /// 1414 fn state(&self) -> cpu::Result<CpuState> { 1415 unimplemented!() 1416 } 1417 1418 #[cfg(target_arch = "x86_64")] 1419 /// 1420 /// Translate guest virtual address to guest physical address 1421 /// 1422 fn translate_gva(&self, gva: u64, flags: u64) -> cpu::Result<(u64, u32)> { 1423 let r = self 1424 .fd 1425 .translate_gva(gva, flags) 1426 .map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?; 1427 1428 let gpa = r.0; 1429 // SAFETY: r is valid, otherwise this function will have returned 1430 let result_code = unsafe { r.1.__bindgen_anon_1.result_code }; 1431 1432 Ok((gpa, result_code)) 1433 } 1434 1435 #[cfg(target_arch = "x86_64")] 1436 /// 1437 /// Return the list of initial MSR entries for a VCPU 1438 /// 1439 fn boot_msr_entries(&self) -> Vec<MsrEntry> { 1440 use crate::arch::x86::{msr_index, MTRR_ENABLE, MTRR_MEM_TYPE_WB}; 1441 1442 [ 1443 msr!(msr_index::MSR_IA32_SYSENTER_CS), 1444 msr!(msr_index::MSR_IA32_SYSENTER_ESP), 1445 msr!(msr_index::MSR_IA32_SYSENTER_EIP), 1446 msr!(msr_index::MSR_STAR), 1447 msr!(msr_index::MSR_CSTAR), 1448 msr!(msr_index::MSR_LSTAR), 1449 msr!(msr_index::MSR_KERNEL_GS_BASE), 1450 msr!(msr_index::MSR_SYSCALL_MASK), 1451 msr_data!(msr_index::MSR_MTRRdefType, MTRR_ENABLE | MTRR_MEM_TYPE_WB), 1452 ] 1453 .to_vec() 1454 } 1455 1456 /// 1457 /// Sets the AMD specific vcpu's sev control register. 1458 /// 1459 #[cfg(feature = "sev_snp")] 1460 fn set_sev_control_register(&self, vmsa_pfn: u64) -> cpu::Result<()> { 1461 let sev_control_reg = snp::get_sev_control_register(vmsa_pfn); 1462 1463 self.fd 1464 .set_sev_control_register(sev_control_reg) 1465 .map_err(|e| cpu::HypervisorCpuError::SetSevControlRegister(e.into())) 1466 } 1467 #[cfg(target_arch = "x86_64")] 1468 /// 1469 /// Trigger NMI interrupt 1470 /// 1471 fn nmi(&self) -> cpu::Result<()> { 1472 let cfg = InterruptRequest { 1473 interrupt_type: hv_interrupt_type_HV_X64_INTERRUPT_TYPE_NMI, 1474 apic_id: self.vp_index as u64, 1475 level_triggered: false, 1476 vector: 0, 1477 logical_destination_mode: false, 1478 long_mode: false, 1479 }; 1480 self.vm_fd 1481 .request_virtual_interrupt(&cfg) 1482 .map_err(|e| cpu::HypervisorCpuError::Nmi(e.into())) 1483 } 1484 } 1485 1486 impl MshvVcpu { 1487 /// 1488 /// Deactivate previously used GHCB page. 1489 /// 1490 #[cfg(feature = "sev_snp")] 1491 fn disable_prev_ghcb_page(&self) -> cpu::Result<()> { 1492 let mut reg_assocs = [hv_register_assoc { 1493 name: hv_register_name_HV_X64_REGISTER_SEV_GHCB_GPA, 1494 ..Default::default() 1495 }]; 1496 self.fd.get_reg(&mut reg_assocs).unwrap(); 1497 // SAFETY: Accessing a union element from bindgen generated bindings. 1498 let prev_ghcb_gpa = unsafe { reg_assocs[0].value.reg64 }; 1499 1500 debug!("Prev GHCB GPA is {:x}", prev_ghcb_gpa); 1501 1502 let mut ghcb_gpa = hv_x64_register_sev_ghcb::default(); 1503 1504 // SAFETY: Accessing a union element from bindgen generated bindings. 1505 unsafe { 1506 ghcb_gpa.__bindgen_anon_1.set_enabled(0); 1507 ghcb_gpa.__bindgen_anon_1.set_page_number(prev_ghcb_gpa); 1508 } 1509 1510 // SAFETY: Accessing a union element from bindgen generated bindings. 1511 let reg_name_value = unsafe { 1512 [( 1513 hv_register_name_HV_X64_REGISTER_SEV_GHCB_GPA, 1514 ghcb_gpa.as_uint64, 1515 )] 1516 }; 1517 1518 set_registers_64!(self.fd, reg_name_value) 1519 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 1520 1521 Ok(()) 1522 } 1523 #[cfg(target_arch = "x86_64")] 1524 /// 1525 /// X86 specific call that returns the vcpu's current "xcrs". 1526 /// 1527 fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> { 1528 self.fd 1529 .get_xcrs() 1530 .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into())) 1531 } 1532 1533 #[cfg(target_arch = "x86_64")] 1534 /// 1535 /// X86 specific call that sets the vcpu's current "xcrs". 1536 /// 1537 fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> { 1538 self.fd 1539 .set_xcrs(xcrs) 1540 .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into())) 1541 } 1542 1543 #[cfg(target_arch = "x86_64")] 1544 /// 1545 /// Returns currently pending exceptions, interrupts, and NMIs as well as related 1546 /// states of the vcpu. 1547 /// 1548 fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> { 1549 self.fd 1550 .get_vcpu_events() 1551 .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into())) 1552 } 1553 1554 #[cfg(target_arch = "x86_64")] 1555 /// 1556 /// Sets pending exceptions, interrupts, and NMIs as well as related states 1557 /// of the vcpu. 1558 /// 1559 fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> { 1560 self.fd 1561 .set_vcpu_events(events) 1562 .map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into())) 1563 } 1564 1565 /// 1566 /// Clear SW_EXIT_INFO1 register for SEV-SNP guests. 1567 /// 1568 #[cfg(feature = "sev_snp")] 1569 fn clear_swexit_info1(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> { 1570 // Clear the SW_EXIT_INFO1 register to indicate no error 1571 // Safe to use unwrap, for sev_snp guest we already have the 1572 // GHCB pointer wrapped in the option, otherwise this place is not reached. 1573 let ghcb = self.ghcb.as_ref().unwrap().0; 1574 set_svm_field_u64_ptr!(ghcb, exit_info1, 0); 1575 1576 Ok(cpu::VmExit::Ignore) 1577 } 1578 1579 #[cfg(feature = "sev_snp")] 1580 fn gpa_write(&self, gpa: u64, data: &[u8]) -> cpu::Result<()> { 1581 for (gpa, chunk) in (gpa..) 1582 .step_by(HV_READ_WRITE_GPA_MAX_SIZE as usize) 1583 .zip(data.chunks(HV_READ_WRITE_GPA_MAX_SIZE as usize)) 1584 { 1585 let mut data = [0; HV_READ_WRITE_GPA_MAX_SIZE as usize]; 1586 data[..chunk.len()].copy_from_slice(chunk); 1587 1588 let mut rw_gpa_arg = mshv_bindings::mshv_read_write_gpa { 1589 base_gpa: gpa, 1590 byte_count: chunk.len() as u32, 1591 data, 1592 ..Default::default() 1593 }; 1594 self.fd 1595 .gpa_write(&mut rw_gpa_arg) 1596 .map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?; 1597 } 1598 1599 Ok(()) 1600 } 1601 } 1602 1603 /// Wrapper over Mshv VM ioctls. 1604 pub struct MshvVm { 1605 fd: Arc<VmFd>, 1606 #[cfg(target_arch = "x86_64")] 1607 msrs: Vec<MsrEntry>, 1608 dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>, 1609 #[cfg(feature = "sev_snp")] 1610 sev_snp_enabled: bool, 1611 #[cfg(feature = "sev_snp")] 1612 host_access_pages: ArcSwap<AtomicBitmap>, 1613 } 1614 1615 impl MshvVm { 1616 /// 1617 /// Creates an in-kernel device. 1618 /// 1619 /// See the documentation for `MSHV_CREATE_DEVICE`. 1620 fn create_device(&self, device: &mut CreateDevice) -> vm::Result<VfioDeviceFd> { 1621 let device_fd = self 1622 .fd 1623 .create_device(device) 1624 .map_err(|e| vm::HypervisorVmError::CreateDevice(e.into()))?; 1625 Ok(VfioDeviceFd::new_from_mshv(device_fd)) 1626 } 1627 } 1628 1629 /// 1630 /// Implementation of Vm trait for Mshv 1631 /// 1632 /// # Examples 1633 /// 1634 /// ``` 1635 /// extern crate hypervisor; 1636 /// use hypervisor::mshv::MshvHypervisor; 1637 /// use std::sync::Arc; 1638 /// let mshv = MshvHypervisor::new().unwrap(); 1639 /// let hypervisor = Arc::new(mshv); 1640 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 1641 /// ``` 1642 impl vm::Vm for MshvVm { 1643 #[cfg(target_arch = "x86_64")] 1644 /// 1645 /// Sets the address of the one-page region in the VM's address space. 1646 /// 1647 fn set_identity_map_address(&self, _address: u64) -> vm::Result<()> { 1648 Ok(()) 1649 } 1650 1651 #[cfg(target_arch = "x86_64")] 1652 /// 1653 /// Sets the address of the three-page region in the VM's address space. 1654 /// 1655 fn set_tss_address(&self, _offset: usize) -> vm::Result<()> { 1656 Ok(()) 1657 } 1658 1659 /// 1660 /// Creates an in-kernel interrupt controller. 1661 /// 1662 fn create_irq_chip(&self) -> vm::Result<()> { 1663 Ok(()) 1664 } 1665 1666 /// 1667 /// Registers an event that will, when signaled, trigger the `gsi` IRQ. 1668 /// 1669 fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> { 1670 debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi); 1671 1672 self.fd 1673 .register_irqfd(fd, gsi) 1674 .map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?; 1675 1676 Ok(()) 1677 } 1678 1679 /// 1680 /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ. 1681 /// 1682 fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> { 1683 debug!("unregister_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi); 1684 1685 self.fd 1686 .unregister_irqfd(fd, gsi) 1687 .map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))?; 1688 1689 Ok(()) 1690 } 1691 1692 /// 1693 /// Creates a VcpuFd object from a vcpu RawFd. 1694 /// 1695 fn create_vcpu( 1696 &self, 1697 id: u8, 1698 vm_ops: Option<Arc<dyn VmOps>>, 1699 ) -> vm::Result<Arc<dyn cpu::Vcpu>> { 1700 let vcpu_fd = self 1701 .fd 1702 .create_vcpu(id) 1703 .map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?; 1704 1705 /* Map the GHCB page to the VMM(root) address space 1706 * The map is available after the vcpu creation. This address is mapped 1707 * to the overlay ghcb page of the Microsoft Hypervisor, don't have 1708 * to worry about the scenario when a guest changes the GHCB mapping. 1709 */ 1710 #[cfg(feature = "sev_snp")] 1711 let ghcb = if self.sev_snp_enabled { 1712 // SAFETY: Safe to call as VCPU has this map already available upon creation 1713 let addr = unsafe { 1714 libc::mmap( 1715 std::ptr::null_mut(), 1716 HV_PAGE_SIZE, 1717 libc::PROT_READ | libc::PROT_WRITE, 1718 libc::MAP_SHARED, 1719 vcpu_fd.as_raw_fd(), 1720 MSHV_VP_MMAP_OFFSET_GHCB as i64 * libc::sysconf(libc::_SC_PAGE_SIZE), 1721 ) 1722 }; 1723 if addr == libc::MAP_FAILED { 1724 // No point of continuing, without this mmap VMGEXIT will fail anyway 1725 // Return error 1726 return Err(vm::HypervisorVmError::MmapToRoot); 1727 } 1728 Some(Ghcb(addr as *mut svm_ghcb_base)) 1729 } else { 1730 None 1731 }; 1732 let vcpu = MshvVcpu { 1733 fd: vcpu_fd, 1734 vp_index: id, 1735 #[cfg(target_arch = "x86_64")] 1736 cpuid: Vec::new(), 1737 #[cfg(target_arch = "x86_64")] 1738 msrs: self.msrs.clone(), 1739 vm_ops, 1740 vm_fd: self.fd.clone(), 1741 #[cfg(feature = "sev_snp")] 1742 ghcb, 1743 #[cfg(feature = "sev_snp")] 1744 host_access_pages: ArcSwap::new(self.host_access_pages.load().clone()), 1745 }; 1746 Ok(Arc::new(vcpu)) 1747 } 1748 1749 #[cfg(target_arch = "x86_64")] 1750 fn enable_split_irq(&self) -> vm::Result<()> { 1751 Ok(()) 1752 } 1753 1754 #[cfg(target_arch = "x86_64")] 1755 fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> { 1756 Ok(()) 1757 } 1758 1759 fn register_ioevent( 1760 &self, 1761 fd: &EventFd, 1762 addr: &IoEventAddress, 1763 datamatch: Option<DataMatch>, 1764 ) -> vm::Result<()> { 1765 #[cfg(feature = "sev_snp")] 1766 if self.sev_snp_enabled { 1767 return Ok(()); 1768 } 1769 1770 let addr = &mshv_ioctls::IoEventAddress::from(*addr); 1771 debug!( 1772 "register_ioevent fd {} addr {:x?} datamatch {:?}", 1773 fd.as_raw_fd(), 1774 addr, 1775 datamatch 1776 ); 1777 if let Some(dm) = datamatch { 1778 match dm { 1779 vm::DataMatch::DataMatch32(mshv_dm32) => self 1780 .fd 1781 .register_ioevent(fd, addr, mshv_dm32) 1782 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())), 1783 vm::DataMatch::DataMatch64(mshv_dm64) => self 1784 .fd 1785 .register_ioevent(fd, addr, mshv_dm64) 1786 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())), 1787 } 1788 } else { 1789 self.fd 1790 .register_ioevent(fd, addr, NoDatamatch) 1791 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())) 1792 } 1793 } 1794 1795 /// Unregister an event from a certain address it has been previously registered to. 1796 fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> { 1797 #[cfg(feature = "sev_snp")] 1798 if self.sev_snp_enabled { 1799 return Ok(()); 1800 } 1801 1802 let addr = &mshv_ioctls::IoEventAddress::from(*addr); 1803 debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr); 1804 1805 self.fd 1806 .unregister_ioevent(fd, addr, NoDatamatch) 1807 .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into())) 1808 } 1809 1810 /// Creates a guest physical memory region. 1811 fn create_user_memory_region(&self, user_memory_region: UserMemoryRegion) -> vm::Result<()> { 1812 let user_memory_region: mshv_user_mem_region = user_memory_region.into(); 1813 // No matter read only or not we keep track the slots. 1814 // For readonly hypervisor can enable the dirty bits, 1815 // but a VM exit happens before setting the dirty bits 1816 self.dirty_log_slots.write().unwrap().insert( 1817 user_memory_region.guest_pfn, 1818 MshvDirtyLogSlot { 1819 guest_pfn: user_memory_region.guest_pfn, 1820 memory_size: user_memory_region.size, 1821 }, 1822 ); 1823 1824 self.fd 1825 .map_user_memory(user_memory_region) 1826 .map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))?; 1827 Ok(()) 1828 } 1829 1830 /// Removes a guest physical memory region. 1831 fn remove_user_memory_region(&self, user_memory_region: UserMemoryRegion) -> vm::Result<()> { 1832 let user_memory_region: mshv_user_mem_region = user_memory_region.into(); 1833 // Remove the corresponding entry from "self.dirty_log_slots" if needed 1834 self.dirty_log_slots 1835 .write() 1836 .unwrap() 1837 .remove(&user_memory_region.guest_pfn); 1838 1839 self.fd 1840 .unmap_user_memory(user_memory_region) 1841 .map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))?; 1842 Ok(()) 1843 } 1844 1845 fn make_user_memory_region( 1846 &self, 1847 _slot: u32, 1848 guest_phys_addr: u64, 1849 memory_size: u64, 1850 userspace_addr: u64, 1851 readonly: bool, 1852 _log_dirty_pages: bool, 1853 ) -> UserMemoryRegion { 1854 let mut flags = 1 << MSHV_SET_MEM_BIT_EXECUTABLE; 1855 if !readonly { 1856 flags |= 1 << MSHV_SET_MEM_BIT_WRITABLE; 1857 } 1858 1859 mshv_user_mem_region { 1860 flags, 1861 guest_pfn: guest_phys_addr >> PAGE_SHIFT, 1862 size: memory_size, 1863 userspace_addr, 1864 ..Default::default() 1865 } 1866 .into() 1867 } 1868 1869 fn create_passthrough_device(&self) -> vm::Result<VfioDeviceFd> { 1870 let mut vfio_dev = mshv_create_device { 1871 type_: mshv_device_type_MSHV_DEV_TYPE_VFIO, 1872 fd: 0, 1873 flags: 0, 1874 }; 1875 1876 self.create_device(&mut vfio_dev) 1877 .map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into())) 1878 } 1879 1880 /// 1881 /// Constructs a routing entry 1882 /// 1883 fn make_routing_entry(&self, gsi: u32, config: &InterruptSourceConfig) -> IrqRoutingEntry { 1884 match config { 1885 InterruptSourceConfig::MsiIrq(cfg) => mshv_user_irq_entry { 1886 gsi, 1887 address_lo: cfg.low_addr, 1888 address_hi: cfg.high_addr, 1889 data: cfg.data, 1890 } 1891 .into(), 1892 _ => { 1893 unreachable!() 1894 } 1895 } 1896 } 1897 1898 fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> { 1899 let mut msi_routing = 1900 vec_with_array_field::<mshv_user_irq_table, mshv_user_irq_entry>(entries.len()); 1901 msi_routing[0].nr = entries.len() as u32; 1902 1903 let entries: Vec<mshv_user_irq_entry> = entries 1904 .iter() 1905 .map(|entry| match entry { 1906 IrqRoutingEntry::Mshv(e) => *e, 1907 #[allow(unreachable_patterns)] 1908 _ => panic!("IrqRoutingEntry type is wrong"), 1909 }) 1910 .collect(); 1911 1912 // SAFETY: msi_routing initialized with entries.len() and now it is being turned into 1913 // entries_slice with entries.len() again. It is guaranteed to be large enough to hold 1914 // everything from entries. 1915 unsafe { 1916 let entries_slice: &mut [mshv_user_irq_entry] = 1917 msi_routing[0].entries.as_mut_slice(entries.len()); 1918 entries_slice.copy_from_slice(&entries); 1919 } 1920 1921 self.fd 1922 .set_msi_routing(&msi_routing[0]) 1923 .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into())) 1924 } 1925 1926 /// 1927 /// Start logging dirty pages 1928 /// 1929 fn start_dirty_log(&self) -> vm::Result<()> { 1930 self.fd 1931 .enable_dirty_page_tracking() 1932 .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into())) 1933 } 1934 1935 /// 1936 /// Stop logging dirty pages 1937 /// 1938 fn stop_dirty_log(&self) -> vm::Result<()> { 1939 let dirty_log_slots = self.dirty_log_slots.read().unwrap(); 1940 // Before disabling the dirty page tracking we need 1941 // to set the dirty bits in the Hypervisor 1942 // This is a requirement from Microsoft Hypervisor 1943 for (_, s) in dirty_log_slots.iter() { 1944 self.fd 1945 .get_dirty_log( 1946 s.guest_pfn, 1947 s.memory_size as usize, 1948 MSHV_GPAP_ACCESS_OP_SET as u8, 1949 ) 1950 .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?; 1951 } 1952 self.fd 1953 .disable_dirty_page_tracking() 1954 .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?; 1955 Ok(()) 1956 } 1957 1958 /// 1959 /// Get dirty pages bitmap (one bit per page) 1960 /// 1961 fn get_dirty_log(&self, _slot: u32, base_gpa: u64, memory_size: u64) -> vm::Result<Vec<u64>> { 1962 self.fd 1963 .get_dirty_log( 1964 base_gpa >> PAGE_SHIFT, 1965 memory_size as usize, 1966 MSHV_GPAP_ACCESS_OP_CLEAR as u8, 1967 ) 1968 .map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into())) 1969 } 1970 1971 /// Retrieve guest clock. 1972 #[cfg(target_arch = "x86_64")] 1973 fn get_clock(&self) -> vm::Result<ClockData> { 1974 let val = self 1975 .fd 1976 .get_partition_property(hv_partition_property_code_HV_PARTITION_PROPERTY_REFERENCE_TIME) 1977 .map_err(|e| vm::HypervisorVmError::GetClock(e.into()))?; 1978 Ok(MshvClockData { ref_time: val }.into()) 1979 } 1980 1981 /// Set guest clock. 1982 #[cfg(target_arch = "x86_64")] 1983 fn set_clock(&self, data: &ClockData) -> vm::Result<()> { 1984 let data: MshvClockData = (*data).into(); 1985 self.fd 1986 .set_partition_property( 1987 hv_partition_property_code_HV_PARTITION_PROPERTY_REFERENCE_TIME, 1988 data.ref_time, 1989 ) 1990 .map_err(|e| vm::HypervisorVmError::SetClock(e.into())) 1991 } 1992 1993 /// Downcast to the underlying MshvVm type 1994 fn as_any(&self) -> &dyn Any { 1995 self 1996 } 1997 1998 /// Initialize the SEV-SNP VM 1999 #[cfg(feature = "sev_snp")] 2000 fn sev_snp_init(&self) -> vm::Result<()> { 2001 self.fd 2002 .set_partition_property( 2003 hv_partition_property_code_HV_PARTITION_PROPERTY_ISOLATION_STATE, 2004 hv_partition_isolation_state_HV_PARTITION_ISOLATION_SECURE as u64, 2005 ) 2006 .map_err(|e| vm::HypervisorVmError::InitializeSevSnp(e.into())) 2007 } 2008 2009 /// 2010 /// Importing isolated pages, these pages will be used 2011 /// for the PSP(Platform Security Processor) measurement. 2012 #[cfg(feature = "sev_snp")] 2013 fn import_isolated_pages( 2014 &self, 2015 page_type: u32, 2016 page_size: u32, 2017 pages: &[u64], 2018 ) -> vm::Result<()> { 2019 debug_assert!(page_size == hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB); 2020 if pages.is_empty() { 2021 return Ok(()); 2022 } 2023 2024 let mut isolated_pages = 2025 vec_with_array_field::<mshv_import_isolated_pages, u64>(pages.len()); 2026 isolated_pages[0].page_type = page_type as u8; 2027 isolated_pages[0].page_count = pages.len() as u64; 2028 // SAFETY: isolated_pages initialized with pages.len() and now it is being turned into 2029 // pages_slice with pages.len() again. It is guaranteed to be large enough to hold 2030 // everything from pages. 2031 unsafe { 2032 let pages_slice: &mut [u64] = isolated_pages[0].guest_pfns.as_mut_slice(pages.len()); 2033 pages_slice.copy_from_slice(pages); 2034 } 2035 self.fd 2036 .import_isolated_pages(&isolated_pages[0]) 2037 .map_err(|e| vm::HypervisorVmError::ImportIsolatedPages(e.into())) 2038 } 2039 2040 /// 2041 /// Complete isolated import, telling the hypervisor that 2042 /// importing the pages to guest memory is complete. 2043 /// 2044 #[cfg(feature = "sev_snp")] 2045 fn complete_isolated_import( 2046 &self, 2047 snp_id_block: IGVM_VHS_SNP_ID_BLOCK, 2048 host_data: [u8; 32], 2049 id_block_enabled: u8, 2050 ) -> vm::Result<()> { 2051 let mut auth_info = hv_snp_id_auth_info { 2052 id_key_algorithm: snp_id_block.id_key_algorithm, 2053 auth_key_algorithm: snp_id_block.author_key_algorithm, 2054 ..Default::default() 2055 }; 2056 // Each of r/s component is 576 bits long 2057 auth_info.id_block_signature[..SIG_R_COMPONENT_SIZE_IN_BYTES] 2058 .copy_from_slice(snp_id_block.id_key_signature.r_comp.as_ref()); 2059 auth_info.id_block_signature 2060 [SIG_R_COMPONENT_SIZE_IN_BYTES..SIG_R_AND_S_COMPONENT_SIZE_IN_BYTES] 2061 .copy_from_slice(snp_id_block.id_key_signature.s_comp.as_ref()); 2062 auth_info.id_key[..ECDSA_CURVE_ID_SIZE_IN_BYTES] 2063 .copy_from_slice(snp_id_block.id_public_key.curve.to_le_bytes().as_ref()); 2064 auth_info.id_key[ECDSA_SIG_X_COMPONENT_START..ECDSA_SIG_X_COMPONENT_END] 2065 .copy_from_slice(snp_id_block.id_public_key.qx.as_ref()); 2066 auth_info.id_key[ECDSA_SIG_Y_COMPONENT_START..ECDSA_SIG_Y_COMPONENT_END] 2067 .copy_from_slice(snp_id_block.id_public_key.qy.as_ref()); 2068 2069 let data = mshv_complete_isolated_import { 2070 import_data: hv_partition_complete_isolated_import_data { 2071 psp_parameters: hv_psp_launch_finish_data { 2072 id_block: hv_snp_id_block { 2073 launch_digest: snp_id_block.ld, 2074 family_id: snp_id_block.family_id, 2075 image_id: snp_id_block.image_id, 2076 version: snp_id_block.version, 2077 guest_svn: snp_id_block.guest_svn, 2078 policy: get_default_snp_guest_policy(), 2079 }, 2080 id_auth_info: auth_info, 2081 host_data, 2082 id_block_enabled, 2083 author_key_enabled: 0, 2084 }, 2085 }, 2086 }; 2087 self.fd 2088 .complete_isolated_import(&data) 2089 .map_err(|e| vm::HypervisorVmError::CompleteIsolatedImport(e.into())) 2090 } 2091 2092 #[cfg(target_arch = "aarch64")] 2093 fn create_vgic(&self, config: VgicConfig) -> vm::Result<Arc<Mutex<dyn Vgic>>> { 2094 unimplemented!() 2095 } 2096 2097 #[cfg(target_arch = "aarch64")] 2098 fn get_preferred_target(&self, kvi: &mut VcpuInit) -> vm::Result<()> { 2099 unimplemented!() 2100 } 2101 2102 /// Pause the VM 2103 fn pause(&self) -> vm::Result<()> { 2104 // Freeze the partition 2105 self.fd 2106 .set_partition_property( 2107 hv_partition_property_code_HV_PARTITION_PROPERTY_TIME_FREEZE, 2108 1u64, 2109 ) 2110 .map_err(|e| { 2111 vm::HypervisorVmError::SetVmProperty(anyhow!( 2112 "Failed to set partition property: {}", 2113 e 2114 )) 2115 }) 2116 } 2117 2118 /// Resume the VM 2119 fn resume(&self) -> vm::Result<()> { 2120 // Resuming the partition using TIME_FREEZE property 2121 self.fd 2122 .set_partition_property( 2123 hv_partition_property_code_HV_PARTITION_PROPERTY_TIME_FREEZE, 2124 0u64, 2125 ) 2126 .map_err(|e| { 2127 vm::HypervisorVmError::SetVmProperty(anyhow!( 2128 "Failed to set partition property: {}", 2129 e 2130 )) 2131 }) 2132 } 2133 2134 #[cfg(feature = "sev_snp")] 2135 fn gain_page_access(&self, gpa: u64, size: u32) -> vm::Result<()> { 2136 use mshv_ioctls::set_bits; 2137 const ONE_GB: usize = 1024 * 1024 * 1024; 2138 2139 if !self.sev_snp_enabled { 2140 return Ok(()); 2141 } 2142 2143 let start_gpfn: u64 = gpa >> PAGE_SHIFT; 2144 let end_gpfn: u64 = (gpa + size as u64 - 1) >> PAGE_SHIFT; 2145 2146 // Enlarge the bitmap if the PFN is greater than the bitmap length 2147 if end_gpfn >= self.host_access_pages.load().as_ref().len() as u64 { 2148 self.host_access_pages.rcu(|bitmap| { 2149 let mut bm = bitmap.as_ref().clone(); 2150 bm.enlarge(ONE_GB); 2151 bm 2152 }); 2153 } 2154 2155 let gpas: Vec<u64> = (start_gpfn..=end_gpfn) 2156 .filter(|x| { 2157 !self 2158 .host_access_pages 2159 .load() 2160 .as_ref() 2161 .is_bit_set(*x as usize) 2162 }) 2163 .map(|x| x << PAGE_SHIFT) 2164 .collect(); 2165 2166 if !gpas.is_empty() { 2167 let mut gpa_list = vec_with_array_field::<mshv_modify_gpa_host_access, u64>(gpas.len()); 2168 gpa_list[0].page_count = gpas.len() as u64; 2169 gpa_list[0].flags = set_bits!( 2170 u8, 2171 MSHV_GPA_HOST_ACCESS_BIT_ACQUIRE, 2172 MSHV_GPA_HOST_ACCESS_BIT_READABLE, 2173 MSHV_GPA_HOST_ACCESS_BIT_WRITABLE 2174 ); 2175 2176 // SAFETY: gpa_list initialized with gpas.len() and now it is being turned into 2177 // gpas_slice with gpas.len() again. It is guaranteed to be large enough to hold 2178 // everything from gpas. 2179 unsafe { 2180 let gpas_slice: &mut [u64] = gpa_list[0].guest_pfns.as_mut_slice(gpas.len()); 2181 gpas_slice.copy_from_slice(gpas.as_slice()); 2182 } 2183 2184 self.fd 2185 .modify_gpa_host_access(&gpa_list[0]) 2186 .map_err(|e| vm::HypervisorVmError::ModifyGpaHostAccess(e.into()))?; 2187 2188 for acquired_gpa in gpas { 2189 self.host_access_pages.rcu(|bitmap| { 2190 let bm = bitmap.clone(); 2191 bm.set_bit((acquired_gpa >> PAGE_SHIFT) as usize); 2192 bm 2193 }); 2194 } 2195 } 2196 2197 Ok(()) 2198 } 2199 } 2200