xref: /cloud-hypervisor/hypervisor/src/kvm/aarch64/gic/mod.rs (revision eea9bcea38e0c5649f444c829f3a4f9c22aa486c)
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     #[allow(clippy::new_ret_no_self)]
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