vmm: device_manager: console input should be only consumed by one device

Cloud Hypervisor allows either the serial or virtio console to output to
TTY, but TTY input is pushed to both.

This is not correct. When Linux guest is configured to spawn TTYs on
both ttyS0 and hvc0, the user effectively issues the same commands twice
in different TTYs.

Fix this by only direct input to the one choice that is using host side
TTY.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2020-07-30 13:02:43 +00:00 committed by Sebastien Boeuf
parent 5ed794a44c
commit a52b614a61

View File

@ -399,30 +399,41 @@ pub fn get_win_size() -> (u16, u16) {
(ws.cols, ws.rows) (ws.cols, ws.rows)
} }
enum ConsoleInput {
Serial,
VirtioConsole,
}
#[derive(Default)] #[derive(Default)]
pub struct Console { pub struct Console {
// Serial port on 0x3f8 // Serial port on 0x3f8
serial: Option<Arc<Mutex<Serial>>>, serial: Option<Arc<Mutex<Serial>>>,
virtio_console_input: Option<Arc<virtio_devices::ConsoleInput>>, virtio_console_input: Option<Arc<virtio_devices::ConsoleInput>>,
input_enabled: bool, input: Option<ConsoleInput>,
} }
impl Console { impl Console {
pub fn queue_input_bytes(&self, out: &[u8]) -> vmm_sys_util::errno::Result<()> { pub fn queue_input_bytes(&self, out: &[u8]) -> vmm_sys_util::errno::Result<()> {
if self.serial.is_some() { match self.input {
self.serial Some(ConsoleInput::Serial) => {
.as_ref() if self.serial.is_some() {
.unwrap() self.serial
.lock() .as_ref()
.expect("Failed to process stdin event due to poisoned lock") .unwrap()
.queue_input_bytes(out)?; .lock()
} .expect("Failed to process stdin event due to poisoned lock")
.queue_input_bytes(out)?;
}
}
if self.virtio_console_input.is_some() { Some(ConsoleInput::VirtioConsole) => {
self.virtio_console_input if self.virtio_console_input.is_some() {
.as_ref() self.virtio_console_input
.unwrap() .as_ref()
.queue_input_bytes(out); .unwrap()
.queue_input_bytes(out);
}
}
None => {}
} }
Ok(()) Ok(())
@ -438,7 +449,7 @@ impl Console {
} }
pub fn input_enabled(&self) -> bool { pub fn input_enabled(&self) -> bool {
self.input_enabled self.input.is_some()
} }
} }
@ -1519,11 +1530,18 @@ impl DeviceManager {
None None
}; };
let input = if serial_config.mode.input_enabled() {
Some(ConsoleInput::Serial)
} else if console_config.mode.input_enabled() {
Some(ConsoleInput::VirtioConsole)
} else {
None
};
Ok(Arc::new(Console { Ok(Arc::new(Console {
serial, serial,
virtio_console_input, virtio_console_input,
input_enabled: serial_config.mode.input_enabled() input,
|| console_config.mode.input_enabled(),
})) }))
} }