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