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