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