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