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