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