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