@@ -6,7 +6,7 @@ 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_SET_DEVICE_ATTR ;
9
+ use kvm_ioctls:: { KVM_HAS_DEVICE_ATTR , KVM_SET_DEVICE_ATTR } ;
10
10
use vmm_sys_util:: errno;
11
11
use vmm_sys_util:: ioctl:: ioctl_with_ref;
12
12
@@ -16,13 +16,63 @@ pub struct DeviceFd {
16
16
}
17
17
18
18
impl DeviceFd {
19
+ /// Tests whether a device supports a particular attribute.
20
+ ///
21
+ /// See the documentation for `KVM_HAS_DEVICE_ATTR`.
22
+ /// # Arguments
23
+ ///
24
+ /// * `device_attr` - The device attribute to be tested. `addr` field is ignored.
25
+ ///
26
+ pub fn has_device_attr ( & self , device_attr : & kvm_device_attr ) -> Result < ( ) > {
27
+ let ret = unsafe { ioctl_with_ref ( self , KVM_HAS_DEVICE_ATTR ( ) , device_attr) } ;
28
+ if ret != 0 {
29
+ return Err ( errno:: Error :: last ( ) ) ;
30
+ }
31
+ Ok ( ( ) )
32
+ }
33
+
19
34
/// Sets a specified piece of device configuration and/or state.
20
35
///
21
36
/// See the documentation for `KVM_SET_DEVICE_ATTR`.
22
37
/// # Arguments
23
38
///
24
39
/// * `device_attr` - The device attribute to be set.
25
40
///
41
+ /// # Example
42
+ ///
43
+ /// ```rust
44
+ /// # extern crate kvm_ioctls;
45
+ /// # extern crate kvm_bindings;
46
+ /// # use kvm_ioctls::Kvm;
47
+ /// # use kvm_bindings::{
48
+ /// kvm_device_type_KVM_DEV_TYPE_VFIO,
49
+ /// KVM_DEV_VFIO_GROUP, KVM_DEV_VFIO_GROUP_ADD, KVM_CREATE_DEVICE_TEST
50
+ /// };
51
+ /// let kvm = Kvm::new().unwrap();
52
+ /// let vm = kvm.create_vm().unwrap();
53
+ ///
54
+ /// let mut device = kvm_bindings::kvm_create_device {
55
+ /// type_: kvm_device_type_KVM_DEV_TYPE_VFIO,
56
+ /// fd: 0,
57
+ /// flags: KVM_CREATE_DEVICE_TEST,
58
+ /// };
59
+ ///
60
+ /// let device_fd = vm
61
+ /// .create_device(&mut device)
62
+ /// .expect("Cannot create KVM device");
63
+ ///
64
+ /// let dist_attr = kvm_bindings::kvm_device_attr {
65
+ /// group: KVM_DEV_VFIO_GROUP,
66
+ /// attr: u64::from(KVM_DEV_VFIO_GROUP_ADD),
67
+ /// addr: 0x0,
68
+ /// flags: 0,
69
+ /// };
70
+ ///
71
+ /// if (device_fd.has_device_attr(&dist_attr).is_ok()) {
72
+ /// device_fd.set_device_attr(&dist_attr).unwrap();
73
+ /// }
74
+ /// ```
75
+ ///
26
76
pub fn set_device_attr ( & self , device_attr : & kvm_device_attr ) -> Result < ( ) > {
27
77
let ret = unsafe { ioctl_with_ref ( self , KVM_SET_DEVICE_ATTR ( ) , device_attr) } ;
28
78
if ret != 0 {
@@ -62,8 +112,15 @@ mod tests {
62
112
#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
63
113
use kvm_bindings:: {
64
114
kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3, kvm_device_type_KVM_DEV_TYPE_VFIO,
115
+ KVM_DEV_VFIO_GROUP , KVM_DEV_VFIO_GROUP_ADD ,
65
116
} ;
66
- use kvm_bindings:: { KVM_CREATE_DEVICE_TEST , KVM_DEV_VFIO_GROUP , KVM_DEV_VFIO_GROUP_ADD } ;
117
+ #[ cfg( target_arch = "aarch64" ) ]
118
+ use kvm_bindings:: {
119
+ KVM_DEV_ARM_VGIC_CTRL_INIT , KVM_DEV_ARM_VGIC_GRP_CTRL , KVM_DEV_VFIO_GROUP ,
120
+ KVM_DEV_VFIO_GROUP_ADD ,
121
+ } ;
122
+
123
+ use kvm_bindings:: KVM_CREATE_DEVICE_TEST ;
67
124
68
125
#[ test]
69
126
#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
@@ -100,6 +157,7 @@ mod tests {
100
157
101
158
// We are just creating a test device. Creating a real device would make the CI dependent
102
159
// on host configuration (like having /dev/vfio). We expect this to fail.
160
+ assert ! ( device_fd. has_device_attr( & dist_attr) . is_err( ) ) ;
103
161
assert ! ( device_fd. set_device_attr( & dist_attr) . is_err( ) ) ;
104
162
assert_eq ! ( errno:: Error :: last( ) . errno( ) , 25 ) ;
105
163
}
@@ -118,31 +176,36 @@ mod tests {
118
176
fd : 0 ,
119
177
flags : KVM_CREATE_DEVICE_TEST ,
120
178
} ;
121
- // This fails on aarch64 as it does not use MPIC (MultiProcessor Interrupt Controller), it uses
122
- // the VGIC.
179
+ // This fails on aarch64 as it does not use MPIC (MultiProcessor Interrupt Controller),
180
+ // it uses the VGIC.
123
181
assert ! ( vm. create_device( & mut gic_device) . is_err( ) ) ;
124
182
125
- let device_fd = create_gic_device ( & vm, KVM_CREATE_DEVICE_TEST ) ;
183
+ let device_fd = create_gic_device ( & vm, 0 ) ;
126
184
127
185
// Following lines to re-construct device_fd are used to test
128
186
// DeviceFd::from_raw_fd() and DeviceFd::as_raw_fd().
129
187
let raw_fd = unsafe { libc:: dup ( device_fd. as_raw_fd ( ) ) } ;
130
188
assert ! ( raw_fd >= 0 ) ;
131
189
let device_fd = unsafe { DeviceFd :: from_raw_fd ( raw_fd) } ;
132
190
191
+ // Set some attribute that does not apply to VGIC, expect the test to fail.
133
192
let dist_attr = kvm_bindings:: kvm_device_attr {
134
193
group : KVM_DEV_VFIO_GROUP ,
135
194
attr : u64:: from ( KVM_DEV_VFIO_GROUP_ADD ) ,
136
195
addr : 0x0 ,
137
196
flags : 0 ,
138
197
} ;
198
+ assert ! ( device_fd. has_device_attr( & dist_attr) . is_err( ) ) ;
139
199
140
- // We are just creating a test device. Creating a real device would make the CI dependent
141
- // on host configuration (like having /dev/vfio). We expect this to fail.
142
- assert ! ( device_fd. set_device_attr( & dist_attr) . is_err( ) ) ;
143
- // Comment this assertion as a workaround for arm coverage test CI, as it is testing the error
144
- // case that cannot be reproduced in a real case scenario. This assertion will lead to failure
145
- // caused by ioctl returning `EINVAL` instead of `ENOTTY` when using gnu toolchain.
146
- //assert_eq!(errno::Error::last().errno(), 25);
200
+ // Following attribute works with VGIC, they should be accepted.
201
+ let dist_attr = kvm_bindings:: kvm_device_attr {
202
+ group : KVM_DEV_ARM_VGIC_GRP_CTRL ,
203
+ attr : u64:: from ( KVM_DEV_ARM_VGIC_CTRL_INIT ) ,
204
+ addr : 0x0 ,
205
+ flags : 0 ,
206
+ } ;
207
+
208
+ assert ! ( device_fd. has_device_attr( & dist_attr) . is_ok( ) ) ;
209
+ assert ! ( device_fd. set_device_attr( & dist_attr) . is_ok( ) ) ;
147
210
}
148
211
}
0 commit comments