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