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