From d2db34edf228a8a7821232d074aee8f1ddcdc652 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 6 Sep 2019 16:42:41 +0100 Subject: [PATCH] vmm: Hide underlying console setup from VM Refactor the underlying console details into the DeviceManager and abstract away. Signed-off-by: Rob Bradford --- vmm/src/device_manager.rs | 64 ++++++++++++++++++++++++++++++++++----- vmm/src/vm.rs | 47 +++++++--------------------- 2 files changed, 67 insertions(+), 44 deletions(-) diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 759321530..e1ce88487 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -209,13 +209,51 @@ pub fn get_win_size() -> (u16, u16) { (ws.cols, ws.rows) } +pub struct Console { + // Serial port on 0x3f8 + serial: Option>>, + console_input: Option>, + 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 { io_bus: devices::Bus, mmio_bus: devices::Bus, - // Serial port on 0x3f8 - pub serial: Option>>, - pub console_input: Option>, + // Console abstraction + console: Arc, // i8042 device for i8042 reset i8042: Arc>, @@ -321,7 +359,7 @@ impl DeviceManager { ConsoleOutputMode::Off => None, }; 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) = vm_virtio::Console::new(console_writer, col, row) .map_err(DeviceManagerError::CreateVirtioConsole)?; @@ -339,6 +377,13 @@ impl DeviceManager { 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(); DeviceManager::add_virtio_devices( @@ -358,8 +403,7 @@ impl DeviceManager { Ok(DeviceManager { io_bus, mmio_bus, - serial, - console_input: console, + console, i8042, #[cfg(feature = "acpi")] acpi_device, @@ -906,10 +950,10 @@ impl DeviceManager { } pub fn register_devices(&mut self) -> DeviceManagerResult<()> { - if self.serial.is_some() { + if self.console.serial.is_some() { // Insert serial device 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)?; } @@ -949,6 +993,10 @@ impl DeviceManager { pub fn ioapic(&self) -> &Option>> { &self.ioapic } + + pub fn console(&self) -> &Arc { + &self.console + } } impl Drop for DeviceManager { diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index cc1be4578..e7c4419c1 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -24,7 +24,7 @@ extern crate vm_virtio; extern crate vmm_sys_util; 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 devices::ioapic; use kvm_bindings::{ @@ -172,10 +172,7 @@ pub enum Error { /// Cannot create epoll context. EpollError(io::Error), - /// Write to the serial console failed. - Serial(vmm_sys_util::errno::Error), - - /// Write to the virtio console failed. + /// Write to the console failed. Console(vmm_sys_util::errno::Error), /// 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 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() .lock() .set_raw_mode() @@ -878,29 +875,13 @@ impl<'a> Vm<'a> { let count = io::stdin() .lock() .read_raw(&mut out) - .map_err(Error::Serial)?; + .map_err(Error::Console)?; - if self.devices.serial.is_some() - && self.config.serial.mode.input_enabled() - { + if self.devices.console().input_enabled() { self.devices - .serial - .as_ref() - .unwrap() - .lock() - .expect("Failed to process stdin event due to poisoned lock") + .console() .queue_input_bytes(&out[..count]) - .map_err(Error::Serial)?; - } - - 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]); + .map_err(Error::Console)?; } } } @@ -938,11 +919,7 @@ impl<'a> Vm<'a> { Ok(exit_behaviour) } - fn os_signal_handler( - signals: Signals, - console_input_clone: Arc, - quit_signum: i32, - ) { + fn os_signal_handler(signals: Signals, console_input_clone: Arc, quit_signum: i32) { for signal in signals.forever() { match signal { SIGWINCH => { @@ -1030,8 +1007,8 @@ impl<'a> Vm<'a> { // Unblock all CPU threads. vcpu_thread_barrier.wait(); - if let Some(console_input) = &self.devices.console_input { - let console_input_clone = console_input.clone(); + if self.devices.console().input_enabled() { + let console = self.devices.console().clone(); let quit_signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap(); let signals = Signals::new(&[SIGWINCH, quit_signum]); match signals { @@ -1039,9 +1016,7 @@ impl<'a> Vm<'a> { self.threads.push( thread::Builder::new() .name("signal_handler".to_string()) - .spawn(move || { - Vm::os_signal_handler(sig, console_input_clone, quit_signum) - }) + .spawn(move || Vm::os_signal_handler(sig, console, quit_signum)) .map_err(Error::SignalHandlerSpawn)?, ); ;