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