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