summary refs log tree commit diff
path: root/kvm/src/lib.rs
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2018-02-01 19:12:32 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-02-12 22:42:36 -0800
commit7a4d7b1f50d07e7f0ae350c27659c6e852da62c7 (patch)
tree5efb7e9cb9d7f32e90985a19b7875f9f6936470b /kvm/src/lib.rs
parent53528e33eda615ef309915447b227d2dcacb2090 (diff)
downloadcrosvm-7a4d7b1f50d07e7f0ae350c27659c6e852da62c7.tar
crosvm-7a4d7b1f50d07e7f0ae350c27659c6e852da62c7.tar.gz
crosvm-7a4d7b1f50d07e7f0ae350c27659c6e852da62c7.tar.bz2
crosvm-7a4d7b1f50d07e7f0ae350c27659c6e852da62c7.tar.lz
crosvm-7a4d7b1f50d07e7f0ae350c27659c6e852da62c7.tar.xz
crosvm-7a4d7b1f50d07e7f0ae350c27659c6e852da62c7.tar.zst
crosvm-7a4d7b1f50d07e7f0ae350c27659c6e852da62c7.zip
add plugin support for model specific registers
The MSRs are useful for booting a full operating system that requires
them.

TEST=cargo test --features plugin; cargo test -p kvm; ./build_test
BUG=chromium:800626

Change-Id: I817fbf3e6868c85b373808bd48e568b5b2b458eb
Reviewed-on: https://chromium-review.googlesource.com/897412
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'kvm/src/lib.rs')
-rw-r--r--kvm/src/lib.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs
index 82e8939..1c1ce2e 100644
--- a/kvm/src/lib.rs
+++ b/kvm/src/lib.rs
@@ -830,6 +830,41 @@ impl Vcpu {
         Ok(())
     }
 
+    /// X86 specific call to get the MSRS
+    ///
+    /// See the documentation for KVM_SET_MSRS.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_msrs(&self, msr_entries: &mut [kvm_msr_entry]) -> Result<()> {
+        let vec_size_bytes = size_of::<kvm_msrs>() +
+                             (msr_entries.len() * size_of::<kvm_msr_entry>());
+        let vec: Vec<u8> = vec![0; vec_size_bytes];
+        let msrs: &mut kvm_msrs = unsafe {
+            // Converting the vector's memory to a struct is unsafe.  Carefully using the read-only
+            // vector to size and set the members ensures no out-of-bounds erros below.
+            &mut *(vec.as_ptr() as *mut kvm_msrs)
+        };
+        unsafe {
+            // Mapping the unsized array to a slice is unsafe becase the length isn't known.
+            // Providing the length used to create the struct guarantees the entire slice is valid.
+            let entries: &mut [kvm_msr_entry] = msrs.entries.as_mut_slice(msr_entries.len());
+            entries.copy_from_slice(&msr_entries);
+        }
+        msrs.nmsrs = msr_entries.len() as u32;
+        let ret = unsafe {
+            // Here we trust the kernel not to read or write past the end of the kvm_msrs struct.
+            ioctl_with_ref(self, KVM_GET_MSRS(), msrs)
+        };
+        if ret < 0 {
+            // KVM_SET_MSRS actually returns the number of msr entries written.
+            return errno_result();
+        }
+        unsafe {
+            let entries: &mut [kvm_msr_entry] = msrs.entries.as_mut_slice(msr_entries.len());
+            msr_entries.copy_from_slice(&entries);
+        }
+        Ok(())
+    }
+
     /// X86 specific call to setup the MSRS
     ///
     /// See the documentation for KVM_SET_MSRS.
@@ -1184,6 +1219,24 @@ mod tests {
     }
 
     #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn get_msrs() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
+        vcpu.get_msrs(&mut [kvm_msr_entry {
+                                index: 0x0000011e,
+                                ..Default::default()
+                            },
+                            kvm_msr_entry {
+                                index: 0x000003f1,
+                                ..Default::default()
+                            }])
+            .unwrap();
+    }
+
+    #[test]
     fn vcpu_mmap_size() {
         let kvm = Kvm::new().unwrap();
         let mmap_size = kvm.get_vcpu_mmap_size().unwrap();