Skip to content

Commit 471169d

Browse files
zulinx86jiangliu
authored andcommitted
feat: add MSR-related system ioctls
This commit adds two system ioctls for MSR: `KVM_GET_MSR_FEATURE_INDEX_LIST` and `KVM_GET_MSRS`. Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
1 parent 534d040 commit 471169d

File tree

4 files changed

+121
-5
lines changed

4 files changed

+121
-5
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# Upcoming Release
2+
3+
## Added
4+
- [[#219](https://github.com/rust-vmm/kvm-ioctls/pull/219)] Support for
5+
`KVM_GET_MSR_FEATURE_INDEX_LIST` and `KVM_GET_MSRS` system ioctls.
6+
17
# v0.13.0
28

39
## Added

src/cap.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,5 @@ pub enum Cap {
146146
HypervSynic2 = KVM_CAP_HYPERV_SYNIC2,
147147
DebugHwBps = KVM_CAP_GUEST_DEBUG_HW_BPS,
148148
DebugHwWps = KVM_CAP_GUEST_DEBUG_HW_WPS,
149+
GetMsrFeatures = KVM_CAP_GET_MSR_FEATURES,
149150
}

src/ioctls/system.rs

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::kvm_ioctls::*;
1717
#[cfg(any(target_arch = "aarch64"))]
1818
use kvm_bindings::KVM_VM_TYPE_ARM_IPA_SIZE_MASK;
1919
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
20-
use kvm_bindings::{CpuId, MsrList, KVM_MAX_CPUID_ENTRIES, KVM_MAX_MSR_ENTRIES};
20+
use kvm_bindings::{CpuId, MsrList, Msrs, KVM_MAX_CPUID_ENTRIES, KVM_MAX_MSR_ENTRIES};
2121
use vmm_sys_util::errno;
2222
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2323
use vmm_sys_util::ioctl::ioctl_with_mut_ptr;
@@ -425,7 +425,7 @@ impl Kvm {
425425

426426
// SAFETY: The kernel is trusted not to write beyond the bounds of the memory
427427
// allocated for the struct. The limit is read from nmsrs, which is set to the allocated
428-
// size (MAX_KVM_MSR_ENTRIES) above.
428+
// size (KVM_MAX_MSR_ENTRIES) above.
429429
let ret = unsafe {
430430
ioctl_with_mut_ptr(
431431
self,
@@ -441,6 +441,83 @@ impl Kvm {
441441
Ok(msr_list)
442442
}
443443

444+
/// X86 specific call to get a list of MSRs that can be passed to the KVM_GET_MSRS system ioctl.
445+
///
446+
/// See the documentation for `KVM_GET_MSR_FEATURE_INDEX_LIST`.
447+
///
448+
/// # Example
449+
///
450+
/// ```
451+
/// use kvm_bindings::{kvm_msr_entry, Msrs};
452+
/// use kvm_ioctls::Kvm;
453+
///
454+
/// let kvm = Kvm::new().unwrap();
455+
/// let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap();
456+
/// ```
457+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
458+
pub fn get_msr_feature_index_list(&self) -> Result<MsrList> {
459+
let mut msr_list =
460+
MsrList::new(KVM_MAX_MSR_ENTRIES).map_err(|_| errno::Error::new(libc::ENOMEM))?;
461+
462+
// SAFETY: The kernel is trusted not to write beyond the bounds of the memory
463+
// allocated for the struct. The limit is read from nmsrs, which is set to the allocated
464+
// size (KVM_MAX_MSR_ENTRIES) above.
465+
let ret = unsafe {
466+
ioctl_with_mut_ptr(
467+
self,
468+
KVM_GET_MSR_FEATURE_INDEX_LIST(),
469+
msr_list.as_mut_fam_struct_ptr(),
470+
)
471+
};
472+
if ret < 0 {
473+
return Err(errno::Error::last());
474+
}
475+
476+
Ok(msr_list)
477+
}
478+
479+
/// X86 specific call to read the values of MSR-based features that are available for the VM.
480+
/// As opposed to `VcpuFd::get_msrs()`, this call returns all the MSRs supported by the
481+
/// system, similar to `get_supported_cpuid()` for CPUID.
482+
///
483+
/// See the documentation for `KVM_GET_MSRS`.
484+
///
485+
/// # Arguments
486+
///
487+
/// * `msrs` - MSRs (input/output). For details check the `kvm_msrs` structure in the
488+
/// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt).
489+
///
490+
/// # Example
491+
///
492+
/// ```
493+
/// use kvm_bindings::{kvm_msr_entry, Msrs};
494+
/// use kvm_ioctls::Kvm;
495+
///
496+
/// let kvm = Kvm::new().unwrap();
497+
/// let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap();
498+
/// let mut msrs = Msrs::from_entries(
499+
/// &msr_feature_index_list
500+
/// .as_slice()
501+
/// .iter()
502+
/// .map(|&idx| kvm_msr_entry {
503+
/// index: idx,
504+
/// ..Default::default()
505+
/// })
506+
/// .collect::<Vec<_>>(),
507+
/// )
508+
/// .unwrap();
509+
/// let ret = kvm.get_msrs(&mut msrs).unwrap();
510+
/// ```
511+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
512+
pub fn get_msrs(&self, msrs: &mut Msrs) -> Result<usize> {
513+
// SAFETY: Here we trust the kernel not to read past the end of the kvm_msrs struct.
514+
let ret = unsafe { ioctl_with_mut_ptr(self, KVM_GET_MSRS(), msrs.as_mut_fam_struct_ptr()) };
515+
if ret < 0 {
516+
return Err(errno::Error::last());
517+
}
518+
Ok(ret as usize)
519+
}
520+
444521
/// Creates a VM fd using the KVM fd.
445522
///
446523
/// See the documentation for `KVM_CREATE_VM`.
@@ -812,6 +889,36 @@ mod tests {
812889
assert!(msr_list.as_slice().len() >= 2);
813890
}
814891

892+
#[test]
893+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
894+
fn get_msr_feature_index_list() {
895+
let kvm = Kvm::new().unwrap();
896+
let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap();
897+
assert!(!msr_feature_index_list.as_slice().is_empty());
898+
}
899+
900+
#[test]
901+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
902+
fn get_msrs() {
903+
use kvm_bindings::kvm_msr_entry;
904+
905+
let kvm = Kvm::new().unwrap();
906+
let mut msrs = Msrs::from_entries(&[
907+
kvm_msr_entry {
908+
index: 0x0000010a, // MSR_IA32_ARCH_CAPABILITIES
909+
..Default::default()
910+
},
911+
kvm_msr_entry {
912+
index: 0x00000345, // MSR_IA32_PERF_CAPABILITIES
913+
..Default::default()
914+
},
915+
])
916+
.unwrap();
917+
let nmsrs = kvm.get_msrs(&mut msrs).unwrap();
918+
919+
assert_eq!(nmsrs, 2);
920+
}
921+
815922
#[test]
816923
fn test_bad_kvm_fd() {
817924
let badf_errno = libc::EBADF;

src/kvm_ioctls.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use kvm_bindings::*;
1313

1414
ioctl_io_nr!(KVM_GET_API_VERSION, KVMIO, 0x00);
1515
ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01);
16+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
17+
ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list);
1618
ioctl_io_nr!(KVM_CHECK_EXTENSION, KVMIO, 0x03);
1719
ioctl_io_nr!(KVM_GET_VCPU_MMAP_SIZE, KVMIO, 0x04);
1820
/* Available with KVM_CAP_EXT_CPUID */
@@ -21,6 +23,9 @@ ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2);
2123
/* Available with KVM_CAP_EXT_EMUL_CPUID */
2224
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2325
ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2);
26+
/* Available with KVM_CAP_GET_MSR_FEATURES */
27+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
28+
ioctl_iowr_nr!(KVM_GET_MSR_FEATURE_INDEX_LIST, KVMIO, 0x0a, kvm_msr_list);
2429

2530
// Ioctls for VM fds.
2631

@@ -129,9 +134,6 @@ ioctl_ior_nr!(KVM_GET_SREGS, KVMIO, 0x83, kvm_sregs);
129134
ioctl_iow_nr!(KVM_SET_SREGS, KVMIO, 0x84, kvm_sregs);
130135
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
131136
ioctl_iowr_nr!(KVM_TRANSLATE, KVMIO, 0x85, kvm_translation);
132-
/* Available with KVM_CAP_GET_MSR_FEATURES */
133-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
134-
ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list);
135137
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
136138
ioctl_iowr_nr!(KVM_GET_MSRS, KVMIO, 0x88, kvm_msrs);
137139
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]

0 commit comments

Comments
 (0)