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