xref: /cloud-hypervisor/hypervisor/src/kvm/aarch64/gic/mod.rs (revision 1968805ba291ae08e07abf0ef8c0ade4cf11ab68)
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             /* Needed in case other hypervisors are enabled */
133             #[allow(unreachable_patterns)]
134             _ => panic!("GicState is not valid"),
135         }
136     }
137 }
138 
139 impl From<Gicv3ItsState> for GicState {
140     fn from(state: Gicv3ItsState) -> Self {
141         GicState::Kvm(state)
142     }
143 }
144 
145 impl KvmGicV3Its {
146     /// Device trees specific constants
147     pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
148 
149     /// Returns the GIC version of the device
150     fn version() -> u32 {
151         kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3
152     }
153 
154     /// Setup the device-specific attributes
155     fn init_device_attributes(&mut self, vm: &KvmVm, nr_irqs: u32) -> Result<()> {
156         // GicV3 part attributes
157         /* Setting up the distributor attribute. */
158         Self::set_device_attribute(
159             &self.device,
160             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
161             u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
162             &self.dist_addr as *const u64 as u64,
163             0,
164         )?;
165 
166         /* Setting up the redistributors' attribute. */
167         Self::set_device_attribute(
168             &self.device,
169             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
170             u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
171             &self.redists_addr as *const u64 as u64,
172             0,
173         )?;
174 
175         // ITS part attributes
176         let mut its_device = kvm_bindings::kvm_create_device {
177             type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
178             fd: 0,
179             flags: 0,
180         };
181 
182         let its_fd = vm
183             .create_device(&mut its_device)
184             .map_err(Error::CreateGic)?;
185 
186         // We know vm is KvmVm
187         let its_fd = its_fd.to_kvm().unwrap();
188 
189         Self::set_device_attribute(
190             &its_fd,
191             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
192             u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
193             &self.msi_addr as *const u64 as u64,
194             0,
195         )?;
196 
197         Self::set_device_attribute(
198             &its_fd,
199             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
200             u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
201             0,
202             0,
203         )?;
204 
205         self.its_device = Some(its_fd);
206 
207         /* We need to tell the kernel how many irqs to support with this vgic.
208          * See the `layout` module for details.
209          */
210         let nr_irqs_ptr = &nr_irqs as *const u32;
211         Self::set_device_attribute(
212             &self.device,
213             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
214             0,
215             nr_irqs_ptr as u64,
216             0,
217         )?;
218 
219         /* Finalize the GIC.
220          * See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
221          */
222         Self::set_device_attribute(
223             &self.device,
224             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
225             u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
226             0,
227             0,
228         )
229     }
230 
231     /// Create a KVM Vgic device
232     fn create_device(vm: &KvmVm) -> Result<DeviceFd> {
233         let mut gic_device = kvm_bindings::kvm_create_device {
234             type_: Self::version(),
235             fd: 0,
236             flags: 0,
237         };
238 
239         let device_fd = vm
240             .create_device(&mut gic_device)
241             .map_err(Error::CreateGic)?;
242 
243         // We know for sure this is a KVM fd
244         Ok(device_fd.to_kvm().unwrap())
245     }
246 
247     /// Set a GIC device attribute
248     fn set_device_attribute(
249         device: &DeviceFd,
250         group: u32,
251         attr: u64,
252         addr: u64,
253         flags: u32,
254     ) -> Result<()> {
255         let attr = kvm_bindings::kvm_device_attr {
256             flags,
257             group,
258             attr,
259             addr,
260         };
261         device.set_device_attr(&attr).map_err(|e| {
262             Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))
263         })
264     }
265 
266     /// Method to initialize the GIC device
267     pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
268         // This is inside KVM module
269         let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");
270 
271         let vgic = Self::create_device(vm)?;
272 
273         let mut gic_device = KvmGicV3Its {
274             device: vgic,
275             its_device: None,
276             gicr_typers: vec![0; config.vcpu_count.try_into().unwrap()],
277             dist_addr: config.dist_addr,
278             dist_size: config.dist_size,
279             redists_addr: config.redists_addr,
280             redists_size: config.redists_size,
281             msi_addr: config.msi_addr,
282             msi_size: config.msi_size,
283             vcpu_count: config.vcpu_count,
284         };
285 
286         gic_device.init_device_attributes(vm, config.nr_irqs)?;
287 
288         Ok(gic_device)
289     }
290 }
291 
292 impl Vgic for KvmGicV3Its {
293     fn fdt_compatibility(&self) -> &str {
294         "arm,gic-v3"
295     }
296 
297     fn msi_compatible(&self) -> bool {
298         true
299     }
300 
301     fn msi_compatibility(&self) -> &str {
302         "arm,gic-v3-its"
303     }
304 
305     fn fdt_maint_irq(&self) -> u32 {
306         KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ
307     }
308 
309     fn vcpu_count(&self) -> u64 {
310         self.vcpu_count
311     }
312 
313     fn device_properties(&self) -> [u64; 4] {
314         [
315             self.dist_addr,
316             self.dist_size,
317             self.redists_addr,
318             self.redists_size,
319         ]
320     }
321 
322     fn msi_properties(&self) -> [u64; 2] {
323         [self.msi_addr, self.msi_size]
324     }
325 
326     fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
327         let gicr_typers = construct_gicr_typers(vcpu_states);
328         self.gicr_typers = gicr_typers;
329     }
330 
331     fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
332         self
333     }
334 
335     /// Save the state of GICv3ITS.
336     fn state(&self) -> Result<GicState> {
337         let gicr_typers = self.gicr_typers.clone();
338 
339         let gicd_ctlr = read_ctlr(&self.device)?;
340 
341         let dist_state = get_dist_regs(&self.device)?;
342 
343         let rdist_state = get_redist_regs(&self.device, &gicr_typers)?;
344 
345         let icc_state = get_icc_regs(&self.device, &gicr_typers)?;
346 
347         let mut its_baser_state: [u64; 8] = [0; 8];
348         for i in 0..8 {
349             its_baser_state[i as usize] = gicv3_its_attr_get(
350                 self.its_device.as_ref().unwrap(),
351                 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
352                 GITS_BASER + i * 8,
353             )?;
354         }
355 
356         let its_ctlr_state = gicv3_its_attr_get(
357             self.its_device.as_ref().unwrap(),
358             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
359             GITS_CTLR,
360         )?;
361 
362         let its_cbaser_state = gicv3_its_attr_get(
363             self.its_device.as_ref().unwrap(),
364             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
365             GITS_CBASER,
366         )?;
367 
368         let its_creadr_state = gicv3_its_attr_get(
369             self.its_device.as_ref().unwrap(),
370             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
371             GITS_CREADR,
372         )?;
373 
374         let its_cwriter_state = gicv3_its_attr_get(
375             self.its_device.as_ref().unwrap(),
376             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
377             GITS_CWRITER,
378         )?;
379 
380         let its_iidr_state = gicv3_its_attr_get(
381             self.its_device.as_ref().unwrap(),
382             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
383             GITS_IIDR,
384         )?;
385 
386         let gic_state: GicState = Gicv3ItsState {
387             dist: dist_state,
388             rdist: rdist_state,
389             icc: icc_state,
390             gicd_ctlr,
391             its_ctlr: its_ctlr_state,
392             its_iidr: its_iidr_state,
393             its_cbaser: its_cbaser_state,
394             its_cwriter: its_cwriter_state,
395             its_creadr: its_creadr_state,
396             its_baser: its_baser_state,
397         }
398         .into();
399 
400         Ok(gic_state)
401     }
402 
403     /// Restore the state of GICv3ITS.
404     fn set_state(&mut self, state: &GicState) -> Result<()> {
405         let kvm_state: Gicv3ItsState = state.clone().into();
406 
407         let gicr_typers = self.gicr_typers.clone();
408 
409         write_ctlr(&self.device, kvm_state.gicd_ctlr)?;
410 
411         set_dist_regs(&self.device, &kvm_state.dist)?;
412 
413         set_redist_regs(&self.device, &gicr_typers, &kvm_state.rdist)?;
414 
415         set_icc_regs(&self.device, &gicr_typers, &kvm_state.icc)?;
416 
417         //Restore GICv3ITS registers
418         gicv3_its_attr_set(
419             self.its_device.as_ref().unwrap(),
420             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
421             GITS_IIDR,
422             kvm_state.its_iidr,
423         )?;
424 
425         gicv3_its_attr_set(
426             self.its_device.as_ref().unwrap(),
427             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
428             GITS_CBASER,
429             kvm_state.its_cbaser,
430         )?;
431 
432         gicv3_its_attr_set(
433             self.its_device.as_ref().unwrap(),
434             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
435             GITS_CREADR,
436             kvm_state.its_creadr,
437         )?;
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_CWRITER,
443             kvm_state.its_cwriter,
444         )?;
445 
446         for i in 0..8 {
447             gicv3_its_attr_set(
448                 self.its_device.as_ref().unwrap(),
449                 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
450                 GITS_BASER + i * 8,
451                 kvm_state.its_baser[i as usize],
452             )?;
453         }
454 
455         // Restore ITS tables
456         gicv3_its_tables_access(self.its_device.as_ref().unwrap(), false)?;
457 
458         gicv3_its_attr_set(
459             self.its_device.as_ref().unwrap(),
460             kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
461             GITS_CTLR,
462             kvm_state.its_ctlr,
463         )
464     }
465 
466     /// Saves GIC internal data tables into RAM, including:
467     /// - RDIST pending tables
468     /// - ITS tables into guest RAM.
469     fn save_data_tables(&self) -> Result<()> {
470         // Flash RDIST pending tables
471         let init_gic_attr = kvm_bindings::kvm_device_attr {
472             group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
473             attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
474             addr: 0,
475             flags: 0,
476         };
477         self.device.set_device_attr(&init_gic_attr).map_err(|e| {
478             Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))
479         })?;
480         // Flush ITS tables to guest RAM.
481         gicv3_its_tables_access(self.its_device.as_ref().unwrap(), true)
482     }
483 }
484 
485 #[cfg(test)]
486 mod tests {
487     use crate::aarch64::gic::{
488         get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
489     };
490     use crate::arch::aarch64::gic::VgicConfig;
491     use crate::kvm::KvmGicV3Its;
492 
493     fn create_test_vgic_config() -> VgicConfig {
494         VgicConfig {
495             vcpu_count: 1,
496             dist_addr: 0x0900_0000 - 0x01_0000,
497             dist_size: 0x01_0000,
498             // dist_addr - redists_size
499             redists_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000,
500             redists_size: 0x02_0000,
501             // redists_addr - msi_size
502             msi_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000 - 0x02_0000,
503             msi_size: 0x02_0000,
504             nr_irqs: 256,
505         }
506     }
507 
508     #[test]
509     fn test_create_gic() {
510         let hv = crate::new().unwrap();
511         let vm = hv.create_vm().unwrap();
512 
513         KvmGicV3Its::new(&*vm, create_test_vgic_config()).unwrap();
514     }
515 
516     #[test]
517     fn test_get_set_dist_regs() {
518         let hv = crate::new().unwrap();
519         let vm = hv.create_vm().unwrap();
520         let _ = vm.create_vcpu(0, None).unwrap();
521         let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
522 
523         let state = get_dist_regs(&gic.device).unwrap();
524         assert_eq!(state.len(), 568);
525 
526         set_dist_regs(&gic.device, &state).unwrap();
527     }
528 
529     #[test]
530     fn test_get_set_redist_regs() {
531         let hv = crate::new().unwrap();
532         let vm = hv.create_vm().unwrap();
533         let _ = vm.create_vcpu(0, None).unwrap();
534         let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
535 
536         let gicr_typer = vec![123];
537         let state = get_redist_regs(&gic.device, &gicr_typer).unwrap();
538         println!("{}", state.len());
539         assert!(state.len() == 24);
540 
541         set_redist_regs(&gic.device, &gicr_typer, &state).unwrap();
542     }
543 
544     #[test]
545     fn test_get_set_icc_regs() {
546         let hv = crate::new().unwrap();
547         let vm = hv.create_vm().unwrap();
548         let _ = vm.create_vcpu(0, None).unwrap();
549         let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic");
550 
551         let gicr_typer = vec![123];
552         let state = get_icc_regs(&gic.device, &gicr_typer).unwrap();
553         println!("{}", state.len());
554         assert!(state.len() == 9);
555 
556         set_icc_regs(&gic.device, &gicr_typer, &state).unwrap();
557     }
558 
559     #[test]
560     fn test_save_data_tables() {
561         let hv = crate::new().unwrap();
562         let vm = hv.create_vm().unwrap();
563         let _ = vm.create_vcpu(0, None).unwrap();
564         let gic = vm
565             .create_vgic(create_test_vgic_config())
566             .expect("Cannot create gic");
567 
568         gic.lock().unwrap().save_data_tables().unwrap();
569     }
570 }
571