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