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