diff options
author | Zhuocheng Ding <zhuocheng.ding@intel.corp-partner.google.com> | 2019-12-02 15:50:28 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-05 13:12:23 +0000 |
commit | b9f4c9bca30e65eacfb055951fa994ad5127a8f0 (patch) | |
tree | 8c8c886824f819620cf6d5c8b39ee4571ed7fb9b /devices | |
parent | 2f7dabbd6a0d8620e4b19b92cdae24c08e4c7ccc (diff) | |
download | crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.gz crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.bz2 crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.lz crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.xz crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.zst crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.zip |
crosvm: Add plumbing for split-irqchip interrupts
Devices use irqfd to inject interrupts, we listen to them in the main thread and activate userspace pic/ioapic accordingly. BUG=chromium:908689 TEST=lanuch linux guest with `--split-irqchip` flag Change-Id: If30d17ce7ec9e26dba782c89cc1b9b2ff897a70d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1945798 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Stephen Barber <smbarber@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Zhuocheng Ding <zhuocheng.ding@intel.corp-partner.google.com>
Diffstat (limited to 'devices')
-rw-r--r-- | devices/src/ioapic.rs | 13 | ||||
-rw-r--r-- | devices/src/pic.rs | 37 | ||||
-rw-r--r-- | devices/src/split_irqchip_common.rs | 34 |
3 files changed, 63 insertions, 21 deletions
diff --git a/devices/src/ioapic.rs b/devices/src/ioapic.rs index e1fbfb8..09ccb89 100644 --- a/devices/src/ioapic.rs +++ b/devices/src/ioapic.rs @@ -10,6 +10,7 @@ use crate::BusDevice; use bit_field::*; use kvm::Vm; use msg_socket::{MsgReceiver, MsgSender}; +use std::sync::Arc; use sys_util::{error, warn, EventFd, Result}; use vm_control::{VmIrqRequest, VmIrqRequestSocket, VmIrqResponse}; @@ -89,6 +90,7 @@ pub struct Ioapic { redirect_table: [RedirectionTableEntry; kvm::NUM_IOAPIC_PINS], // IOREGSEL is technically 32 bits, but only bottom 8 are writable: all others are fixed to 0. ioregsel: u8, + relay: Arc<GsiRelay>, irqfd: Vec<EventFd>, socket: VmIrqRequestSocket, } @@ -166,11 +168,16 @@ impl Ioapic { current_interrupt_level_bitmap: 0, redirect_table: entries, ioregsel: 0, + relay: Default::default(), irqfd, socket, }) } + pub fn register_relay(&mut self, relay: Arc<GsiRelay>) { + self.relay = relay; + } + // The ioapic must be informed about EOIs in order to avoid sending multiple interrupts of the // same type at the same time. pub fn end_of_interrupt(&mut self, vector: u8) { @@ -183,6 +190,12 @@ impl Ioapic { if self.redirect_table[i].get_vector() == vector && self.redirect_table[i].get_trigger_mode() == TriggerMode::Level { + if self.relay.irqfd_resample[i].is_some() { + self.service_irq(i, false); + } + if let Some(resample_evt) = &self.relay.irqfd_resample[i] { + resample_evt.write(1).unwrap(); + } self.redirect_table[i].set_remote_irr(false); } // There is an inherent race condition in hardware if the OS is finished processing an diff --git a/devices/src/pic.rs b/devices/src/pic.rs index c18abef..f562be6 100644 --- a/devices/src/pic.rs +++ b/devices/src/pic.rs @@ -12,7 +12,9 @@ // For the purposes of both using more descriptive terms and avoiding terms with lots of charged // emotional context, this file refers to them instead as "primary" and "secondary" PICs. +use crate::split_irqchip_common::GsiRelay; use crate::BusDevice; +use std::sync::Arc; use sys_util::{debug, warn}; #[repr(usize)] @@ -30,7 +32,7 @@ enum PicInitState { Icw4 = 3, } -#[derive(Debug, Default, Clone, Copy, PartialEq)] +#[derive(Default)] struct PicState { last_irr: u8, // Edge detection. irr: u8, // Interrupt Request Register. @@ -53,6 +55,8 @@ struct PicState { elcr: u8, elcr_mask: u8, init_state: Option<PicInitState>, + is_primary: bool, + relay: Arc<GsiRelay>, } pub struct Pic { @@ -176,12 +180,18 @@ impl Pic { // that should be masked here. In this case, bits 8 - 8 = 0 and 13 - 8 = 5. secondary_pic.elcr_mask = !((1 << 0) | (1 << 5)); + primary_pic.is_primary = true; Pic { interrupt_request: false, pics: [primary_pic, secondary_pic], } } + pub fn register_relay(&mut self, relay: Arc<GsiRelay>) { + self.pics[0].relay = relay.clone(); + self.pics[1].relay = relay; + } + pub fn service_irq(&mut self, irq: u8, level: bool) -> bool { assert!(irq <= 15, "Unexpectedly high value irq: {} vs 15", irq); @@ -391,6 +401,11 @@ impl Pic { fn clear_isr(pic: &mut PicState, irq: u8) { assert!(irq <= 7, "Unexpectedly high value for irq: {} vs 7", irq); pic.isr &= !(1 << irq); + Pic::set_irq_internal(pic, irq, false); + let irq = if pic.is_primary { irq } else { irq + 8 }; + if let Some(resample_evt) = &pic.relay.irqfd_resample[irq as usize] { + resample_evt.write(1).unwrap(); + } } fn update_irq(&mut self) -> bool { @@ -1088,26 +1103,6 @@ mod tests { assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 6); } - /// Verify that no-op doesn't change state. - #[test] - fn no_op_ocw2() { - let mut data = set_up(); - icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); - - // TODO(mutexlox): Verify APIC interaction when it is implemented. - data.pic.service_irq(/*irq=*/ 5, /*level=*/ true); - assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5)); - data.pic.service_irq(/*irq=*/ 5, /*level=*/ false); - - let orig = data.pic.pics[PicSelect::Primary as usize].clone(); - - // Run a no-op. - data.pic.write(PIC_PRIMARY_COMMAND, &[0x40]); - - // Nothing should have changed. - assert_eq!(orig, data.pic.pics[PicSelect::Primary as usize]); - } - /// Tests cascade IRQ that happens on secondary PIC. #[test] fn cascade_irq() { diff --git a/devices/src/split_irqchip_common.rs b/devices/src/split_irqchip_common.rs index b54c35a..1e513f2 100644 --- a/devices/src/split_irqchip_common.rs +++ b/devices/src/split_irqchip_common.rs @@ -5,6 +5,7 @@ // Common constants and types used for Split IRQ chip devices (e.g. PIC, PIT, IOAPIC). use bit_field::*; +use sys_util::EventFd; #[bitfield] #[derive(Clone, Copy, Debug, PartialEq)] @@ -58,3 +59,36 @@ pub struct MsiDataMessage { trigger: TriggerMode, reserved2: BitField16, } + +/// Acts as a relay of interrupt signals between devices and IRQ chips. +#[derive(Default)] +pub struct GsiRelay { + pub irqfd: [Option<EventFd>; kvm::NUM_IOAPIC_PINS], + pub irqfd_resample: [Option<EventFd>; kvm::NUM_IOAPIC_PINS], +} + +impl GsiRelay { + pub fn new() -> GsiRelay { + GsiRelay { + irqfd: Default::default(), + irqfd_resample: Default::default(), + } + } + + pub fn register_irqfd(&mut self, evt: EventFd, gsi: usize) { + if gsi >= kvm::NUM_IOAPIC_PINS { + // Invalid gsi; ignore. + return; + } + self.irqfd[gsi] = Some(evt); + } + + pub fn register_irqfd_resample(&mut self, evt: EventFd, resample_evt: EventFd, gsi: usize) { + if gsi >= kvm::NUM_IOAPIC_PINS { + // Invalid gsi; ignore. + return; + } + self.irqfd[gsi] = Some(evt); + self.irqfd_resample[gsi] = Some(resample_evt); + } +} |