diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 61ddab8ef..d19eb0973 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -5,12 +5,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-BSD-3-Clause file. +use crate::{BusDevice, Interrupt}; use std::collections::VecDeque; use std::{io, result}; - -use vmm_sys_util::{EventFd, Result}; - -use BusDevice; +use vmm_sys_util::Result; const LOOP_SIZE: usize = 0x40; @@ -57,7 +55,7 @@ const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps pub struct Serial { interrupt_enable: u8, interrupt_identification: u8, - interrupt_evt: EventFd, + interrupt: Box, line_control: u8, line_status: u8, modem_control: u8, @@ -69,11 +67,11 @@ pub struct Serial { } impl Serial { - fn new(interrupt_evt: EventFd, out: Option>) -> Serial { + fn new(interrupt: Box, out: Option>) -> Serial { Serial { interrupt_enable: 0, interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION, - interrupt_evt, + interrupt, line_control: DEFAULT_LINE_CONTROL, line_status: DEFAULT_LINE_STATUS, modem_control: DEFAULT_MODEM_CONTROL, @@ -86,13 +84,13 @@ impl Serial { } /// Constructs a Serial port ready for output. - pub fn new_out(interrupt_evt: EventFd, out: Box) -> Serial { - Self::new(interrupt_evt, Some(out)) + pub fn new_out(interrupt: Box, out: Box) -> Serial { + Self::new(interrupt, Some(out)) } /// Constructs a Serial port with no connected output. - pub fn new_sink(interrupt_evt: EventFd) -> Serial { - Self::new(interrupt_evt, None) + pub fn new_sink(interrupt: Box) -> Serial { + Self::new(interrupt, None) } /// Queues raw bytes for the guest to read and signals the interrupt if the line status would @@ -151,7 +149,7 @@ impl Serial { } fn trigger_interrupt(&mut self) -> result::Result<(), io::Error> { - self.interrupt_evt.write(1) + self.interrupt.deliver() } fn iir_reset(&mut self) { diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 9f5ffcf7e..49e53c547 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -14,7 +14,7 @@ extern crate vm_memory; extern crate vmm_sys_util; use std::fs::File; -use std::io; +use std::{io, result}; mod bus; pub mod legacy; @@ -58,3 +58,7 @@ pub enum Error { }, IoError(io::Error), } + +pub trait Interrupt: Send { + fn deliver(&self) -> result::Result<(), std::io::Error>; +} diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index e5a6c00e9..b38c71d54 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -135,9 +135,6 @@ pub enum Error { /// Cannot setup terminal in canonical mode. SetTerminalCanon(vmm_sys_util::Error), - /// Cannot configure the IRQ. - Irq(io::Error), - /// Cannot create the system allocator CreateSystemAllocator, @@ -371,13 +368,28 @@ impl Vcpu { } } +struct KernelIoapicIrq { + evt: EventFd, +} + +impl KernelIoapicIrq { + fn new(evt: EventFd) -> Self { + KernelIoapicIrq { evt } + } +} + +impl devices::Interrupt for KernelIoapicIrq { + fn deliver(&self) -> result::Result<(), io::Error> { + self.evt.write(1) + } +} + struct DeviceManager { io_bus: devices::Bus, mmio_bus: devices::Bus, // Serial port on 0x3f8 serial: Arc>, - serial_evt: EventFd, // i8042 device for exit i8042: Arc>, @@ -397,14 +409,21 @@ impl DeviceManager { ) -> DeviceManagerResult { let io_bus = devices::Bus::new(); let mut mmio_bus = devices::Bus::new(); + + // Serial is tied to IRQ #4 + let serial_irq = 4; let serial_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?; + vm_fd + .register_irqfd(serial_evt.as_raw_fd(), serial_irq as u32) + .map_err(DeviceManagerError::Irq)?; + + // Add serial device let serial = Arc::new(Mutex::new(devices::legacy::Serial::new_out( - serial_evt - .try_clone() - .map_err(DeviceManagerError::EventFd)?, + Box::new(KernelIoapicIrq::new(serial_evt)), Box::new(stdout()), ))); + // Add a shutdown device (i8042) let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?; let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new( exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?, @@ -498,7 +517,6 @@ impl DeviceManager { io_bus, mmio_bus, serial, - serial_evt, i8042, exit_evt, pci, @@ -769,8 +787,6 @@ impl<'a> Vm<'a> { kvm.check_extension(Cap::SignalMsi), ) .map_err(Error::DeviceManager)?; - fd.register_irqfd(device_manager.serial_evt.as_raw_fd(), 4) - .map_err(Error::Irq)?; // Let's add our STDIN fd. let mut epoll = EpollContext::new().map_err(Error::EpollError)?;