vmm: Hide underlying console setup from VM

Refactor the underlying console details into the DeviceManager and
abstract away.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2019-09-06 16:42:41 +01:00 committed by Sebastien Boeuf
parent d089ee4e25
commit d2db34edf2
2 changed files with 67 additions and 44 deletions

View File

@ -209,13 +209,51 @@ pub fn get_win_size() -> (u16, u16) {
(ws.cols, ws.rows) (ws.cols, ws.rows)
} }
pub struct Console {
// Serial port on 0x3f8
serial: Option<Arc<Mutex<devices::legacy::Serial>>>,
console_input: Option<Arc<vm_virtio::ConsoleInput>>,
input_enabled: bool,
}
impl Console {
pub fn queue_input_bytes(&self, out: &[u8]) -> vmm_sys_util::errno::Result<()> {
if self.serial.is_some() {
self.serial
.as_ref()
.unwrap()
.lock()
.expect("Failed to process stdin event due to poisoned lock")
.queue_input_bytes(out)?;
}
if self.console_input.is_some() {
self.console_input.as_ref().unwrap().queue_input_bytes(out);
}
Ok(())
}
pub fn update_console_size(&self, cols: u16, rows: u16) {
if self.console_input.is_some() {
self.console_input
.as_ref()
.unwrap()
.update_console_size(cols, rows)
}
}
pub fn input_enabled(&self) -> bool {
self.input_enabled
}
}
pub struct DeviceManager { pub struct DeviceManager {
io_bus: devices::Bus, io_bus: devices::Bus,
mmio_bus: devices::Bus, mmio_bus: devices::Bus,
// Serial port on 0x3f8 // Console abstraction
pub serial: Option<Arc<Mutex<devices::legacy::Serial>>>, console: Arc<Console>,
pub console_input: Option<Arc<vm_virtio::ConsoleInput>>,
// i8042 device for i8042 reset // i8042 device for i8042 reset
i8042: Arc<Mutex<devices::legacy::I8042Device>>, i8042: Arc<Mutex<devices::legacy::I8042Device>>,
@ -321,7 +359,7 @@ impl DeviceManager {
ConsoleOutputMode::Off => None, ConsoleOutputMode::Off => None,
}; };
let (col, row) = get_win_size(); let (col, row) = get_win_size();
let console = if console_writer.is_some() { let console_input = if console_writer.is_some() {
let (virtio_console_device, console_input) = let (virtio_console_device, console_input) =
vm_virtio::Console::new(console_writer, col, row) vm_virtio::Console::new(console_writer, col, row)
.map_err(DeviceManagerError::CreateVirtioConsole)?; .map_err(DeviceManagerError::CreateVirtioConsole)?;
@ -339,6 +377,13 @@ impl DeviceManager {
None None
}; };
let console = Arc::new(Console {
serial,
console_input,
input_enabled: vm_info.vm_cfg.serial.mode.input_enabled()
|| vm_info.vm_cfg.console.mode.input_enabled(),
});
let mut mmap_regions = Vec::new(); let mut mmap_regions = Vec::new();
DeviceManager::add_virtio_devices( DeviceManager::add_virtio_devices(
@ -358,8 +403,7 @@ impl DeviceManager {
Ok(DeviceManager { Ok(DeviceManager {
io_bus, io_bus,
mmio_bus, mmio_bus,
serial, console,
console_input: console,
i8042, i8042,
#[cfg(feature = "acpi")] #[cfg(feature = "acpi")]
acpi_device, acpi_device,
@ -906,10 +950,10 @@ impl DeviceManager {
} }
pub fn register_devices(&mut self) -> DeviceManagerResult<()> { pub fn register_devices(&mut self) -> DeviceManagerResult<()> {
if self.serial.is_some() { if self.console.serial.is_some() {
// Insert serial device // Insert serial device
self.io_bus self.io_bus
.insert(self.serial.as_ref().unwrap().clone(), 0x3f8, 0x8) .insert(self.console.serial.as_ref().unwrap().clone(), 0x3f8, 0x8)
.map_err(DeviceManagerError::BusError)?; .map_err(DeviceManagerError::BusError)?;
} }
@ -949,6 +993,10 @@ impl DeviceManager {
pub fn ioapic(&self) -> &Option<Arc<Mutex<ioapic::Ioapic>>> { pub fn ioapic(&self) -> &Option<Arc<Mutex<ioapic::Ioapic>>> {
&self.ioapic &self.ioapic
} }
pub fn console(&self) -> &Arc<Console> {
&self.console
}
} }
impl Drop for DeviceManager { impl Drop for DeviceManager {

View File

@ -24,7 +24,7 @@ extern crate vm_virtio;
extern crate vmm_sys_util; extern crate vmm_sys_util;
use crate::config::{ConsoleOutputMode, VmConfig}; use crate::config::{ConsoleOutputMode, VmConfig};
use crate::device_manager::{get_win_size, DeviceManager, DeviceManagerError}; use crate::device_manager::{get_win_size, Console, DeviceManager, DeviceManagerError};
use arch::RegionType; use arch::RegionType;
use devices::ioapic; use devices::ioapic;
use kvm_bindings::{ use kvm_bindings::{
@ -172,10 +172,7 @@ pub enum Error {
/// Cannot create epoll context. /// Cannot create epoll context.
EpollError(io::Error), EpollError(io::Error),
/// Write to the serial console failed. /// Write to the console failed.
Serial(vmm_sys_util::errno::Error),
/// Write to the virtio console failed.
Console(vmm_sys_util::errno::Error), Console(vmm_sys_util::errno::Error),
/// Cannot setup terminal in raw mode. /// Cannot setup terminal in raw mode.
@ -827,7 +824,7 @@ impl<'a> Vm<'a> {
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
let epoll_fd = self.epoll.as_raw_fd(); let epoll_fd = self.epoll.as_raw_fd();
if (self.devices.serial.is_some() || self.devices.console_input.is_some()) && self.on_tty { if self.devices.console().input_enabled() && self.on_tty {
io::stdin() io::stdin()
.lock() .lock()
.set_raw_mode() .set_raw_mode()
@ -878,29 +875,13 @@ impl<'a> Vm<'a> {
let count = io::stdin() let count = io::stdin()
.lock() .lock()
.read_raw(&mut out) .read_raw(&mut out)
.map_err(Error::Serial)?; .map_err(Error::Console)?;
if self.devices.serial.is_some() if self.devices.console().input_enabled() {
&& self.config.serial.mode.input_enabled()
{
self.devices self.devices
.serial .console()
.as_ref()
.unwrap()
.lock()
.expect("Failed to process stdin event due to poisoned lock")
.queue_input_bytes(&out[..count]) .queue_input_bytes(&out[..count])
.map_err(Error::Serial)?; .map_err(Error::Console)?;
}
if self.devices.console_input.is_some()
&& self.config.console.mode.input_enabled()
{
self.devices
.console_input
.as_ref()
.unwrap()
.queue_input_bytes(&out[..count]);
} }
} }
} }
@ -938,11 +919,7 @@ impl<'a> Vm<'a> {
Ok(exit_behaviour) Ok(exit_behaviour)
} }
fn os_signal_handler( fn os_signal_handler(signals: Signals, console_input_clone: Arc<Console>, quit_signum: i32) {
signals: Signals,
console_input_clone: Arc<vm_virtio::ConsoleInput>,
quit_signum: i32,
) {
for signal in signals.forever() { for signal in signals.forever() {
match signal { match signal {
SIGWINCH => { SIGWINCH => {
@ -1030,8 +1007,8 @@ impl<'a> Vm<'a> {
// Unblock all CPU threads. // Unblock all CPU threads.
vcpu_thread_barrier.wait(); vcpu_thread_barrier.wait();
if let Some(console_input) = &self.devices.console_input { if self.devices.console().input_enabled() {
let console_input_clone = console_input.clone(); let console = self.devices.console().clone();
let quit_signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap(); let quit_signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap();
let signals = Signals::new(&[SIGWINCH, quit_signum]); let signals = Signals::new(&[SIGWINCH, quit_signum]);
match signals { match signals {
@ -1039,9 +1016,7 @@ impl<'a> Vm<'a> {
self.threads.push( self.threads.push(
thread::Builder::new() thread::Builder::new()
.name("signal_handler".to_string()) .name("signal_handler".to_string())
.spawn(move || { .spawn(move || Vm::os_signal_handler(sig, console, quit_signum))
Vm::os_signal_handler(sig, console_input_clone, quit_signum)
})
.map_err(Error::SignalHandlerSpawn)?, .map_err(Error::SignalHandlerSpawn)?,
); );
; ;