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