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

Commit fbbef95

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 b9e4cbe commit fbbef95

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

src/x86_64/fam_wrappers.rs

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

0 commit comments

Comments
 (0)