1 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 2 // 3 // Copyright © 2020, Microsoft Corporation 4 // 5 6 use crate::arch::emulator::{PlatformEmulator, PlatformError}; 7 8 #[cfg(target_arch = "x86_64")] 9 use crate::arch::x86::emulator::{Emulator, EmulatorCpuState}; 10 use crate::cpu; 11 use crate::cpu::Vcpu; 12 use crate::hypervisor; 13 use crate::vec_with_array_field; 14 use crate::vm::{self, VmmOps}; 15 pub use mshv_bindings::*; 16 pub use mshv_ioctls::IoEventAddress; 17 use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd}; 18 use serde_derive::{Deserialize, Serialize}; 19 use std::sync::Arc; 20 use vm::DataMatch; 21 // x86_64 dependencies 22 #[cfg(target_arch = "x86_64")] 23 pub mod x86_64; 24 use crate::device; 25 use vmm_sys_util::eventfd::EventFd; 26 #[cfg(target_arch = "x86_64")] 27 pub use x86_64::VcpuMshvState as CpuState; 28 #[cfg(target_arch = "x86_64")] 29 pub use x86_64::*; 30 31 #[cfg(target_arch = "x86_64")] 32 use std::fs::File; 33 use std::os::unix::io::AsRawFd; 34 use std::sync::RwLock; 35 36 pub const PAGE_SHIFT: usize = 12; 37 38 #[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)] 39 pub struct HvState { 40 hypercall_page: u64, 41 } 42 43 pub use HvState as VmState; 44 45 /// Wrapper over mshv system ioctls. 46 pub struct MshvHypervisor { 47 mshv: Mshv, 48 } 49 50 impl MshvHypervisor { 51 /// Create a hypervisor based on Mshv 52 pub fn new() -> hypervisor::Result<MshvHypervisor> { 53 let mshv_obj = 54 Mshv::new().map_err(|e| hypervisor::HypervisorError::HypervisorCreate(e.into()))?; 55 Ok(MshvHypervisor { mshv: mshv_obj }) 56 } 57 } 58 /// Implementation of Hypervisor trait for Mshv 59 /// Example: 60 /// #[cfg(feature = "mshv")] 61 /// extern crate hypervisor 62 /// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap(); 63 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv); 64 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 65 /// 66 impl hypervisor::Hypervisor for MshvHypervisor { 67 /// Create a mshv vm object and return the object as Vm trait object 68 /// Example 69 /// # extern crate hypervisor; 70 /// # use hypervisor::MshvHypervisor; 71 /// use hypervisor::MshvVm; 72 /// let hypervisor = MshvHypervisor::new().unwrap(); 73 /// let vm = hypervisor.create_vm().unwrap() 74 /// 75 fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> { 76 let fd: VmFd; 77 loop { 78 match self.mshv.create_vm() { 79 Ok(res) => fd = res, 80 Err(e) => { 81 if e.errno() == libc::EINTR { 82 // If the error returned is EINTR, which means the 83 // ioctl has been interrupted, we have to retry as 84 // this can't be considered as a regular error. 85 continue; 86 } else { 87 return Err(hypervisor::HypervisorError::VmCreate(e.into())); 88 } 89 } 90 } 91 break; 92 } 93 94 let msr_list = self.get_msr_list()?; 95 let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize; 96 let mut msrs = MsrEntries::new(num_msrs).unwrap(); 97 let indices = msr_list.as_slice(); 98 let msr_entries = msrs.as_mut_slice(); 99 for (pos, index) in indices.iter().enumerate() { 100 msr_entries[pos].index = *index; 101 } 102 let vm_fd = Arc::new(fd); 103 104 Ok(Arc::new(MshvVm { 105 fd: vm_fd, 106 msrs, 107 hv_state: hv_state_init(), 108 vmmops: None, 109 })) 110 } 111 /// 112 /// Get the supported CpuID 113 /// 114 fn get_cpuid(&self) -> hypervisor::Result<CpuId> { 115 Ok(CpuId::new(1).unwrap()) 116 } 117 #[cfg(target_arch = "x86_64")] 118 /// 119 /// Retrieve the list of MSRs supported by KVM. 120 /// 121 fn get_msr_list(&self) -> hypervisor::Result<MsrList> { 122 self.mshv 123 .get_msr_index_list() 124 .map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into())) 125 } 126 } 127 128 #[allow(dead_code)] 129 /// Vcpu struct for Microsoft Hypervisor 130 pub struct MshvVcpu { 131 fd: VcpuFd, 132 vp_index: u8, 133 cpuid: CpuId, 134 msrs: MsrEntries, 135 hv_state: Arc<RwLock<HvState>>, // Mshv State 136 vmmops: Option<Arc<Box<dyn vm::VmmOps>>>, 137 } 138 139 /// Implementation of Vcpu trait for Microsoft Hypervisor 140 /// Example: 141 /// #[cfg(feature = "mshv")] 142 /// extern crate hypervisor 143 /// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap(); 144 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv); 145 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 146 /// let vcpu = vm.create_vcpu(0).unwrap(); 147 /// vcpu.get/set().unwrap() 148 /// 149 impl cpu::Vcpu for MshvVcpu { 150 #[cfg(target_arch = "x86_64")] 151 /// 152 /// Returns the vCPU general purpose registers. 153 /// 154 fn get_regs(&self) -> cpu::Result<StandardRegisters> { 155 self.fd 156 .get_regs() 157 .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into())) 158 } 159 #[cfg(target_arch = "x86_64")] 160 /// 161 /// Sets the vCPU general purpose registers. 162 /// 163 fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> { 164 self.fd 165 .set_regs(regs) 166 .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into())) 167 } 168 #[cfg(target_arch = "x86_64")] 169 /// 170 /// Returns the vCPU special registers. 171 /// 172 fn get_sregs(&self) -> cpu::Result<SpecialRegisters> { 173 self.fd 174 .get_sregs() 175 .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into())) 176 } 177 #[cfg(target_arch = "x86_64")] 178 /// 179 /// Sets the vCPU special registers. 180 /// 181 fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> { 182 self.fd 183 .set_sregs(sregs) 184 .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into())) 185 } 186 #[cfg(target_arch = "x86_64")] 187 /// 188 /// Returns the floating point state (FPU) from the vCPU. 189 /// 190 fn get_fpu(&self) -> cpu::Result<FpuState> { 191 self.fd 192 .get_fpu() 193 .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into())) 194 } 195 #[cfg(target_arch = "x86_64")] 196 /// 197 /// Set the floating point state (FPU) of a vCPU. 198 /// 199 fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> { 200 self.fd 201 .set_fpu(fpu) 202 .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into())) 203 } 204 205 #[cfg(target_arch = "x86_64")] 206 /// 207 /// Returns the model-specific registers (MSR) for this vCPU. 208 /// 209 fn get_msrs(&self, msrs: &mut MsrEntries) -> cpu::Result<usize> { 210 self.fd 211 .get_msrs(msrs) 212 .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into())) 213 } 214 #[cfg(target_arch = "x86_64")] 215 /// 216 /// Setup the model-specific registers (MSR) for this vCPU. 217 /// Returns the number of MSR entries actually written. 218 /// 219 fn set_msrs(&self, msrs: &MsrEntries) -> cpu::Result<usize> { 220 self.fd 221 .set_msrs(msrs) 222 .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into())) 223 } 224 225 #[cfg(target_arch = "x86_64")] 226 /// 227 /// X86 specific call that returns the vcpu's current "xcrs". 228 /// 229 fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> { 230 self.fd 231 .get_xcrs() 232 .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into())) 233 } 234 #[cfg(target_arch = "x86_64")] 235 /// 236 /// X86 specific call that sets the vcpu's current "xcrs". 237 /// 238 fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> { 239 self.fd 240 .set_xcrs(xcrs) 241 .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into())) 242 } 243 #[cfg(target_arch = "x86_64")] 244 /// 245 /// Returns currently pending exceptions, interrupts, and NMIs as well as related 246 /// states of the vcpu. 247 /// 248 fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> { 249 self.fd 250 .get_vcpu_events() 251 .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into())) 252 } 253 #[cfg(target_arch = "x86_64")] 254 /// 255 /// Sets pending exceptions, interrupts, and NMIs as well as related states 256 /// of the vcpu. 257 /// 258 fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> { 259 self.fd 260 .set_vcpu_events(events) 261 .map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into())) 262 } 263 #[cfg(target_arch = "x86_64")] 264 /// 265 /// X86 specific call to enable HyperV SynIC 266 /// 267 fn enable_hyperv_synic(&self) -> cpu::Result<()> { 268 /* We always have SynIC enabled on MSHV */ 269 Ok(()) 270 } 271 #[allow(non_upper_case_globals)] 272 fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> { 273 // Safe because this is just only done during initialization. 274 // TODO don't zero it everytime we enter this function. 275 let hv_message: hv_message = unsafe { std::mem::zeroed() }; 276 match self.fd.run(hv_message) { 277 Ok(x) => match x.header.message_type { 278 hv_message_type_HVMSG_X64_HALT => { 279 debug!("HALT"); 280 Ok(cpu::VmExit::Reset) 281 } 282 hv_message_type_HVMSG_UNRECOVERABLE_EXCEPTION => { 283 warn!("TRIPLE FAULT"); 284 Ok(cpu::VmExit::Shutdown) 285 } 286 hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => { 287 let info = x.to_ioport_info().unwrap(); 288 let access_info = info.access_info; 289 let len = unsafe { access_info.__bindgen_anon_1.access_size() } as usize; 290 let is_write = info.header.intercept_access_type == 1; 291 let port = info.port_number; 292 let mut data: [u8; 4] = [0; 4]; 293 let mut ret_rax = info.rax; 294 295 /* 296 * XXX: Ignore QEMU fw_cfg (0x5xx) and debug console (0x402) ports. 297 * 298 * Cloud Hypervisor doesn't support fw_cfg at the moment. It does support 0x402 299 * under the "fwdebug" feature flag. But that feature is not enabled by default 300 * and is considered legacy. 301 * 302 * OVMF unconditionally pokes these IO ports with string IO. 303 * 304 * Instead of trying to implement string IO support now which does not do much 305 * now, skip those ports explicitly to avoid panicking. 306 * 307 * Proper string IO support can be added once we gain the ability to translate 308 * guest virtual addresses to guest physical addresses on MSHV. 309 */ 310 match port { 311 0x402 | 0x510 | 0x511 | 0x514 => { 312 let insn_len = info.header.instruction_length() as u64; 313 314 /* Advance RIP and update RAX */ 315 let arr_reg_name_value = [ 316 ( 317 hv_register_name::HV_X64_REGISTER_RIP, 318 info.header.rip + insn_len, 319 ), 320 (hv_register_name::HV_X64_REGISTER_RAX, ret_rax), 321 ]; 322 set_registers_64!(self.fd, arr_reg_name_value) 323 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 324 return Ok(cpu::VmExit::Ignore); 325 } 326 _ => {} 327 } 328 329 if unsafe { access_info.__bindgen_anon_1.string_op() } == 1 { 330 panic!("String IN/OUT not supported"); 331 } 332 if unsafe { access_info.__bindgen_anon_1.rep_prefix() } == 1 { 333 panic!("Rep IN/OUT not supported"); 334 } 335 336 if is_write { 337 let data = (info.rax as u32).to_le_bytes(); 338 if let Some(vmmops) = &self.vmmops { 339 vmmops 340 .pio_write(port.into(), &data[0..len]) 341 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 342 } 343 } else { 344 if let Some(vmmops) = &self.vmmops { 345 vmmops 346 .pio_read(port.into(), &mut data[0..len]) 347 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 348 } 349 350 let v = u32::from_le_bytes(data); 351 /* Preserve high bits in EAX but clear out high bits in RAX */ 352 let mask = 0xffffffff >> (32 - len * 8); 353 let eax = (info.rax as u32 & !mask) | (v & mask); 354 ret_rax = eax as u64; 355 } 356 357 let insn_len = info.header.instruction_length() as u64; 358 359 /* Advance RIP and update RAX */ 360 let arr_reg_name_value = [ 361 ( 362 hv_register_name::HV_X64_REGISTER_RIP, 363 info.header.rip + insn_len, 364 ), 365 (hv_register_name::HV_X64_REGISTER_RAX, ret_rax), 366 ]; 367 set_registers_64!(self.fd, arr_reg_name_value) 368 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; 369 Ok(cpu::VmExit::Ignore) 370 } 371 hv_message_type_HVMSG_UNMAPPED_GPA => { 372 let info = x.to_memory_info().unwrap(); 373 let insn_len = info.instruction_byte_count as usize; 374 assert!(insn_len > 0 && insn_len <= 16); 375 376 let mut context = MshvEmulatorContext { 377 vcpu: self, 378 map: (info.guest_virtual_address, info.guest_physical_address), 379 }; 380 381 // Create a new emulator. 382 let mut emul = Emulator::new(&mut context); 383 384 // Emulate the trapped instruction, and only the first one. 385 let new_state = emul 386 .emulate_first_insn(self.vp_index as usize, &info.instruction_bytes) 387 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 388 389 // Set CPU state back. 390 context 391 .set_cpu_state(self.vp_index as usize, new_state) 392 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; 393 394 Ok(cpu::VmExit::Ignore) 395 } 396 hv_message_type_HVMSG_X64_CPUID_INTERCEPT => { 397 let info = x.to_cpuid_info().unwrap(); 398 debug!("cpuid eax: {:x}", { info.rax }); 399 Ok(cpu::VmExit::Ignore) 400 } 401 hv_message_type_HVMSG_X64_MSR_INTERCEPT => { 402 let info = x.to_msr_info().unwrap(); 403 if info.header.intercept_access_type == 0 { 404 debug!("msr read: {:x}", { info.msr_number }); 405 } else { 406 debug!("msr write: {:x}", { info.msr_number }); 407 } 408 Ok(cpu::VmExit::Ignore) 409 } 410 hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT => { 411 //TODO: Handler for VMCALL here. 412 let info = x.to_exception_info().unwrap(); 413 debug!("Exception Info {:?}", { info.exception_vector }); 414 Ok(cpu::VmExit::Ignore) 415 } 416 exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( 417 "Unhandled VCPU exit {:?}", 418 exit 419 ))), 420 }, 421 422 Err(e) => match e.errno() { 423 libc::EAGAIN | libc::EINTR => Ok(cpu::VmExit::Ignore), 424 _ => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( 425 "VCPU error {:?}", 426 e 427 ))), 428 }, 429 } 430 } 431 #[cfg(target_arch = "x86_64")] 432 /// 433 /// X86 specific call to setup the CPUID registers. 434 /// 435 fn set_cpuid2(&self, _cpuid: &CpuId) -> cpu::Result<()> { 436 Ok(()) 437 } 438 #[cfg(target_arch = "x86_64")] 439 /// 440 /// X86 specific call to retrieve the CPUID registers. 441 /// 442 fn get_cpuid2(&self, _num_entries: usize) -> cpu::Result<CpuId> { 443 Ok(self.cpuid.clone()) 444 } 445 #[cfg(target_arch = "x86_64")] 446 /// 447 /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 448 /// 449 fn get_lapic(&self) -> cpu::Result<LapicState> { 450 self.fd 451 .get_lapic() 452 .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into())) 453 } 454 #[cfg(target_arch = "x86_64")] 455 /// 456 /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 457 /// 458 fn set_lapic(&self, lapic: &LapicState) -> cpu::Result<()> { 459 self.fd 460 .set_lapic(lapic) 461 .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into())) 462 } 463 #[cfg(target_arch = "x86_64")] 464 /// 465 /// X86 specific call that returns the vcpu's current "xsave struct". 466 /// 467 fn get_xsave(&self) -> cpu::Result<Xsave> { 468 self.fd 469 .get_xsave() 470 .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into())) 471 } 472 #[cfg(target_arch = "x86_64")] 473 /// 474 /// X86 specific call that sets the vcpu's current "xsave struct". 475 /// 476 fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> { 477 self.fd 478 .set_xsave(xsave) 479 .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into())) 480 } 481 /// 482 /// Set CPU state 483 /// 484 fn set_state(&self, state: &CpuState) -> cpu::Result<()> { 485 self.set_msrs(&state.msrs)?; 486 self.set_vcpu_events(&state.vcpu_events)?; 487 self.set_regs(&state.regs)?; 488 self.set_sregs(&state.sregs)?; 489 self.set_fpu(&state.fpu)?; 490 self.set_xcrs(&state.xcrs)?; 491 self.set_lapic(&state.lapic)?; 492 self.set_xsave(&state.xsave)?; 493 self.fd 494 .set_debug_regs(&state.dbg) 495 .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?; 496 Ok(()) 497 } 498 /// 499 /// Get CPU State 500 /// 501 fn state(&self) -> cpu::Result<CpuState> { 502 let regs = self.get_regs()?; 503 let sregs = self.get_sregs()?; 504 let xcrs = self.get_xcrs()?; 505 let fpu = self.get_fpu()?; 506 let vcpu_events = self.get_vcpu_events()?; 507 let mut msrs = self.msrs.clone(); 508 self.get_msrs(&mut msrs)?; 509 let lapic = self.get_lapic()?; 510 let xsave = self.get_xsave()?; 511 let dbg = self 512 .fd 513 .get_debug_regs() 514 .map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?; 515 Ok(CpuState { 516 msrs, 517 vcpu_events, 518 regs, 519 sregs, 520 fpu, 521 xcrs, 522 lapic, 523 dbg, 524 xsave, 525 }) 526 } 527 #[cfg(target_arch = "x86_64")] 528 /// 529 /// Translate guest virtual address to guest physical address 530 /// 531 fn translate_gva(&self, gva: u64, flags: u64) -> cpu::Result<(u64, hv_translate_gva_result)> { 532 let r = self 533 .fd 534 .translate_gva(gva, flags) 535 .map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?; 536 537 Ok(r) 538 } 539 #[cfg(target_arch = "x86_64")] 540 /// 541 /// X86 specific call that returns the vcpu's current "suspend registers". 542 /// 543 fn get_suspend_regs(&self) -> cpu::Result<SuspendRegisters> { 544 self.fd 545 .get_suspend_regs() 546 .map_err(|e| cpu::HypervisorCpuError::GetSuspendRegs(e.into())) 547 } 548 } 549 550 struct MshvEmulatorContext<'a> { 551 vcpu: &'a MshvVcpu, 552 map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor 553 } 554 555 impl<'a> MshvEmulatorContext<'a> { 556 // Do the actual gva -> gpa translation 557 #[allow(non_upper_case_globals)] 558 fn translate(&self, gva: u64) -> Result<u64, PlatformError> { 559 if self.map.0 == gva { 560 return Ok(self.map.1); 561 } 562 563 // TODO: More fine-grained control for the flags 564 let flags = HV_TRANSLATE_GVA_VALIDATE_READ | HV_TRANSLATE_GVA_VALIDATE_WRITE; 565 566 let r = self 567 .vcpu 568 .translate_gva(gva, flags.into()) 569 .map_err(|e| PlatformError::TranslateVirtualAddress(anyhow!(e)))?; 570 571 let result_code = unsafe { r.1.__bindgen_anon_1.result_code }; 572 match result_code { 573 hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(r.0), 574 _ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))), 575 } 576 } 577 } 578 579 /// Platform emulation for Hyper-V 580 impl<'a> PlatformEmulator for MshvEmulatorContext<'a> { 581 type CpuState = EmulatorCpuState; 582 583 fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError> { 584 let gpa = self.translate(gva)?; 585 debug!( 586 "mshv emulator: memory read {} bytes from [{:#x} -> {:#x}]", 587 data.len(), 588 gva, 589 gpa 590 ); 591 592 if let Some(vmmops) = &self.vcpu.vmmops { 593 if vmmops.guest_mem_read(gpa, data).is_err() { 594 vmmops 595 .mmio_read(gpa, data) 596 .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?; 597 } 598 } 599 600 Ok(()) 601 } 602 603 fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> { 604 let gpa = self.translate(gva)?; 605 debug!( 606 "mshv emulator: memory write {} bytes at [{:#x} -> {:#x}]", 607 data.len(), 608 gva, 609 gpa 610 ); 611 612 if let Some(vmmops) = &self.vcpu.vmmops { 613 if vmmops.guest_mem_write(gpa, data).is_err() { 614 vmmops 615 .mmio_write(gpa, data) 616 .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?; 617 } 618 } 619 620 Ok(()) 621 } 622 623 fn cpu_state(&self, cpu_id: usize) -> Result<Self::CpuState, PlatformError> { 624 if cpu_id != self.vcpu.vp_index as usize { 625 return Err(PlatformError::GetCpuStateFailure(anyhow!( 626 "CPU id mismatch {:?} {:?}", 627 cpu_id, 628 self.vcpu.vp_index 629 ))); 630 } 631 632 let regs = self 633 .vcpu 634 .get_regs() 635 .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; 636 let sregs = self 637 .vcpu 638 .get_sregs() 639 .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?; 640 641 debug!("mshv emulator: Getting new CPU state"); 642 debug!("mshv emulator: {:#x?}", regs); 643 644 Ok(EmulatorCpuState { regs, sregs }) 645 } 646 647 fn set_cpu_state(&self, cpu_id: usize, state: Self::CpuState) -> Result<(), PlatformError> { 648 if cpu_id != self.vcpu.vp_index as usize { 649 return Err(PlatformError::SetCpuStateFailure(anyhow!( 650 "CPU id mismatch {:?} {:?}", 651 cpu_id, 652 self.vcpu.vp_index 653 ))); 654 } 655 656 debug!("mshv emulator: Setting new CPU state"); 657 debug!("mshv emulator: {:#x?}", state.regs); 658 659 self.vcpu 660 .set_regs(&state.regs) 661 .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?; 662 self.vcpu 663 .set_sregs(&state.sregs) 664 .map_err(|e| PlatformError::SetCpuStateFailure(e.into())) 665 } 666 667 fn gva_to_gpa(&self, gva: u64) -> Result<u64, PlatformError> { 668 self.translate(gva) 669 } 670 671 fn fetch(&self, _ip: u64, _instruction_bytes: &mut [u8]) -> Result<(), PlatformError> { 672 Err(PlatformError::MemoryReadFailure(anyhow!("unimplemented"))) 673 } 674 } 675 676 #[allow(dead_code)] 677 /// Wrapper over Mshv VM ioctls. 678 pub struct MshvVm { 679 fd: Arc<VmFd>, 680 msrs: MsrEntries, 681 // Hypervisor State 682 hv_state: Arc<RwLock<HvState>>, 683 vmmops: Option<Arc<Box<dyn vm::VmmOps>>>, 684 } 685 686 fn hv_state_init() -> Arc<RwLock<HvState>> { 687 Arc::new(RwLock::new(HvState { hypercall_page: 0 })) 688 } 689 690 /// 691 /// Implementation of Vm trait for Mshv 692 /// Example: 693 /// #[cfg(feature = "mshv")] 694 /// # extern crate hypervisor; 695 /// # use hypervisor::MshvHypervisor; 696 /// let mshv = MshvHypervisor::new().unwrap(); 697 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv); 698 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 699 /// vm.set/get().unwrap() 700 /// 701 impl vm::Vm for MshvVm { 702 #[cfg(target_arch = "x86_64")] 703 /// 704 /// Sets the address of the three-page region in the VM's address space. 705 /// 706 fn set_tss_address(&self, _offset: usize) -> vm::Result<()> { 707 Ok(()) 708 } 709 /// 710 /// Creates an in-kernel interrupt controller. 711 /// 712 fn create_irq_chip(&self) -> vm::Result<()> { 713 Ok(()) 714 } 715 /// 716 /// Registers an event that will, when signaled, trigger the `gsi` IRQ. 717 /// 718 fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> { 719 debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi); 720 721 self.fd 722 .register_irqfd(fd, gsi) 723 .map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?; 724 725 Ok(()) 726 } 727 /// 728 /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ. 729 /// 730 fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> { 731 debug!("unregister_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi); 732 733 self.fd 734 .unregister_irqfd(fd, gsi) 735 .map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))?; 736 737 Ok(()) 738 } 739 /// 740 /// Creates a VcpuFd object from a vcpu RawFd. 741 /// 742 fn create_vcpu( 743 &self, 744 id: u8, 745 vmmops: Option<Arc<Box<dyn VmmOps>>>, 746 ) -> vm::Result<Arc<dyn cpu::Vcpu>> { 747 let vcpu_fd = self 748 .fd 749 .create_vcpu(id) 750 .map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?; 751 let vcpu = MshvVcpu { 752 fd: vcpu_fd, 753 vp_index: id, 754 cpuid: CpuId::new(1).unwrap(), 755 msrs: self.msrs.clone(), 756 hv_state: self.hv_state.clone(), 757 vmmops, 758 }; 759 Ok(Arc::new(vcpu)) 760 } 761 #[cfg(target_arch = "x86_64")] 762 fn enable_split_irq(&self) -> vm::Result<()> { 763 Ok(()) 764 } 765 #[cfg(target_arch = "x86_64")] 766 fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> { 767 Ok(()) 768 } 769 fn register_ioevent( 770 &self, 771 fd: &EventFd, 772 addr: &IoEventAddress, 773 datamatch: Option<DataMatch>, 774 ) -> vm::Result<()> { 775 debug!( 776 "register_ioevent fd {} addr {:x?} datamatch {:?}", 777 fd.as_raw_fd(), 778 addr, 779 datamatch 780 ); 781 if let Some(dm) = datamatch { 782 match dm { 783 vm::DataMatch::DataMatch32(mshv_dm32) => self 784 .fd 785 .register_ioevent(fd, addr, mshv_dm32) 786 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())), 787 vm::DataMatch::DataMatch64(mshv_dm64) => self 788 .fd 789 .register_ioevent(fd, addr, mshv_dm64) 790 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())), 791 } 792 } else { 793 self.fd 794 .register_ioevent(fd, addr, NoDatamatch) 795 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())) 796 } 797 } 798 /// Unregister an event from a certain address it has been previously registered to. 799 fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> { 800 debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr); 801 802 self.fd 803 .unregister_ioevent(fd, addr, NoDatamatch) 804 .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into())) 805 } 806 807 /// Creates a guest physical memory region. 808 fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> { 809 self.fd 810 .map_user_memory(user_memory_region) 811 .map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))?; 812 Ok(()) 813 } 814 815 /// Removes a guest physical memory region. 816 fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> { 817 self.fd 818 .unmap_user_memory(user_memory_region) 819 .map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))?; 820 Ok(()) 821 } 822 823 fn make_user_memory_region( 824 &self, 825 _slot: u32, 826 guest_phys_addr: u64, 827 memory_size: u64, 828 userspace_addr: u64, 829 readonly: bool, 830 _log_dirty_pages: bool, 831 ) -> MemoryRegion { 832 let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE; 833 if !readonly { 834 flags |= HV_MAP_GPA_WRITABLE; 835 } 836 837 mshv_user_mem_region { 838 flags, 839 guest_pfn: guest_phys_addr >> PAGE_SHIFT, 840 size: memory_size, 841 userspace_addr: userspace_addr as u64, 842 } 843 } 844 845 fn create_passthrough_device(&self) -> vm::Result<Arc<dyn device::Device>> { 846 Err(vm::HypervisorVmError::CreatePassthroughDevice(anyhow!( 847 "No passthrough support" 848 ))) 849 } 850 851 fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> { 852 let mut msi_routing = 853 vec_with_array_field::<mshv_msi_routing, mshv_msi_routing_entry>(entries.len()); 854 msi_routing[0].nr = entries.len() as u32; 855 856 unsafe { 857 let entries_slice: &mut [mshv_msi_routing_entry] = 858 msi_routing[0].entries.as_mut_slice(entries.len()); 859 entries_slice.copy_from_slice(entries); 860 } 861 862 self.fd 863 .set_msi_routing(&msi_routing[0]) 864 .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into())) 865 } 866 /// 867 /// Get the Vm state. Return VM specific data 868 /// 869 fn state(&self) -> vm::Result<VmState> { 870 Ok(*self.hv_state.read().unwrap()) 871 } 872 /// 873 /// Set the VM state 874 /// 875 fn set_state(&self, state: VmState) -> vm::Result<()> { 876 self.hv_state.write().unwrap().hypercall_page = state.hypercall_page; 877 Ok(()) 878 } 879 /// 880 /// Get dirty pages bitmap (one bit per page) 881 /// 882 fn get_dirty_log(&self, _slot: u32, _memory_size: u64) -> vm::Result<Vec<u64>> { 883 Err(vm::HypervisorVmError::GetDirtyLog(anyhow!( 884 "get_dirty_log not implemented" 885 ))) 886 } 887 } 888 pub use hv_cpuid_entry as CpuIdEntry; 889 890 pub type IrqRoutingEntry = mshv_msi_routing_entry; 891 892 pub const CPUID_FLAG_VALID_INDEX: u32 = 0; 893