mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-02 01:45:21 +00:00
devices: Create Interrupt trait to abstract interrupt delivery
This commit anticipate the future need from having support for both in kernel and userspace IOAPIC. The way to signal an interrupt from the serial device will vary depending on the use case, but this should be independent from the serial implementation itself. That's why this patch provides a generic trait for the serial device to call from, so that it can trigger interrupts independently from the IOAPIC type chosen (in kernel vs userspace). Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
2a7fbe8eae
commit
c8c4a4d444
@ -5,12 +5,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use crate::{BusDevice, Interrupt};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::{io, result};
|
use std::{io, result};
|
||||||
|
use vmm_sys_util::Result;
|
||||||
use vmm_sys_util::{EventFd, Result};
|
|
||||||
|
|
||||||
use BusDevice;
|
|
||||||
|
|
||||||
const LOOP_SIZE: usize = 0x40;
|
const LOOP_SIZE: usize = 0x40;
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
|
|||||||
pub struct Serial {
|
pub struct Serial {
|
||||||
interrupt_enable: u8,
|
interrupt_enable: u8,
|
||||||
interrupt_identification: u8,
|
interrupt_identification: u8,
|
||||||
interrupt_evt: EventFd,
|
interrupt: Box<Interrupt>,
|
||||||
line_control: u8,
|
line_control: u8,
|
||||||
line_status: u8,
|
line_status: u8,
|
||||||
modem_control: u8,
|
modem_control: u8,
|
||||||
@ -69,11 +67,11 @@ pub struct Serial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Serial {
|
impl Serial {
|
||||||
fn new(interrupt_evt: EventFd, out: Option<Box<io::Write + Send>>) -> Serial {
|
fn new(interrupt: Box<Interrupt>, out: Option<Box<io::Write + Send>>) -> Serial {
|
||||||
Serial {
|
Serial {
|
||||||
interrupt_enable: 0,
|
interrupt_enable: 0,
|
||||||
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
|
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
|
||||||
interrupt_evt,
|
interrupt,
|
||||||
line_control: DEFAULT_LINE_CONTROL,
|
line_control: DEFAULT_LINE_CONTROL,
|
||||||
line_status: DEFAULT_LINE_STATUS,
|
line_status: DEFAULT_LINE_STATUS,
|
||||||
modem_control: DEFAULT_MODEM_CONTROL,
|
modem_control: DEFAULT_MODEM_CONTROL,
|
||||||
@ -86,13 +84,13 @@ impl Serial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a Serial port ready for output.
|
/// Constructs a Serial port ready for output.
|
||||||
pub fn new_out(interrupt_evt: EventFd, out: Box<io::Write + Send>) -> Serial {
|
pub fn new_out(interrupt: Box<Interrupt>, out: Box<io::Write + Send>) -> Serial {
|
||||||
Self::new(interrupt_evt, Some(out))
|
Self::new(interrupt, Some(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a Serial port with no connected output.
|
/// Constructs a Serial port with no connected output.
|
||||||
pub fn new_sink(interrupt_evt: EventFd) -> Serial {
|
pub fn new_sink(interrupt: Box<Interrupt>) -> Serial {
|
||||||
Self::new(interrupt_evt, None)
|
Self::new(interrupt, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queues raw bytes for the guest to read and signals the interrupt if the line status would
|
/// 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> {
|
fn trigger_interrupt(&mut self) -> result::Result<(), io::Error> {
|
||||||
self.interrupt_evt.write(1)
|
self.interrupt.deliver()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iir_reset(&mut self) {
|
fn iir_reset(&mut self) {
|
||||||
|
@ -14,7 +14,7 @@ extern crate vm_memory;
|
|||||||
extern crate vmm_sys_util;
|
extern crate vmm_sys_util;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::{io, result};
|
||||||
|
|
||||||
mod bus;
|
mod bus;
|
||||||
pub mod legacy;
|
pub mod legacy;
|
||||||
@ -58,3 +58,7 @@ pub enum Error {
|
|||||||
},
|
},
|
||||||
IoError(io::Error),
|
IoError(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Interrupt: Send {
|
||||||
|
fn deliver(&self) -> result::Result<(), std::io::Error>;
|
||||||
|
}
|
||||||
|
@ -135,9 +135,6 @@ pub enum Error {
|
|||||||
/// Cannot setup terminal in canonical mode.
|
/// Cannot setup terminal in canonical mode.
|
||||||
SetTerminalCanon(vmm_sys_util::Error),
|
SetTerminalCanon(vmm_sys_util::Error),
|
||||||
|
|
||||||
/// Cannot configure the IRQ.
|
|
||||||
Irq(io::Error),
|
|
||||||
|
|
||||||
/// Cannot create the system allocator
|
/// Cannot create the system allocator
|
||||||
CreateSystemAllocator,
|
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 {
|
struct DeviceManager {
|
||||||
io_bus: devices::Bus,
|
io_bus: devices::Bus,
|
||||||
mmio_bus: devices::Bus,
|
mmio_bus: devices::Bus,
|
||||||
|
|
||||||
// Serial port on 0x3f8
|
// Serial port on 0x3f8
|
||||||
serial: Arc<Mutex<devices::legacy::Serial>>,
|
serial: Arc<Mutex<devices::legacy::Serial>>,
|
||||||
serial_evt: EventFd,
|
|
||||||
|
|
||||||
// i8042 device for exit
|
// i8042 device for exit
|
||||||
i8042: Arc<Mutex<devices::legacy::I8042Device>>,
|
i8042: Arc<Mutex<devices::legacy::I8042Device>>,
|
||||||
@ -397,14 +409,21 @@ impl DeviceManager {
|
|||||||
) -> DeviceManagerResult<Self> {
|
) -> DeviceManagerResult<Self> {
|
||||||
let io_bus = devices::Bus::new();
|
let io_bus = devices::Bus::new();
|
||||||
let mut mmio_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)?;
|
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(
|
let serial = Arc::new(Mutex::new(devices::legacy::Serial::new_out(
|
||||||
serial_evt
|
Box::new(KernelIoapicIrq::new(serial_evt)),
|
||||||
.try_clone()
|
|
||||||
.map_err(DeviceManagerError::EventFd)?,
|
|
||||||
Box::new(stdout()),
|
Box::new(stdout()),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
// Add a shutdown device (i8042)
|
||||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?;
|
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?;
|
||||||
let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new(
|
let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new(
|
||||||
exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
|
exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
|
||||||
@ -498,7 +517,6 @@ impl DeviceManager {
|
|||||||
io_bus,
|
io_bus,
|
||||||
mmio_bus,
|
mmio_bus,
|
||||||
serial,
|
serial,
|
||||||
serial_evt,
|
|
||||||
i8042,
|
i8042,
|
||||||
exit_evt,
|
exit_evt,
|
||||||
pci,
|
pci,
|
||||||
@ -769,8 +787,6 @@ impl<'a> Vm<'a> {
|
|||||||
kvm.check_extension(Cap::SignalMsi),
|
kvm.check_extension(Cap::SignalMsi),
|
||||||
)
|
)
|
||||||
.map_err(Error::DeviceManager)?;
|
.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's add our STDIN fd.
|
||||||
let mut epoll = EpollContext::new().map_err(Error::EpollError)?;
|
let mut epoll = EpollContext::new().map_err(Error::EpollError)?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user