1 // Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 mod dist_regs;
6 mod icc_regs;
7 mod redist_regs;
8
9 use std::any::Any;
10
11 use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
12 use icc_regs::{get_icc_regs, set_icc_regs};
13 use kvm_ioctls::DeviceFd;
14 use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs};
15 use serde::{Deserialize, Serialize};
16
17 use crate::arch::aarch64::gic::{Error, GicState, Result, Vgic, VgicConfig};
18 use crate::device::HypervisorDeviceError;
19 use crate::kvm::KvmVm;
20 use crate::{CpuState, Vm};
21
22 const GITS_CTLR: u32 = 0x0000;
23 const GITS_IIDR: u32 = 0x0004;
24 const GITS_CBASER: u32 = 0x0080;
25 const GITS_CWRITER: u32 = 0x0088;
26 const GITS_CREADR: u32 = 0x0090;
27 const GITS_BASER: u32 = 0x0100;
28
gicv3_its_attr_set(its_device: &DeviceFd, group: u32, attr: u32, val: u64) -> Result<()>29 fn gicv3_its_attr_set(its_device: &DeviceFd, group: u32, attr: u32, val: u64) -> Result<()> {
30 let gicv3_its_attr = kvm_bindings::kvm_device_attr {
31 group,
32 attr: attr as u64,
33 addr: &val as *const u64 as u64,
34 flags: 0,
35 };
36
37 its_device
38 .set_device_attr(&gicv3_its_attr)
39 .map_err(|e| Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())))
40 }
41
gicv3_its_attr_get(its_device: &DeviceFd, group: u32, attr: u32) -> Result<u64>42 fn gicv3_its_attr_get(its_device: &DeviceFd, group: u32, attr: u32) -> Result<u64> {
43 let mut val = 0;
44
45 let mut gicv3_its_attr = kvm_bindings::kvm_device_attr {
46 group,
47 attr: attr as u64,
48 addr: &mut val as *mut u64 as u64,
49 flags: 0,
50 };
51
52 // SAFETY: gicv3_its_attr.addr is safe to write to.
53 unsafe { its_device.get_device_attr(&mut gicv3_its_attr) }.map_err(|e| {
54 Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
55 })?;
56
57 Ok(val)
58 }
59
60 /// Function that saves/restores ITS tables into guest RAM.
61 ///
62 /// The tables get flushed to guest RAM whenever the VM gets stopped.
gicv3_its_tables_access(its_device: &DeviceFd, save: bool) -> Result<()>63 pub fn gicv3_its_tables_access(its_device: &DeviceFd, save: bool) -> Result<()> {
64 let attr = if save {
65 u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES)
66 } else {
67 u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES)
68 };
69
70 let init_gic_attr = kvm_bindings::kvm_device_attr {
71 group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
72 attr,
73 addr: 0,
74 flags: 0,
75 };
76 its_device
77 .set_device_attr(&init_gic_attr)
78 .map_err(|e| Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())))
79 }
80
81 pub struct KvmGicV3Its {
82 /// The KVM device for the GicV3
83 device: DeviceFd,
84
85 /// The KVM device for the Its device
86 its_device: Option<DeviceFd>,
87
88 /// Vector holding values of GICR_TYPER for each vCPU
89 gicr_typers: Vec<u64>,
90
91 /// GIC distributor address
92 dist_addr: u64,
93
94 /// GIC distributor size
95 dist_size: u64,
96
97 /// GIC distributors address
98 redists_addr: u64,
99
100 /// GIC distributors size
101 redists_size: u64,
102
103 /// GIC MSI address
104 msi_addr: u64,
105
106 /// GIC MSI size
107 msi_size: u64,
108
109 /// Number of CPUs handled by the device
110 vcpu_count: u64,
111 }
112
113 #[derive(Clone, Default, Serialize, Deserialize)]
114 pub struct Gicv3ItsState {
115 dist: Vec<u32>,
116 rdist: Vec<u32>,
117 icc: Vec<u32>,
118 // special register that enables interrupts and affinity routing
119 gicd_ctlr: u32,
120 its_ctlr: u64,
121 its_iidr: u64,
122 its_cbaser: u64,
123 its_cwriter: u64,
124 its_creadr: u64,
125 its_baser: [u64; 8],
126 }
127
128 impl From<GicState> for Gicv3ItsState {
from(state: GicState) -> Self129 fn from(state: GicState) -> Self {
130 match state {
131 GicState::Kvm(state) => state,
132 /* Needed in case other hypervisors are enabled */
133 #[allow(unreachable_patterns)]
134 _ => panic!("GicState is not valid"),
135 }
136 }
137 }
138
139 impl From<Gicv3ItsState> for GicState {
from(state: Gicv3ItsState) -> Self140 fn from(state: Gicv3ItsState) -> Self {
141 GicState::Kvm(state)
142 }
143 }
144
145 impl KvmGicV3Its {
146 /// Device trees specific constants
147 pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
148
149 /// Returns the GIC version of the device
version() -> u32150 fn version() -> u32 {
151 kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3
152 }
153
154 /// Setup the device-specific attributes
init_device_attributes(&mut self, vm: &KvmVm, nr_irqs: u32) -> Result<()>155 fn init_device_attributes(&mut self, vm: &KvmVm, nr_irqs: u32) -> Result<()> {
156 // GicV3 part attributes
157 /* Setting up the distributor attribute. */
158 Self::set_device_attribute(
159 &self.device,
160 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
161 u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
162 &self.dist_addr as *const u64 as u64,
163 0,
164 )?;
165
166 /* Setting up the redistributors' attribute. */
167 Self::set_device_attribute(
168 &self.device,
169 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
170 u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
171 &self.redists_addr as *const u64 as u64,
172 0,
173 )?;
174
175 // ITS part attributes
176 let mut its_device = kvm_bindings::kvm_create_device {
177 type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
178 fd: 0,
179 flags: 0,
180 };
181
182 let its_fd = vm
183 .create_device(&mut its_device)
184 .map_err(Error::CreateGic)?;
185
186 // We know vm is KvmVm
187 let its_fd = its_fd.to_kvm().unwrap();
188
189 Self::set_device_attribute(
190 &its_fd,
191 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
192 u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
193 &self.msi_addr as *const u64 as u64,
194 0,
195 )?;
196
197 Self::set_device_attribute(
198 &its_fd,
199 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
200 u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
201 0,
202 0,
203 )?;
204
205 self.its_device = Some(its_fd);
206
207 /* We need to tell the kernel how many irqs to support with this vgic.
208 * See the `layout` module for details.
209 */
210 let nr_irqs_ptr = &nr_irqs as *const u32;
211 Self::set_device_attribute(
212 &self.device,
213 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
214 0,
215 nr_irqs_ptr as u64,
216 0,
217 )?;
218
219 /* Finalize the GIC.
220 * See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
221 */
222 Self::set_device_attribute(
223 &self.device,
224 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
225 u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
226 0,
227 0,
228 )
229 }
230
231 /// Create a KVM Vgic device
create_device(vm: &KvmVm) -> Result<DeviceFd>232 fn create_device(vm: &KvmVm) -> Result<DeviceFd> {
233 let mut gic_device = kvm_bindings::kvm_create_device {
234 type_: Self::version(),
235 fd: 0,
236 flags: 0,
237 };
238
239 let device_fd = vm
240 .create_device(&mut gic_device)
241 .map_err(Error::CreateGic)?;
242
243 // We know for sure this is a KVM fd
244 Ok(device_fd.to_kvm().unwrap())
245 }
246
247 /// Set a GIC device attribute
set_device_attribute( device: &DeviceFd, group: u32, attr: u64, addr: u64, flags: u32, ) -> Result<()>248 fn set_device_attribute(
249 device: &DeviceFd,
250 group: u32,
251 attr: u64,
252 addr: u64,
253 flags: u32,
254 ) -> Result<()> {
255 let attr = kvm_bindings::kvm_device_attr {
256 flags,
257 group,
258 attr,
259 addr,
260 };
261 device.set_device_attr(&attr).map_err(|e| {
262 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))
263 })
264 }
265
266 /// Method to initialize the GIC device
new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its>267 pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
268 // This is inside KVM module
269 let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");
270
271 let vgic = Self::create_device(vm)?;
272
273 let mut gic_device = KvmGicV3Its {
274 device: vgic,
275 its_device: None,
276 gicr_typers: vec![0; config.vcpu_count.try_into().unwrap()],
277 dist_addr: config.dist_addr,
278 dist_size: config.dist_size,
279 redists_addr: config.redists_addr,
280 redists_size: config.redists_size,
281 msi_addr: config.msi_addr,
282 msi_size: config.msi_size,
283 vcpu_count: config.vcpu_count,
284 };
285
286 gic_device.init_device_attributes(vm, config.nr_irqs)?;
287
288 Ok(gic_device)
289 }
290 }
291
292 impl Vgic for KvmGicV3Its {
fdt_compatibility(&self) -> &str293 fn fdt_compatibility(&self) -> &str {
294 "arm,gic-v3"
295 }
296
msi_compatible(&self) -> bool297 fn msi_compatible(&self) -> bool {
298 true
299 }
300
msi_compatibility(&self) -> &str301 fn msi_compatibility(&self) -> &str {
302 "arm,gic-v3-its"
303 }
304
fdt_maint_irq(&self) -> u32305 fn fdt_maint_irq(&self) -> u32 {
306 KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ
307 }
308
vcpu_count(&self) -> u64309 fn vcpu_count(&self) -> u64 {
310 self.vcpu_count
311 }
312
device_properties(&self) -> [u64; 4]313 fn device_properties(&self) -> [u64; 4] {
314 [
315 self.dist_addr,
316 self.dist_size,
317 self.redists_addr,
318 self.redists_size,
319 ]
320 }
321
msi_properties(&self) -> [u64; 2]322 fn msi_properties(&self) -> [u64; 2] {
323 [self.msi_addr, self.msi_size]
324 }
325
set_gicr_typers(&mut self, vcpu_states: &[CpuState])326 fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
327 let gicr_typers = construct_gicr_typers(vcpu_states);
328 self.gicr_typers = gicr_typers;
329 }
330
as_any_concrete_mut(&mut self) -> &mut dyn Any331 fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
332 self
333 }
334
335 /// Save the state of GICv3ITS.
state(&self) -> Result<GicState>336 fn state(&self) -> Result<GicState> {
337 let gicr_typers = self.gicr_typers.clone();
338
339 let gicd_ctlr = read_ctlr(&self.device)?;
340
341 let dist_state = get_dist_regs(&self.device)?;
342
343 let rdist_state = get_redist_regs(&self.device, &gicr_typers)?;
344
345 let icc_state = get_icc_regs(&self.device, &gicr_typers)?;
346
347 let mut its_baser_state: [u64; 8] = [0; 8];
348 for i in 0..8 {
349 its_baser_state[i as usize] = gicv3_its_attr_get(
350 self.its_device.as_ref().unwrap(),
351 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
352 GITS_BASER + i * 8,
353 )?;
354 }
355
356 let its_ctlr_state = gicv3_its_attr_get(
357 self.its_device.as_ref().unwrap(),
358 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
359 GITS_CTLR,
360 )?;
361
362 let its_cbaser_state = gicv3_its_attr_get(
363 self.its_device.as_ref().unwrap(),
364 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
365 GITS_CBASER,
366 )?;
367
368 let its_creadr_state = gicv3_its_attr_get(
369 self.its_device.as_ref().unwrap(),
370 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
371 GITS_CREADR,
372 )?;
373
374 let its_cwriter_state = gicv3_its_attr_get(
375 self.its_device.as_ref().unwrap(),
376 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
377 GITS_CWRITER,
378 )?;
379
380 let its_iidr_state = gicv3_its_attr_get(
381 self.its_device.as_ref().unwrap(),
382 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
383 GITS_IIDR,
384 )?;
385
386 let gic_state: GicState = Gicv3ItsState {
387 dist: dist_state,
388 rdist: rdist_state,
389 icc: icc_state,
390 gicd_ctlr,
391 its_ctlr: its_ctlr_state,
392 its_iidr: its_iidr_state,
393 its_cbaser: its_cbaser_state,
394 its_cwriter: its_cwriter_state,
395 its_creadr: its_creadr_state,
396 its_baser: its_baser_state,
397 }
398 .into();
399
400 Ok(gic_state)
401 }
402
403 /// Restore the state of GICv3ITS.
set_state(&mut self, state: &GicState) -> Result<()>404 fn set_state(&mut self, state: &GicState) -> Result<()> {
405 let kvm_state: Gicv3ItsState = state.clone().into();
406
407 let gicr_typers = self.gicr_typers.clone();
408
409 write_ctlr(&self.device, kvm_state.gicd_ctlr)?;
410
411 set_dist_regs(&self.device, &kvm_state.dist)?;
412
413 set_redist_regs(&self.device, &gicr_typers, &kvm_state.rdist)?;
414
415 set_icc_regs(&self.device, &gicr_typers, &kvm_state.icc)?;
416
417 //Restore GICv3ITS registers
418 gicv3_its_attr_set(
419 self.its_device.as_ref().unwrap(),
420 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
421 GITS_IIDR,
422 kvm_state.its_iidr,
423 )?;
424
425 gicv3_its_attr_set(
426 self.its_device.as_ref().unwrap(),
427 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
428 GITS_CBASER,
429 kvm_state.its_cbaser,
430 )?;
431
432 gicv3_its_attr_set(
433 self.its_device.as_ref().unwrap(),
434 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
435 GITS_CREADR,
436 kvm_state.its_creadr,
437 )?;
438
439 gicv3_its_attr_set(
440 self.its_device.as_ref().unwrap(),
441 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
442 GITS_CWRITER,
443 kvm_state.its_cwriter,
444 )?;
445
446 for i in 0..8 {
447 gicv3_its_attr_set(
448 self.its_device.as_ref().unwrap(),
449 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
450 GITS_BASER + i * 8,
451 kvm_state.its_baser[i as usize],
452 )?;
453 }
454
455 // Restore ITS tables
456 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), false)?;
457
458 gicv3_its_attr_set(
459 self.its_device.as_ref().unwrap(),
460 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
461 GITS_CTLR,
462 kvm_state.its_ctlr,
463 )
464 }
465
466 /// Saves GIC internal data tables into RAM, including:
467 /// - RDIST pending tables
468 /// - ITS tables into guest RAM.
save_data_tables(&self) -> Result<()>469 fn save_data_tables(&self) -> Result<()> {
470 // Flash RDIST pending tables
471 let init_gic_attr = kvm_bindings::kvm_device_attr {
472 group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
473 attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
474 addr: 0,
475 flags: 0,
476 };
477 self.device.set_device_attr(&init_gic_attr).map_err(|e| {
478 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))
479 })?;
480 // Flush ITS tables to guest RAM.
481 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), true)
482 }
483 }
484
485 #[cfg(test)]
486 mod tests {
487 use crate::aarch64::gic::{
488 get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
489 };
490 use crate::arch::aarch64::gic::VgicConfig;
491 use crate::kvm::KvmGicV3Its;
492
create_test_vgic_config() -> VgicConfig493 fn create_test_vgic_config() -> VgicConfig {
494 VgicConfig {
495 vcpu_count: 1,
496 dist_addr: 0x0900_0000 - 0x01_0000,
497 dist_size: 0x01_0000,
498 // dist_addr - redists_size
499 redists_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000,
500 redists_size: 0x02_0000,
501 // redists_addr - msi_size
502 msi_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000 - 0x02_0000,
503 msi_size: 0x02_0000,
504 nr_irqs: 256,
505 }
506 }
507
508 #[test]
test_create_gic()509 fn test_create_gic() {
510 let hv = crate::new().unwrap();
511 let vm = hv.create_vm().unwrap();
512
513 KvmGicV3Its::new(&*vm, create_test_vgic_config()).unwrap();
514 }
515
516 #[test]
test_get_set_dist_regs()517 fn test_get_set_dist_regs() {
518 let hv = crate::new().unwrap();
519 let vm = hv.create_vm().unwrap();
520 let _ = vm.create_vcpu(0, None).unwrap();
521 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
522
523 let state = get_dist_regs(&gic.device).unwrap();
524 assert_eq!(state.len(), 568);
525
526 set_dist_regs(&gic.device, &state).unwrap();
527 }
528
529 #[test]
test_get_set_redist_regs()530 fn test_get_set_redist_regs() {
531 let hv = crate::new().unwrap();
532 let vm = hv.create_vm().unwrap();
533 let _ = vm.create_vcpu(0, None).unwrap();
534 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
535
536 let gicr_typer = vec![123];
537 let state = get_redist_regs(&gic.device, &gicr_typer).unwrap();
538 println!("{}", state.len());
539 assert!(state.len() == 24);
540
541 set_redist_regs(&gic.device, &gicr_typer, &state).unwrap();
542 }
543
544 #[test]
test_get_set_icc_regs()545 fn test_get_set_icc_regs() {
546 let hv = crate::new().unwrap();
547 let vm = hv.create_vm().unwrap();
548 let _ = vm.create_vcpu(0, None).unwrap();
549 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
550
551 let gicr_typer = vec![123];
552 let state = get_icc_regs(&gic.device, &gicr_typer).unwrap();
553 println!("{}", state.len());
554 assert!(state.len() == 9);
555
556 set_icc_regs(&gic.device, &gicr_typer, &state).unwrap();
557 }
558
559 #[test]
test_save_data_tables()560 fn test_save_data_tables() {
561 let hv = crate::new().unwrap();
562 let vm = hv.create_vm().unwrap();
563 let _ = vm.create_vcpu(0, None).unwrap();
564 let gic = vm
565 .create_vgic(create_test_vgic_config())
566 .expect("Cannot create gic");
567
568 gic.lock().unwrap().save_data_tables().unwrap();
569 }
570 }
571