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