xref: /aosp_15_r20/external/crosvm/devices/src/irqchip/x86_64.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2020 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::ops::Index;
6 use std::vec::Vec;
7 
8 use anyhow::anyhow;
9 use anyhow::Context;
10 use base::Error;
11 use base::Event;
12 use base::Result;
13 use hypervisor::IoapicState;
14 use hypervisor::IrqRoute;
15 use hypervisor::IrqSource;
16 use hypervisor::IrqSourceChip;
17 use hypervisor::LapicState;
18 use hypervisor::MPState;
19 use hypervisor::PicSelect;
20 use hypervisor::PicState;
21 use hypervisor::PitState;
22 use serde::Deserialize;
23 use serde::Serialize;
24 
25 use crate::IrqChip;
26 use crate::IrqChipCap;
27 
28 pub trait IrqChipX86_64: IrqChip {
29     // Clones this trait as a `Box` version of itself.
try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>30     fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>;
31 
32     // Get this as the super-trait IrqChip.
as_irq_chip(&self) -> &dyn IrqChip33     fn as_irq_chip(&self) -> &dyn IrqChip;
34 
35     // Get this as the mutable super-trait IrqChip.
as_irq_chip_mut(&mut self) -> &mut dyn IrqChip36     fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip;
37 
38     /// Get the current state of the PIC
get_pic_state(&self, select: PicSelect) -> Result<PicState>39     fn get_pic_state(&self, select: PicSelect) -> Result<PicState>;
40 
41     /// Set the current state of the PIC
set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>42     fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>;
43 
44     /// Get the current state of the IOAPIC
get_ioapic_state(&self) -> Result<IoapicState>45     fn get_ioapic_state(&self) -> Result<IoapicState>;
46 
47     /// Set the current state of the IOAPIC
set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>48     fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>;
49 
50     /// Get the current state of the specified VCPU's local APIC
get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>51     fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>;
52 
53     /// Set the current state of the specified VCPU's local APIC
set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>54     fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>;
55 
56     /// Get the lapic frequency in Hz
lapic_frequency(&self) -> u3257     fn lapic_frequency(&self) -> u32;
58 
59     /// Retrieves the state of the PIT.
get_pit(&self) -> Result<PitState>60     fn get_pit(&self) -> Result<PitState>;
61 
62     /// Sets the state of the PIT.
set_pit(&mut self, state: &PitState) -> Result<()>63     fn set_pit(&mut self, state: &PitState) -> Result<()>;
64 
65     /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused.
pit_uses_speaker_port(&self) -> bool66     fn pit_uses_speaker_port(&self) -> bool;
67 
68     /// Snapshot state specific to different IrqChips.
snapshot_chip_specific(&self) -> anyhow::Result<serde_json::Value>69     fn snapshot_chip_specific(&self) -> anyhow::Result<serde_json::Value>;
70 
71     /// Restore state specific to different IrqChips.
restore_chip_specific(&mut self, data: serde_json::Value) -> anyhow::Result<()>72     fn restore_chip_specific(&mut self, data: serde_json::Value) -> anyhow::Result<()>;
73 
74     /// Snapshot state common to IrqChips.
snapshot(&self, cpus_num: usize) -> anyhow::Result<serde_json::Value>75     fn snapshot(&self, cpus_num: usize) -> anyhow::Result<serde_json::Value> {
76         let mut lapics: Vec<LapicState> = Vec::new();
77         let mut mp_states: Vec<MPState> = Vec::new();
78         let has_mp_states = self.check_capability(IrqChipCap::MpStateGetSet);
79         for i in 0..cpus_num {
80             lapics.push(self.get_lapic_state(i)?);
81             if has_mp_states {
82                 mp_states.push(self.get_mp_state(i)?);
83             }
84         }
85         serde_json::to_value(IrqChipSnapshot {
86             ioapic_state: self.get_ioapic_state()?,
87             lapic_state: lapics,
88             pic_state_1: self.get_pic_state(PicSelect::Primary)?,
89             pic_state_2: self.get_pic_state(PicSelect::Secondary)?,
90             pit_state: self.get_pit()?,
91             chip_specific_state: self.snapshot_chip_specific()?,
92             mp_state: mp_states,
93         })
94         .context("failed to serialize KvmKernelIrqChip")
95     }
96 
97     /// Restore state common to IrqChips.
restore(&mut self, data: serde_json::Value, vcpus_num: usize) -> anyhow::Result<()>98     fn restore(&mut self, data: serde_json::Value, vcpus_num: usize) -> anyhow::Result<()> {
99         let deser: IrqChipSnapshot =
100             serde_json::from_value(data).context("failed to deserialize data")?;
101 
102         if deser.lapic_state.len() != vcpus_num {
103             return Err(anyhow!(
104                 "IrqChip has the wrong number of LAPIC state snapshots: got {}, expected {}",
105                 deser.lapic_state.len(),
106                 vcpus_num
107             ));
108         }
109         let supports_mp_states = self.check_capability(IrqChipCap::MpStateGetSet);
110 
111         if supports_mp_states {
112             if deser.mp_state.len() != vcpus_num {
113                 return Err(anyhow!(
114                     "IrqChip has the wrong number of mp state snapshots: got {}, expected {}",
115                     deser.mp_state.len(),
116                     vcpus_num
117                 ));
118             }
119         } else if !deser.mp_state.is_empty() {
120             return Err(anyhow!(
121                 "IrqChip does not support mp state, but mp state was in the snapshot"
122             ));
123         }
124 
125         self.set_pit(&deser.pit_state)?;
126         self.set_pic_state(PicSelect::Primary, &deser.pic_state_1)
127             .context("failed to set primary PIC")?;
128         self.set_pic_state(PicSelect::Secondary, &deser.pic_state_2)
129             .context("failed to set secondary PIC")?;
130         self.set_ioapic_state(&deser.ioapic_state)
131             .context("failed to set IOAPIC state")?;
132         self.restore_chip_specific(deser.chip_specific_state)
133             .context("failed to set chip specific data")?;
134         for (i, lapic) in deser.lapic_state.iter().enumerate() {
135             self.set_lapic_state(i, lapic)
136                 .context("failed to set LAPIC state")?;
137         }
138 
139         if supports_mp_states {
140             for (i, mp_state) in deser.mp_state.iter().enumerate() {
141                 self.set_mp_state(i, mp_state)
142                     .context("failed to set mp state")?;
143             }
144         }
145         Ok(())
146     }
147 }
148 
149 #[derive(Serialize, Deserialize)]
150 struct IrqChipSnapshot {
151     ioapic_state: IoapicState,
152     lapic_state: Vec<LapicState>,
153     pic_state_1: PicState,
154     pic_state_2: PicState,
155     pit_state: PitState,
156     chip_specific_state: serde_json::Value,
157     mp_state: Vec<MPState>,
158 }
159 
160 /// A container for x86 IrqRoutes, grouped by GSI.
161 pub struct Routes {
162     /// A list of routes, indexed by GSI.  Each GSI can map to zero or more routes, so this is a
163     /// Vec of Vecs.  Specifically, a GSI can map to:
164     ///   * no routes; or
165     ///   * one IrqSource::Msi route; or
166     ///   * one or more IrqSource::Irqchip routes (PicPrimary, PicSecondary, or Ioapic)
167     routes: Vec<Vec<IrqSource>>,
168 }
169 
170 impl Routes {
171     /// Constructs a new `Routes` with an empty routing table.
new() -> Self172     pub fn new() -> Self {
173         Routes { routes: vec![] }
174     }
175 
176     /// Inserts a route, replacing any existing route that conflicts.  Two routes conflict if they
177     /// have the same GSI, and they're both `IrqSource::Irqchip` routes with the same chip or
178     /// they're both `IrqSource::Msi`.  Returns Err if an `IrqSource::Irqchip` and `IrqSource::Msi`
179     /// route have the same GSI.
add(&mut self, route: IrqRoute) -> Result<()>180     pub fn add(&mut self, route: IrqRoute) -> Result<()> {
181         let routes = self.get_mut(route.gsi as usize);
182         if routes.iter().any(|r| !Self::same_source(&route.source, r)) {
183             // We keep an invariant that legacy and MSI routes can't be mixed on the same GSI.
184             // Irqchip routes are only on GSIs [0..24) and Msi routes are only on GSIs >= 24.  This
185             // guarantees that in UserspaceIrqChip, the ioapic's incoming Irqchip routes and
186             // outgoing Msi routes can't trigger each other in a cycle.
187             return Err(Error::new(libc::EINVAL));
188         }
189         routes.retain(|r| !Self::conflict(&route.source, r));
190         routes.push(route.source);
191         Ok(())
192     }
193 
194     /// Deletes all existing routes and replaces them with `routes`.  If two routes in `routes`
195     /// conflict with each other, the one earlier in the slice is dropped.
replace_all(&mut self, routes: &[IrqRoute]) -> Result<()>196     pub fn replace_all(&mut self, routes: &[IrqRoute]) -> Result<()> {
197         self.routes.clear();
198         for r in routes {
199             self.add(*r)?;
200         }
201         Ok(())
202     }
203 
204     /// Default x86 routing table.  Pins 0-7 go to primary pic and ioapic, pins 8-15 go to secondary
205     /// pic and ioapic, and pins 16-23 go only to the ioapic.
default_pic_ioapic_routes(ioapic_pins: usize) -> Vec<IrqRoute>206     pub fn default_pic_ioapic_routes(ioapic_pins: usize) -> Vec<IrqRoute> {
207         let mut routes: Vec<IrqRoute> = Vec::new();
208 
209         for i in 0..8 {
210             routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicPrimary, i));
211             routes.push(IrqRoute::ioapic_irq_route(i));
212         }
213         for i in 8..16 {
214             routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicSecondary, i));
215             routes.push(IrqRoute::ioapic_irq_route(i));
216         }
217         for i in 16..ioapic_pins as u32 {
218             routes.push(IrqRoute::ioapic_irq_route(i));
219         }
220 
221         routes
222     }
223 
224     /// Gets the routes as a flat Vec of `IrqRoute`s.
get_routes(&self) -> Vec<IrqRoute>225     pub fn get_routes(&self) -> Vec<IrqRoute> {
226         let mut routes = Vec::with_capacity(self.routes.len());
227         for (gsi, sources) in self.routes.iter().enumerate() {
228             for source in sources.iter() {
229                 routes.push(IrqRoute {
230                     gsi: gsi.try_into().expect("GSIs must be < u32::MAX"),
231                     source: *source,
232                 });
233             }
234         }
235         routes
236     }
237 
238     /// Determines whether or not two irq routes on the same GSI conflict.
239     /// Returns true if they conflict.
conflict(source: &IrqSource, other: &IrqSource) -> bool240     fn conflict(source: &IrqSource, other: &IrqSource) -> bool {
241         use IrqSource::*;
242 
243         // If they're both MSI then they conflict.
244         if let (Msi { .. }, Msi { .. }) = (source, other) {
245             return true;
246         }
247 
248         // If the route chips match then they conflict.
249         if let (
250             Irqchip { chip, .. },
251             Irqchip {
252                 chip: other_chip, ..
253             },
254         ) = (source, other)
255         {
256             return chip == other_chip;
257         }
258 
259         // Otherwise they do not conflict.
260         false
261     }
262 
263     /// Determines whether two routes have the same IrqSource variant (IrqSource::Irqchip or
264     /// IrqSource::Msi).
same_source(source: &IrqSource, other: &IrqSource) -> bool265     fn same_source(source: &IrqSource, other: &IrqSource) -> bool {
266         use IrqSource::*;
267         matches!(
268             (source, other),
269             (Irqchip { .. }, Irqchip { .. }) | (Msi { .. }, Msi { .. })
270         )
271     }
272 
273     /// Returns the routes vec for `irq`.  If `irq` is past the end of self.routes, then self.routes
274     /// is first resized with empty vecs.
get_mut(&mut self, irq: usize) -> &mut Vec<IrqSource>275     fn get_mut(&mut self, irq: usize) -> &mut Vec<IrqSource> {
276         if irq >= self.routes.len() {
277             self.routes.resize_with(irq + 1, Vec::new);
278         }
279         self.routes.get_mut(irq).unwrap()
280     }
281 }
282 
283 impl Default for Routes {
default() -> Self284     fn default() -> Self {
285         Self::new()
286     }
287 }
288 
289 const EMPTY_ROUTE: [IrqSource; 0] = [];
290 
291 impl Index<usize> for Routes {
292     type Output = [IrqSource];
293 
294     /// Returns all routes for `irq`, or an empty slice if no routes registered for `irq`.
index(&self, irq: usize) -> &Self::Output295     fn index(&self, irq: usize) -> &Self::Output {
296         if irq < self.routes.len() {
297             self.routes[irq].as_slice()
298         } else {
299             &EMPTY_ROUTE
300         }
301     }
302 }
303 
304 pub(super) struct DelayedIoApicIrqEvents {
305     /// Vec of ioapic irq events that have been delayed because the ioapic was locked when
306     /// service_irq was called on the irqchip.
307     pub events: Vec<usize>,
308     /// Event which is meant to trigger process of any irqs events that were delayed.
309     pub trigger: Event,
310 }
311 
312 impl DelayedIoApicIrqEvents {
new() -> Result<Self>313     pub fn new() -> Result<Self> {
314         Ok(DelayedIoApicIrqEvents {
315             events: Vec::new(),
316             trigger: Event::new()?,
317         })
318     }
319 }
320