1 // Copyright 2020 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use core::ffi::c_void; 6 use std::arch::x86_64::CpuidResult; 7 use std::collections::BTreeMap; 8 use std::mem::size_of; 9 10 use base::errno_result; 11 use base::ioctl; 12 use base::ioctl_with_mut_ref; 13 use base::ioctl_with_ptr_sized; 14 use base::ioctl_with_ref; 15 use base::warn; 16 use base::AsRawDescriptor; 17 use base::Error; 18 use base::RawDescriptor; 19 use base::Result; 20 use base::SafeDescriptor; 21 use data_model::vec_with_array_field; 22 use libc::EINVAL; 23 use libc::ENOENT; 24 use libc::ENXIO; 25 use libc::EOPNOTSUPP; 26 use snapshot::AnySnapshot; 27 use vm_memory::GuestAddress; 28 29 use super::*; 30 use crate::CpuId; 31 use crate::CpuIdEntry; 32 use crate::DebugRegs; 33 use crate::DescriptorTable; 34 use crate::Fpu; 35 use crate::FpuReg; 36 use crate::IoOperation; 37 use crate::IoParams; 38 use crate::Regs; 39 use crate::Segment; 40 use crate::Sregs; 41 use crate::Vcpu; 42 use crate::VcpuExit; 43 use crate::VcpuShutdownError; 44 use crate::VcpuShutdownErrorKind; 45 use crate::VcpuX86_64; 46 use crate::Xsave; 47 48 // HAXM exit reasons 49 // IO port request 50 const HAX_EXIT_IO: u32 = 1; 51 // MMIO instruction emulation, should not happen anymore, replaced with 52 // HAX_EXIT_FAST_MMIO 53 #[allow(dead_code)] 54 const HAX_EXIT_MMIO: u32 = 2; 55 // Real mode emulation when unrestricted guest is disabled 56 #[allow(dead_code)] 57 const HAX_EXIT_REALMODE: u32 = 3; 58 // Interrupt window open, crosvm can inject an interrupt now. 59 // Also used when vcpu thread receives a signal 60 const HAX_EXIT_INTERRUPT: u32 = 4; 61 // Unknown vmexit, mostly trigger reboot 62 #[allow(dead_code)] 63 const HAX_EXIT_UNKNOWN: u32 = 5; 64 // HALT from guest 65 const HAX_EXIT_HLT: u32 = 6; 66 // VCPU panic, like because of triple fault in guest 67 const HAX_EXIT_VCPU_PANIC: u32 = 7; 68 // Paused by crosvm setting _exit_reason to HAX_EXIT_PAUSED before entry 69 pub(crate) const HAX_EXIT_PAUSED: u32 = 8; 70 // MMIO instruction emulation through io_buffer 71 const HAX_EXIT_FAST_MMIO: u32 = 9; 72 // Page fault that was not able to be handled by HAXM 73 const HAX_EXIT_PAGEFAULT: u32 = 10; 74 // A debug exception caused a vmexit 75 const HAX_EXIT_DEBUG: u32 = 11; 76 77 // HAXM exit directions 78 const HAX_EXIT_DIRECTION_PIO_IN: u32 = 1; 79 const HAX_EXIT_DIRECTION_PIO_OUT: u32 = 0; 80 const HAX_EXIT_DIRECTION_MMIO_READ: u8 = 0; 81 const HAX_EXIT_DIRECTION_MMIO_WRITE: u8 = 1; 82 83 pub struct HaxmVcpu { 84 pub(super) descriptor: SafeDescriptor, 85 pub(super) id: usize, 86 pub(super) tunnel: *mut hax_tunnel, 87 pub(super) io_buffer: *mut c_void, 88 } 89 90 // TODO(b/315998194): Add safety comment 91 #[allow(clippy::undocumented_unsafe_blocks)] 92 unsafe impl Send for HaxmVcpu {} 93 // TODO(b/315998194): Add safety comment 94 #[allow(clippy::undocumented_unsafe_blocks)] 95 unsafe impl Sync for HaxmVcpu {} 96 97 impl AsRawDescriptor for HaxmVcpu { as_raw_descriptor(&self) -> RawDescriptor98 fn as_raw_descriptor(&self) -> RawDescriptor { 99 self.descriptor.as_raw_descriptor() 100 } 101 } 102 103 impl HaxmVcpu { get_vcpu_state(&self) -> Result<VcpuState>104 fn get_vcpu_state(&self) -> Result<VcpuState> { 105 let mut state = vcpu_state_t::default(); 106 107 // SAFETY: trivially safe with return value checked. 108 let ret = unsafe { ioctl_with_mut_ref(self, HAX_VCPU_GET_REGS, &mut state) }; 109 if ret != 0 { 110 return errno_result(); 111 } 112 113 // Also read efer MSR 114 state.efer = self.get_msr(IA32_EFER)? as u32; 115 116 Ok(VcpuState { state }) 117 } 118 set_vcpu_state(&self, state: &mut VcpuState) -> Result<()>119 fn set_vcpu_state(&self, state: &mut VcpuState) -> Result<()> { 120 // SAFETY: trivially safe with return value checked. 121 let ret = unsafe { ioctl_with_mut_ref(self, HAX_VCPU_SET_REGS, &mut state.state) }; 122 if ret != 0 { 123 return errno_result(); 124 } 125 126 // Also set efer MSR 127 self.set_msr(IA32_EFER, state.state.efer as u64) 128 } 129 } 130 131 impl Vcpu for HaxmVcpu { 132 /// Makes a shallow clone of this `Vcpu`. try_clone(&self) -> Result<Self>133 fn try_clone(&self) -> Result<Self> { 134 Ok(HaxmVcpu { 135 descriptor: self.descriptor.try_clone()?, 136 id: self.id, 137 tunnel: self.tunnel, 138 io_buffer: self.io_buffer, 139 }) 140 } 141 as_vcpu(&self) -> &dyn Vcpu142 fn as_vcpu(&self) -> &dyn Vcpu { 143 self 144 } 145 146 /// Returns the vcpu id. id(&self) -> usize147 fn id(&self) -> usize { 148 self.id 149 } 150 151 /// Sets the bit that requests an immediate exit. set_immediate_exit(&self, exit: bool)152 fn set_immediate_exit(&self, exit: bool) { 153 // SAFETY: 154 // Safe because we know the tunnel is a pointer to a hax_tunnel and we know its size. 155 // Crosvm's HAXM implementation does not use the _exit_reason, so it's fine if we 156 // overwrite it. 157 unsafe { 158 (*self.tunnel).exit_reason = if exit { HAX_EXIT_PAUSED } else { 0 }; 159 } 160 } 161 162 /// Signals to the hypervisor that this guest is being paused by userspace. on_suspend(&self) -> Result<()>163 fn on_suspend(&self) -> Result<()> { 164 Ok(()) 165 } 166 167 /// Enables a hypervisor-specific extension on this Vcpu. `cap` is a constant defined by the 168 /// hypervisor API. `args` are the arguments for enabling the feature, if any. enable_raw_capability(&self, _cap: u32, _args: &[u64; 4]) -> Result<()>169 unsafe fn enable_raw_capability(&self, _cap: u32, _args: &[u64; 4]) -> Result<()> { 170 // Haxm does not support enable_capability 171 Err(Error::new(libc::ENXIO)) 172 } 173 174 /// This function should be called after `Vcpu::run` returns `VcpuExit::Mmio`. 175 /// 176 /// Once called, it will determine whether a mmio read or mmio write was the reason for the mmio 177 /// exit, call `handle_fn` with the respective IoOperation to perform the mmio read or 178 /// write, and set the return data in the vcpu so that the vcpu can resume running. handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()>179 fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()> { 180 // SAFETY: 181 // Safe because we know we mapped enough memory to hold the hax_tunnel struct because the 182 // kernel told us how large it was. 183 // Verify that the handler is called for mmio context only. 184 unsafe { 185 assert!((*self.tunnel).exit_status == HAX_EXIT_FAST_MMIO); 186 } 187 let mmio = self.io_buffer as *mut hax_fastmmio; 188 let (address, size, direction) = 189 // SAFETY: 190 // Safe because the exit_reason (which comes from the kernel) told us which 191 // union field to use. 192 unsafe { ((*mmio).gpa, (*mmio).size as usize, (*mmio).direction) }; 193 // SAFETY: 194 // Safe because the exit_reason (which comes from the kernel) told us which 195 // union field to use. We use `addr_of_mut!()` to get a potentially unaligned u64 pointer, 196 // but it is then cast via a u8 pointer to a u8 slice, which has no alignment requirements. 197 let data = unsafe { 198 assert!(size <= size_of::<u64>()); 199 std::slice::from_raw_parts_mut( 200 std::ptr::addr_of_mut!((*mmio).__bindgen_anon_1.value) as *mut u8, 201 size, 202 ) 203 }; 204 205 match direction { 206 HAX_EXIT_DIRECTION_MMIO_READ => { 207 handle_fn(IoParams { 208 address, 209 operation: IoOperation::Read(data), 210 }) 211 // We have to unwrap/panic here because HAXM doesn't have a 212 // facility to inject a GP fault here. Once HAXM can do that, we 213 // should inject a GP fault & bubble the error. 214 .unwrap(); 215 Ok(()) 216 } 217 HAX_EXIT_DIRECTION_MMIO_WRITE => { 218 handle_fn(IoParams { 219 address, 220 operation: IoOperation::Write(data), 221 }) 222 // Similarly to the read direction, we MUST panic here. 223 .unwrap(); 224 Ok(()) 225 } 226 _ => Err(Error::new(EINVAL)), 227 } 228 } 229 230 /// This function should be called after `Vcpu::run` returns `VcpuExit::Io`. 231 /// 232 /// Once called, it will determine whether an io in or io out was the reason for the io exit, 233 /// call `handle_fn` with the respective IoOperation to perform the io in or io out, 234 /// and set the return data in the vcpu so that the vcpu can resume running. 235 #[allow(clippy::cast_ptr_alignment)] handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()>236 fn handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()> { 237 // SAFETY: 238 // Safe because we know we mapped enough memory to hold the hax_tunnel struct because the 239 // kernel told us how large it was. 240 // Verify that the handler is called for io context only. 241 unsafe { 242 assert!((*self.tunnel).exit_status == HAX_EXIT_IO); 243 } 244 // SAFETY: 245 // Safe because the exit_reason (which comes from the kernel) told us which 246 // union field to use. 247 let io = unsafe { (*self.tunnel).__bindgen_anon_1.io }; 248 let address = io.port.into(); 249 let size = io.size as usize; 250 let count = io.count as usize; 251 let data_len = count * size; 252 // SAFETY: 253 // Safe because the exit_reason (which comes from the kernel) told us that this is port io, 254 // where the iobuf can be treated as a *u8 255 let buffer: &mut [u8] = 256 unsafe { std::slice::from_raw_parts_mut(self.io_buffer as *mut u8, data_len) }; 257 let data_chunks = buffer.chunks_mut(size); 258 259 match io.direction as u32 { 260 HAX_EXIT_DIRECTION_PIO_IN => { 261 for data in data_chunks { 262 handle_fn(IoParams { 263 address, 264 operation: IoOperation::Read(data), 265 }); 266 } 267 Ok(()) 268 } 269 HAX_EXIT_DIRECTION_PIO_OUT => { 270 for data in data_chunks { 271 handle_fn(IoParams { 272 address, 273 operation: IoOperation::Write(data), 274 }); 275 } 276 Ok(()) 277 } 278 _ => Err(Error::new(EINVAL)), 279 } 280 } 281 282 #[allow(clippy::cast_ptr_alignment)] 283 // The pointer is page aligned so casting to a different type is well defined, hence the clippy 284 // allow attribute. run(&mut self) -> Result<VcpuExit>285 fn run(&mut self) -> Result<VcpuExit> { 286 // TODO(b/315998194): Add safety comment 287 #[allow(clippy::undocumented_unsafe_blocks)] 288 let ret = unsafe { ioctl(self, HAX_VCPU_IOCTL_RUN) }; 289 if ret != 0 { 290 return errno_result(); 291 } 292 293 // SAFETY: 294 // Safe because we know we mapped enough memory to hold the hax_tunnel struct because the 295 // kernel told us how large it was. 296 let exit_status = unsafe { (*self.tunnel).exit_status }; 297 298 match exit_status { 299 HAX_EXIT_IO => Ok(VcpuExit::Io), 300 HAX_EXIT_INTERRUPT => Ok(VcpuExit::Intr), 301 HAX_EXIT_HLT => Ok(VcpuExit::Hlt), 302 HAX_EXIT_VCPU_PANIC => { 303 // SAFETY: 304 // 1) we mapped enough memory to hold the hax_tunnel struct because the kernel told 305 // us how large it was. That memory is still alive here. 306 let panic_reason = unsafe { (*self.tunnel).vcpu_panic_reason }; 307 Ok(VcpuExit::Shutdown(Err(VcpuShutdownError::new( 308 VcpuShutdownErrorKind::Other, 309 panic_reason as u64, 310 )))) 311 } 312 HAX_EXIT_FAST_MMIO => Ok(VcpuExit::Mmio), 313 HAX_EXIT_PAGEFAULT => Ok(VcpuExit::Exception), 314 HAX_EXIT_DEBUG => Ok(VcpuExit::Debug), 315 HAX_EXIT_PAUSED => Ok(VcpuExit::Exception), 316 r => panic!("unknown exit reason: {}", r), 317 } 318 } 319 } 320 321 impl VcpuX86_64 for HaxmVcpu { 322 /// Sets or clears the flag that requests the VCPU to exit when it becomes possible to inject 323 /// interrupts into the guest. set_interrupt_window_requested(&self, requested: bool)324 fn set_interrupt_window_requested(&self, requested: bool) { 325 // SAFETY: 326 // Safe because we know we mapped enough memory to hold the hax_tunnel struct because the 327 // kernel told us how large it was. 328 unsafe { 329 (*self.tunnel).request_interrupt_window = i32::from(requested); 330 } 331 } 332 333 /// Checks if we can inject an interrupt into the VCPU. ready_for_interrupt(&self) -> bool334 fn ready_for_interrupt(&self) -> bool { 335 // SAFETY: 336 // Safe because we know we mapped enough memory to hold the hax_tunnel struct because the 337 // kernel told us how large it was. 338 unsafe { (*self.tunnel).ready_for_interrupt_injection != 0 } 339 } 340 341 /// Injects interrupt vector `irq` into the VCPU. interrupt(&self, irq: u8) -> Result<()>342 fn interrupt(&self, irq: u8) -> Result<()> { 343 let irq: u32 = irq.into(); 344 // TODO(b/315998194): Add safety comment 345 #[allow(clippy::undocumented_unsafe_blocks)] 346 let ret = unsafe { ioctl_with_ref(self, HAX_VCPU_IOCTL_INTERRUPT, &irq) }; 347 if ret != 0 { 348 return errno_result(); 349 } 350 Ok(()) 351 } 352 353 /// Injects a non-maskable interrupt into the VCPU. inject_nmi(&self) -> Result<()>354 fn inject_nmi(&self) -> Result<()> { 355 warn!("HAXM does not support injecting NMIs"); 356 Ok(()) 357 } 358 359 /// Gets the VCPU general purpose registers. get_regs(&self) -> Result<Regs>360 fn get_regs(&self) -> Result<Regs> { 361 Ok(self.get_vcpu_state()?.get_regs()) 362 } 363 364 /// Sets the VCPU general purpose registers. set_regs(&self, regs: &Regs) -> Result<()>365 fn set_regs(&self, regs: &Regs) -> Result<()> { 366 let mut state = self.get_vcpu_state()?; 367 state.set_regs(regs); 368 self.set_vcpu_state(&mut state)?; 369 Ok(()) 370 } 371 372 /// Gets the VCPU special registers. get_sregs(&self) -> Result<Sregs>373 fn get_sregs(&self) -> Result<Sregs> { 374 Ok(self.get_vcpu_state()?.get_sregs()) 375 } 376 377 /// Sets the VCPU special registers. set_sregs(&self, sregs: &Sregs) -> Result<()>378 fn set_sregs(&self, sregs: &Sregs) -> Result<()> { 379 let mut state = self.get_vcpu_state()?; 380 state.set_sregs(sregs); 381 self.set_vcpu_state(&mut state)?; 382 Ok(()) 383 } 384 385 /// Gets the VCPU FPU registers. get_fpu(&self) -> Result<Fpu>386 fn get_fpu(&self) -> Result<Fpu> { 387 let mut fpu = fx_layout::default(); 388 // TODO(b/315998194): Add safety comment 389 #[allow(clippy::undocumented_unsafe_blocks)] 390 let ret = unsafe { ioctl_with_mut_ref(self, HAX_VCPU_IOCTL_GET_FPU, &mut fpu) }; 391 392 if ret != 0 { 393 return errno_result(); 394 } 395 396 Ok(Fpu::from(&fpu)) 397 } 398 399 /// Sets the VCPU FPU registers. set_fpu(&self, fpu: &Fpu) -> Result<()>400 fn set_fpu(&self, fpu: &Fpu) -> Result<()> { 401 let mut current_fpu = fx_layout::default(); 402 // TODO(b/315998194): Add safety comment 403 #[allow(clippy::undocumented_unsafe_blocks)] 404 let ret = unsafe { ioctl_with_mut_ref(self, HAX_VCPU_IOCTL_GET_FPU, &mut current_fpu) }; 405 406 if ret != 0 { 407 return errno_result(); 408 } 409 410 let mut new_fpu = fx_layout::from(fpu); 411 412 // the mxcsr mask is something that isn't part of the Fpu state, so we make the new 413 // fpu state's mxcsr_mask matches its current value 414 new_fpu.mxcsr_mask = current_fpu.mxcsr_mask; 415 416 // TODO(b/315998194): Add safety comment 417 #[allow(clippy::undocumented_unsafe_blocks)] 418 let ret = unsafe { ioctl_with_ref(self, HAX_VCPU_IOCTL_SET_FPU, &new_fpu) }; 419 420 if ret != 0 { 421 return errno_result(); 422 } 423 424 Ok(()) 425 } 426 get_xsave(&self) -> Result<Xsave>427 fn get_xsave(&self) -> Result<Xsave> { 428 Err(Error::new(EOPNOTSUPP)) 429 } 430 set_xsave(&self, _xsave: &Xsave) -> Result<()>431 fn set_xsave(&self, _xsave: &Xsave) -> Result<()> { 432 Err(Error::new(EOPNOTSUPP)) 433 } 434 get_interrupt_state(&self) -> Result<AnySnapshot>435 fn get_interrupt_state(&self) -> Result<AnySnapshot> { 436 Err(Error::new(EOPNOTSUPP)) 437 } 438 set_interrupt_state(&self, _data: AnySnapshot) -> Result<()>439 fn set_interrupt_state(&self, _data: AnySnapshot) -> Result<()> { 440 Err(Error::new(EOPNOTSUPP)) 441 } 442 443 /// Gets the VCPU debug registers. get_debugregs(&self) -> Result<DebugRegs>444 fn get_debugregs(&self) -> Result<DebugRegs> { 445 Ok(self.get_vcpu_state()?.get_debugregs()) 446 } 447 448 /// Sets the VCPU debug registers. set_debugregs(&self, debugregs: &DebugRegs) -> Result<()>449 fn set_debugregs(&self, debugregs: &DebugRegs) -> Result<()> { 450 let mut state = self.get_vcpu_state()?; 451 state.set_debugregs(debugregs); 452 self.set_vcpu_state(&mut state)?; 453 Ok(()) 454 } 455 456 /// Gets the VCPU extended control registers. get_xcrs(&self) -> Result<BTreeMap<u32, u64>>457 fn get_xcrs(&self) -> Result<BTreeMap<u32, u64>> { 458 // Haxm does not support getting XCRs 459 Err(Error::new(libc::ENXIO)) 460 } 461 462 /// Sets a VCPU extended control register. set_xcr(&self, _xcr_index: u32, _value: u64) -> Result<()>463 fn set_xcr(&self, _xcr_index: u32, _value: u64) -> Result<()> { 464 // Haxm does not support setting XCRs 465 Err(Error::new(libc::ENXIO)) 466 } 467 468 /// Gets the value of one model-specific register. get_msr(&self, msr_index: u32) -> Result<u64>469 fn get_msr(&self, msr_index: u32) -> Result<u64> { 470 let mut msr_data = hax_msr_data { 471 nr_msr: 1, 472 ..Default::default() 473 }; 474 msr_data.entries[0].entry = u64::from(msr_index); 475 476 // TODO(b/315998194): Add safety comment 477 #[allow(clippy::undocumented_unsafe_blocks)] 478 let ret = unsafe { ioctl_with_mut_ref(self, HAX_VCPU_IOCTL_GET_MSRS, &mut msr_data) }; 479 if ret != 0 { 480 return errno_result(); 481 } 482 483 Ok(msr_data.entries[0].value) 484 } 485 get_all_msrs(&self) -> Result<BTreeMap<u32, u64>>486 fn get_all_msrs(&self) -> Result<BTreeMap<u32, u64>> { 487 Err(Error::new(EOPNOTSUPP)) 488 } 489 490 /// Sets the value of one model-specific register. set_msr(&self, msr_index: u32, value: u64) -> Result<()>491 fn set_msr(&self, msr_index: u32, value: u64) -> Result<()> { 492 let mut msr_data = hax_msr_data { 493 nr_msr: 1, 494 ..Default::default() 495 }; 496 msr_data.entries[0].entry = u64::from(msr_index); 497 msr_data.entries[0].value = value; 498 499 // TODO(b/315998194): Add safety comment 500 #[allow(clippy::undocumented_unsafe_blocks)] 501 let ret = unsafe { ioctl_with_mut_ref(self, HAX_VCPU_IOCTL_SET_MSRS, &mut msr_data) }; 502 if ret != 0 { 503 return errno_result(); 504 } 505 506 Ok(()) 507 } 508 509 /// Sets up the data returned by the CPUID instruction. set_cpuid(&self, cpuid: &CpuId) -> Result<()>510 fn set_cpuid(&self, cpuid: &CpuId) -> Result<()> { 511 let total = cpuid.cpu_id_entries.len(); 512 let mut hax = vec_with_array_field::<hax_cpuid, hax_cpuid_entry>(total); 513 hax[0].total = total as u32; 514 // TODO(b/315998194): Add safety comment 515 #[allow(clippy::undocumented_unsafe_blocks)] 516 let entries = unsafe { hax[0].entries.as_mut_slice(total) }; 517 for (i, e) in cpuid.cpu_id_entries.iter().enumerate() { 518 entries[i] = hax_cpuid_entry::from(e); 519 } 520 521 // TODO(b/315998194): Add safety comment 522 #[allow(clippy::undocumented_unsafe_blocks)] 523 let ret = unsafe { 524 ioctl_with_ptr_sized( 525 self, 526 HAX_VCPU_IOCTL_SET_CPUID, 527 hax.as_ptr(), 528 size_of::<hax_cpuid>() + total * size_of::<hax_cpuid_entry>(), 529 ) 530 }; 531 532 if ret != 0 { 533 return errno_result(); 534 } 535 Ok(()) 536 } 537 538 /// This function should be called after `Vcpu::run` returns `VcpuExit::Cpuid`, and `entry` 539 /// should represent the result of emulating the CPUID instruction. The `handle_cpuid` function 540 /// will then set the appropriate registers on the vcpu. 541 /// HAXM does not support the VcpuExit::Cpuid exit type. handle_cpuid(&mut self, _entry: &CpuIdEntry) -> Result<()>542 fn handle_cpuid(&mut self, _entry: &CpuIdEntry) -> Result<()> { 543 Err(Error::new(ENXIO)) 544 } 545 set_guest_debug(&self, _addrs: &[GuestAddress], _enable_singlestep: bool) -> Result<()>546 fn set_guest_debug(&self, _addrs: &[GuestAddress], _enable_singlestep: bool) -> Result<()> { 547 // TODO(b/173807302): Implement this 548 Err(Error::new(ENOENT)) 549 } 550 restore_timekeeping(&self, _host_tsc_reference_moment: u64, tsc_offset: u64) -> Result<()>551 fn restore_timekeeping(&self, _host_tsc_reference_moment: u64, tsc_offset: u64) -> Result<()> { 552 // HAXM sets TSC_OFFSET based on what we set TSC to; however, it does 553 // not yet handle syncing. This means it computes 554 // TSC_OFFSET = new_tsc - rdtsc(), so if we want to target the same 555 // offset value, we need new_tsc = rdtsc() + target_offset. This is what 556 // Self::set_tsc_offset does. 557 // 558 // TODO(b/311793539): haxm doesn't yet support syncing TSCs across VCPUs 559 // if the TSC value is non-zero. Once we have that support, we can 560 // switch to calling Self::set_tsc_value here with the common host 561 // reference moment. (Alternatively, we may just expose a way to set the 562 // offset directly.) 563 self.set_tsc_offset(tsc_offset) 564 } 565 } 566 567 struct VcpuState { 568 state: vcpu_state_t, 569 } 570 571 impl VcpuState { get_regs(&self) -> Regs572 fn get_regs(&self) -> Regs { 573 // TODO(b/315998194): Add safety comment 574 #[allow(clippy::undocumented_unsafe_blocks)] 575 unsafe { 576 Regs { 577 rax: self 578 .state 579 .__bindgen_anon_1 580 .__bindgen_anon_1 581 .__bindgen_anon_1 582 .rax, 583 rbx: self 584 .state 585 .__bindgen_anon_1 586 .__bindgen_anon_1 587 .__bindgen_anon_4 588 .rbx, 589 rcx: self 590 .state 591 .__bindgen_anon_1 592 .__bindgen_anon_1 593 .__bindgen_anon_2 594 .rcx, 595 rdx: self 596 .state 597 .__bindgen_anon_1 598 .__bindgen_anon_1 599 .__bindgen_anon_3 600 .rdx, 601 rsi: self 602 .state 603 .__bindgen_anon_1 604 .__bindgen_anon_1 605 .__bindgen_anon_7 606 .rsi, 607 rdi: self 608 .state 609 .__bindgen_anon_1 610 .__bindgen_anon_1 611 .__bindgen_anon_8 612 .rdi, 613 rsp: self 614 .state 615 .__bindgen_anon_1 616 .__bindgen_anon_1 617 .__bindgen_anon_5 618 .rsp, 619 rbp: self 620 .state 621 .__bindgen_anon_1 622 .__bindgen_anon_1 623 .__bindgen_anon_6 624 .rbp, 625 r8: self.state.__bindgen_anon_1.__bindgen_anon_1.r8, 626 r9: self.state.__bindgen_anon_1.__bindgen_anon_1.r9, 627 r10: self.state.__bindgen_anon_1.__bindgen_anon_1.r10, 628 r11: self.state.__bindgen_anon_1.__bindgen_anon_1.r11, 629 r12: self.state.__bindgen_anon_1.__bindgen_anon_1.r12, 630 r13: self.state.__bindgen_anon_1.__bindgen_anon_1.r13, 631 r14: self.state.__bindgen_anon_1.__bindgen_anon_1.r14, 632 r15: self.state.__bindgen_anon_1.__bindgen_anon_1.r15, 633 rip: self.state.__bindgen_anon_2.rip, 634 rflags: self.state.__bindgen_anon_3.rflags, 635 } 636 } 637 } 638 set_regs(&mut self, regs: &Regs)639 fn set_regs(&mut self, regs: &Regs) { 640 self.state 641 .__bindgen_anon_1 642 .__bindgen_anon_1 643 .__bindgen_anon_1 644 .rax = regs.rax; 645 self.state 646 .__bindgen_anon_1 647 .__bindgen_anon_1 648 .__bindgen_anon_4 649 .rbx = regs.rbx; 650 self.state 651 .__bindgen_anon_1 652 .__bindgen_anon_1 653 .__bindgen_anon_2 654 .rcx = regs.rcx; 655 self.state 656 .__bindgen_anon_1 657 .__bindgen_anon_1 658 .__bindgen_anon_3 659 .rdx = regs.rdx; 660 self.state 661 .__bindgen_anon_1 662 .__bindgen_anon_1 663 .__bindgen_anon_7 664 .rsi = regs.rsi; 665 self.state 666 .__bindgen_anon_1 667 .__bindgen_anon_1 668 .__bindgen_anon_8 669 .rdi = regs.rdi; 670 self.state 671 .__bindgen_anon_1 672 .__bindgen_anon_1 673 .__bindgen_anon_5 674 .rsp = regs.rsp; 675 self.state 676 .__bindgen_anon_1 677 .__bindgen_anon_1 678 .__bindgen_anon_6 679 .rbp = regs.rbp; 680 self.state.__bindgen_anon_1.__bindgen_anon_1.r8 = regs.r8; 681 self.state.__bindgen_anon_1.__bindgen_anon_1.r9 = regs.r9; 682 self.state.__bindgen_anon_1.__bindgen_anon_1.r10 = regs.r10; 683 self.state.__bindgen_anon_1.__bindgen_anon_1.r11 = regs.r11; 684 self.state.__bindgen_anon_1.__bindgen_anon_1.r12 = regs.r12; 685 self.state.__bindgen_anon_1.__bindgen_anon_1.r13 = regs.r13; 686 self.state.__bindgen_anon_1.__bindgen_anon_1.r14 = regs.r14; 687 self.state.__bindgen_anon_1.__bindgen_anon_1.r15 = regs.r15; 688 self.state.__bindgen_anon_2.rip = regs.rip; 689 self.state.__bindgen_anon_3.rflags = regs.rflags; 690 } 691 get_sregs(&self) -> Sregs692 fn get_sregs(&self) -> Sregs { 693 Sregs { 694 cs: Segment::from(&self.state.cs), 695 ds: Segment::from(&self.state.ds), 696 es: Segment::from(&self.state.es), 697 fs: Segment::from(&self.state.fs), 698 gs: Segment::from(&self.state.gs), 699 ss: Segment::from(&self.state.ss), 700 tr: Segment::from(&self.state.tr), 701 ldt: Segment::from(&self.state.ldt), 702 gdt: DescriptorTable::from(&self.state.gdt), 703 idt: DescriptorTable::from(&self.state.idt), 704 cr0: self.state.cr0, 705 cr2: self.state.cr2, 706 cr3: self.state.cr3, 707 cr4: self.state.cr4, 708 // HAXM does not support setting cr8 709 cr8: 0, 710 efer: self.state.efer as u64, 711 } 712 } 713 set_sregs(&mut self, sregs: &Sregs)714 fn set_sregs(&mut self, sregs: &Sregs) { 715 self.state.cs = segment_desc_t::from(&sregs.cs); 716 self.state.ds = segment_desc_t::from(&sregs.ds); 717 self.state.es = segment_desc_t::from(&sregs.es); 718 self.state.fs = segment_desc_t::from(&sregs.fs); 719 self.state.gs = segment_desc_t::from(&sregs.gs); 720 self.state.ss = segment_desc_t::from(&sregs.ss); 721 self.state.tr = segment_desc_t::from(&sregs.tr); 722 self.state.ldt = segment_desc_t::from(&sregs.ldt); 723 self.state.gdt = segment_desc_t::from(&sregs.gdt); 724 self.state.idt = segment_desc_t::from(&sregs.idt); 725 self.state.cr0 = sregs.cr0; 726 self.state.cr2 = sregs.cr2; 727 self.state.cr3 = sregs.cr3; 728 self.state.cr4 = sregs.cr4; 729 self.state.efer = sregs.efer as u32; 730 } 731 get_debugregs(&self) -> DebugRegs732 fn get_debugregs(&self) -> DebugRegs { 733 DebugRegs { 734 db: [ 735 self.state.dr0, 736 self.state.dr1, 737 self.state.dr2, 738 self.state.dr3, 739 ], 740 dr6: self.state.dr6, 741 dr7: self.state.dr7, 742 } 743 } 744 set_debugregs(&mut self, debugregs: &DebugRegs)745 fn set_debugregs(&mut self, debugregs: &DebugRegs) { 746 self.state.dr0 = debugregs.db[0]; 747 self.state.dr1 = debugregs.db[1]; 748 self.state.dr2 = debugregs.db[2]; 749 self.state.dr3 = debugregs.db[3]; 750 self.state.dr6 = debugregs.dr6; 751 self.state.dr7 = debugregs.dr7; 752 } 753 } 754 755 // HAXM's segment descriptor format matches exactly with the VMCS structure. The format 756 // of the AR bits is described in the Intel System Programming Guide Part 3, chapter 24.4.1, 757 // table 24-2. The main confusing thing is that the type_ field in haxm is 4 bits, meaning 758 // the 3 least significant bits represent the normal type field, and the most significant 759 // bit represents the "descriptor type" field. 760 761 impl From<&segment_desc_t> for Segment { from(item: &segment_desc_t) -> Self762 fn from(item: &segment_desc_t) -> Self { 763 // TODO(b/315998194): Add safety comment 764 #[allow(clippy::undocumented_unsafe_blocks)] 765 unsafe { 766 Segment { 767 base: item.base, 768 limit_bytes: item.limit, 769 selector: item.selector, 770 type_: item.__bindgen_anon_1.__bindgen_anon_1.type_() as u8, 771 present: item.__bindgen_anon_1.__bindgen_anon_1.present() as u8, 772 dpl: item.__bindgen_anon_1.__bindgen_anon_1.dpl() as u8, 773 db: item.__bindgen_anon_1.__bindgen_anon_1.operand_size() as u8, 774 s: item.__bindgen_anon_1.__bindgen_anon_1.desc() as u8, 775 l: item.__bindgen_anon_1.__bindgen_anon_1.long_mode() as u8, 776 g: item.__bindgen_anon_1.__bindgen_anon_1.granularity() as u8, 777 avl: item.__bindgen_anon_1.__bindgen_anon_1.available() as u8, 778 } 779 } 780 } 781 } 782 783 impl From<&Segment> for segment_desc_t { from(item: &Segment) -> Self784 fn from(item: &Segment) -> Self { 785 let mut segment = segment_desc_t { 786 base: item.base, 787 limit: item.limit_bytes, 788 selector: item.selector, 789 ..Default::default() 790 }; 791 792 // TODO(b/315998194): Add safety comment 793 #[allow(clippy::undocumented_unsafe_blocks)] 794 unsafe { 795 segment 796 .__bindgen_anon_1 797 .__bindgen_anon_1 798 .set_type(item.type_ as u32); 799 segment 800 .__bindgen_anon_1 801 .__bindgen_anon_1 802 .set_desc(item.s as u32); 803 segment 804 .__bindgen_anon_1 805 .__bindgen_anon_1 806 .set_present(item.present as u32); 807 segment 808 .__bindgen_anon_1 809 .__bindgen_anon_1 810 .set_dpl(item.dpl as u32); 811 segment 812 .__bindgen_anon_1 813 .__bindgen_anon_1 814 .set_operand_size(item.db as u32); 815 segment 816 .__bindgen_anon_1 817 .__bindgen_anon_1 818 .set_long_mode(item.l as u32); 819 segment 820 .__bindgen_anon_1 821 .__bindgen_anon_1 822 .set_granularity(item.g as u32); 823 segment 824 .__bindgen_anon_1 825 .__bindgen_anon_1 826 .set_available(item.avl as u32); 827 } 828 829 segment 830 } 831 } 832 833 impl From<&segment_desc_t> for DescriptorTable { from(item: &segment_desc_t) -> Self834 fn from(item: &segment_desc_t) -> Self { 835 DescriptorTable { 836 base: item.base, 837 limit: item.limit as u16, 838 } 839 } 840 } 841 842 impl From<&DescriptorTable> for segment_desc_t { from(item: &DescriptorTable) -> Self843 fn from(item: &DescriptorTable) -> Self { 844 segment_desc_t { 845 base: item.base, 846 limit: item.limit as u32, 847 ..Default::default() 848 } 849 } 850 } 851 852 impl From<&fx_layout> for Fpu { from(item: &fx_layout) -> Self853 fn from(item: &fx_layout) -> Self { 854 let mut fpu = Fpu { 855 fpr: FpuReg::from_16byte_arrays(&item.st_mm), 856 fcw: item.fcw, 857 fsw: item.fsw, 858 ftwx: item.ftw, 859 last_opcode: item.fop, 860 // SAFETY: trivially safe 861 last_ip: unsafe { item.__bindgen_anon_1.fpu_ip }, 862 // SAFETY: trivially safe 863 last_dp: unsafe { item.__bindgen_anon_2.fpu_dp }, 864 xmm: [[0; 16]; 16], 865 mxcsr: item.mxcsr, 866 }; 867 868 fpu.xmm[..8].copy_from_slice(&item.mmx_1[..]); 869 fpu.xmm[8..].copy_from_slice(&item.mmx_2[..]); 870 871 fpu 872 } 873 } 874 875 impl From<&Fpu> for fx_layout { from(item: &Fpu) -> Self876 fn from(item: &Fpu) -> Self { 877 let mut fpu = fx_layout { 878 fcw: item.fcw, 879 fsw: item.fsw, 880 ftw: item.ftwx, 881 res1: 0, 882 fop: item.last_opcode, 883 __bindgen_anon_1: fx_layout__bindgen_ty_1 { 884 fpu_ip: item.last_ip, 885 }, 886 __bindgen_anon_2: fx_layout__bindgen_ty_2 { 887 fpu_dp: item.last_dp, 888 }, 889 mxcsr: item.mxcsr, 890 mxcsr_mask: 0, 891 st_mm: FpuReg::to_16byte_arrays(&item.fpr), 892 mmx_1: [[0; 16]; 8], 893 mmx_2: [[0; 16]; 8], 894 pad: [0; 96], 895 }; 896 897 fpu.mmx_1.copy_from_slice(&item.xmm[..8]); 898 fpu.mmx_2.copy_from_slice(&item.xmm[8..]); 899 900 fpu 901 } 902 } 903 904 impl From<&hax_cpuid_entry> for CpuIdEntry { from(item: &hax_cpuid_entry) -> Self905 fn from(item: &hax_cpuid_entry) -> Self { 906 CpuIdEntry { 907 function: item.function, 908 index: item.index, 909 flags: item.flags, 910 cpuid: CpuidResult { 911 eax: item.eax, 912 ebx: item.ebx, 913 ecx: item.ecx, 914 edx: item.edx, 915 }, 916 } 917 } 918 } 919 920 impl From<&CpuIdEntry> for hax_cpuid_entry { from(item: &CpuIdEntry) -> Self921 fn from(item: &CpuIdEntry) -> Self { 922 hax_cpuid_entry { 923 function: item.function, 924 index: item.index, 925 flags: item.flags, 926 eax: item.cpuid.eax, 927 ebx: item.cpuid.ebx, 928 ecx: item.cpuid.ecx, 929 edx: item.cpuid.edx, 930 pad: Default::default(), 931 } 932 } 933 } 934 935 // TODO(b:241252288): Enable tests disabled with dummy feature flag - enable_haxm_tests. 936 #[cfg(test)] 937 #[cfg(feature = "enable_haxm_tests")] 938 mod tests { 939 use vm_memory::GuestAddress; 940 use vm_memory::GuestMemory; 941 942 use super::*; 943 use crate::VmX86_64; 944 945 // EFER Bits 946 const EFER_SCE: u64 = 0x00000001; 947 const EFER_LME: u64 = 0x00000100; 948 const EFER_LMA: u64 = 0x00000400; 949 const EFER_SVME: u64 = 1 << 12; 950 951 // CR0 bits 952 const CR0_PG: u64 = 1 << 31; 953 954 #[test] get_regs()955 fn get_regs() { 956 let haxm = Haxm::new().expect("failed to instantiate HAXM"); 957 let mem = 958 GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory"); 959 let vm = HaxmVm::new(&haxm, mem).expect("failed to create vm"); 960 let vcpu = vm.create_vcpu(0).expect("failed to create vcpu"); 961 962 vcpu.get_regs().expect("failed to get regs"); 963 } 964 965 #[test] get_fpu()966 fn get_fpu() { 967 let haxm = Haxm::new().expect("failed to instantiate HAXM"); 968 let mem = 969 GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory"); 970 let vm = HaxmVm::new(&haxm, mem).expect("failed to create vm"); 971 let vcpu = vm.create_vcpu(0).expect("failed to create vcpu"); 972 973 vcpu.get_fpu().expect("failed to get fpu"); 974 } 975 976 #[test] set_msr()977 fn set_msr() { 978 let haxm = Haxm::new().expect("failed to instantiate HAXM"); 979 let mem = 980 GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory"); 981 let vm = HaxmVm::new(&haxm, mem).expect("failed to create vm"); 982 let vcpu = vm.create_vcpu(0).expect("failed to create vcpu"); 983 984 vcpu.set_msr(38, 0x300).expect("failed to set MSR"); 985 } 986 987 #[test] get_msr()988 fn get_msr() { 989 let haxm = Haxm::new().expect("failed to instantiate HAXM"); 990 let mem = 991 GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory"); 992 let vm = HaxmVm::new(&haxm, mem).expect("failed to create vm"); 993 let vcpu = vm.create_vcpu(0).expect("failed to create vcpu"); 994 995 let _value = vcpu.get_msr(38).expect("failed to get MSR"); 996 } 997 998 #[test] set_cpuid()999 fn set_cpuid() { 1000 let haxm = Haxm::new().expect("failed to instantiate HAXM"); 1001 let mem = 1002 GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory"); 1003 let vm = HaxmVm::new(&haxm, mem).expect("failed to create vm"); 1004 let vcpu = vm.create_vcpu(0).expect("failed to create vcpu"); 1005 1006 let mut cpuid = haxm 1007 .get_supported_cpuid() 1008 .expect("failed to get supported cpuids"); 1009 for entry in &mut cpuid.cpu_id_entries { 1010 if entry.function == 1 { 1011 // Disable XSAVE and OSXSAVE 1012 entry.cpuid.ecx &= !(1 << 26); 1013 entry.cpuid.ecx &= !(1 << 27); 1014 } 1015 } 1016 1017 vcpu.set_cpuid(&cpuid).expect("failed to set cpuid"); 1018 } 1019 1020 #[test] set_efer()1021 fn set_efer() { 1022 // HAXM efer setting requires some extra code, so we have this test specifically 1023 // checking that it's working. 1024 let haxm = Haxm::new().expect("failed to instantiate HAXM"); 1025 let mem = 1026 GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory"); 1027 let vm = HaxmVm::new(&haxm, mem).expect("failed to create vm"); 1028 let vcpu = vm.create_vcpu(0).expect("failed to create vcpu"); 1029 1030 let mut sregs = vcpu.get_sregs().expect("failed to get sregs"); 1031 // Initial value should be 0 1032 assert_eq!(sregs.efer & !EFER_SVME, 0); 1033 1034 // Enable and activate long mode 1035 sregs.efer = EFER_LMA | EFER_LME; 1036 // Need to enable paging or LMA will be turned off 1037 sregs.cr0 |= CR0_PG; 1038 vcpu.set_sregs(&sregs).expect("failed to set sregs"); 1039 1040 // Verify that setting stuck 1041 let sregs = vcpu.get_sregs().expect("failed to get sregs"); 1042 assert_eq!(sregs.efer & !EFER_SVME, EFER_LMA | EFER_LME); 1043 1044 // IA32_EFER register value should match 1045 let efer = vcpu.get_msr(IA32_EFER).expect("failed to get msr"); 1046 assert_eq!(efer & !EFER_SVME, EFER_LMA | EFER_LME); 1047 1048 // Enable SCE via set_msrs 1049 vcpu.set_msr(IA32_EFER, efer | EFER_SCE) 1050 .expect("failed to set msr"); 1051 1052 // Verify that setting stuck 1053 let sregs = vcpu.get_sregs().expect("failed to get sregs"); 1054 assert_eq!(sregs.efer & !EFER_SVME, EFER_SCE | EFER_LME | EFER_LMA); 1055 let new_efer = vcpu.get_msr(IA32_EFER).expect("failed to get msrs"); 1056 assert_eq!(new_efer & !EFER_SVME, EFER_SCE | EFER_LME | EFER_LMA); 1057 } 1058 } 1059