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