Skip to content

Commit

Permalink
implement CpuId and MsrList using KvmVec
Browse files Browse the repository at this point in the history
Signed-off-by: Serban Iorga <[email protected]>
  • Loading branch information
Serban Iorga committed Apr 17, 2019
1 parent dff9210 commit 0ed9715
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 236 deletions.
146 changes: 134 additions & 12 deletions src/ioctls/common/kvm_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,55 @@ pub enum Error {
SizeLimitExceeded,
}

// Trait for accessing some properties of certain KVM structures that resemble an array.
//
// The kvm API has many structs that resemble the following `T` structure:
//
// ```
// #[repr(C)]
// struct T {
// len: u32,
// some_data: u32,
// entries: __IncompleteArrayField<KvmArray::Entry>,
// }
// ```
/// Trait for accessing some properties of certain KVM structures that resemble an array.
///
/// The kvm API has many structs that resemble the following `MockKvmArray` structure:
///
/// # Example
///
/// ```
/// extern crate kvm_bindings;
/// use kvm_bindings::*;
///
/// use kvm_ioctls::{KvmArray, KvmVec};
///
/// const MAX_LEN: usize = 100;
///
/// #[repr(C)]
/// #[derive(Default)]
/// struct MockKvmArray {
/// pub len: __u32,
/// pub padding: __u32,
/// pub entries: __IncompleteArrayField<__u32>,
/// }
///
/// impl KvmArray for MockKvmArray {
/// type Entry = u32;
///
/// fn len(&self) -> usize {
/// self.len as usize
/// }
///
/// fn set_len(&mut self, len: usize) {
/// self.len = len as u32
/// }
///
/// fn max_len() -> usize {
/// MAX_LEN
/// }
///
/// fn entries(&self) -> &__IncompleteArrayField<u32> {
/// &self.entries
/// }
///
/// fn entries_mut(&mut self) -> &mut __IncompleteArrayField<u32> {
/// &mut self.entries
/// }
/// }
/// ```
#[allow(clippy::len_without_is_empty)]
pub trait KvmArray {
/// The type of the __IncompleteArrayField entries
type Entry: PartialEq;

/// Get the array length
Expand Down Expand Up @@ -89,6 +124,25 @@ impl<T: Default + KvmArray> KvmVec<T> {
///
/// * `num_elements` - The number of empty elements of type `KvmArray::Entry` in the initial `KvmVec`
///
/// # Example
///
/// ```
/// extern crate kvm_bindings;
/// use kvm_bindings::*;
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// use kvm_ioctls::{KvmArray, KvmVec, CpuId};
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// fn example() {
/// let cpuid = CpuId::new(3);
/// assert_eq!(cpuid.as_entries_slice().len(), 3);
/// for entry in cpuid.as_entries_slice().iter() {
/// assert_eq!(*entry, kvm_cpuid_entry2::default())
/// }
/// }
/// ```
///
pub fn new(num_elements: usize) -> KvmVec<T> {
let required_mem_allocator_capacity =
KvmVec::<T>::kvm_vec_len_to_mem_allocator_len(num_elements);
Expand Down Expand Up @@ -143,13 +197,38 @@ impl<T: Default + KvmArray> KvmVec<T> {

/// Get the mutable elements slice so they can be modified before passing to the VCPU.
///
/// # Example
/// ```
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// use kvm_ioctls::{CpuId, Kvm, MAX_KVM_CPUID_ENTRIES};
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// fn example() {
/// let kvm = Kvm::new().unwrap();
/// let mut cpuid = kvm.get_supported_cpuid(MAX_KVM_CPUID_ENTRIES).unwrap();
/// let cpuid_entries = cpuid.as_entries_slice();
/// }
/// ```
pub fn as_entries_slice(&self) -> &[T::Entry] {
let len = self.as_kvm_struct().len();
unsafe { self.as_kvm_struct().entries().as_slice(len as usize) }
}

/// Get the mutable elements slice so they can be modified before passing to the VCPU.
///
/// # Example
/// ```
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// use kvm_ioctls::{CpuId, Kvm, MAX_KVM_CPUID_ENTRIES};
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// fn example() {
/// let kvm = Kvm::new().unwrap();
/// let mut cpuid = kvm.get_supported_cpuid(MAX_KVM_CPUID_ENTRIES).unwrap();
/// let cpuid_entries = cpuid.as_mut_entries_slice();
/// }
/// ```
///
pub fn as_mut_entries_slice(&mut self) -> &mut [T::Entry] {
let len = self.as_kvm_struct().len();
unsafe {
Expand Down Expand Up @@ -202,6 +281,31 @@ impl<T: Default + KvmArray> KvmVec<T> {
///
/// # Error: When len is already equal to max possible len it returns Error::SizeLimitExceeded
///
/// # Example
/// ```
/// extern crate kvm_bindings;
/// use kvm_bindings::*;
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// use kvm_ioctls::{KvmArray, KvmVec, CpuId};
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// fn example() {
/// let mut cpuid = CpuId::new(3);
/// cpuid.push(kvm_cpuid_entry2 {
/// function: 1,
/// index: 0,
/// flags: 0,
/// eax: 0,
/// ebx: 0,
/// ecx: 0,
/// edx: 0,
/// padding: [0, 0, 0]
/// });
/// assert_eq!(cpuid.as_entries_slice()[3].function, 1)
/// }
/// ```
///
pub fn push(&mut self, entry: T::Entry) -> Result<(), Error> {
let desired_len = self.len + 1;
if desired_len > T::max_len() {
Expand All @@ -225,6 +329,24 @@ impl<T: Default + KvmArray> KvmVec<T> {
///
/// * `f` - The function used to evaluate whether an entry will be kept or not. When `f` returns `true` the entry is kept.
///
/// # Example
/// ```
/// extern crate kvm_bindings;
/// use kvm_bindings::*;
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// use kvm_ioctls::{KvmArray, KvmVec, CpuId};
///
/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// fn example() {
/// let mut cpuid = CpuId::new(3);
/// cpuid.retain(|entry| {
/// entry.function != 0
/// });
/// assert_eq!(cpuid.as_entries_slice().len(), 0);
/// }
/// ```
///
pub fn retain<P>(&mut self, f: P)
where
P: FnMut(&T::Entry) -> bool,
Expand Down
Loading

0 comments on commit 0ed9715

Please sign in to comment.