mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vm-virtio: Implement console size config feature
One of the features of the virtio console device is its size can be configured and updated. Our first iteration of the console device implementation is lack of this feature. As a result, it had a default fixed size which could not be changed. This commit implements the console config feature and lets us change the console size from the vmm side. During the activation of the device, vmm reads the current terminal size, sets the console configuration accordinly, and lets the driver know about this configuration by sending an interrupt. Later, if someone changes the terminal size, the vmm detects the corresponding event, updates the configuration, and sends interrupt as before. As a result, the console device driver, in the guest, updates the console size. Signed-off-by: A K M Fazla Mehrab <fazla.mehrab.akm@intel.com>
This commit is contained in:
committed by
Sebastien Boeuf
parent
d9a355f85a
commit
df5058ec0a
@@ -16,6 +16,7 @@ extern crate kvm_ioctls;
|
||||
extern crate libc;
|
||||
extern crate linux_loader;
|
||||
extern crate net_util;
|
||||
extern crate signal_hook;
|
||||
extern crate vfio;
|
||||
extern crate vm_allocator;
|
||||
extern crate vm_memory;
|
||||
@@ -31,13 +32,14 @@ use kvm_bindings::{
|
||||
};
|
||||
use kvm_ioctls::*;
|
||||
use libc::O_TMPFILE;
|
||||
use libc::{c_void, siginfo_t, EFD_NONBLOCK};
|
||||
use libc::{c_void, siginfo_t, EFD_NONBLOCK, TIOCGWINSZ};
|
||||
use linux_loader::loader::KernelLoader;
|
||||
use net_util::Tap;
|
||||
use pci::{
|
||||
InterruptDelivery, InterruptParameters, PciConfigIo, PciDevice, PciInterruptPin, PciRoot,
|
||||
};
|
||||
use qcow::{self, ImageType, QcowFile};
|
||||
use signal_hook::{iterator::Signals, SIGWINCH};
|
||||
use std::ffi::CString;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, sink, stdout};
|
||||
@@ -491,6 +493,23 @@ impl UserIoapicIrq {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_win_size() -> (u16, u16) {
|
||||
#[repr(C)]
|
||||
struct WS {
|
||||
rows: u16,
|
||||
cols: u16,
|
||||
};
|
||||
let ws: WS = WS {
|
||||
rows: 0u16,
|
||||
cols: 0u16,
|
||||
};
|
||||
unsafe {
|
||||
libc::ioctl(0, TIOCGWINSZ, &ws);
|
||||
}
|
||||
|
||||
(ws.cols, ws.rows)
|
||||
}
|
||||
|
||||
impl devices::Interrupt for UserIoapicIrq {
|
||||
fn deliver(&self) -> result::Result<(), io::Error> {
|
||||
self.ioapic
|
||||
@@ -512,7 +531,7 @@ struct DeviceManager {
|
||||
|
||||
// Serial port on 0x3f8
|
||||
serial: Option<Arc<Mutex<devices::legacy::Serial>>>,
|
||||
console: Option<Arc<vm_virtio::ConsoleInput>>,
|
||||
console_input: Option<Arc<vm_virtio::ConsoleInput>>,
|
||||
|
||||
// i8042 device for exit
|
||||
i8042: Arc<Mutex<devices::legacy::I8042Device>>,
|
||||
@@ -604,9 +623,11 @@ impl DeviceManager {
|
||||
ConsoleOutputMode::Null => Some(Box::new(sink())),
|
||||
ConsoleOutputMode::Off => None,
|
||||
};
|
||||
let (col, row) = get_win_size();
|
||||
let console = if console_writer.is_some() {
|
||||
let (virtio_console_device, console) = vm_virtio::Console::new(console_writer)
|
||||
.map_err(DeviceManagerError::CreateVirtioConsole)?;
|
||||
let (virtio_console_device, console_input) =
|
||||
vm_virtio::Console::new(console_writer, col, row)
|
||||
.map_err(DeviceManagerError::CreateVirtioConsole)?;
|
||||
DeviceManager::add_virtio_pci_device(
|
||||
Box::new(virtio_console_device),
|
||||
vm_info.memory.clone(),
|
||||
@@ -616,7 +637,7 @@ impl DeviceManager {
|
||||
&mut buses,
|
||||
&interrupt_info,
|
||||
)?;
|
||||
Some(console)
|
||||
Some(console_input)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -638,7 +659,7 @@ impl DeviceManager {
|
||||
io_bus,
|
||||
mmio_bus,
|
||||
serial,
|
||||
console,
|
||||
console_input: console,
|
||||
i8042,
|
||||
exit_evt,
|
||||
ioapic,
|
||||
@@ -1447,7 +1468,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.is_some()) && self.on_tty {
|
||||
if (self.devices.serial.is_some() || self.devices.console_input.is_some()) && self.on_tty {
|
||||
io::stdin()
|
||||
.lock()
|
||||
.set_raw_mode()
|
||||
@@ -1503,11 +1524,11 @@ impl<'a> Vm<'a> {
|
||||
.map_err(Error::Serial)?;
|
||||
}
|
||||
|
||||
if self.devices.console.is_some()
|
||||
if self.devices.console_input.is_some()
|
||||
&& self.config.console.mode.input_enabled()
|
||||
{
|
||||
self.devices
|
||||
.console
|
||||
.console_input
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.queue_input_bytes(&out[..count]);
|
||||
@@ -1530,6 +1551,15 @@ impl<'a> Vm<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn os_signal_handler(signals: Signals, console_input_clone: Arc<vm_virtio::ConsoleInput>) {
|
||||
for signal in signals.forever() {
|
||||
if signal == SIGWINCH {
|
||||
let (col, row) = get_win_size();
|
||||
console_input_clone.update_console_size(col, row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self, entry_addr: GuestAddress) -> Result<()> {
|
||||
self.devices.register_devices()?;
|
||||
|
||||
@@ -1581,6 +1611,16 @@ 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();
|
||||
let signals = Signals::new(&[SIGWINCH]);
|
||||
match signals {
|
||||
Ok(sig) => {
|
||||
thread::spawn(move || Vm::os_signal_handler(sig, console_input_clone));
|
||||
}
|
||||
Err(e) => error!("Signal not found {}", e),
|
||||
}
|
||||
}
|
||||
self.control_loop()?;
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user