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