xref: /cloud-hypervisor/hypervisor/src/kvm/aarch64/gic/mod.rs (revision 3ce0fef7fd546467398c914dbc74d8542e45cf6f)
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::{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         Self::set_device_attribute(
138             &self.device,
139             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
140             u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
141             &self.dist_addr as *const u64 as u64,
142             0,
143         )?;
144 
145         /* Setting up the redistributors' attribute. */
146         Self::set_device_attribute(
147             &self.device,
148             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
149             u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
150             &self.redists_addr as *const u64 as u64,
151             0,
152         )?;
153 
154         // ITS part attributes
155         let mut its_device = kvm_bindings::kvm_create_device {
156             type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
157             fd: 0,
158             flags: 0,
159         };
160 
161         let its_fd = vm
162             .create_device(&mut its_device)
163             .map_err(Error::CreateGic)?;
164 
165         // We know vm is KvmVm
166         let its_fd = its_fd.to_kvm().unwrap();
167 
168         Self::set_device_attribute(
169             &its_fd,
170             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
171             u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
172             &self.msi_addr as *const u64 as u64,
173             0,
174         )?;
175 
176         Self::set_device_attribute(
177             &its_fd,
178             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
179             u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
180             0,
181             0,
182         )?;
183 
184         self.its_device = Some(its_fd);
185 
186         /* We need to tell the kernel how many irqs to support with this vgic.
187          * See the `layout` module for details.
188          */
189         let nr_irqs_ptr = &nr_irqs as *const u32;
190         Self::set_device_attribute(
191             &self.device,
192             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
193             0,
194             nr_irqs_ptr as u64,
195             0,
196         )?;
197 
198         /* Finalize the GIC.
199          * See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
200          */
201         Self::set_device_attribute(
202             &self.device,
203             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
204             u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
205             0,
206             0,
207         )
208     }
209 
210     /// Create a KVM Vgic device
211     fn create_device(vm: &KvmVm) -> Result<DeviceFd> {
212         let mut gic_device = kvm_bindings::kvm_create_device {
213             type_: Self::version(),
214             fd: 0,
215             flags: 0,
216         };
217 
218         let device_fd = vm
219             .create_device(&mut gic_device)
220             .map_err(Error::CreateGic)?;
221 
222         // We know for sure this is a KVM fd
223         Ok(device_fd.to_kvm().unwrap())
224     }
225 
226     /// Set a GIC device attribute
227     fn set_device_attribute(
228         device: &DeviceFd,
229         group: u32,
230         attr: u64,
231         addr: u64,
232         flags: u32,
233     ) -> Result<()> {
234         let attr = kvm_bindings::kvm_device_attr {
235             flags,
236             group,
237             attr,
238             addr,
239         };
240         device.set_device_attr(&attr).map_err(|e| {
241             Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))
242         })
243     }
244 
245     /// Method to initialize the GIC device
246     pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
247         // This is inside KVM module
248         let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");
249 
250         let vgic = Self::create_device(vm)?;
251 
252         let mut gic_device = KvmGicV3Its {
253             device: vgic,
254             its_device: None,
255             gicr_typers: vec![0; config.vcpu_count.try_into().unwrap()],
256             dist_addr: config.dist_addr,
257             dist_size: config.dist_size,
258             redists_addr: config.redists_addr,
259             redists_size: config.redists_size,
260             msi_addr: config.msi_addr,
261             msi_size: config.msi_size,
262             vcpu_count: config.vcpu_count,
263         };
264 
265         gic_device.init_device_attributes(vm, config.nr_irqs)?;
266 
267         Ok(gic_device)
268     }
269 }
270 
271 impl Vgic for KvmGicV3Its {
272     fn fdt_compatibility(&self) -> &str {
273         "arm,gic-v3"
274     }
275 
276     fn msi_compatible(&self) -> bool {
277         true
278     }
279 
280     fn msi_compatibility(&self) -> &str {
281         "arm,gic-v3-its"
282     }
283 
284     fn fdt_maint_irq(&self) -> u32 {
285         KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ
286     }
287 
288     fn vcpu_count(&self) -> u64 {
289         self.vcpu_count
290     }
291 
292     fn device_properties(&self) -> [u64; 4] {
293         [
294             self.dist_addr,
295             self.dist_size,
296             self.redists_addr,
297             self.redists_size,
298         ]
299     }
300 
301     fn msi_properties(&self) -> [u64; 2] {
302         [self.msi_addr, self.msi_size]
303     }
304 
305     fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
306         let gicr_typers = construct_gicr_typers(vcpu_states);
307         self.gicr_typers = gicr_typers;
308     }
309 
310     fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
311         self
312     }
313 
314     /// Save the state of GICv3ITS.
315     fn state(&self) -> Result<Gicv3ItsState> {
316         let gicr_typers = self.gicr_typers.clone();
317 
318         let gicd_ctlr = read_ctlr(&self.device)?;
319 
320         let dist_state = get_dist_regs(&self.device)?;
321 
322         let rdist_state = get_redist_regs(&self.device, &gicr_typers)?;
323 
324         let icc_state = get_icc_regs(&self.device, &gicr_typers)?;
325 
326         let its_baser_state: [u64; 8] = [0; 8];
327         for i in 0..8 {
328             gicv3_its_attr_access(
329                 self.its_device.as_ref().unwrap(),
330                 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
331                 GITS_BASER + i * 8,
332                 &its_baser_state[i as usize],
333                 false,
334             )?;
335         }
336 
337         let its_ctlr_state: u64 = 0;
338         gicv3_its_attr_access(
339             self.its_device.as_ref().unwrap(),
340             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
341             GITS_CTLR,
342             &its_ctlr_state,
343             false,
344         )?;
345 
346         let its_cbaser_state: u64 = 0;
347         gicv3_its_attr_access(
348             self.its_device.as_ref().unwrap(),
349             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
350             GITS_CBASER,
351             &its_cbaser_state,
352             false,
353         )?;
354 
355         let its_creadr_state: u64 = 0;
356         gicv3_its_attr_access(
357             self.its_device.as_ref().unwrap(),
358             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
359             GITS_CREADR,
360             &its_creadr_state,
361             false,
362         )?;
363 
364         let its_cwriter_state: u64 = 0;
365         gicv3_its_attr_access(
366             self.its_device.as_ref().unwrap(),
367             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
368             GITS_CWRITER,
369             &its_cwriter_state,
370             false,
371         )?;
372 
373         let its_iidr_state: u64 = 0;
374         gicv3_its_attr_access(
375             self.its_device.as_ref().unwrap(),
376             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
377             GITS_IIDR,
378             &its_iidr_state,
379             false,
380         )?;
381 
382         Ok(Gicv3ItsState {
383             dist: dist_state,
384             rdist: rdist_state,
385             icc: icc_state,
386             gicd_ctlr,
387             its_ctlr: its_ctlr_state,
388             its_iidr: its_iidr_state,
389             its_cbaser: its_cbaser_state,
390             its_cwriter: its_cwriter_state,
391             its_creadr: its_creadr_state,
392             its_baser: its_baser_state,
393         })
394     }
395 
396     /// Restore the state of GICv3ITS.
397     fn set_state(&mut self, state: &Gicv3ItsState) -> Result<()> {
398         let gicr_typers = self.gicr_typers.clone();
399 
400         write_ctlr(&self.device, state.gicd_ctlr)?;
401 
402         set_dist_regs(&self.device, &state.dist)?;
403 
404         set_redist_regs(&self.device, &gicr_typers, &state.rdist)?;
405 
406         set_icc_regs(&self.device, &gicr_typers, &state.icc)?;
407 
408         //Restore GICv3ITS registers
409         gicv3_its_attr_access(
410             self.its_device.as_ref().unwrap(),
411             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
412             GITS_IIDR,
413             &state.its_iidr,
414             true,
415         )?;
416 
417         gicv3_its_attr_access(
418             self.its_device.as_ref().unwrap(),
419             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
420             GITS_CBASER,
421             &state.its_cbaser,
422             true,
423         )?;
424 
425         gicv3_its_attr_access(
426             self.its_device.as_ref().unwrap(),
427             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
428             GITS_CREADR,
429             &state.its_creadr,
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_CWRITER,
437             &state.its_cwriter,
438             true,
439         )?;
440 
441         for i in 0..8 {
442             gicv3_its_attr_access(
443                 self.its_device.as_ref().unwrap(),
444                 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
445                 GITS_BASER + i * 8,
446                 &state.its_baser[i as usize],
447                 true,
448             )?;
449         }
450 
451         // Restore ITS tables
452         gicv3_its_tables_access(self.its_device.as_ref().unwrap(), false)?;
453 
454         gicv3_its_attr_access(
455             self.its_device.as_ref().unwrap(),
456             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
457             GITS_CTLR,
458             &state.its_ctlr,
459             true,
460         )
461     }
462 
463     /// Saves GIC internal data tables into RAM, including:
464     /// - RDIST pending tables
465     /// - ITS tables into guest RAM.
466     fn save_data_tables(&self) -> Result<()> {
467         // Flash RDIST pending tables
468         let init_gic_attr = kvm_bindings::kvm_device_attr {
469             group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
470             attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
471             addr: 0,
472             flags: 0,
473         };
474         self.device.set_device_attr(&init_gic_attr).map_err(|e| {
475             Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))
476         })?;
477         // Flush ITS tables to guest RAM.
478         gicv3_its_tables_access(self.its_device.as_ref().unwrap(), true)
479     }
480 }
481 
482 #[cfg(test)]
483 mod tests {
484     use crate::aarch64::gic::{
485         get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
486     };
487     use crate::arch::aarch64::gic::VgicConfig;
488     use crate::kvm::KvmGicV3Its;
489 
490     fn create_test_vgic_config() -> VgicConfig {
491         VgicConfig {
492             vcpu_count: 1,
493             dist_addr: 0x0900_0000 - 0x01_0000,
494             dist_size: 0x01_0000,
495             // dist_addr - redists_size
496             redists_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000,
497             redists_size: 0x02_0000,
498             // redists_addr - msi_size
499             msi_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000 - 0x02_0000,
500             msi_size: 0x02_0000,
501             nr_irqs: 256,
502         }
503     }
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(&*vm, create_test_vgic_config()).is_ok());
511     }
512 
513     #[test]
514     fn test_get_set_dist_regs() {
515         let hv = crate::new().unwrap();
516         let vm = hv.create_vm().unwrap();
517         let _ = vm.create_vcpu(0, None).unwrap();
518         let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
519 
520         let res = get_dist_regs(&gic.device);
521         assert!(res.is_ok());
522         let state = res.unwrap();
523         assert_eq!(state.len(), 568);
524 
525         let res = set_dist_regs(&gic.device, &state);
526         assert!(res.is_ok());
527     }
528 
529     #[test]
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 res = get_redist_regs(&gic.device, &gicr_typer);
538         assert!(res.is_ok());
539         let state = res.unwrap();
540         println!("{}", state.len());
541         assert!(state.len() == 24);
542 
543         assert!(set_redist_regs(&gic.device, &gicr_typer, &state).is_ok());
544     }
545 
546     #[test]
547     fn test_get_set_icc_regs() {
548         let hv = crate::new().unwrap();
549         let vm = hv.create_vm().unwrap();
550         let _ = vm.create_vcpu(0, None).unwrap();
551         let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
552 
553         let gicr_typer = vec![123];
554         let res = get_icc_regs(&gic.device, &gicr_typer);
555         assert!(res.is_ok());
556         let state = res.unwrap();
557         println!("{}", state.len());
558         assert!(state.len() == 9);
559 
560         assert!(set_icc_regs(&gic.device, &gicr_typer, &state).is_ok());
561     }
562 
563     #[test]
564     fn test_save_data_tables() {
565         let hv = crate::new().unwrap();
566         let vm = hv.create_vm().unwrap();
567         let _ = vm.create_vcpu(0, None).unwrap();
568         let gic = vm
569             .create_vgic(create_test_vgic_config())
570             .expect("Cannot create gic");
571 
572         assert!(gic.lock().unwrap().save_data_tables().is_ok());
573     }
574 }
575