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