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