• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
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 sync::Mutex;
8 
9 #[cfg(not(test))]
10 use base::Clock;
11 #[cfg(test)]
12 use base::FakeClock as Clock;
13 use hypervisor::kvm::{KvmVcpu, KvmVm};
14 use hypervisor::{
15     HypervisorCap, IoapicState, IrqRoute, IrqSource, IrqSourceChip, LapicState, MPState, PicSelect,
16     PicState, PitState, Vcpu, VcpuX86_64, Vm, VmX86_64, NUM_IOAPIC_PINS,
17 };
18 use kvm_sys::*;
19 use resources::SystemAllocator;
20 
21 use base::{error, Error, Event, Result, Tube};
22 
23 use crate::irqchip::{
24     Ioapic, IrqEvent, IrqEventIndex, Pic, VcpuRunState, IOAPIC_BASE_ADDRESS,
25     IOAPIC_MEM_LENGTH_BYTES,
26 };
27 use crate::{Bus, IrqChip, IrqChipCap, IrqChipX86_64, Pit, PitError};
28 
29 /// PIT tube 0 timer is connected to IRQ 0
30 const PIT_CHANNEL0_IRQ: u32 = 0;
31 
32 /// Default x86 routing table.  Pins 0-7 go to primary pic and ioapic, pins 8-15 go to secondary
33 /// pic and ioapic, and pins 16-23 go only to the ioapic.
kvm_default_irq_routing_table(ioapic_pins: usize) -> Vec<IrqRoute>34 fn kvm_default_irq_routing_table(ioapic_pins: usize) -> Vec<IrqRoute> {
35     let mut routes: Vec<IrqRoute> = Vec::new();
36 
37     for i in 0..8 {
38         routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicPrimary, i));
39         routes.push(IrqRoute::ioapic_irq_route(i));
40     }
41     for i in 8..16 {
42         routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicSecondary, i));
43         routes.push(IrqRoute::ioapic_irq_route(i));
44     }
45     for i in 16..ioapic_pins as u32 {
46         routes.push(IrqRoute::ioapic_irq_route(i));
47     }
48 
49     routes
50 }
51 
52 /// IrqChip implementation where the entire IrqChip is emulated by KVM.
53 ///
54 /// This implementation will use the KVM API to create and configure the in-kernel irqchip.
55 pub struct KvmKernelIrqChip {
56     pub(super) vm: KvmVm,
57     pub(super) vcpus: Arc<Mutex<Vec<Option<KvmVcpu>>>>,
58     pub(super) routes: Arc<Mutex<Vec<IrqRoute>>>,
59 }
60 
61 impl KvmKernelIrqChip {
62     /// Construct a new KvmKernelIrqchip.
new(vm: KvmVm, num_vcpus: usize) -> Result<KvmKernelIrqChip>63     pub fn new(vm: KvmVm, num_vcpus: usize) -> Result<KvmKernelIrqChip> {
64         vm.create_irq_chip()?;
65         vm.create_pit()?;
66 
67         Ok(KvmKernelIrqChip {
68             vm,
69             vcpus: Arc::new(Mutex::new((0..num_vcpus).map(|_| None).collect())),
70             routes: Arc::new(Mutex::new(kvm_default_irq_routing_table(NUM_IOAPIC_PINS))),
71         })
72     }
73     /// Attempt to create a shallow clone of this x86_64 KvmKernelIrqChip instance.
arch_try_clone(&self) -> Result<Self>74     pub(super) fn arch_try_clone(&self) -> Result<Self> {
75         Ok(KvmKernelIrqChip {
76             vm: self.vm.try_clone()?,
77             vcpus: self.vcpus.clone(),
78             routes: self.routes.clone(),
79         })
80     }
81 }
82 
83 impl IrqChipX86_64 for KvmKernelIrqChip {
84     /// Get the current state of the PIC
get_pic_state(&self, select: PicSelect) -> Result<PicState>85     fn get_pic_state(&self, select: PicSelect) -> Result<PicState> {
86         Ok(PicState::from(&self.vm.get_pic_state(select)?))
87     }
88 
89     /// Set the current state of the PIC
set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>90     fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()> {
91         self.vm.set_pic_state(select, &kvm_pic_state::from(state))
92     }
93 
94     /// Get the current state of the IOAPIC
get_ioapic_state(&self) -> Result<IoapicState>95     fn get_ioapic_state(&self) -> Result<IoapicState> {
96         Ok(IoapicState::from(&self.vm.get_ioapic_state()?))
97     }
98 
99     /// Set the current state of the IOAPIC
set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>100     fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()> {
101         self.vm.set_ioapic_state(&kvm_ioapic_state::from(state))
102     }
103 
104     /// Get the current state of the specified VCPU's local APIC
get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>105     fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
106         match self.vcpus.lock().get(vcpu_id) {
107             Some(Some(vcpu)) => Ok(LapicState::from(&vcpu.get_lapic()?)),
108             _ => Err(Error::new(libc::ENOENT)),
109         }
110     }
111 
112     /// Set the current state of the specified VCPU's local APIC
set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>113     fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()> {
114         match self.vcpus.lock().get(vcpu_id) {
115             Some(Some(vcpu)) => vcpu.set_lapic(&kvm_lapic_state::from(state)),
116             _ => Err(Error::new(libc::ENOENT)),
117         }
118     }
119 
120     /// Retrieves the state of the PIT. Gets the pit state via the KVM API.
get_pit(&self) -> Result<PitState>121     fn get_pit(&self) -> Result<PitState> {
122         Ok(PitState::from(&self.vm.get_pit_state()?))
123     }
124 
125     /// Sets the state of the PIT. Sets the pit state via the KVM API.
set_pit(&mut self, state: &PitState) -> Result<()>126     fn set_pit(&mut self, state: &PitState) -> Result<()> {
127         self.vm.set_pit_state(&kvm_pit_state2::from(state))
128     }
129 
130     /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused.
131     /// KVM's kernel PIT doesn't use 0x61.
pit_uses_speaker_port(&self) -> bool132     fn pit_uses_speaker_port(&self) -> bool {
133         false
134     }
135 }
136 
137 /// The KvmSplitIrqsChip supports KVM's SPLIT_IRQCHIP feature, where the PIC and IOAPIC
138 /// are emulated in userspace, while the local APICs are emulated in the kernel.
139 /// The SPLIT_IRQCHIP feature only supports x86/x86_64 so we only define this IrqChip in crosvm
140 /// for x86/x86_64.
141 pub struct KvmSplitIrqChip {
142     vm: KvmVm,
143     vcpus: Arc<Mutex<Vec<Option<KvmVcpu>>>>,
144     routes: Arc<Mutex<Vec<IrqRoute>>>,
145     pit: Arc<Mutex<Pit>>,
146     pic: Arc<Mutex<Pic>>,
147     ioapic: Arc<Mutex<Ioapic>>,
148     ioapic_pins: usize,
149     /// Vec of ioapic irq events that have been delayed because the ioapic was locked when
150     /// service_irq was called on the irqchip. This prevents deadlocks when a Vcpu thread has
151     /// locked the ioapic and the ioapic sends a AddMsiRoute signal to the main thread (which
152     /// itself may be busy trying to call service_irq).
153     delayed_ioapic_irq_events: Arc<Mutex<Vec<usize>>>,
154     /// Array of Events that devices will use to assert ioapic pins.
155     irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>,
156 }
157 
kvm_dummy_msi_routes(ioapic_pins: usize) -> Vec<IrqRoute>158 fn kvm_dummy_msi_routes(ioapic_pins: usize) -> Vec<IrqRoute> {
159     let mut routes: Vec<IrqRoute> = Vec::new();
160     for i in 0..ioapic_pins {
161         routes.push(
162             // Add dummy MSI routes to replace the default IRQChip routes.
163             IrqRoute {
164                 gsi: i as u32,
165                 source: IrqSource::Msi {
166                     address: 0,
167                     data: 0,
168                 },
169             },
170         );
171     }
172     routes
173 }
174 
175 impl KvmSplitIrqChip {
176     /// Construct a new KvmSplitIrqChip.
new( vm: KvmVm, num_vcpus: usize, irq_tube: Tube, ioapic_pins: Option<usize>, ) -> Result<Self>177     pub fn new(
178         vm: KvmVm,
179         num_vcpus: usize,
180         irq_tube: Tube,
181         ioapic_pins: Option<usize>,
182     ) -> Result<Self> {
183         let ioapic_pins = ioapic_pins.unwrap_or(hypervisor::NUM_IOAPIC_PINS);
184         vm.enable_split_irqchip(ioapic_pins)?;
185         let pit_evt = Event::new()?;
186         let pit = Arc::new(Mutex::new(
187             Pit::new(pit_evt.try_clone()?, Arc::new(Mutex::new(Clock::new()))).map_err(
188                 |e| match e {
189                     PitError::CloneEvent(err) => err,
190                     PitError::CreateEvent(err) => err,
191                     PitError::CreateWaitContext(err) => err,
192                     PitError::WaitError(err) => err,
193                     PitError::TimerCreateError(err) => err,
194                     PitError::SpawnThread(_) => Error::new(libc::EIO),
195                 },
196             )?,
197         ));
198 
199         let mut chip = KvmSplitIrqChip {
200             vm,
201             vcpus: Arc::new(Mutex::new((0..num_vcpus).map(|_| None).collect())),
202             routes: Arc::new(Mutex::new(Vec::new())),
203             pit,
204             pic: Arc::new(Mutex::new(Pic::new())),
205             ioapic: Arc::new(Mutex::new(Ioapic::new(irq_tube, ioapic_pins)?)),
206             ioapic_pins,
207             delayed_ioapic_irq_events: Arc::new(Mutex::new(Vec::new())),
208             irq_events: Arc::new(Mutex::new(Default::default())),
209         };
210 
211         // Setup standard x86 irq routes
212         let mut routes = kvm_default_irq_routing_table(ioapic_pins);
213         // Add dummy MSI routes for the first ioapic_pins GSIs
214         routes.append(&mut kvm_dummy_msi_routes(ioapic_pins));
215 
216         // Set the routes so they get sent to KVM
217         chip.set_irq_routes(&routes)?;
218 
219         chip.register_irq_event(PIT_CHANNEL0_IRQ, &pit_evt, None)?;
220         Ok(chip)
221     }
222 }
223 
224 impl KvmSplitIrqChip {
225     /// Convenience function for determining which chips the supplied irq routes to.
routes_to_chips(&self, irq: u32) -> Vec<(IrqSourceChip, u32)>226     fn routes_to_chips(&self, irq: u32) -> Vec<(IrqSourceChip, u32)> {
227         let mut chips = Vec::new();
228         for route in self.routes.lock().iter() {
229             match route {
230                 IrqRoute {
231                     gsi,
232                     source: IrqSource::Irqchip { chip, pin },
233                 } if *gsi == irq => match chip {
234                     IrqSourceChip::PicPrimary
235                     | IrqSourceChip::PicSecondary
236                     | IrqSourceChip::Ioapic => chips.push((*chip, *pin)),
237                     IrqSourceChip::Gic => {
238                         error!("gic irq should not be possible on a KvmSplitIrqChip")
239                     }
240                 },
241                 // Ignore MSIs and other routes
242                 _ => {}
243             }
244         }
245         chips
246     }
247 
248     /// Return true if there is a pending interrupt for the specified vcpu. For KvmSplitIrqChip
249     /// this calls interrupt_requested on the pic.
interrupt_requested(&self, vcpu_id: usize) -> bool250     fn interrupt_requested(&self, vcpu_id: usize) -> bool {
251         // Pic interrupts for the split irqchip only go to vcpu 0
252         if vcpu_id != 0 {
253             return false;
254         }
255         self.pic.lock().interrupt_requested()
256     }
257 
258     /// Check if the specified vcpu has any pending interrupts. Returns None for no interrupts,
259     /// otherwise Some(u32) should be the injected interrupt vector. For KvmSplitIrqChip
260     /// this calls get_external_interrupt on the pic.
get_external_interrupt(&self, vcpu_id: usize) -> Option<u32>261     fn get_external_interrupt(&self, vcpu_id: usize) -> Option<u32> {
262         // Pic interrupts for the split irqchip only go to vcpu 0
263         if vcpu_id != 0 {
264             return None;
265         }
266         self.pic
267             .lock()
268             .get_external_interrupt()
269             .map(|vector| vector as u32)
270     }
271 }
272 
273 /// Convenience function for determining whether or not two irq routes conflict.
274 /// Returns true if they conflict.
routes_conflict(route: &IrqRoute, other: &IrqRoute) -> bool275 fn routes_conflict(route: &IrqRoute, other: &IrqRoute) -> bool {
276     // They don't conflict if they have different GSIs.
277     if route.gsi != other.gsi {
278         return false;
279     }
280 
281     // If they're both MSI with the same GSI then they conflict.
282     if let (IrqSource::Msi { .. }, IrqSource::Msi { .. }) = (route.source, other.source) {
283         return true;
284     }
285 
286     // If the route chips match and they have the same GSI then they conflict.
287     if let (
288         IrqSource::Irqchip {
289             chip: route_chip, ..
290         },
291         IrqSource::Irqchip {
292             chip: other_chip, ..
293         },
294     ) = (route.source, other.source)
295     {
296         return route_chip == other_chip;
297     }
298 
299     // Otherwise they do not conflict.
300     false
301 }
302 
303 /// This IrqChip only works with Kvm so we only implement it for KvmVcpu.
304 impl IrqChip for KvmSplitIrqChip {
305     /// Add a vcpu to the irq chip.
add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>306     fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()> {
307         let vcpu: &KvmVcpu = vcpu
308             .downcast_ref()
309             .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
310         self.vcpus.lock()[vcpu_id] = Some(vcpu.try_clone()?);
311         Ok(())
312     }
313 
314     /// 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>, ) -> Result<Option<IrqEventIndex>>315     fn register_irq_event(
316         &mut self,
317         irq: u32,
318         irq_event: &Event,
319         resample_event: Option<&Event>,
320     ) -> Result<Option<IrqEventIndex>> {
321         if irq < self.ioapic_pins as u32 {
322             let mut evt = IrqEvent {
323                 gsi: irq,
324                 event: irq_event.try_clone()?,
325                 resample_event: None,
326             };
327 
328             if let Some(resample_event) = resample_event {
329                 evt.resample_event = Some(resample_event.try_clone()?);
330             }
331 
332             let mut irq_events = self.irq_events.lock();
333             let index = irq_events.len();
334             irq_events.push(Some(evt));
335             Ok(Some(index))
336         } else {
337             self.vm.register_irqfd(irq, irq_event, resample_event)?;
338             Ok(None)
339         }
340     }
341 
342     /// Unregister an event for a particular GSI.
unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()>343     fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()> {
344         if irq < self.ioapic_pins as u32 {
345             let mut irq_events = self.irq_events.lock();
346             for (index, evt) in irq_events.iter().enumerate() {
347                 if let Some(evt) = evt {
348                     if evt.gsi == irq && irq_event.eq(&evt.event) {
349                         irq_events[index] = None;
350                         break;
351                     }
352                 }
353             }
354             Ok(())
355         } else {
356             self.vm.unregister_irqfd(irq, irq_event)
357         }
358     }
359 
360     /// Route an IRQ line to an interrupt controller, or to a particular MSI vector.
route_irq(&mut self, route: IrqRoute) -> Result<()>361     fn route_irq(&mut self, route: IrqRoute) -> Result<()> {
362         let mut routes = self.routes.lock();
363         routes.retain(|r| !routes_conflict(r, &route));
364 
365         routes.push(route);
366 
367         // We only call set_gsi_routing with the msi routes
368         let mut msi_routes = routes.clone();
369         msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
370 
371         self.vm.set_gsi_routing(&*msi_routes)
372     }
373 
374     /// Replace all irq routes with the supplied routes
set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>375     fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()> {
376         let mut current_routes = self.routes.lock();
377         *current_routes = routes.to_vec();
378 
379         // We only call set_gsi_routing with the msi routes
380         let mut msi_routes = routes.to_vec();
381         msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
382 
383         self.vm.set_gsi_routing(&*msi_routes)
384     }
385 
386     /// Return a vector of all registered irq numbers and their associated events and event
387     /// indices. These should be used by the main thread to wait for irq events.
irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, u32, Event)>>388     fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, u32, Event)>> {
389         let mut tokens: Vec<(IrqEventIndex, u32, Event)> = Vec::new();
390         for (index, evt) in self.irq_events.lock().iter().enumerate() {
391             if let Some(evt) = evt {
392                 tokens.push((index, evt.gsi, evt.event.try_clone()?));
393             }
394         }
395         Ok(tokens)
396     }
397 
398     /// Either assert or deassert an IRQ line.  Sends to either an interrupt controller, or does
399     /// a send_msi if the irq is associated with an MSI.
service_irq(&mut self, irq: u32, level: bool) -> Result<()>400     fn service_irq(&mut self, irq: u32, level: bool) -> Result<()> {
401         let chips = self.routes_to_chips(irq);
402         for (chip, pin) in chips {
403             match chip {
404                 IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
405                     self.pic.lock().service_irq(pin as u8, level);
406                 }
407                 IrqSourceChip::Ioapic => {
408                     self.ioapic.lock().service_irq(pin as usize, level);
409                 }
410                 _ => {}
411             }
412         }
413         Ok(())
414     }
415 
416     /// Service an IRQ event by asserting then deasserting an IRQ line. The associated Event
417     /// that triggered the irq event will be read from. If the irq is associated with a resample
418     /// Event, then the deassert will only happen after an EOI is broadcast for a vector
419     /// associated with the irq line.
420     /// For the KvmSplitIrqChip, this function identifies which chips the irq routes to, then
421     /// attempts to call service_irq on those chips. If the ioapic is unable to be immediately
422     /// locked, we add the irq to the delayed_ioapic_irq_events Vec (though we still read
423     /// from the Event that triggered the irq event).
service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>424     fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()> {
425         if let Some(evt) = &self.irq_events.lock()[event_index] {
426             evt.event.read()?;
427             let chips = self.routes_to_chips(evt.gsi);
428 
429             for (chip, pin) in chips {
430                 match chip {
431                     IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
432                         let mut pic = self.pic.lock();
433                         if evt.resample_event.is_some() {
434                             pic.service_irq(pin as u8, true);
435                         } else {
436                             pic.service_irq(pin as u8, true);
437                             pic.service_irq(pin as u8, false);
438                         }
439                     }
440                     IrqSourceChip::Ioapic => {
441                         if let Ok(mut ioapic) = self.ioapic.try_lock() {
442                             if evt.resample_event.is_some() {
443                                 ioapic.service_irq(pin as usize, true);
444                             } else {
445                                 ioapic.service_irq(pin as usize, true);
446                                 ioapic.service_irq(pin as usize, false);
447                             }
448                         } else {
449                             self.delayed_ioapic_irq_events.lock().push(event_index);
450                         }
451                     }
452                     _ => {}
453                 }
454             }
455         }
456 
457         Ok(())
458     }
459 
460     /// Broadcast an end of interrupt. For KvmSplitIrqChip this sends the EOI to the ioapic
broadcast_eoi(&self, vector: u8) -> Result<()>461     fn broadcast_eoi(&self, vector: u8) -> Result<()> {
462         self.ioapic.lock().end_of_interrupt(vector);
463         Ok(())
464     }
465 
466     /// Injects any pending interrupts for `vcpu`.
467     /// For KvmSplitIrqChip this injects any PIC interrupts on vcpu_id 0.
inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>468     fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()> {
469         let vcpu: &KvmVcpu = vcpu
470             .downcast_ref()
471             .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
472 
473         let vcpu_id = vcpu.id();
474         if !self.interrupt_requested(vcpu_id) || !vcpu.ready_for_interrupt() {
475             return Ok(());
476         }
477 
478         if let Some(vector) = self.get_external_interrupt(vcpu_id) {
479             vcpu.interrupt(vector)?;
480         }
481 
482         // The second interrupt request should be handled immediately, so ask vCPU to exit as soon as
483         // possible.
484         if self.interrupt_requested(vcpu_id) {
485             vcpu.set_interrupt_window_requested(true);
486         }
487         Ok(())
488     }
489 
490     /// Notifies the irq chip that the specified VCPU has executed a halt instruction.
491     /// For KvmSplitIrqChip this is a no-op because KVM handles VCPU blocking.
halted(&self, _vcpu_id: usize)492     fn halted(&self, _vcpu_id: usize) {}
493 
494     /// Blocks until `vcpu` is in a runnable state or until interrupted by
495     /// `IrqChip::kick_halted_vcpus`.  Returns `VcpuRunState::Runnable if vcpu is runnable, or
496     /// `VcpuRunState::Interrupted` if the wait was interrupted.
497     /// For KvmSplitIrqChip this is a no-op and always returns Runnable because KVM handles VCPU
498     /// blocking.
wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState>499     fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> {
500         Ok(VcpuRunState::Runnable)
501     }
502 
503     /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.
504     /// For KvmSplitIrqChip this is a no-op because KVM handles VCPU blocking.
kick_halted_vcpus(&self)505     fn kick_halted_vcpus(&self) {}
506 
507     /// Get the current MP state of the specified VCPU.
get_mp_state(&self, vcpu_id: usize) -> Result<MPState>508     fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState> {
509         match self.vcpus.lock().get(vcpu_id) {
510             Some(Some(vcpu)) => Ok(MPState::from(&vcpu.get_mp_state()?)),
511             _ => Err(Error::new(libc::ENOENT)),
512         }
513     }
514 
515     /// Set the current MP state of the specified VCPU.
set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>516     fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()> {
517         match self.vcpus.lock().get(vcpu_id) {
518             Some(Some(vcpu)) => vcpu.set_mp_state(&kvm_mp_state::from(state)),
519             _ => Err(Error::new(libc::ENOENT)),
520         }
521     }
522 
523     /// Attempt to clone this IrqChip instance.
try_clone(&self) -> Result<Self>524     fn try_clone(&self) -> Result<Self> {
525         Ok(KvmSplitIrqChip {
526             vm: self.vm.try_clone()?,
527             vcpus: self.vcpus.clone(),
528             routes: self.routes.clone(),
529             pit: self.pit.clone(),
530             pic: self.pic.clone(),
531             ioapic: self.ioapic.clone(),
532             ioapic_pins: self.ioapic_pins,
533             delayed_ioapic_irq_events: self.delayed_ioapic_irq_events.clone(),
534             irq_events: self.irq_events.clone(),
535         })
536     }
537 
538     /// Finalize irqchip setup. Should be called once all devices have registered irq events and
539     /// been added to the io_bus and mmio_bus.
finalize_devices( &mut self, resources: &mut SystemAllocator, io_bus: &mut Bus, mmio_bus: &mut Bus, ) -> Result<()>540     fn finalize_devices(
541         &mut self,
542         resources: &mut SystemAllocator,
543         io_bus: &mut Bus,
544         mmio_bus: &mut Bus,
545     ) -> Result<()> {
546         // Insert pit into io_bus
547         io_bus.insert(self.pit.clone(), 0x040, 0x8).unwrap();
548         io_bus.insert(self.pit.clone(), 0x061, 0x1).unwrap();
549 
550         // Insert pic into io_bus
551         io_bus.insert(self.pic.clone(), 0x20, 0x2).unwrap();
552         io_bus.insert(self.pic.clone(), 0xa0, 0x2).unwrap();
553         io_bus.insert(self.pic.clone(), 0x4d0, 0x2).unwrap();
554 
555         // Insert ioapic into mmio_bus
556         mmio_bus
557             .insert(
558                 self.ioapic.clone(),
559                 IOAPIC_BASE_ADDRESS,
560                 IOAPIC_MEM_LENGTH_BYTES,
561             )
562             .unwrap();
563 
564         // At this point, all of our devices have been created and they have registered their
565         // irq events, so we can clone our resample events
566         let mut ioapic_resample_events: Vec<Vec<Event>> =
567             (0..self.ioapic_pins).map(|_| Vec::new()).collect();
568         let mut pic_resample_events: Vec<Vec<Event>> =
569             (0..self.ioapic_pins).map(|_| Vec::new()).collect();
570 
571         for evt in self.irq_events.lock().iter() {
572             if let Some(evt) = evt {
573                 if (evt.gsi as usize) >= self.ioapic_pins {
574                     continue;
575                 }
576                 if let Some(resample_evt) = &evt.resample_event {
577                     ioapic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
578                     pic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
579                 }
580             }
581         }
582 
583         // Register resample events with the ioapic
584         self.ioapic
585             .lock()
586             .register_resample_events(ioapic_resample_events);
587         // Register resample events with the pic
588         self.pic
589             .lock()
590             .register_resample_events(pic_resample_events);
591 
592         // Make sure all future irq numbers are beyond IO-APIC range.
593         let mut irq_num = resources.allocate_irq().unwrap();
594         while irq_num < self.ioapic_pins as u32 {
595             irq_num = resources.allocate_irq().unwrap();
596         }
597 
598         Ok(())
599     }
600 
601     /// The KvmSplitIrqChip's ioapic may be locked because a vcpu thread is currently writing to
602     /// the ioapic, and the ioapic may be blocking on adding MSI routes, which requires blocking
603     /// socket communication back to the main thread.  Thus, we do not want the main thread to
604     /// block on a locked ioapic, so any irqs that could not be serviced because the ioapic could
605     /// not be immediately locked are added to the delayed_ioapic_irq_events Vec. This function
606     /// processes each delayed event in the vec each time it's called. If the ioapic is still
607     /// locked, we keep the queued irqs for the next time this function is called.
process_delayed_irq_events(&mut self) -> Result<()>608     fn process_delayed_irq_events(&mut self) -> Result<()> {
609         self.delayed_ioapic_irq_events
610             .lock()
611             .retain(|&event_index| {
612                 if let Some(evt) = &self.irq_events.lock()[event_index] {
613                     if let Ok(mut ioapic) = self.ioapic.try_lock() {
614                         if evt.resample_event.is_some() {
615                             ioapic.service_irq(evt.gsi as usize, true);
616                         } else {
617                             ioapic.service_irq(evt.gsi as usize, true);
618                             ioapic.service_irq(evt.gsi as usize, false);
619                         }
620 
621                         false
622                     } else {
623                         true
624                     }
625                 } else {
626                     true
627                 }
628             });
629 
630         Ok(())
631     }
632 
check_capability(&self, c: IrqChipCap) -> bool633     fn check_capability(&self, c: IrqChipCap) -> bool {
634         match c {
635             IrqChipCap::TscDeadlineTimer => self
636                 .vm
637                 .get_hypervisor()
638                 .check_capability(&HypervisorCap::TscDeadlineTimer),
639             IrqChipCap::X2Apic => true,
640         }
641     }
642 }
643 
644 impl IrqChipX86_64 for KvmSplitIrqChip {
645     /// Get the current state of the PIC
get_pic_state(&self, select: PicSelect) -> Result<PicState>646     fn get_pic_state(&self, select: PicSelect) -> Result<PicState> {
647         Ok(self.pic.lock().get_pic_state(select))
648     }
649 
650     /// Set the current state of the PIC
set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>651     fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()> {
652         self.pic.lock().set_pic_state(select, state);
653         Ok(())
654     }
655 
656     /// Get the current state of the IOAPIC
get_ioapic_state(&self) -> Result<IoapicState>657     fn get_ioapic_state(&self) -> Result<IoapicState> {
658         Ok(self.ioapic.lock().get_ioapic_state())
659     }
660 
661     /// Set the current state of the IOAPIC
set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>662     fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()> {
663         self.ioapic.lock().set_ioapic_state(state);
664         Ok(())
665     }
666 
667     /// Get the current state of the specified VCPU's local APIC
get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>668     fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
669         match self.vcpus.lock().get(vcpu_id) {
670             Some(Some(vcpu)) => Ok(LapicState::from(&vcpu.get_lapic()?)),
671             _ => Err(Error::new(libc::ENOENT)),
672         }
673     }
674 
675     /// Set the current state of the specified VCPU's local APIC
set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>676     fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()> {
677         match self.vcpus.lock().get(vcpu_id) {
678             Some(Some(vcpu)) => vcpu.set_lapic(&kvm_lapic_state::from(state)),
679             _ => Err(Error::new(libc::ENOENT)),
680         }
681     }
682 
683     /// Retrieves the state of the PIT. Gets the pit state via the KVM API.
get_pit(&self) -> Result<PitState>684     fn get_pit(&self) -> Result<PitState> {
685         Ok(self.pit.lock().get_pit_state())
686     }
687 
688     /// Sets the state of the PIT. Sets the pit state via the KVM API.
set_pit(&mut self, state: &PitState) -> Result<()>689     fn set_pit(&mut self, state: &PitState) -> Result<()> {
690         self.pit.lock().set_pit_state(state);
691         Ok(())
692     }
693 
694     /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused.
695     /// devices::Pit uses 0x61.
pit_uses_speaker_port(&self) -> bool696     fn pit_uses_speaker_port(&self) -> bool {
697         true
698     }
699 }
700 
701 #[cfg(test)]
702 mod tests {
703 
704     use super::*;
705     use base::EventReadResult;
706     use hypervisor::kvm::Kvm;
707     use vm_memory::GuestMemory;
708 
709     use hypervisor::{IoapicRedirectionTableEntry, PitRWMode, TriggerMode, Vm, VmX86_64};
710 
711     use super::super::super::tests::*;
712     use crate::IrqChip;
713 
714     /// Helper function for setting up a KvmKernelIrqChip
get_kernel_chip() -> KvmKernelIrqChip715     fn get_kernel_chip() -> KvmKernelIrqChip {
716         let kvm = Kvm::new().expect("failed to instantiate Kvm");
717         let mem = GuestMemory::new(&[]).unwrap();
718         let vm = KvmVm::new(&kvm, mem).expect("failed tso instantiate vm");
719 
720         let mut chip = KvmKernelIrqChip::new(vm.try_clone().expect("failed to clone vm"), 1)
721             .expect("failed to instantiate KvmKernelIrqChip");
722 
723         let vcpu = vm.create_vcpu(0).expect("failed to instantiate vcpu");
724         chip.add_vcpu(0, vcpu.as_vcpu())
725             .expect("failed to add vcpu");
726 
727         chip
728     }
729 
730     /// Helper function for setting up a KvmSplitIrqChip
get_split_chip() -> KvmSplitIrqChip731     fn get_split_chip() -> KvmSplitIrqChip {
732         let kvm = Kvm::new().expect("failed to instantiate Kvm");
733         let mem = GuestMemory::new(&[]).unwrap();
734         let vm = KvmVm::new(&kvm, mem).expect("failed tso instantiate vm");
735 
736         let (_, device_tube) = Tube::pair().expect("failed to create irq tube");
737 
738         let mut chip = KvmSplitIrqChip::new(
739             vm.try_clone().expect("failed to clone vm"),
740             1,
741             device_tube,
742             None,
743         )
744         .expect("failed to instantiate KvmKernelIrqChip");
745 
746         let vcpu = vm.create_vcpu(0).expect("failed to instantiate vcpu");
747         chip.add_vcpu(0, vcpu.as_vcpu())
748             .expect("failed to add vcpu");
749         chip
750     }
751 
752     #[test]
kernel_irqchip_get_pic()753     fn kernel_irqchip_get_pic() {
754         test_get_pic(get_kernel_chip());
755     }
756 
757     #[test]
kernel_irqchip_set_pic()758     fn kernel_irqchip_set_pic() {
759         test_set_pic(get_kernel_chip());
760     }
761 
762     #[test]
kernel_irqchip_get_ioapic()763     fn kernel_irqchip_get_ioapic() {
764         test_get_ioapic(get_kernel_chip());
765     }
766 
767     #[test]
kernel_irqchip_set_ioapic()768     fn kernel_irqchip_set_ioapic() {
769         test_set_ioapic(get_kernel_chip());
770     }
771 
772     #[test]
kernel_irqchip_get_pit()773     fn kernel_irqchip_get_pit() {
774         test_get_pit(get_kernel_chip());
775     }
776 
777     #[test]
kernel_irqchip_set_pit()778     fn kernel_irqchip_set_pit() {
779         test_set_pit(get_kernel_chip());
780     }
781 
782     #[test]
kernel_irqchip_get_lapic()783     fn kernel_irqchip_get_lapic() {
784         test_get_lapic(get_kernel_chip())
785     }
786 
787     #[test]
kernel_irqchip_set_lapic()788     fn kernel_irqchip_set_lapic() {
789         test_set_lapic(get_kernel_chip())
790     }
791 
792     #[test]
kernel_irqchip_route_irq()793     fn kernel_irqchip_route_irq() {
794         test_route_irq(get_kernel_chip());
795     }
796 
797     #[test]
split_irqchip_get_pic()798     fn split_irqchip_get_pic() {
799         test_get_pic(get_split_chip());
800     }
801 
802     #[test]
split_irqchip_set_pic()803     fn split_irqchip_set_pic() {
804         test_set_pic(get_split_chip());
805     }
806 
807     #[test]
split_irqchip_get_ioapic()808     fn split_irqchip_get_ioapic() {
809         test_get_ioapic(get_split_chip());
810     }
811 
812     #[test]
split_irqchip_set_ioapic()813     fn split_irqchip_set_ioapic() {
814         test_set_ioapic(get_split_chip());
815     }
816 
817     #[test]
split_irqchip_get_pit()818     fn split_irqchip_get_pit() {
819         test_get_pit(get_split_chip());
820     }
821 
822     #[test]
split_irqchip_set_pit()823     fn split_irqchip_set_pit() {
824         test_set_pit(get_split_chip());
825     }
826 
827     #[test]
split_irqchip_route_irq()828     fn split_irqchip_route_irq() {
829         test_route_irq(get_split_chip());
830     }
831 
832     #[test]
split_irqchip_routes_conflict()833     fn split_irqchip_routes_conflict() {
834         let mut chip = get_split_chip();
835         chip.route_irq(IrqRoute {
836             gsi: 5,
837             source: IrqSource::Msi {
838                 address: 4276092928,
839                 data: 0,
840             },
841         })
842         .expect("failed to set msi rout");
843         // this second route should replace the first
844         chip.route_irq(IrqRoute {
845             gsi: 5,
846             source: IrqSource::Msi {
847                 address: 4276092928,
848                 data: 32801,
849             },
850         })
851         .expect("failed to set msi rout");
852     }
853 
854     #[test]
irq_event_tokens()855     fn irq_event_tokens() {
856         let mut chip = get_split_chip();
857         let tokens = chip
858             .irq_event_tokens()
859             .expect("could not get irq_event_tokens");
860 
861         // there should be one token on a fresh split irqchip, for the pit
862         assert_eq!(tokens.len(), 1);
863         assert_eq!(tokens[0].1, 0);
864 
865         // register another irq event
866         let evt = Event::new().expect("failed to create event");
867         chip.register_irq_event(6, &evt, None)
868             .expect("failed to register irq event");
869 
870         let tokens = chip
871             .irq_event_tokens()
872             .expect("could not get irq_event_tokens");
873 
874         // now there should be two tokens
875         assert_eq!(tokens.len(), 2);
876         assert_eq!(tokens[0].1, 0);
877         assert_eq!(tokens[1].1, 6);
878         assert_eq!(tokens[1].2, evt);
879     }
880 
881     #[test]
finalize_devices()882     fn finalize_devices() {
883         let mut chip = get_split_chip();
884 
885         let mut mmio_bus = Bus::new();
886         let mut io_bus = Bus::new();
887         let mut resources = SystemAllocator::builder()
888             .add_io_addresses(0xc000, 0x10000)
889             .add_low_mmio_addresses(0, 2048)
890             .add_high_mmio_addresses(2048, 4096)
891             .create_allocator(5)
892             .expect("failed to create SystemAllocator");
893 
894         // setup an event and a resample event for irq line 1
895         let evt = Event::new().expect("failed to create event");
896         let mut resample_evt = Event::new().expect("failed to create event");
897 
898         let evt_index = chip
899             .register_irq_event(1, &evt, Some(&resample_evt))
900             .expect("failed to register_irq_event")
901             .expect("register_irq_event should not return None");
902 
903         // Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses
904         chip.finalize_devices(&mut resources, &mut io_bus, &mut mmio_bus)
905             .expect("failed to finalize devices");
906 
907         // Should not be able to allocate an irq < 24 now
908         assert!(resources.allocate_irq().expect("failed to allocate irq") >= 24);
909 
910         // set PIT counter 2 to "SquareWaveGen"(aka 3) mode and "Both" access mode
911         io_bus.write(0x43, &[0b10110110]);
912 
913         let state = chip.get_pit().expect("failed to get pit state");
914         assert_eq!(state.channels[2].mode, 3);
915         assert_eq!(state.channels[2].rw_mode, PitRWMode::Both);
916 
917         // ICW1 0x11: Edge trigger, cascade mode, ICW4 needed.
918         // ICW2 0x08: Interrupt vector base address 0x08.
919         // ICW3 0xff: Value written does not matter.
920         // ICW4 0x13: Special fully nested mode, auto EOI.
921         io_bus.write(0x20, &[0x11]);
922         io_bus.write(0x21, &[0x08]);
923         io_bus.write(0x21, &[0xff]);
924         io_bus.write(0x21, &[0x13]);
925 
926         let state = chip
927             .get_pic_state(PicSelect::Primary)
928             .expect("failed to get pic state");
929 
930         // auto eoi and special fully nested mode should be turned on
931         assert!(state.auto_eoi);
932         assert!(state.special_fully_nested_mode);
933 
934         // Need to write to the irq event before servicing it
935         evt.write(1).expect("failed to write to event");
936 
937         // if we assert irq line one, and then get the resulting interrupt, an auto-eoi should
938         // occur and cause the resample_event to be written to
939         chip.service_irq_event(evt_index)
940             .expect("failed to service irq");
941 
942         assert!(chip.interrupt_requested(0));
943         assert_eq!(
944             chip.get_external_interrupt(0)
945                 .expect("failed to get external interrupt"),
946             // Vector is 9 because the interrupt vector base address is 0x08 and this is irq
947             // line 1 and 8+1 = 9
948             0x9
949         );
950 
951         assert_eq!(
952             resample_evt
953                 .read_timeout(std::time::Duration::from_secs(1))
954                 .expect("failed to read_timeout"),
955             EventReadResult::Count(1)
956         );
957 
958         // setup a ioapic redirection table entry 14
959         let mut entry = IoapicRedirectionTableEntry::default();
960         entry.set_vector(44);
961 
962         let irq_14_offset = 0x10 + 14 * 2;
963         mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_14_offset]);
964         mmio_bus.write(
965             IOAPIC_BASE_ADDRESS + 0x10,
966             &(entry.get(0, 32) as u32).to_ne_bytes(),
967         );
968         mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_14_offset + 1]);
969         mmio_bus.write(
970             IOAPIC_BASE_ADDRESS + 0x10,
971             &(entry.get(32, 32) as u32).to_ne_bytes(),
972         );
973 
974         let state = chip.get_ioapic_state().expect("failed to get ioapic state");
975 
976         // redirection table entry 14 should have a vector of 44
977         assert_eq!(state.redirect_table[14].get_vector(), 44);
978     }
979 
980     #[test]
get_external_interrupt()981     fn get_external_interrupt() {
982         let mut chip = get_split_chip();
983         assert!(!chip.interrupt_requested(0));
984 
985         chip.service_irq(0, true).expect("failed to service irq");
986         assert!(chip.interrupt_requested(0));
987 
988         // Should return Some interrupt
989         assert_eq!(
990             chip.get_external_interrupt(0)
991                 .expect("failed to get external interrupt"),
992             0,
993         );
994 
995         // interrupt is not requested twice
996         assert!(!chip.interrupt_requested(0));
997     }
998 
999     #[test]
broadcast_eoi()1000     fn broadcast_eoi() {
1001         let mut chip = get_split_chip();
1002 
1003         let mut mmio_bus = Bus::new();
1004         let mut io_bus = Bus::new();
1005         let mut resources = SystemAllocator::builder()
1006             .add_io_addresses(0xc000, 0x10000)
1007             .add_low_mmio_addresses(0, 2048)
1008             .add_high_mmio_addresses(2048, 4096)
1009             .create_allocator(5)
1010             .expect("failed to create SystemAllocator");
1011 
1012         // setup an event and a resample event for irq line 1
1013         let evt = Event::new().expect("failed to create event");
1014         let mut resample_evt = Event::new().expect("failed to create event");
1015 
1016         chip.register_irq_event(1, &evt, Some(&resample_evt))
1017             .expect("failed to register_irq_event");
1018 
1019         // Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses
1020         chip.finalize_devices(&mut resources, &mut io_bus, &mut mmio_bus)
1021             .expect("failed to finalize devices");
1022 
1023         // setup a ioapic redirection table entry 1 with a vector of 123
1024         let mut entry = IoapicRedirectionTableEntry::default();
1025         entry.set_vector(123);
1026         entry.set_trigger_mode(TriggerMode::Level);
1027 
1028         let irq_write_offset = 0x10 + 1 * 2;
1029         mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_write_offset]);
1030         mmio_bus.write(
1031             IOAPIC_BASE_ADDRESS + 0x10,
1032             &(entry.get(0, 32) as u32).to_ne_bytes(),
1033         );
1034         mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_write_offset + 1]);
1035         mmio_bus.write(
1036             IOAPIC_BASE_ADDRESS + 0x10,
1037             &(entry.get(32, 32) as u32).to_ne_bytes(),
1038         );
1039 
1040         // Assert line 1
1041         chip.service_irq(1, true).expect("failed to service irq");
1042 
1043         // resample event should not be written to
1044         assert_eq!(
1045             resample_evt
1046                 .read_timeout(std::time::Duration::from_millis(10))
1047                 .expect("failed to read_timeout"),
1048             EventReadResult::Timeout
1049         );
1050 
1051         // irq line 1 should be asserted
1052         let state = chip.get_ioapic_state().expect("failed to get ioapic state");
1053         assert_eq!(state.current_interrupt_level_bitmap, 1 << 1);
1054 
1055         // Now broadcast an eoi for vector 123
1056         chip.broadcast_eoi(123).expect("failed to broadcast eoi");
1057 
1058         // irq line 1 should be deasserted
1059         let state = chip.get_ioapic_state().expect("failed to get ioapic state");
1060         assert_eq!(state.current_interrupt_level_bitmap, 0);
1061 
1062         // resample event should be written to by ioapic
1063         assert_eq!(
1064             resample_evt
1065                 .read_timeout(std::time::Duration::from_millis(10))
1066                 .expect("failed to read_timeout"),
1067             EventReadResult::Count(1)
1068         );
1069     }
1070 }
1071