2019-07-22 18:50:56 +00:00
|
|
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2019-12-31 10:49:11 +00:00
|
|
|
use super::Error as DeviceError;
|
|
|
|
use super::{
|
2020-08-11 15:38:13 +00:00
|
|
|
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
2020-09-03 09:37:36 +00:00
|
|
|
VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST,
|
2020-08-11 15:38:13 +00:00
|
|
|
VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1,
|
2019-12-31 10:49:11 +00:00
|
|
|
};
|
2020-08-04 18:12:05 +00:00
|
|
|
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
2019-12-31 10:49:11 +00:00
|
|
|
use crate::VirtioInterrupt;
|
2019-07-22 18:50:56 +00:00
|
|
|
use libc::EFD_NONBLOCK;
|
2020-08-04 18:12:05 +00:00
|
|
|
use seccomp::{SeccompAction, SeccompFilter};
|
2019-07-22 18:50:56 +00:00
|
|
|
use std::cmp;
|
|
|
|
use std::collections::VecDeque;
|
|
|
|
use std::io;
|
|
|
|
use std::io::Write;
|
2019-10-04 16:38:43 +00:00
|
|
|
use std::ops::DerefMut;
|
2020-08-11 15:38:13 +00:00
|
|
|
use std::os::unix::io::AsRawFd;
|
2019-07-22 18:50:56 +00:00
|
|
|
use std::result;
|
2019-11-19 00:42:31 +00:00
|
|
|
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
2020-08-11 14:05:06 +00:00
|
|
|
use std::sync::{Arc, Barrier, Mutex};
|
2019-12-31 10:49:11 +00:00
|
|
|
use std::thread;
|
2021-05-06 13:34:31 +00:00
|
|
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
|
|
use versionize_derive::Versionize;
|
2020-02-11 16:22:40 +00:00
|
|
|
use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
|
2021-05-06 13:34:31 +00:00
|
|
|
use vm_migration::VersionMapped;
|
2021-04-08 09:20:10 +00:00
|
|
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
2019-08-02 14:23:52 +00:00
|
|
|
use vmm_sys_util::eventfd::EventFd;
|
2019-07-22 18:50:56 +00:00
|
|
|
|
|
|
|
const QUEUE_SIZE: u16 = 256;
|
|
|
|
const NUM_QUEUES: usize = 2;
|
|
|
|
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
|
|
|
|
|
|
|
|
// New descriptors are pending on the virtio queue.
|
2020-08-11 15:38:13 +00:00
|
|
|
const INPUT_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
|
|
|
|
const OUTPUT_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
|
2019-07-22 18:50:56 +00:00
|
|
|
// Some input from the VMM is ready to be injected into the VM.
|
2020-08-11 15:38:13 +00:00
|
|
|
const INPUT_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
// Console configuration change event is triggered.
|
2020-08-11 15:38:13 +00:00
|
|
|
const CONFIG_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
|
|
|
|
//Console size feature bit
|
|
|
|
const VIRTIO_CONSOLE_F_SIZE: u64 = 0;
|
|
|
|
|
2021-05-11 14:02:43 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
2020-04-09 08:41:52 +00:00
|
|
|
#[repr(C, packed)]
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
pub struct VirtioConsoleConfig {
|
|
|
|
cols: u16,
|
|
|
|
rows: u16,
|
|
|
|
max_nr_ports: u32,
|
|
|
|
emerg_wr: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Safe because it only has data and has no implicit padding.
|
|
|
|
unsafe impl ByteValued for VirtioConsoleConfig {}
|
2019-07-22 18:50:56 +00:00
|
|
|
|
|
|
|
struct ConsoleEpollHandler {
|
|
|
|
queues: Vec<Queue>,
|
2020-02-11 16:22:40 +00:00
|
|
|
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
2020-01-13 17:52:19 +00:00
|
|
|
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
2019-07-22 18:50:56 +00:00
|
|
|
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
2019-10-04 16:38:43 +00:00
|
|
|
out: Arc<Mutex<Box<dyn io::Write + Send + Sync + 'static>>>,
|
2019-07-22 18:50:56 +00:00
|
|
|
input_queue_evt: EventFd,
|
|
|
|
output_queue_evt: EventFd,
|
|
|
|
input_evt: EventFd,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
config_evt: EventFd,
|
2019-07-22 18:50:56 +00:00
|
|
|
kill_evt: EventFd,
|
2019-11-19 00:42:31 +00:00
|
|
|
pause_evt: EventFd,
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConsoleEpollHandler {
|
|
|
|
/*
|
|
|
|
* Each port of virtio console device has one receive
|
|
|
|
* queue. One or more empty buffers are placed by the
|
2021-05-07 00:57:33 +00:00
|
|
|
* driver in the receive queue for incoming data. Here,
|
2019-07-22 18:50:56 +00:00
|
|
|
* we place the input data to these empty buffers.
|
|
|
|
*/
|
|
|
|
fn process_input_queue(&mut self) -> bool {
|
|
|
|
let mut in_buffer = self.in_buffer.lock().unwrap();
|
|
|
|
let recv_queue = &mut self.queues[0]; //receiveq
|
|
|
|
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
|
|
|
let mut used_count = 0;
|
2020-01-08 10:55:30 +00:00
|
|
|
|
|
|
|
if in_buffer.is_empty() {
|
|
|
|
return false;
|
|
|
|
}
|
2019-07-22 18:50:56 +00:00
|
|
|
|
2020-02-11 16:22:40 +00:00
|
|
|
let mem = self.mem.memory();
|
2019-08-20 22:43:23 +00:00
|
|
|
for avail_desc in recv_queue.iter(&mem) {
|
2020-01-08 10:55:30 +00:00
|
|
|
let len = cmp::min(avail_desc.len as u32, in_buffer.len() as u32);
|
|
|
|
let source_slice = in_buffer.drain(..len as usize).collect::<Vec<u8>>();
|
|
|
|
if let Err(e) = mem.write_slice(&source_slice[..], avail_desc.addr) {
|
|
|
|
error!("Failed to write slice: {:?}", e);
|
2020-01-08 13:42:12 +00:00
|
|
|
recv_queue.go_to_previous_position();
|
2020-01-08 10:55:30 +00:00
|
|
|
break;
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
used_desc_heads[used_count] = (avail_desc.index, len);
|
|
|
|
used_count += 1;
|
|
|
|
|
2020-01-08 10:55:30 +00:00
|
|
|
if in_buffer.is_empty() {
|
2019-07-22 18:50:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
2019-08-20 22:43:23 +00:00
|
|
|
recv_queue.add_used(&mem, desc_index, len);
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
2020-01-08 10:55:30 +00:00
|
|
|
|
2019-07-22 18:50:56 +00:00
|
|
|
used_count > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Each port of virtio console device has one transmit
|
|
|
|
* queue. For outgoing data, characters are placed in
|
|
|
|
* the transmit queue by the driver. Therefore, here
|
|
|
|
* we read data from the transmit queue and flush them
|
|
|
|
* to the referenced address.
|
|
|
|
*/
|
|
|
|
fn process_output_queue(&mut self) -> bool {
|
|
|
|
let trans_queue = &mut self.queues[1]; //transmitq
|
|
|
|
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
|
|
|
let mut used_count = 0;
|
|
|
|
|
2020-02-11 16:22:40 +00:00
|
|
|
let mem = self.mem.memory();
|
2019-08-20 22:43:23 +00:00
|
|
|
for avail_desc in trans_queue.iter(&mem) {
|
2019-07-22 18:50:56 +00:00
|
|
|
let len;
|
2019-10-04 16:38:43 +00:00
|
|
|
let mut out = self.out.lock().unwrap();
|
|
|
|
let _ = mem.write_to(
|
|
|
|
avail_desc.addr,
|
|
|
|
&mut out.deref_mut(),
|
|
|
|
avail_desc.len as usize,
|
|
|
|
);
|
|
|
|
let _ = out.flush();
|
2019-07-22 18:50:56 +00:00
|
|
|
|
|
|
|
len = avail_desc.len;
|
|
|
|
used_desc_heads[used_count] = (avail_desc.index, len);
|
|
|
|
used_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
2019-08-20 22:43:23 +00:00
|
|
|
trans_queue.add_used(&mem, desc_index, len);
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
used_count > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn signal_used_queue(&self) -> result::Result<(), DeviceError> {
|
2020-01-13 17:52:19 +00:00
|
|
|
self.interrupt_cb
|
|
|
|
.trigger(&VirtioInterruptType::Queue, Some(&self.queues[0]))
|
|
|
|
.map_err(|e| {
|
|
|
|
error!("Failed to signal used queue: {:?}", e);
|
|
|
|
DeviceError::FailedSignalingUsedQueue(e)
|
|
|
|
})
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 14:05:06 +00:00
|
|
|
fn run(
|
|
|
|
&mut self,
|
|
|
|
paused: Arc<AtomicBool>,
|
|
|
|
paused_sync: Arc<Barrier>,
|
|
|
|
) -> result::Result<(), EpollHelperError> {
|
2020-08-11 15:38:13 +00:00
|
|
|
let mut helper = EpollHelper::new(&self.kill_evt, &self.pause_evt)?;
|
|
|
|
helper.add_event(self.input_queue_evt.as_raw_fd(), INPUT_QUEUE_EVENT)?;
|
|
|
|
helper.add_event(self.output_queue_evt.as_raw_fd(), OUTPUT_QUEUE_EVENT)?;
|
|
|
|
helper.add_event(self.input_evt.as_raw_fd(), INPUT_EVENT)?;
|
|
|
|
helper.add_event(self.config_evt.as_raw_fd(), CONFIG_EVENT)?;
|
2020-08-11 14:05:06 +00:00
|
|
|
helper.run(paused, paused_sync, self)?;
|
2020-06-22 14:00:02 +00:00
|
|
|
|
2020-08-11 15:38:13 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
|
2020-08-11 15:38:13 +00:00
|
|
|
impl EpollHelperHandler for ConsoleEpollHandler {
|
2020-08-11 17:12:02 +00:00
|
|
|
fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool {
|
|
|
|
let ev_type = event.data as u16;
|
|
|
|
match ev_type {
|
2020-08-11 15:38:13 +00:00
|
|
|
INPUT_QUEUE_EVENT => {
|
|
|
|
if let Err(e) = self.input_queue_evt.read() {
|
|
|
|
error!("Failed to get queue event: {:?}", e);
|
|
|
|
return true;
|
|
|
|
} else if self.process_input_queue() {
|
|
|
|
if let Err(e) = self.signal_used_queue() {
|
|
|
|
error!("Failed to signal used queue: {:?}", e);
|
|
|
|
return true;
|
2019-11-19 00:42:31 +00:00
|
|
|
}
|
2020-08-11 15:38:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
OUTPUT_QUEUE_EVENT => {
|
|
|
|
if let Err(e) = self.output_queue_evt.read() {
|
|
|
|
error!("Failed to get queue event: {:?}", e);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
self.process_output_queue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
INPUT_EVENT => {
|
|
|
|
if let Err(e) = self.input_evt.read() {
|
|
|
|
error!("Failed to get input event: {:?}", e);
|
|
|
|
return true;
|
|
|
|
} else if self.process_input_queue() {
|
|
|
|
if let Err(e) = self.signal_used_queue() {
|
|
|
|
error!("Failed to signal used queue: {:?}", e);
|
|
|
|
return true;
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-11 15:38:13 +00:00
|
|
|
CONFIG_EVENT => {
|
|
|
|
if let Err(e) = self.config_evt.read() {
|
|
|
|
error!("Failed to get config event: {:?}", e);
|
|
|
|
return true;
|
|
|
|
} else if let Err(e) = self
|
|
|
|
.interrupt_cb
|
|
|
|
.trigger(&VirtioInterruptType::Config, None)
|
|
|
|
{
|
|
|
|
error!("Failed to signal console driver: {:?}", e);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
error!("Unknown event for virtio-console");
|
|
|
|
return true;
|
|
|
|
}
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
2020-08-11 15:38:13 +00:00
|
|
|
false
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Input device.
|
|
|
|
pub struct ConsoleInput {
|
|
|
|
input_evt: EventFd,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
config_evt: EventFd,
|
2019-07-22 18:50:56 +00:00
|
|
|
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
config: Arc<Mutex<VirtioConsoleConfig>>,
|
|
|
|
acked_features: AtomicU64,
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConsoleInput {
|
|
|
|
pub fn queue_input_bytes(&self, input: &[u8]) {
|
|
|
|
let mut in_buffer = self.in_buffer.lock().unwrap();
|
|
|
|
in_buffer.extend(input);
|
|
|
|
let _ = self.input_evt.write(1);
|
|
|
|
}
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
|
|
|
|
pub fn update_console_size(&self, cols: u16, rows: u16) {
|
|
|
|
if self
|
|
|
|
.acked_features
|
2020-12-01 16:15:26 +00:00
|
|
|
.fetch_and(1u64 << VIRTIO_CONSOLE_F_SIZE, Ordering::AcqRel)
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
!= 0
|
|
|
|
{
|
|
|
|
self.config.lock().unwrap().update_console_size(cols, rows);
|
|
|
|
//Send the interrupt to the driver
|
|
|
|
let _ = self.config_evt.write(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VirtioConsoleConfig {
|
|
|
|
pub fn new(cols: u16, rows: u16) -> Self {
|
|
|
|
VirtioConsoleConfig {
|
|
|
|
cols,
|
|
|
|
rows,
|
|
|
|
max_nr_ports: 1u32,
|
|
|
|
emerg_wr: 0u32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_console_size(&mut self, cols: u16, rows: u16) {
|
|
|
|
self.cols = cols;
|
|
|
|
self.rows = rows;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Virtio device for exposing console to the guest OS through virtio.
|
|
|
|
pub struct Console {
|
2020-09-03 09:37:36 +00:00
|
|
|
common: VirtioCommon,
|
2020-04-27 12:05:29 +00:00
|
|
|
id: String,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
config: Arc<Mutex<VirtioConsoleConfig>>,
|
|
|
|
input: Arc<ConsoleInput>,
|
2019-10-04 16:38:43 +00:00
|
|
|
out: Arc<Mutex<Box<dyn io::Write + Send + Sync + 'static>>>,
|
2020-08-04 18:12:05 +00:00
|
|
|
seccomp_action: SeccompAction,
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 14:02:43 +00:00
|
|
|
#[derive(Versionize)]
|
2020-04-09 08:41:52 +00:00
|
|
|
pub struct ConsoleState {
|
|
|
|
avail_features: u64,
|
|
|
|
acked_features: u64,
|
|
|
|
config: VirtioConsoleConfig,
|
2021-04-23 09:55:05 +00:00
|
|
|
in_buffer: Vec<u8>,
|
2020-04-09 08:41:52 +00:00
|
|
|
}
|
|
|
|
|
2021-05-06 13:34:31 +00:00
|
|
|
impl VersionMapped for ConsoleState {}
|
|
|
|
|
2019-07-22 18:50:56 +00:00
|
|
|
impl Console {
|
|
|
|
/// Create a new virtio console device that gets random data from /dev/urandom.
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
pub fn new(
|
2020-04-27 12:05:29 +00:00
|
|
|
id: String,
|
2019-10-04 16:38:43 +00:00
|
|
|
out: Box<dyn io::Write + Send + Sync + 'static>,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
cols: u16,
|
|
|
|
rows: u16,
|
2019-10-04 17:32:26 +00:00
|
|
|
iommu: bool,
|
2020-08-04 18:12:05 +00:00
|
|
|
seccomp_action: SeccompAction,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
) -> io::Result<(Console, Arc<ConsoleInput>)> {
|
2019-10-04 17:32:26 +00:00
|
|
|
let mut avail_features = 1u64 << VIRTIO_F_VERSION_1 | 1u64 << VIRTIO_CONSOLE_F_SIZE;
|
|
|
|
|
|
|
|
if iommu {
|
|
|
|
avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
|
|
|
|
}
|
2019-07-22 18:50:56 +00:00
|
|
|
|
|
|
|
let input_evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
let config_evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
|
|
|
let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::new(cols, rows)));
|
2019-07-22 18:50:56 +00:00
|
|
|
let console_input = Arc::new(ConsoleInput {
|
|
|
|
input_evt,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
config_evt,
|
2019-07-22 18:50:56 +00:00
|
|
|
in_buffer: Arc::new(Mutex::new(VecDeque::new())),
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
config: console_config.clone(),
|
|
|
|
acked_features: AtomicU64::new(0),
|
2019-07-22 18:50:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
Ok((
|
|
|
|
Console {
|
2020-09-03 09:37:36 +00:00
|
|
|
common: VirtioCommon {
|
2021-03-25 16:54:09 +00:00
|
|
|
device_type: VirtioDeviceType::Console as u32,
|
2020-09-04 08:37:37 +00:00
|
|
|
queue_sizes: QUEUE_SIZES.to_vec(),
|
2020-09-03 09:37:36 +00:00
|
|
|
avail_features,
|
2020-09-04 08:37:37 +00:00
|
|
|
paused_sync: Some(Arc::new(Barrier::new(2))),
|
2021-01-19 06:11:07 +00:00
|
|
|
min_queues: NUM_QUEUES as u16,
|
2020-09-03 15:56:32 +00:00
|
|
|
..Default::default()
|
2020-09-03 09:37:36 +00:00
|
|
|
},
|
2020-04-27 12:05:29 +00:00
|
|
|
id,
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
config: console_config,
|
2019-07-22 18:50:56 +00:00
|
|
|
input: console_input.clone(),
|
2019-10-04 16:38:43 +00:00
|
|
|
out: Arc::new(Mutex::new(out)),
|
2020-08-04 18:12:05 +00:00
|
|
|
seccomp_action,
|
2019-07-22 18:50:56 +00:00
|
|
|
},
|
|
|
|
console_input,
|
|
|
|
))
|
|
|
|
}
|
2020-04-09 08:41:52 +00:00
|
|
|
|
|
|
|
fn state(&self) -> ConsoleState {
|
|
|
|
ConsoleState {
|
2020-09-03 09:37:36 +00:00
|
|
|
avail_features: self.common.avail_features,
|
|
|
|
acked_features: self.common.acked_features,
|
2020-04-09 08:41:52 +00:00
|
|
|
config: *(self.config.lock().unwrap()),
|
2021-04-23 09:55:05 +00:00
|
|
|
in_buffer: self.input.in_buffer.lock().unwrap().clone().into(),
|
2020-04-09 08:41:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-11 16:00:53 +00:00
|
|
|
fn set_state(&mut self, state: &ConsoleState) {
|
2020-09-03 09:37:36 +00:00
|
|
|
self.common.avail_features = state.avail_features;
|
|
|
|
self.common.acked_features = state.acked_features;
|
2020-04-09 08:41:52 +00:00
|
|
|
*(self.config.lock().unwrap()) = state.config;
|
2021-04-23 09:55:05 +00:00
|
|
|
*(self.input.in_buffer.lock().unwrap()) = state.in_buffer.clone().into();
|
2020-04-09 08:41:52 +00:00
|
|
|
}
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Console {
|
|
|
|
fn drop(&mut self) {
|
2020-09-04 08:37:37 +00:00
|
|
|
if let Some(kill_evt) = self.common.kill_evt.take() {
|
2019-07-22 18:50:56 +00:00
|
|
|
// Ignore the result because there is nothing we can do about it.
|
|
|
|
let _ = kill_evt.write(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VirtioDevice for Console {
|
|
|
|
fn device_type(&self) -> u32 {
|
2020-09-04 08:37:37 +00:00
|
|
|
self.common.device_type
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn queue_max_sizes(&self) -> &[u16] {
|
2020-09-04 08:37:37 +00:00
|
|
|
&self.common.queue_sizes
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 10:14:38 +00:00
|
|
|
fn features(&self) -> u64 {
|
2020-09-03 09:37:36 +00:00
|
|
|
self.common.avail_features
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 10:14:38 +00:00
|
|
|
fn ack_features(&mut self, value: u64) {
|
2020-09-03 09:37:36 +00:00
|
|
|
self.common.ack_features(value)
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
2020-07-16 09:34:51 +00:00
|
|
|
fn read_config(&self, offset: u64, data: &mut [u8]) {
|
|
|
|
self.read_config_from_slice(self.config.lock().unwrap().as_slice(), offset, data);
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn activate(
|
|
|
|
&mut self,
|
2020-02-11 16:22:40 +00:00
|
|
|
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
2020-01-13 17:52:19 +00:00
|
|
|
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
2019-07-22 18:50:56 +00:00
|
|
|
queues: Vec<Queue>,
|
|
|
|
mut queue_evts: Vec<EventFd>,
|
|
|
|
) -> ActivateResult {
|
2020-09-04 08:37:37 +00:00
|
|
|
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
self.input
|
|
|
|
.acked_features
|
2020-09-03 09:37:36 +00:00
|
|
|
.store(self.common.acked_features, Ordering::Relaxed);
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
|
2020-09-03 09:37:36 +00:00
|
|
|
if self.common.feature_acked(VIRTIO_CONSOLE_F_SIZE) {
|
2020-01-13 17:52:19 +00:00
|
|
|
if let Err(e) = interrupt_cb.trigger(&VirtioInterruptType::Config, None) {
|
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>
2019-07-23 19:18:20 +00:00
|
|
|
error!("Failed to signal console driver: {:?}", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 08:37:37 +00:00
|
|
|
let kill_evt = self
|
|
|
|
.common
|
|
|
|
.kill_evt
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.try_clone()
|
|
|
|
.map_err(|e| {
|
|
|
|
error!("failed to clone kill_evt eventfd: {}", e);
|
|
|
|
ActivateError::BadActivate
|
|
|
|
})?;
|
|
|
|
let pause_evt = self
|
|
|
|
.common
|
|
|
|
.pause_evt
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.try_clone()
|
|
|
|
.map_err(|e| {
|
|
|
|
error!("failed to clone pause_evt eventfd: {}", e);
|
|
|
|
ActivateError::BadActivate
|
|
|
|
})?;
|
|
|
|
|
2019-10-04 16:38:43 +00:00
|
|
|
let mut handler = ConsoleEpollHandler {
|
|
|
|
queues,
|
|
|
|
mem,
|
|
|
|
interrupt_cb,
|
|
|
|
in_buffer: self.input.in_buffer.clone(),
|
|
|
|
out: self.out.clone(),
|
|
|
|
input_queue_evt: queue_evts.remove(0),
|
|
|
|
output_queue_evt: queue_evts.remove(0),
|
|
|
|
input_evt: self.input.input_evt.try_clone().unwrap(),
|
|
|
|
config_evt: self.input.config_evt.try_clone().unwrap(),
|
|
|
|
kill_evt,
|
2019-11-19 00:42:31 +00:00
|
|
|
pause_evt,
|
2019-10-04 16:38:43 +00:00
|
|
|
};
|
2019-07-22 18:50:56 +00:00
|
|
|
|
2020-09-04 08:37:37 +00:00
|
|
|
let paused = self.common.paused.clone();
|
|
|
|
let paused_sync = self.common.paused_sync.clone();
|
2020-01-27 12:56:05 +00:00
|
|
|
let mut epoll_threads = Vec::new();
|
2020-08-04 18:12:05 +00:00
|
|
|
// Retrieve seccomp filter for virtio_console thread
|
|
|
|
let virtio_console_seccomp_filter =
|
|
|
|
get_seccomp_filter(&self.seccomp_action, Thread::VirtioConsole)
|
|
|
|
.map_err(ActivateError::CreateSeccompFilter)?;
|
2019-11-19 00:42:31 +00:00
|
|
|
thread::Builder::new()
|
2021-01-13 13:10:36 +00:00
|
|
|
.name(self.id.clone())
|
2020-08-04 18:12:05 +00:00
|
|
|
.spawn(move || {
|
2020-08-11 15:38:13 +00:00
|
|
|
if let Err(e) = SeccompFilter::apply(virtio_console_seccomp_filter) {
|
|
|
|
error!("Error applying seccomp filter: {:?}", e);
|
2020-09-04 08:37:37 +00:00
|
|
|
} else if let Err(e) = handler.run(paused, paused_sync.unwrap()) {
|
2020-08-11 15:38:13 +00:00
|
|
|
error!("Error running worker: {:?}", e);
|
|
|
|
}
|
2020-08-04 18:12:05 +00:00
|
|
|
})
|
2020-01-27 12:56:05 +00:00
|
|
|
.map(|thread| epoll_threads.push(thread))
|
2019-11-19 00:42:31 +00:00
|
|
|
.map_err(|e| {
|
|
|
|
error!("failed to clone the virtio-console epoll thread: {}", e);
|
|
|
|
ActivateError::BadActivate
|
|
|
|
})?;
|
2019-07-22 18:50:56 +00:00
|
|
|
|
2020-09-04 08:37:37 +00:00
|
|
|
self.common.epoll_threads = Some(epoll_threads);
|
2020-01-27 12:56:05 +00:00
|
|
|
|
2021-02-18 15:10:51 +00:00
|
|
|
event!("virtio-device", "activated", "id", &self.id);
|
2019-10-04 16:38:43 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-18 12:38:08 +00:00
|
|
|
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
|
2021-02-18 15:10:51 +00:00
|
|
|
let result = self.common.reset();
|
|
|
|
event!("virtio-device", "reset", "id", &self.id);
|
|
|
|
result
|
2020-09-04 08:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-19 00:42:31 +00:00
|
|
|
|
2020-09-04 08:37:37 +00:00
|
|
|
impl Pausable for Console {
|
|
|
|
fn pause(&mut self) -> result::Result<(), MigratableError> {
|
|
|
|
self.common.pause()
|
|
|
|
}
|
2019-10-04 16:38:43 +00:00
|
|
|
|
2020-09-04 08:37:37 +00:00
|
|
|
fn resume(&mut self) -> result::Result<(), MigratableError> {
|
|
|
|
self.common.resume()
|
2019-07-22 18:50:56 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-19 00:42:31 +00:00
|
|
|
|
2020-04-09 08:41:52 +00:00
|
|
|
impl Snapshottable for Console {
|
|
|
|
fn id(&self) -> String {
|
2020-04-27 12:05:29 +00:00
|
|
|
self.id.clone()
|
2020-04-09 08:41:52 +00:00
|
|
|
}
|
|
|
|
|
2020-08-21 12:31:58 +00:00
|
|
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
2021-05-06 13:34:31 +00:00
|
|
|
Snapshot::new_from_versioned_state(&self.id, &self.state())
|
2020-04-09 08:41:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
2021-05-06 13:34:31 +00:00
|
|
|
self.set_state(&snapshot.to_versioned_state(&self.id)?);
|
2021-04-08 09:20:10 +00:00
|
|
|
Ok(())
|
2020-04-09 08:41:52 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-01 16:59:51 +00:00
|
|
|
impl Transportable for Console {}
|
2019-11-19 00:42:31 +00:00
|
|
|
impl Migratable for Console {}
|