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::sync::Arc;
6
7 use anyhow::anyhow;
8 use anyhow::Context;
9 use base::error;
10 #[cfg(not(test))]
11 use base::Clock;
12 use base::Error;
13 use base::Event;
14 #[cfg(test)]
15 use base::FakeClock as Clock;
16 use base::Result;
17 use base::Tube;
18 use hypervisor::kvm::KvmVcpu;
19 use hypervisor::kvm::KvmVm;
20 use hypervisor::HypervisorCap;
21 use hypervisor::IoapicState;
22 use hypervisor::IrqRoute;
23 use hypervisor::IrqSource;
24 use hypervisor::IrqSourceChip;
25 use hypervisor::LapicState;
26 use hypervisor::MPState;
27 use hypervisor::PicSelect;
28 use hypervisor::PicState;
29 use hypervisor::PitState;
30 use hypervisor::Vcpu;
31 use hypervisor::VcpuX86_64;
32 use hypervisor::Vm;
33 use hypervisor::VmX86_64;
34 use kvm_sys::*;
35 use resources::SystemAllocator;
36 use serde::Deserialize;
37 use serde::Serialize;
38 use snapshot::AnySnapshot;
39 use sync::Mutex;
40
41 use crate::irqchip::Ioapic;
42 use crate::irqchip::IrqEvent;
43 use crate::irqchip::IrqEventIndex;
44 use crate::irqchip::Pic;
45 use crate::irqchip::VcpuRunState;
46 use crate::irqchip::IOAPIC_BASE_ADDRESS;
47 use crate::irqchip::IOAPIC_MEM_LENGTH_BYTES;
48 use crate::Bus;
49 use crate::IrqChip;
50 use crate::IrqChipCap;
51 use crate::IrqChipX86_64;
52 use crate::IrqEdgeEvent;
53 use crate::IrqEventSource;
54 use crate::IrqLevelEvent;
55 use crate::Pit;
56 use crate::PitError;
57
58 /// PIT tube 0 timer is connected to IRQ 0
59 const PIT_CHANNEL0_IRQ: u32 = 0;
60
61 /// Default x86 routing table. Pins 0-7 go to primary pic and ioapic, pins 8-15 go to secondary
62 /// pic and ioapic, and pins 16-23 go only to the ioapic.
kvm_default_irq_routing_table(ioapic_pins: usize) -> Vec<IrqRoute>63 fn kvm_default_irq_routing_table(ioapic_pins: usize) -> Vec<IrqRoute> {
64 let mut routes: Vec<IrqRoute> = Vec::new();
65
66 for i in 0..8 {
67 routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicPrimary, i));
68 routes.push(IrqRoute::ioapic_irq_route(i));
69 }
70 for i in 8..16 {
71 routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicSecondary, i));
72 routes.push(IrqRoute::ioapic_irq_route(i));
73 }
74 for i in 16..ioapic_pins as u32 {
75 routes.push(IrqRoute::ioapic_irq_route(i));
76 }
77
78 routes
79 }
80
81 /// IrqChip implementation where the entire IrqChip is emulated by KVM.
82 ///
83 /// This implementation will use the KVM API to create and configure the in-kernel irqchip.
84 pub struct KvmKernelIrqChip {
85 pub(super) vm: KvmVm,
86 pub(super) vcpus: Arc<Mutex<Vec<Option<KvmVcpu>>>>,
87 pub(super) routes: Arc<Mutex<Vec<IrqRoute>>>,
88 }
89
90 #[derive(Serialize, Deserialize)]
91 struct KvmKernelIrqChipSnapshot {
92 routes: Vec<IrqRoute>,
93 // apic_base and interrupt_bitmap are part of the IrqChip, despite the
94 // fact that we get the values from the Vcpu ioctl "KVM_GET_SREGS".
95 // Contains 1 entry per Vcpu.
96 apic_base: Vec<u64>,
97 interrupt_bitmap: Vec<[u64; 4usize]>,
98 }
99
100 impl KvmKernelIrqChip {
101 /// Construct a new KvmKernelIrqchip.
new(vm: KvmVm, num_vcpus: usize) -> Result<KvmKernelIrqChip>102 pub fn new(vm: KvmVm, num_vcpus: usize) -> Result<KvmKernelIrqChip> {
103 vm.create_irq_chip()?;
104 vm.create_pit()?;
105 let ioapic_pins = vm.get_ioapic_num_pins()?;
106
107 Ok(KvmKernelIrqChip {
108 vm,
109 vcpus: Arc::new(Mutex::new((0..num_vcpus).map(|_| None).collect())),
110 routes: Arc::new(Mutex::new(kvm_default_irq_routing_table(ioapic_pins))),
111 })
112 }
113 /// Attempt to create a shallow clone of this x86_64 KvmKernelIrqChip instance.
arch_try_clone(&self) -> Result<Self>114 pub(super) fn arch_try_clone(&self) -> Result<Self> {
115 Ok(KvmKernelIrqChip {
116 vm: self.vm.try_clone()?,
117 vcpus: self.vcpus.clone(),
118 routes: self.routes.clone(),
119 })
120 }
121 }
122
123 impl IrqChipX86_64 for KvmKernelIrqChip {
try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>124 fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>> {
125 Ok(Box::new(self.try_clone()?))
126 }
127
as_irq_chip(&self) -> &dyn IrqChip128 fn as_irq_chip(&self) -> &dyn IrqChip {
129 self
130 }
131
as_irq_chip_mut(&mut self) -> &mut dyn IrqChip132 fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip {
133 self
134 }
135
136 /// Get the current state of the PIC
get_pic_state(&self, select: PicSelect) -> Result<PicState>137 fn get_pic_state(&self, select: PicSelect) -> Result<PicState> {
138 Ok(PicState::from(&self.vm.get_pic_state(select)?))
139 }
140
141 /// Set the current state of the PIC
set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>142 fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()> {
143 self.vm.set_pic_state(select, &kvm_pic_state::from(state))
144 }
145
146 /// Get the current state of the IOAPIC
get_ioapic_state(&self) -> Result<IoapicState>147 fn get_ioapic_state(&self) -> Result<IoapicState> {
148 Ok(IoapicState::from(&self.vm.get_ioapic_state()?))
149 }
150
151 /// Set the current state of the IOAPIC
set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>152 fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()> {
153 self.vm.set_ioapic_state(&kvm_ioapic_state::from(state))
154 }
155
156 /// Get the current state of the specified VCPU's local APIC
get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>157 fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
158 match self.vcpus.lock().get(vcpu_id) {
159 Some(Some(vcpu)) => Ok(LapicState::from(&vcpu.get_lapic()?)),
160 _ => Err(Error::new(libc::ENOENT)),
161 }
162 }
163
164 /// Set the current state of the specified VCPU's local APIC
set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>165 fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()> {
166 match self.vcpus.lock().get(vcpu_id) {
167 Some(Some(vcpu)) => vcpu.set_lapic(&kvm_lapic_state::from(state)),
168 _ => Err(Error::new(libc::ENOENT)),
169 }
170 }
171
172 /// Get the lapic frequency in Hz
lapic_frequency(&self) -> u32173 fn lapic_frequency(&self) -> u32 {
174 // KVM emulates the lapic to have a bus frequency of 1GHz
175 1_000_000_000
176 }
177
178 /// Retrieves the state of the PIT. Gets the pit state via the KVM API.
get_pit(&self) -> Result<PitState>179 fn get_pit(&self) -> Result<PitState> {
180 Ok(PitState::from(&self.vm.get_pit_state()?))
181 }
182
183 /// Sets the state of the PIT. Sets the pit state via the KVM API.
set_pit(&mut self, state: &PitState) -> Result<()>184 fn set_pit(&mut self, state: &PitState) -> Result<()> {
185 self.vm.set_pit_state(&kvm_pit_state2::from(state))
186 }
187
188 /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused.
189 /// KVM's kernel PIT doesn't use 0x61.
pit_uses_speaker_port(&self) -> bool190 fn pit_uses_speaker_port(&self) -> bool {
191 false
192 }
193
snapshot_chip_specific(&self) -> anyhow::Result<AnySnapshot>194 fn snapshot_chip_specific(&self) -> anyhow::Result<AnySnapshot> {
195 let mut apics: Vec<u64> = Vec::new();
196 let mut interrupt_bitmaps: Vec<[u64; 4usize]> = Vec::new();
197 {
198 let vcpus_lock = self.vcpus.lock();
199 for vcpu in (*vcpus_lock).iter().flatten() {
200 apics.push(vcpu.get_apic_base()?);
201 interrupt_bitmaps.push(vcpu.get_interrupt_bitmap()?);
202 }
203 }
204 AnySnapshot::to_any(KvmKernelIrqChipSnapshot {
205 routes: self.routes.lock().clone(),
206 apic_base: apics,
207 interrupt_bitmap: interrupt_bitmaps,
208 })
209 .context("failed to serialize KvmKernelIrqChip")
210 }
211
restore_chip_specific(&mut self, data: AnySnapshot) -> anyhow::Result<()>212 fn restore_chip_specific(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
213 let deser: KvmKernelIrqChipSnapshot =
214 AnySnapshot::from_any(data).context("failed to deserialize data")?;
215 self.set_irq_routes(&deser.routes)?;
216 let vcpus_lock = self.vcpus.lock();
217 assert_eq!(deser.interrupt_bitmap.len(), vcpus_lock.len());
218 assert_eq!(deser.apic_base.len(), vcpus_lock.len());
219 for (i, vcpu) in vcpus_lock.iter().enumerate() {
220 if let Some(vcpu) = vcpu {
221 vcpu.set_apic_base(*deser.apic_base.get(i).unwrap())?;
222 vcpu.set_interrupt_bitmap(*deser.interrupt_bitmap.get(i).unwrap())?;
223 } else {
224 return Err(anyhow!(
225 "Received None instead of Vcpu while restoring apic_base and interrupt_bitmap"
226 ));
227 }
228 }
229 Ok(())
230 }
231 }
232
233 /// The KvmSplitIrqsChip supports KVM's SPLIT_IRQCHIP feature, where the PIC and IOAPIC
234 /// are emulated in userspace, while the local APICs are emulated in the kernel.
235 /// The SPLIT_IRQCHIP feature only supports x86/x86_64 so we only define this IrqChip in crosvm
236 /// for x86/x86_64.
237 pub struct KvmSplitIrqChip {
238 vm: KvmVm,
239 vcpus: Arc<Mutex<Vec<Option<KvmVcpu>>>>,
240 routes: Arc<Mutex<Vec<IrqRoute>>>,
241 pit: Arc<Mutex<Pit>>,
242 pic: Arc<Mutex<Pic>>,
243 ioapic: Arc<Mutex<Ioapic>>,
244 ioapic_pins: usize,
245 /// Vec of ioapic irq events that have been delayed because the ioapic was locked when
246 /// service_irq was called on the irqchip. This prevents deadlocks when a Vcpu thread has
247 /// locked the ioapic and the ioapic sends a AddMsiRoute signal to the main thread (which
248 /// itself may be busy trying to call service_irq).
249 delayed_ioapic_irq_events: Arc<Mutex<Vec<usize>>>,
250 /// Event which is meant to trigger process of any irqs events that were delayed.
251 delayed_ioapic_irq_trigger: Event,
252 /// Array of Events that devices will use to assert ioapic pins.
253 irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>,
254 }
255
kvm_dummy_msi_routes(ioapic_pins: usize) -> Vec<IrqRoute>256 fn kvm_dummy_msi_routes(ioapic_pins: usize) -> Vec<IrqRoute> {
257 let mut routes: Vec<IrqRoute> = Vec::new();
258 for i in 0..ioapic_pins {
259 routes.push(
260 // Add dummy MSI routes to replace the default IRQChip routes.
261 IrqRoute {
262 gsi: i as u32,
263 source: IrqSource::Msi {
264 address: 0,
265 data: 0,
266 },
267 },
268 );
269 }
270 routes
271 }
272
273 impl KvmSplitIrqChip {
274 /// Construct a new KvmSplitIrqChip.
new( vm: KvmVm, num_vcpus: usize, irq_tube: Tube, ioapic_pins: Option<usize>, ) -> Result<Self>275 pub fn new(
276 vm: KvmVm,
277 num_vcpus: usize,
278 irq_tube: Tube,
279 ioapic_pins: Option<usize>,
280 ) -> Result<Self> {
281 let ioapic_pins = ioapic_pins.unwrap_or(vm.get_ioapic_num_pins()?);
282 vm.enable_split_irqchip(ioapic_pins)?;
283 let pit_evt = IrqEdgeEvent::new()?;
284 let pit = Pit::new(pit_evt.try_clone()?, Arc::new(Mutex::new(Clock::new()))).map_err(
285 |e| match e {
286 PitError::CloneEvent(err) => err,
287 PitError::CreateEvent(err) => err,
288 PitError::CreateWaitContext(err) => err,
289 PitError::WaitError(err) => err,
290 PitError::TimerCreateError(err) => err,
291 PitError::SpawnThread(_) => Error::new(libc::EIO),
292 },
293 )?;
294
295 let pit_event_source = IrqEventSource::from_device(&pit);
296
297 let mut chip = KvmSplitIrqChip {
298 vm,
299 vcpus: Arc::new(Mutex::new((0..num_vcpus).map(|_| None).collect())),
300 routes: Arc::new(Mutex::new(Vec::new())),
301 pit: Arc::new(Mutex::new(pit)),
302 pic: Arc::new(Mutex::new(Pic::new())),
303 ioapic: Arc::new(Mutex::new(Ioapic::new(irq_tube, ioapic_pins)?)),
304 ioapic_pins,
305 delayed_ioapic_irq_events: Arc::new(Mutex::new(Vec::new())),
306 delayed_ioapic_irq_trigger: Event::new()?,
307 irq_events: Arc::new(Mutex::new(Default::default())),
308 };
309
310 // Setup standard x86 irq routes
311 let mut routes = kvm_default_irq_routing_table(ioapic_pins);
312 // Add dummy MSI routes for the first ioapic_pins GSIs
313 routes.append(&mut kvm_dummy_msi_routes(ioapic_pins));
314
315 // Set the routes so they get sent to KVM
316 chip.set_irq_routes(&routes)?;
317
318 chip.register_edge_irq_event(PIT_CHANNEL0_IRQ, &pit_evt, pit_event_source)?;
319 Ok(chip)
320 }
321 }
322
323 impl KvmSplitIrqChip {
324 /// Convenience function for determining which chips the supplied irq routes to.
routes_to_chips(&self, irq: u32) -> Vec<(IrqSourceChip, u32)>325 fn routes_to_chips(&self, irq: u32) -> Vec<(IrqSourceChip, u32)> {
326 let mut chips = Vec::new();
327 for route in self.routes.lock().iter() {
328 match route {
329 IrqRoute {
330 gsi,
331 source: IrqSource::Irqchip { chip, pin },
332 } if *gsi == irq => match chip {
333 IrqSourceChip::PicPrimary
334 | IrqSourceChip::PicSecondary
335 | IrqSourceChip::Ioapic => chips.push((*chip, *pin)),
336 IrqSourceChip::Gic => {
337 error!("gic irq should not be possible on a KvmSplitIrqChip")
338 }
339 IrqSourceChip::Aia => {
340 error!("Aia irq should not be possible on x86_64")
341 }
342 },
343 // Ignore MSIs and other routes
344 _ => {}
345 }
346 }
347 chips
348 }
349
350 /// Return true if there is a pending interrupt for the specified vcpu. For KvmSplitIrqChip
351 /// this calls interrupt_requested on the pic.
interrupt_requested(&self, vcpu_id: usize) -> bool352 pub fn interrupt_requested(&self, vcpu_id: usize) -> bool {
353 // Pic interrupts for the split irqchip only go to vcpu 0
354 if vcpu_id != 0 {
355 return false;
356 }
357 self.pic.lock().interrupt_requested()
358 }
359
360 /// Check if the specified vcpu has any pending interrupts. Returns [`None`] for no interrupts,
361 /// otherwise [`Some::<u8>`] should be the injected interrupt vector. For [`KvmSplitIrqChip`]
362 /// this calls `get_external_interrupt` on the pic.
get_external_interrupt(&self, vcpu_id: usize) -> Option<u8>363 pub fn get_external_interrupt(&self, vcpu_id: usize) -> Option<u8> {
364 // Pic interrupts for the split irqchip only go to vcpu 0
365 if vcpu_id != 0 {
366 return None;
367 }
368 self.pic.lock().get_external_interrupt()
369 }
370
371 /// Register an event that can trigger an interrupt for a particular GSI.
register_irq_event( &mut self, irq: u32, irq_event: &Event, resample_event: Option<&Event>, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>372 fn register_irq_event(
373 &mut self,
374 irq: u32,
375 irq_event: &Event,
376 resample_event: Option<&Event>,
377 source: IrqEventSource,
378 ) -> Result<Option<IrqEventIndex>> {
379 if irq < self.ioapic_pins as u32 {
380 let mut evt = IrqEvent {
381 gsi: irq,
382 event: irq_event.try_clone()?,
383 resample_event: None,
384 source,
385 };
386
387 if let Some(resample_event) = resample_event {
388 evt.resample_event = Some(resample_event.try_clone()?);
389 }
390
391 let mut irq_events = self.irq_events.lock();
392 let index = irq_events.len();
393 irq_events.push(Some(evt));
394 Ok(Some(index))
395 } else {
396 self.vm.register_irqfd(irq, irq_event, resample_event)?;
397 Ok(None)
398 }
399 }
400
401 /// Unregister an event for a particular GSI.
unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()>402 fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()> {
403 if irq < self.ioapic_pins as u32 {
404 let mut irq_events = self.irq_events.lock();
405 for (index, evt) in irq_events.iter().enumerate() {
406 if let Some(evt) = evt {
407 if evt.gsi == irq && irq_event.eq(&evt.event) {
408 irq_events[index] = None;
409 break;
410 }
411 }
412 }
413 Ok(())
414 } else {
415 self.vm.unregister_irqfd(irq, irq_event)
416 }
417 }
418 }
419
420 /// Convenience function for determining whether or not two irq routes conflict.
421 /// Returns true if they conflict.
routes_conflict(route: &IrqRoute, other: &IrqRoute) -> bool422 fn routes_conflict(route: &IrqRoute, other: &IrqRoute) -> bool {
423 // They don't conflict if they have different GSIs.
424 if route.gsi != other.gsi {
425 return false;
426 }
427
428 // If they're both MSI with the same GSI then they conflict.
429 if let (IrqSource::Msi { .. }, IrqSource::Msi { .. }) = (route.source, other.source) {
430 return true;
431 }
432
433 // If the route chips match and they have the same GSI then they conflict.
434 if let (
435 IrqSource::Irqchip {
436 chip: route_chip, ..
437 },
438 IrqSource::Irqchip {
439 chip: other_chip, ..
440 },
441 ) = (route.source, other.source)
442 {
443 return route_chip == other_chip;
444 }
445
446 // Otherwise they do not conflict.
447 false
448 }
449
450 /// This IrqChip only works with Kvm so we only implement it for KvmVcpu.
451 impl IrqChip for KvmSplitIrqChip {
452 /// Add a vcpu to the irq chip.
add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>453 fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()> {
454 let vcpu: &KvmVcpu = vcpu
455 .downcast_ref()
456 .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
457 self.vcpus.lock()[vcpu_id] = Some(vcpu.try_clone()?);
458 Ok(())
459 }
460
461 /// Register an event that can trigger an interrupt for a particular GSI.
register_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>462 fn register_edge_irq_event(
463 &mut self,
464 irq: u32,
465 irq_event: &IrqEdgeEvent,
466 source: IrqEventSource,
467 ) -> Result<Option<IrqEventIndex>> {
468 self.register_irq_event(irq, irq_event.get_trigger(), None, source)
469 }
470
unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>471 fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> {
472 self.unregister_irq_event(irq, irq_event.get_trigger())
473 }
474
register_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>475 fn register_level_irq_event(
476 &mut self,
477 irq: u32,
478 irq_event: &IrqLevelEvent,
479 source: IrqEventSource,
480 ) -> Result<Option<IrqEventIndex>> {
481 self.register_irq_event(
482 irq,
483 irq_event.get_trigger(),
484 Some(irq_event.get_resample()),
485 source,
486 )
487 }
488
unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>489 fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> {
490 self.unregister_irq_event(irq, irq_event.get_trigger())
491 }
492
493 /// Route an IRQ line to an interrupt controller, or to a particular MSI vector.
route_irq(&mut self, route: IrqRoute) -> Result<()>494 fn route_irq(&mut self, route: IrqRoute) -> Result<()> {
495 let mut routes = self.routes.lock();
496 routes.retain(|r| !routes_conflict(r, &route));
497
498 routes.push(route);
499
500 // We only call set_gsi_routing with the msi routes
501 let mut msi_routes = routes.clone();
502 msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
503
504 self.vm.set_gsi_routing(&msi_routes)
505 }
506
507 /// Replace all irq routes with the supplied routes
set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>508 fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()> {
509 let mut current_routes = self.routes.lock();
510 *current_routes = routes.to_vec();
511
512 // We only call set_gsi_routing with the msi routes
513 let mut msi_routes = routes.to_vec();
514 msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
515
516 self.vm.set_gsi_routing(&msi_routes)
517 }
518
519 /// Return a vector of all registered irq numbers and their associated events and event
520 /// indices. These should be used by the main thread to wait for irq events.
irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>521 fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> {
522 let mut tokens = vec![];
523 for (index, evt) in self.irq_events.lock().iter().enumerate() {
524 if let Some(evt) = evt {
525 tokens.push((index, evt.source.clone(), evt.event.try_clone()?));
526 }
527 }
528 Ok(tokens)
529 }
530
531 /// Either assert or deassert an IRQ line. Sends to either an interrupt controller, or does
532 /// a send_msi if the irq is associated with an MSI.
service_irq(&mut self, irq: u32, level: bool) -> Result<()>533 fn service_irq(&mut self, irq: u32, level: bool) -> Result<()> {
534 let chips = self.routes_to_chips(irq);
535 for (chip, pin) in chips {
536 match chip {
537 IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
538 self.pic.lock().service_irq(pin as u8, level);
539 }
540 IrqSourceChip::Ioapic => {
541 self.ioapic.lock().service_irq(pin as usize, level);
542 }
543 _ => {}
544 }
545 }
546 Ok(())
547 }
548
549 /// Service an IRQ event by asserting then deasserting an IRQ line. The associated Event
550 /// that triggered the irq event will be read from. If the irq is associated with a resample
551 /// Event, then the deassert will only happen after an EOI is broadcast for a vector
552 /// associated with the irq line.
553 /// For the KvmSplitIrqChip, this function identifies which chips the irq routes to, then
554 /// attempts to call service_irq on those chips. If the ioapic is unable to be immediately
555 /// locked, we add the irq to the delayed_ioapic_irq_events Vec (though we still read
556 /// from the Event that triggered the irq event).
service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>557 fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()> {
558 if let Some(evt) = &self.irq_events.lock()[event_index] {
559 evt.event.wait()?;
560 let chips = self.routes_to_chips(evt.gsi);
561
562 for (chip, pin) in chips {
563 match chip {
564 IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
565 let mut pic = self.pic.lock();
566 pic.service_irq(pin as u8, true);
567 if evt.resample_event.is_none() {
568 pic.service_irq(pin as u8, false);
569 }
570 }
571 IrqSourceChip::Ioapic => {
572 if let Ok(mut ioapic) = self.ioapic.try_lock() {
573 ioapic.service_irq(pin as usize, true);
574 if evt.resample_event.is_none() {
575 ioapic.service_irq(pin as usize, false);
576 }
577 } else {
578 self.delayed_ioapic_irq_events.lock().push(event_index);
579 self.delayed_ioapic_irq_trigger.signal().unwrap();
580 }
581 }
582 _ => {}
583 }
584 }
585 }
586
587 Ok(())
588 }
589
590 /// Broadcast an end of interrupt. For KvmSplitIrqChip this sends the EOI to the ioapic
broadcast_eoi(&self, vector: u8) -> Result<()>591 fn broadcast_eoi(&self, vector: u8) -> Result<()> {
592 self.ioapic.lock().end_of_interrupt(vector);
593 Ok(())
594 }
595
596 /// Injects any pending interrupts for `vcpu`.
597 /// For KvmSplitIrqChip this injects any PIC interrupts on vcpu_id 0.
inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>598 fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()> {
599 let vcpu: &KvmVcpu = vcpu
600 .downcast_ref()
601 .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
602
603 let vcpu_id = vcpu.id();
604 if !self.interrupt_requested(vcpu_id) || !vcpu.ready_for_interrupt() {
605 return Ok(());
606 }
607
608 if let Some(vector) = self.get_external_interrupt(vcpu_id) {
609 vcpu.interrupt(vector)?;
610 }
611
612 // The second interrupt request should be handled immediately, so ask vCPU to exit as soon
613 // as possible.
614 if self.interrupt_requested(vcpu_id) {
615 vcpu.set_interrupt_window_requested(true);
616 }
617 Ok(())
618 }
619
620 /// Notifies the irq chip that the specified VCPU has executed a halt instruction.
621 /// For KvmSplitIrqChip this is a no-op because KVM handles VCPU blocking.
halted(&self, _vcpu_id: usize)622 fn halted(&self, _vcpu_id: usize) {}
623
624 /// Blocks until `vcpu` is in a runnable state or until interrupted by
625 /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or
626 /// `VcpuRunState::Interrupted` if the wait was interrupted.
627 /// For KvmSplitIrqChip this is a no-op and always returns Runnable because KVM handles VCPU
628 /// blocking.
wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState>629 fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> {
630 Ok(VcpuRunState::Runnable)
631 }
632
633 /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.
634 /// For KvmSplitIrqChip this is a no-op because KVM handles VCPU blocking.
kick_halted_vcpus(&self)635 fn kick_halted_vcpus(&self) {}
636
637 /// Get the current MP state of the specified VCPU.
get_mp_state(&self, vcpu_id: usize) -> Result<MPState>638 fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState> {
639 match self.vcpus.lock().get(vcpu_id) {
640 Some(Some(vcpu)) => Ok(MPState::from(&vcpu.get_mp_state()?)),
641 _ => Err(Error::new(libc::ENOENT)),
642 }
643 }
644
645 /// Set the current MP state of the specified VCPU.
set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>646 fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()> {
647 match self.vcpus.lock().get(vcpu_id) {
648 Some(Some(vcpu)) => vcpu.set_mp_state(&kvm_mp_state::from(state)),
649 _ => Err(Error::new(libc::ENOENT)),
650 }
651 }
652
653 /// Attempt to clone this IrqChip instance.
try_clone(&self) -> Result<Self>654 fn try_clone(&self) -> Result<Self> {
655 Ok(KvmSplitIrqChip {
656 vm: self.vm.try_clone()?,
657 vcpus: self.vcpus.clone(),
658 routes: self.routes.clone(),
659 pit: self.pit.clone(),
660 pic: self.pic.clone(),
661 ioapic: self.ioapic.clone(),
662 ioapic_pins: self.ioapic_pins,
663 delayed_ioapic_irq_events: self.delayed_ioapic_irq_events.clone(),
664 delayed_ioapic_irq_trigger: Event::new()?,
665 irq_events: self.irq_events.clone(),
666 })
667 }
668
669 /// Finalize irqchip setup. Should be called once all devices have registered irq events and
670 /// been added to the io_bus and mmio_bus.
finalize_devices( &mut self, resources: &mut SystemAllocator, io_bus: &Bus, mmio_bus: &Bus, ) -> Result<()>671 fn finalize_devices(
672 &mut self,
673 resources: &mut SystemAllocator,
674 io_bus: &Bus,
675 mmio_bus: &Bus,
676 ) -> Result<()> {
677 // Insert pit into io_bus
678 io_bus.insert(self.pit.clone(), 0x040, 0x8).unwrap();
679 io_bus.insert(self.pit.clone(), 0x061, 0x1).unwrap();
680
681 // Insert pic into io_bus
682 io_bus.insert(self.pic.clone(), 0x20, 0x2).unwrap();
683 io_bus.insert(self.pic.clone(), 0xa0, 0x2).unwrap();
684 io_bus.insert(self.pic.clone(), 0x4d0, 0x2).unwrap();
685
686 // Insert ioapic into mmio_bus
687 mmio_bus
688 .insert(
689 self.ioapic.clone(),
690 IOAPIC_BASE_ADDRESS,
691 IOAPIC_MEM_LENGTH_BYTES,
692 )
693 .unwrap();
694
695 // At this point, all of our devices have been created and they have registered their
696 // irq events, so we can clone our resample events
697 let mut ioapic_resample_events: Vec<Vec<Event>> =
698 (0..self.ioapic_pins).map(|_| Vec::new()).collect();
699 let mut pic_resample_events: Vec<Vec<Event>> =
700 (0..self.ioapic_pins).map(|_| Vec::new()).collect();
701
702 for evt in self.irq_events.lock().iter().flatten() {
703 if (evt.gsi as usize) >= self.ioapic_pins {
704 continue;
705 }
706 if let Some(resample_evt) = &evt.resample_event {
707 ioapic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
708 pic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
709 }
710 }
711
712 // Register resample events with the ioapic
713 self.ioapic
714 .lock()
715 .register_resample_events(ioapic_resample_events);
716 // Register resample events with the pic
717 self.pic
718 .lock()
719 .register_resample_events(pic_resample_events);
720
721 // Make sure all future irq numbers are beyond IO-APIC range.
722 let mut irq_num = resources.allocate_irq().unwrap();
723 while irq_num < self.ioapic_pins as u32 {
724 irq_num = resources.allocate_irq().unwrap();
725 }
726
727 Ok(())
728 }
729
730 /// The KvmSplitIrqChip's ioapic may be locked because a vcpu thread is currently writing to
731 /// the ioapic, and the ioapic may be blocking on adding MSI routes, which requires blocking
732 /// socket communication back to the main thread. Thus, we do not want the main thread to
733 /// block on a locked ioapic, so any irqs that could not be serviced because the ioapic could
734 /// not be immediately locked are added to the delayed_ioapic_irq_events Vec. This function
735 /// processes each delayed event in the vec each time it's called. If the ioapic is still
736 /// locked, we keep the queued irqs for the next time this function is called.
process_delayed_irq_events(&mut self) -> Result<()>737 fn process_delayed_irq_events(&mut self) -> Result<()> {
738 self.delayed_ioapic_irq_events
739 .lock()
740 .retain(|&event_index| {
741 if let Some(evt) = &self.irq_events.lock()[event_index] {
742 if let Ok(mut ioapic) = self.ioapic.try_lock() {
743 ioapic.service_irq(evt.gsi as usize, true);
744 if evt.resample_event.is_none() {
745 ioapic.service_irq(evt.gsi as usize, false);
746 }
747
748 false
749 } else {
750 true
751 }
752 } else {
753 true
754 }
755 });
756
757 if self.delayed_ioapic_irq_events.lock().is_empty() {
758 self.delayed_ioapic_irq_trigger.wait()?;
759 }
760
761 Ok(())
762 }
763
irq_delayed_event_token(&self) -> Result<Option<Event>>764 fn irq_delayed_event_token(&self) -> Result<Option<Event>> {
765 Ok(Some(self.delayed_ioapic_irq_trigger.try_clone()?))
766 }
767
check_capability(&self, c: IrqChipCap) -> bool768 fn check_capability(&self, c: IrqChipCap) -> bool {
769 match c {
770 IrqChipCap::TscDeadlineTimer => self
771 .vm
772 .get_hypervisor()
773 .check_capability(HypervisorCap::TscDeadlineTimer),
774 IrqChipCap::X2Apic => true,
775 IrqChipCap::MpStateGetSet => true,
776 }
777 }
778 }
779
780 #[derive(Serialize, Deserialize)]
781 struct KvmSplitIrqChipSnapshot {
782 routes: Vec<IrqRoute>,
783 }
784
785 impl IrqChipX86_64 for KvmSplitIrqChip {
try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>786 fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>> {
787 Ok(Box::new(self.try_clone()?))
788 }
789
as_irq_chip(&self) -> &dyn IrqChip790 fn as_irq_chip(&self) -> &dyn IrqChip {
791 self
792 }
793
as_irq_chip_mut(&mut self) -> &mut dyn IrqChip794 fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip {
795 self
796 }
797
798 /// Get the current state of the PIC
get_pic_state(&self, select: PicSelect) -> Result<PicState>799 fn get_pic_state(&self, select: PicSelect) -> Result<PicState> {
800 Ok(self.pic.lock().get_pic_state(select))
801 }
802
803 /// Set the current state of the PIC
set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>804 fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()> {
805 self.pic.lock().set_pic_state(select, state);
806 Ok(())
807 }
808
809 /// Get the current state of the IOAPIC
get_ioapic_state(&self) -> Result<IoapicState>810 fn get_ioapic_state(&self) -> Result<IoapicState> {
811 Ok(self.ioapic.lock().get_ioapic_state())
812 }
813
814 /// Set the current state of the IOAPIC
set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>815 fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()> {
816 self.ioapic.lock().set_ioapic_state(state);
817 Ok(())
818 }
819
820 /// Get the current state of the specified VCPU's local APIC
get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>821 fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
822 match self.vcpus.lock().get(vcpu_id) {
823 Some(Some(vcpu)) => Ok(LapicState::from(&vcpu.get_lapic()?)),
824 _ => Err(Error::new(libc::ENOENT)),
825 }
826 }
827
828 /// Set the current state of the specified VCPU's local APIC
set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>829 fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()> {
830 match self.vcpus.lock().get(vcpu_id) {
831 Some(Some(vcpu)) => vcpu.set_lapic(&kvm_lapic_state::from(state)),
832 _ => Err(Error::new(libc::ENOENT)),
833 }
834 }
835
836 /// Get the lapic frequency in Hz
lapic_frequency(&self) -> u32837 fn lapic_frequency(&self) -> u32 {
838 // KVM emulates the lapic to have a bus frequency of 1GHz
839 1_000_000_000
840 }
841
842 /// Retrieves the state of the PIT. Gets the pit state via the KVM API.
get_pit(&self) -> Result<PitState>843 fn get_pit(&self) -> Result<PitState> {
844 Ok(self.pit.lock().get_pit_state())
845 }
846
847 /// Sets the state of the PIT. Sets the pit state via the KVM API.
set_pit(&mut self, state: &PitState) -> Result<()>848 fn set_pit(&mut self, state: &PitState) -> Result<()> {
849 self.pit.lock().set_pit_state(state);
850 Ok(())
851 }
852
853 /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused.
854 /// devices::Pit uses 0x61.
pit_uses_speaker_port(&self) -> bool855 fn pit_uses_speaker_port(&self) -> bool {
856 true
857 }
858
snapshot_chip_specific(&self) -> anyhow::Result<AnySnapshot>859 fn snapshot_chip_specific(&self) -> anyhow::Result<AnySnapshot> {
860 AnySnapshot::to_any(KvmSplitIrqChipSnapshot {
861 routes: self.routes.lock().clone(),
862 })
863 .context("failed to serialize KvmSplitIrqChip")
864 }
865
restore_chip_specific(&mut self, data: AnySnapshot) -> anyhow::Result<()>866 fn restore_chip_specific(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
867 let deser: KvmSplitIrqChipSnapshot =
868 AnySnapshot::from_any(data).context("failed to deserialize KvmSplitIrqChip")?;
869 self.set_irq_routes(&deser.routes)?;
870 Ok(())
871 }
872 }
873