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