mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 10:10:41 +00:00
hypervisor: Trait changes for VmX86_64
There are 3 new methods added to the trait: - `handle_cpuid` - `get_tsc_offset` - `set_tsc_offset` These methods allow handling of cpu exit for reading CPUID which is required for Hyper-V support. The other 2 methods related to TSC are required for special Hyper-V handling. BUG=b:213150327 TEST=Compiled crosvm Change-Id: Ibc95163d9625883521a56ec9a1573725d0f41711 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3630709 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Vaibhav Nagarnaik <vnagarnaik@google.com>
This commit is contained in:
parent
0465b61b1e
commit
609872d779
2 changed files with 72 additions and 5 deletions
|
@ -6,7 +6,7 @@ use std::arch::x86_64::__cpuid;
|
|||
|
||||
use base::IoctlNr;
|
||||
|
||||
use libc::E2BIG;
|
||||
use libc::{E2BIG, ENXIO};
|
||||
|
||||
use base::{
|
||||
errno_result, error, ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr,
|
||||
|
@ -18,10 +18,11 @@ use vm_memory::GuestAddress;
|
|||
|
||||
use super::{Kvm, KvmVcpu, KvmVm};
|
||||
use crate::{
|
||||
ClockState, CpuId, CpuIdEntry, DebugRegs, DescriptorTable, DeviceKind, Fpu, HypervisorX86_64,
|
||||
IoapicRedirectionTableEntry, IoapicState, IrqSourceChip, LapicState, PicSelect, PicState,
|
||||
PitChannelState, PitState, ProtectionType, Register, Regs, Segment, Sregs, VcpuExit,
|
||||
VcpuX86_64, VmCap, VmX86_64, MAX_IOAPIC_PINS, NUM_IOAPIC_PINS,
|
||||
get_tsc_offset_from_msr, set_tsc_offset_via_msr, ClockState, CpuId, CpuIdEntry, DebugRegs,
|
||||
DescriptorTable, DeviceKind, Fpu, HypervisorX86_64, IoapicRedirectionTableEntry, IoapicState,
|
||||
IrqSourceChip, LapicState, PicSelect, PicState, PitChannelState, PitState, ProtectionType,
|
||||
Register, Regs, Segment, Sregs, VcpuExit, VcpuX86_64, VmCap, VmX86_64, MAX_IOAPIC_PINS,
|
||||
NUM_IOAPIC_PINS,
|
||||
};
|
||||
|
||||
type KvmCpuId = kvm::CpuId;
|
||||
|
@ -697,6 +698,21 @@ impl VcpuX86_64 for KvmVcpu {
|
|||
errno_result()
|
||||
}
|
||||
}
|
||||
|
||||
/// KVM does not support the VcpuExit::Cpuid exit type.
|
||||
fn handle_cpuid(&mut self, _entry: &CpuIdEntry) -> Result<()> {
|
||||
Err(Error::new(ENXIO))
|
||||
}
|
||||
|
||||
fn get_tsc_offset(&self) -> Result<u64> {
|
||||
// Use the default MSR-based implementation
|
||||
get_tsc_offset_from_msr(self)
|
||||
}
|
||||
|
||||
fn set_tsc_offset(&self, offset: u64) -> Result<()> {
|
||||
// Use the default MSR-based implementation
|
||||
set_tsc_offset_via_msr(self, offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl KvmVcpu {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::arch::x86_64::_rdtsc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use base::{error, Result};
|
||||
|
@ -99,10 +101,59 @@ pub trait VcpuX86_64: Vcpu {
|
|||
|
||||
/// Sets up debug registers and configure vcpu for handling guest debug events.
|
||||
fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>;
|
||||
|
||||
/// This function should be called after `Vcpu::run` returns `VcpuExit::Cpuid`, and `entry`
|
||||
/// should represent the result of emulating the CPUID instruction. The `handle_cpuid` function
|
||||
/// will then set the appropriate registers on the vcpu.
|
||||
fn handle_cpuid(&mut self, entry: &CpuIdEntry) -> Result<()>;
|
||||
|
||||
/// Get the guest->host TSC offset
|
||||
fn get_tsc_offset(&self) -> Result<u64>;
|
||||
|
||||
/// Set the guest->host TSC offset
|
||||
fn set_tsc_offset(&self, offset: u64) -> Result<()>;
|
||||
}
|
||||
|
||||
impl_downcast!(VcpuX86_64);
|
||||
|
||||
// TSC MSR
|
||||
pub const MSR_IA32_TSC: u32 = 0x00000010;
|
||||
/// Implementation of get_tsc_offset that uses VcpuX86_64::get_msrs.
|
||||
pub(crate) fn get_tsc_offset_from_msr(vcpu: &impl VcpuX86_64) -> Result<u64> {
|
||||
let mut regs = vec![Register {
|
||||
id: crate::MSR_IA32_TSC,
|
||||
value: 0,
|
||||
}];
|
||||
|
||||
// Safe because _rdtsc takes no arguments
|
||||
let host_before_tsc = unsafe { _rdtsc() };
|
||||
|
||||
// get guest TSC value from our hypervisor
|
||||
vcpu.get_msrs(&mut regs)?;
|
||||
|
||||
// Safe because _rdtsc takes no arguments
|
||||
let host_after_tsc = unsafe { _rdtsc() };
|
||||
|
||||
// Average the before and after host tsc to get the best value
|
||||
let host_tsc = ((host_before_tsc as u128 + host_after_tsc as u128) / 2) as u64;
|
||||
|
||||
Ok(regs[0].value.wrapping_sub(host_tsc))
|
||||
}
|
||||
|
||||
/// Implementation of get_tsc_offset that uses VcpuX86_64::get_msrs.
|
||||
pub(crate) fn set_tsc_offset_via_msr(vcpu: &impl VcpuX86_64, offset: u64) -> Result<()> {
|
||||
// Safe because _rdtsc takes no arguments
|
||||
let host_tsc = unsafe { _rdtsc() };
|
||||
|
||||
let regs = vec![Register {
|
||||
id: crate::MSR_IA32_TSC,
|
||||
value: host_tsc.wrapping_add(offset),
|
||||
}];
|
||||
|
||||
// set guest TSC value from our hypervisor
|
||||
vcpu.set_msrs(®s)
|
||||
}
|
||||
|
||||
/// A CpuId Entry contains supported feature information for the given processor.
|
||||
/// This can be modified by the hypervisor to pass additional information to the guest kernel
|
||||
/// about the hypervisor or vm. Information is returned in the eax, ebx, ecx and edx registers
|
||||
|
|
Loading…
Reference in a new issue