@@ -6,9 +6,9 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
6
6
7
7
use ioctls:: Result ;
8
8
use kvm_bindings:: kvm_device_attr;
9
- use kvm_ioctls:: { KVM_HAS_DEVICE_ATTR , KVM_SET_DEVICE_ATTR } ;
9
+ use kvm_ioctls:: { KVM_GET_DEVICE_ATTR , KVM_HAS_DEVICE_ATTR , KVM_SET_DEVICE_ATTR } ;
10
10
use vmm_sys_util:: errno;
11
- use vmm_sys_util:: ioctl:: ioctl_with_ref;
11
+ use vmm_sys_util:: ioctl:: { ioctl_with_mut_ref , ioctl_with_ref} ;
12
12
13
13
/// Wrapper over the file descriptor obtained when creating an emulated device in the kernel.
14
14
pub struct DeviceFd {
@@ -80,6 +80,76 @@ impl DeviceFd {
80
80
}
81
81
Ok ( ( ) )
82
82
}
83
+
84
+ /// Gets a specified piece of device configuration and/or state.
85
+ ///
86
+ /// See the documentation for `KVM_GET_DEVICE_ATTR`.
87
+ ///
88
+ /// # Arguments
89
+ ///
90
+ /// * `device_attr` - The device attribute to be get.
91
+ /// Note: This argument serves as both input and output.
92
+ /// When calling this function, the user should explicitly provide
93
+ /// valid values for the `group` and the `attr` field of the
94
+ /// `kvm_device_attr` structure, and a valid userspace address
95
+ /// (i.e. the `addr` field) to access the returned device attribute
96
+ /// data.
97
+ ///
98
+ /// # Returns
99
+ ///
100
+ /// * Returns the last occured `errno` wrapped in an `Err`.
101
+ /// * `device_attr` - The `addr` field of the `device_attr` structure will point to
102
+ /// the device attribute data.
103
+ ///
104
+ /// # Examples
105
+ /// ```rust
106
+ /// # extern crate kvm_ioctls;
107
+ /// # extern crate kvm_bindings;
108
+ /// # use kvm_ioctls::Kvm;
109
+ ///
110
+ /// let kvm = Kvm::new().unwrap();
111
+ /// let vm = kvm.create_vm().unwrap();
112
+ ///
113
+ /// // As on x86_64, `get_device_attr` is not necessarily needed. Therefore here
114
+ /// // the code example is only for AArch64.
115
+ /// #[cfg(any(target_arch = "aarch64"))]
116
+ /// {
117
+ /// use kvm_bindings::{
118
+ /// KVM_DEV_ARM_VGIC_GRP_NR_IRQS, kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2,
119
+ /// kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3,
120
+ /// };
121
+ ///
122
+ /// // Create a GIC device.
123
+ /// let mut gic_device = kvm_bindings::kvm_create_device {
124
+ /// type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3,
125
+ /// fd: 0,
126
+ /// flags: 0,
127
+ /// };
128
+ /// let device_fd = match vm.create_device(&mut gic_device) {
129
+ /// Ok(fd) => fd,
130
+ /// Err(_) => {
131
+ /// gic_device.type_ = kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2;
132
+ /// vm.create_device(&mut gic_device)
133
+ /// .expect("Cannot create KVM vGIC device")
134
+ /// }
135
+ /// };
136
+ ///
137
+ /// let mut data: u32 = 0;
138
+ /// let mut gic_attr = kvm_bindings::kvm_device_attr::default();
139
+ /// gic_attr.group = KVM_DEV_ARM_VGIC_GRP_NR_IRQS;
140
+ /// gic_attr.addr = &mut data as *const u32 as u64;
141
+ ///
142
+ /// device_fd.get_device_attr(&mut gic_attr).unwrap();
143
+ /// }
144
+ /// ```
145
+ ///
146
+ pub fn get_device_attr ( & self , device_attr : & mut kvm_device_attr ) -> Result < ( ) > {
147
+ let ret = unsafe { ioctl_with_mut_ref ( self , KVM_GET_DEVICE_ATTR ( ) , device_attr) } ;
148
+ if ret != 0 {
149
+ return Err ( errno:: Error :: last ( ) ) ;
150
+ }
151
+ Ok ( ( ) )
152
+ }
83
153
}
84
154
85
155
/// Helper function for creating a new device.
@@ -155,18 +225,24 @@ mod tests {
155
225
flags : 0 ,
156
226
} ;
157
227
228
+ let mut dist_attr_mut = dist_attr;
229
+
158
230
// We are just creating a test device. Creating a real device would make the CI dependent
159
231
// on host configuration (like having /dev/vfio). We expect this to fail.
160
232
assert ! ( device_fd. has_device_attr( & dist_attr) . is_err( ) ) ;
233
+ assert ! ( device_fd. get_device_attr( & mut dist_attr_mut) . is_err( ) ) ;
161
234
assert ! ( device_fd. set_device_attr( & dist_attr) . is_err( ) ) ;
162
235
assert_eq ! ( errno:: Error :: last( ) . errno( ) , 25 ) ;
163
236
}
164
237
165
238
#[ test]
166
239
#[ cfg( target_arch = "aarch64" ) ]
167
240
fn test_create_device ( ) {
168
- use ioctls:: vm:: create_gic_device;
169
- use kvm_bindings:: kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20;
241
+ use ioctls:: vm:: { create_gic_device, set_supported_nr_irqs} ;
242
+ use kvm_bindings:: {
243
+ kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20, KVM_DEV_ARM_VGIC_GRP_NR_IRQS ,
244
+ } ;
245
+ use vmm_sys_util:: errno:: Error ;
170
246
171
247
let kvm = Kvm :: new ( ) . unwrap ( ) ;
172
248
let vm = kvm. create_vm ( ) . unwrap ( ) ;
@@ -197,6 +273,9 @@ mod tests {
197
273
} ;
198
274
assert ! ( device_fd. has_device_attr( & dist_attr) . is_err( ) ) ;
199
275
276
+ // Set maximum supported number of IRQs of the vGIC device to 128.
277
+ set_supported_nr_irqs ( & device_fd, 128 ) ;
278
+
200
279
// Following attribute works with VGIC, they should be accepted.
201
280
let dist_attr = kvm_bindings:: kvm_device_attr {
202
281
group : KVM_DEV_ARM_VGIC_GRP_CTRL ,
@@ -207,5 +286,24 @@ mod tests {
207
286
208
287
assert ! ( device_fd. has_device_attr( & dist_attr) . is_ok( ) ) ;
209
288
assert ! ( device_fd. set_device_attr( & dist_attr) . is_ok( ) ) ;
289
+
290
+ // Test `get_device_attr`. Here we try to extract the maximum supported number of IRQs.
291
+ // This value should be saved in the address provided to the ioctl.
292
+ let mut data: u32 = 0 ;
293
+
294
+ let mut gic_attr = kvm_bindings:: kvm_device_attr:: default ( ) ;
295
+ gic_attr. group = KVM_DEV_ARM_VGIC_GRP_NR_IRQS ;
296
+ gic_attr. addr = data as u64 ;
297
+
298
+ // Without properly providing the address to where the
299
+ // value will be stored, the ioctl fails with EFAULT.
300
+ let res = device_fd. get_device_attr ( & mut gic_attr) ;
301
+ assert_eq ! ( res, Err ( Error :: new( libc:: EFAULT ) ) ) ;
302
+
303
+ gic_attr. addr = & mut data as * const u32 as u64 ;
304
+ assert ! ( device_fd. get_device_attr( & mut gic_attr) . is_ok( ) ) ;
305
+ // The maximum supported number of IRQs should be 128, same as the value
306
+ // when we initialize the GIC.
307
+ assert_eq ! ( data, 128 ) ;
210
308
}
211
309
}
0 commit comments