Skip to content
This repository was archived by the owner on Nov 6, 2024. It is now read-only.

Commit 6f3b013

Browse files
committed
Support treating kvm_xsave as a FamStruct
In linux 5.17, kvm_xsave got turned into a FamStruct by adding the flexible "extra" member to its definition. However, unlike all other such structs, it does not contain a "length" field. Instead, the length of the flexible array member has to be determined by querying the `KVM_CAP_XSAVE2` capability. This requires access to a VM file descriptor, and thus cannot happen in the `FamStruct::len` trait method. To work around this, define a wrapper struct that caches the length of a previous `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2)` call, and implement `FamStruct` for this wrapper. Then in kvm-ioctls, we can expose a function that first query `KVM_CAP_XSAVE2`, then invokes `KVM_GET_XSAVE2` to retrives the `kvm_xsave` structure, and then combine them into the below `kvm_xsave2` structure to be managed as a `FamStruct`. Signed-off-by: Patrick Roy <[email protected]>
1 parent 95dd264 commit 6f3b013

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed

src/x86_64/fam_wrappers.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,64 @@ impl PartialEq for kvm_msr_list {
9494
/// [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html).
9595
pub type MsrList = FamStructWrapper<kvm_msr_list>;
9696

97+
/// Helper structure to treat post-5.17 [`kvm_xsave`] as a FamStruct.
98+
///
99+
/// See also: [`Xsave`].
100+
#[repr(C)]
101+
pub struct kvm_xsave2 {
102+
pub len: usize,
103+
pub xsave: kvm_xsave,
104+
}
105+
106+
// SAFETY:
107+
// - `kvm_xsave2` is a POD
108+
// - `kvm_xsave2` contains a flexible array member as its final field, due to `kvm_xsave` containing
109+
// one, and being `repr(C)`
110+
// - `Entry` is a POD
111+
unsafe impl FamStruct for kvm_xsave2 {
112+
type Entry = __u32;
113+
114+
fn len(&self) -> usize {
115+
self.len
116+
}
117+
118+
unsafe fn set_len(&mut self, len: usize) {
119+
self.len = len;
120+
}
121+
122+
fn max_len() -> usize {
123+
__u32::MAX as usize
124+
}
125+
126+
fn as_slice(&self) -> &[<Self as FamStruct>::Entry] {
127+
let len = self.len();
128+
// SAFETY: By the invariants that the caller of `set_len` has to uphold, `len` matches
129+
// the actual in-memory length of the FAM
130+
unsafe { self.xsave.extra.as_slice(len) }
131+
}
132+
133+
fn as_mut_slice(&mut self) -> &mut [<Self as FamStruct>::Entry] {
134+
let len = self.len();
135+
// SAFETY: By the invariants that the caller of `set_len` has to uphold, `len` matches
136+
// the actual in-memory length of the FAM
137+
unsafe { self.xsave.extra.as_mut_slice(len) }
138+
}
139+
}
140+
141+
/// Wrapper over the post-5.17 [`kvm_xsave`] structure.
142+
///
143+
/// In linux 5.17, kvm_xsave got turned into a FamStruct by adding the flexible "extra" member
144+
/// to its definition. However, unlike all other such structs, it does not contain a "length"
145+
/// field. Instead, the length of the flexible array member has to be determined by querying
146+
/// the [`KVM_CAP_XSAVE2`] capability. This requires access to a VM file descriptor, and thus
147+
/// cannot happen in the [`FamStruct::len`] trait method. To work around this, we define a wrapper
148+
/// struct that caches the length of a previous `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2)` call,
149+
/// and implement [`FamStruct`] for this wrapper. Then in kvm-ioctls, we can expose a function
150+
/// that first queries `KVM_CAP_XSAVE2`, then invokes [`KVM_GET_XSAVE2`] to retrives the `kvm_xsave`
151+
/// structure, and finally combine them into the [`kvm_xsave2`] helper structure to be managed as a
152+
/// `FamStruct`.
153+
pub type Xsave = FamStructWrapper<kvm_xsave2>;
154+
97155
#[cfg(test)]
98156
mod tests {
99157
use super::{CpuId, MsrList, Msrs};

0 commit comments

Comments
 (0)