@@ -18,12 +18,19 @@ impl std::ops::Deref for GICv3 {
18
18
}
19
19
}
20
20
21
+ impl std:: ops:: DerefMut for GICv3 {
22
+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
23
+ & mut self . 0
24
+ }
25
+ }
26
+
21
27
impl GICv3 {
22
28
// Unfortunately bindgen omits defines that are based on other defines.
23
29
// See arch/arm64/include/uapi/asm/kvm.h file from the linux kernel.
24
30
const SZ_64K : u64 = 0x0001_0000 ;
25
31
const KVM_VGIC_V3_DIST_SIZE : u64 = GICv3 :: SZ_64K ;
26
32
const KVM_VGIC_V3_REDIST_SIZE : u64 = ( 2 * GICv3 :: SZ_64K ) ;
33
+ const GIC_V3_ITS_SIZE : u64 = 0x2_0000 ;
27
34
28
35
// Device trees specific constants
29
36
const ARCH_GIC_V3_MAINT_IRQ : u32 = 9 ;
@@ -48,6 +55,16 @@ impl GICv3 {
48
55
vcpu_count * GICv3 :: KVM_VGIC_V3_REDIST_SIZE
49
56
}
50
57
58
+ /// Get the MSI address
59
+ fn get_msi_address ( vcpu_count : u64 ) -> u64 {
60
+ Self :: get_redists_addr ( vcpu_count) - GICv3 :: GIC_V3_ITS_SIZE
61
+ }
62
+
63
+ /// Get the MSI size
64
+ const fn get_msi_size ( ) -> u64 {
65
+ GICv3 :: GIC_V3_ITS_SIZE
66
+ }
67
+
51
68
pub const VERSION : u32 = kvm_bindings:: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3;
52
69
53
70
pub fn fdt_compatibility ( & self ) -> & str {
@@ -59,30 +76,43 @@ impl GICv3 {
59
76
}
60
77
61
78
/// Create the GIC device object
62
- pub fn create_device ( fd : DeviceFd , vcpu_count : u64 ) -> Self {
63
- GICv3 ( super :: GIC {
64
- fd,
79
+ pub fn create_device ( vm : & VmFd , vcpu_count : u64 ) -> Result < Self , GicError > {
80
+ // Create the GIC device
81
+ let mut gic_device = kvm_bindings:: kvm_create_device {
82
+ type_ : Self :: VERSION ,
83
+ fd : 0 ,
84
+ flags : 0 ,
85
+ } ;
86
+
87
+ let gic_fd = vm
88
+ . create_device ( & mut gic_device)
89
+ . map_err ( GicError :: CreateGIC ) ?;
90
+
91
+ Ok ( GICv3 ( super :: GIC {
92
+ fd : gic_fd,
65
93
properties : [
66
94
GICv3 :: get_dist_addr ( ) ,
67
95
GICv3 :: get_dist_size ( ) ,
68
96
GICv3 :: get_redists_addr ( vcpu_count) ,
69
97
GICv3 :: get_redists_size ( vcpu_count) ,
70
98
] ,
99
+ msi_properties : Some ( [ GICv3 :: get_msi_address ( vcpu_count) , GICv3 :: get_msi_size ( ) ] ) ,
71
100
vcpu_count,
72
- } )
101
+ its_device : None ,
102
+ } ) )
73
103
}
74
104
75
105
pub fn save_device ( & self , mpidrs : & [ u64 ] ) -> Result < GicState , GicError > {
76
- regs:: save_state ( & self . fd , mpidrs)
106
+ regs:: save_state ( & self . fd , self . its_device . as_ref ( ) . unwrap ( ) , mpidrs)
77
107
}
78
108
79
109
pub fn restore_device ( & self , mpidrs : & [ u64 ] , state : & GicState ) -> Result < ( ) , GicError > {
80
- regs:: restore_state ( & self . fd , mpidrs, state)
110
+ regs:: restore_state ( & self . fd , self . its_device . as_ref ( ) . unwrap ( ) , mpidrs, state)
81
111
}
82
112
83
113
pub fn init_device_attributes ( gic_device : & Self ) -> Result < ( ) , GicError > {
84
114
// Setting up the distributor attribute.
85
- // We are placing the GIC below 1GB so we need to substract the size of the distributor.
115
+ // We are placing the GIC below 1GB so we need to subtract the size of the distributor.
86
116
Self :: set_device_attribute (
87
117
gic_device. device_fd ( ) ,
88
118
kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_ADDR ,
@@ -104,25 +134,45 @@ impl GICv3 {
104
134
Ok ( ( ) )
105
135
}
106
136
107
- /// Initialize a GIC device
108
- pub fn init_device ( vm : & VmFd ) -> Result < DeviceFd , GicError > {
109
- let mut gic_device = kvm_bindings:: kvm_create_device {
110
- type_ : Self :: VERSION ,
137
+ fn init_its ( vm : & VmFd , gic_device : & mut Self ) -> Result < ( ) , GicError > {
138
+ // ITS part attributes
139
+ let mut its_device = kvm_bindings:: kvm_create_device {
140
+ type_ : kvm_bindings :: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS ,
111
141
fd : 0 ,
112
142
flags : 0 ,
113
143
} ;
114
144
115
- vm. create_device ( & mut gic_device)
116
- . map_err ( GicError :: CreateGIC )
145
+ let its_fd = vm
146
+ . create_device ( & mut its_device)
147
+ . map_err ( GicError :: CreateGIC ) ?;
148
+
149
+ // Setting up the ITS attributes
150
+ Self :: set_device_attribute (
151
+ & its_fd,
152
+ kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_ADDR ,
153
+ u64:: from ( kvm_bindings:: KVM_VGIC_ITS_ADDR_TYPE ) ,
154
+ & Self :: get_msi_address ( gic_device. vcpu_count ( ) ) as * const u64 as u64 ,
155
+ 0 ,
156
+ ) ?;
157
+
158
+ Self :: set_device_attribute (
159
+ & its_fd,
160
+ kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
161
+ u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_CTRL_INIT ) ,
162
+ 0 ,
163
+ 0 ,
164
+ ) ?;
165
+
166
+ gic_device. its_device = Some ( its_fd) ;
167
+ Ok ( ( ) )
117
168
}
118
169
119
170
/// Method to initialize the GIC device
120
171
pub fn create ( vm : & VmFd , vcpu_count : u64 ) -> Result < Self , GicError > {
121
- let vgic_fd = Self :: init_device ( vm) ?;
122
-
123
- let device = Self :: create_device ( vgic_fd, vcpu_count) ;
172
+ let mut device = Self :: create_device ( vm, vcpu_count) ?;
124
173
125
174
Self :: init_device_attributes ( & device) ?;
175
+ Self :: init_its ( vm, & mut device) ?;
126
176
127
177
Self :: finalize_device ( & device) ?;
128
178
@@ -180,20 +230,41 @@ impl GICv3 {
180
230
}
181
231
}
182
232
233
+ /// Function that saves/restores ITS tables into guest RAM.
234
+ pub fn gicv3_its_tables_access ( its_device : & DeviceFd , save : bool ) -> Result < ( ) , GicError > {
235
+ let attr = if save {
236
+ u64:: from ( kvm_bindings:: KVM_DEV_ARM_ITS_SAVE_TABLES )
237
+ } else {
238
+ u64:: from ( kvm_bindings:: KVM_DEV_ARM_ITS_RESTORE_TABLES )
239
+ } ;
240
+
241
+ let init_gic_attr = kvm_bindings:: kvm_device_attr {
242
+ group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
243
+ attr,
244
+ addr : 0 ,
245
+ flags : 0 ,
246
+ } ;
247
+
248
+ its_device. set_device_attr ( & init_gic_attr) . map_err ( |err| {
249
+ GicError :: DeviceAttribute ( err, true , kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL )
250
+ } )
251
+ }
252
+
183
253
/// Function that flushes
184
254
/// RDIST pending tables into guest RAM.
185
255
///
186
256
/// The tables get flushed to guest RAM whenever the VM gets stopped.
187
- fn save_pending_tables ( fd : & DeviceFd ) -> Result < ( ) , GicError > {
257
+ fn save_pending_tables ( gic_device : & DeviceFd , its_device : & DeviceFd ) -> Result < ( ) , GicError > {
188
258
let init_gic_attr = kvm_bindings:: kvm_device_attr {
189
259
group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
190
260
attr : u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES ) ,
191
261
addr : 0 ,
192
262
flags : 0 ,
193
263
} ;
194
- fd . set_device_attr ( & init_gic_attr) . map_err ( |err| {
264
+ gic_device . set_device_attr ( & init_gic_attr) . map_err ( |err| {
195
265
GicError :: DeviceAttribute ( err, true , kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL )
196
- } )
266
+ } ) ?;
267
+ gicv3_its_tables_access ( its_device, true )
197
268
}
198
269
199
270
#[ cfg( test) ]
@@ -211,11 +282,11 @@ mod tests {
211
282
let kvm = Kvm :: new ( ) . unwrap ( ) ;
212
283
let vm = kvm. create_vm ( ) . unwrap ( ) ;
213
284
let gic = create_gic ( & vm, 1 , Some ( GICVersion :: GICV3 ) ) . expect ( "Cannot create gic" ) ;
214
- save_pending_tables ( gic. device_fd ( ) ) . unwrap ( ) ;
285
+ save_pending_tables ( gic. device_fd ( ) , gic . its_fd ( ) . unwrap ( ) ) . unwrap ( ) ;
215
286
216
287
unsafe { libc:: close ( gic. device_fd ( ) . as_raw_fd ( ) ) } ;
217
288
218
- let res = save_pending_tables ( gic. device_fd ( ) ) ;
289
+ let res = save_pending_tables ( gic. device_fd ( ) , gic . its_fd ( ) . unwrap ( ) ) ;
219
290
assert_eq ! (
220
291
format!( "{:?}" , res. unwrap_err( ) ) ,
221
292
"DeviceAttribute(Error(9), true, 4)"
0 commit comments