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