xref: /cloud-hypervisor/devices/src/gic.rs (revision eea9bcea38e0c5649f444c829f3a4f9c22aa486c)
1 // Copyright 2020, ARM Limited.
2 //
3 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
4 
5 use super::interrupt_controller::{Error, InterruptController};
6 extern crate arch;
7 use anyhow::anyhow;
8 use arch::layout;
9 use hypervisor::{
10     arch::aarch64::gic::{Vgic, VgicConfig},
11     CpuState,
12 };
13 use std::result;
14 use std::sync::{Arc, Mutex};
15 use vm_device::interrupt::{
16     InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
17     LegacyIrqSourceConfig, MsiIrqGroupConfig,
18 };
19 use vm_memory::address::Address;
20 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
21 use vmm_sys_util::eventfd::EventFd;
22 
23 type Result<T> = result::Result<T, Error>;
24 
25 // Reserve 32 IRQs for legacy devices.
26 pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
27 pub const IRQ_LEGACY_COUNT: usize = 32;
28 
29 // Gic (Generic Interupt Controller) struct provides all the functionality of a
30 // GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the
31 // `hypervisor` crate.
32 // Gic struct also implements InterruptController to provide interrupt delivery
33 // service.
34 pub struct Gic {
35     interrupt_source_group: Arc<dyn InterruptSourceGroup>,
36     // The hypervisor agnostic virtual GIC
37     vgic: Option<Arc<Mutex<dyn Vgic>>>,
38 }
39 
40 impl Gic {
41     pub fn new(
42         _vcpu_count: u8,
43         interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
44     ) -> Result<Gic> {
45         let interrupt_source_group = interrupt_manager
46             .create_group(MsiIrqGroupConfig {
47                 base: IRQ_LEGACY_BASE as InterruptIndex,
48                 count: IRQ_LEGACY_COUNT as InterruptIndex,
49             })
50             .map_err(Error::CreateInterruptSourceGroup)?;
51 
52         Ok(Gic {
53             interrupt_source_group,
54             vgic: None,
55         })
56     }
57 
58     /// Default config implied by arch::layout
59     pub fn create_default_config(vcpu_count: u64) -> VgicConfig {
60         let redists_size = layout::GIC_V3_REDIST_SIZE * vcpu_count;
61         let redists_addr = layout::GIC_V3_DIST_START.raw_value() - redists_size;
62         VgicConfig {
63             vcpu_count,
64             dist_addr: layout::GIC_V3_DIST_START.raw_value(),
65             dist_size: layout::GIC_V3_DIST_SIZE,
66             redists_addr,
67             redists_size,
68             msi_addr: redists_addr - layout::GIC_V3_ITS_SIZE,
69             msi_size: layout::GIC_V3_ITS_SIZE,
70             nr_irqs: layout::IRQ_NUM,
71         }
72     }
73 
74     pub fn create_vgic(
75         &mut self,
76         vm: &Arc<dyn hypervisor::Vm>,
77         config: VgicConfig,
78     ) -> Result<Arc<Mutex<dyn Vgic>>> {
79         let vgic = vm.create_vgic(config).map_err(Error::CreateGic)?;
80         self.vgic = Some(vgic.clone());
81         Ok(vgic.clone())
82     }
83 
84     pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
85         let vgic = self.vgic.as_ref().unwrap().clone();
86         vgic.lock().unwrap().set_gicr_typers(vcpu_states);
87     }
88 }
89 
90 impl InterruptController for Gic {
91     fn enable(&self) -> Result<()> {
92         // Set irqfd for legacy interrupts
93         self.interrupt_source_group
94             .enable()
95             .map_err(Error::EnableInterrupt)?;
96 
97         // Set irq_routing for legacy interrupts.
98         //   irqchip: Hardcode to 0 as we support only 1 GIC
99         //   pin: Use irq number as pin
100         for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
101             let config = LegacyIrqSourceConfig {
102                 irqchip: 0,
103                 pin: (i - IRQ_LEGACY_BASE) as u32,
104             };
105             self.interrupt_source_group
106                 .update(
107                     i as InterruptIndex,
108                     InterruptSourceConfig::LegacyIrq(config),
109                     false,
110                 )
111                 .map_err(Error::EnableInterrupt)?;
112         }
113         Ok(())
114     }
115 
116     // This should be called anytime an interrupt needs to be injected into the
117     // running guest.
118     fn service_irq(&mut self, irq: usize) -> Result<()> {
119         self.interrupt_source_group
120             .trigger(irq as InterruptIndex)
121             .map_err(Error::TriggerInterrupt)?;
122 
123         Ok(())
124     }
125 
126     fn notifier(&self, irq: usize) -> Option<EventFd> {
127         self.interrupt_source_group.notifier(irq as InterruptIndex)
128     }
129 }
130 
131 pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its";
132 impl Snapshottable for Gic {
133     fn id(&self) -> String {
134         GIC_V3_ITS_SNAPSHOT_ID.to_string()
135     }
136 
137     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
138         let vgic = self.vgic.as_ref().unwrap().clone();
139         let state = vgic.lock().unwrap().state().unwrap();
140         Snapshot::new_from_state(&self.id(), &state)
141     }
142 
143     fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
144         let vgic = self.vgic.as_ref().unwrap().clone();
145         vgic.lock()
146             .unwrap()
147             .set_state(&snapshot.to_state(&self.id())?)
148             .map_err(|e| {
149                 MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e))
150             })?;
151         Ok(())
152     }
153 }
154 
155 impl Pausable for Gic {
156     fn pause(&mut self) -> std::result::Result<(), MigratableError> {
157         // Flush tables to guest RAM
158         let vgic = self.vgic.as_ref().unwrap().clone();
159         vgic.lock().unwrap().save_data_tables().map_err(|e| {
160             MigratableError::Pause(anyhow!(
161                 "Could not save GICv3ITS GIC pending tables {:?}",
162                 e
163             ))
164         })?;
165         Ok(())
166     }
167 }
168 impl Transportable for Gic {}
169 impl Migratable for Gic {}
170