Skip to content

Commit dbbcf17

Browse files
committed
Init virtio console.
Added a virtio console device to replace the UART serial console. The implementation is divided between vm-virtio and vmm-reference. Signed-off-by: Niculae Radu <r.niculae99@gmail.com>
1 parent ad37189 commit dbbcf17

17 files changed

Lines changed: 544 additions & 20 deletions

File tree

Cargo.lock

Lines changed: 16 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ impl Cli {
5050
.required(false)
5151
.takes_value(true)
5252
.help("Block device configuration. \n\tFormat: \"path=<string>\"")
53+
)
54+
.arg(
55+
Arg::with_name("console")
56+
.long("console")
57+
.required(false)
58+
.takes_value(true)
59+
.help("Console configuration. \n\tFormat: \"type=<string>\"")
5360
);
5461

5562
// Save the usage beforehand as a string, because `get_matches` consumes the `App`.
@@ -69,6 +76,7 @@ impl Cli {
6976
.vcpu_config(matches.value_of("vcpu"))
7077
.net_config(matches.value_of("net"))
7178
.block_config(matches.value_of("block"))
79+
.console_config(matches.value_of("console"))
7280
.build()
7381
.map_err(|e| format!("{:?}", e))
7482
}
@@ -236,6 +244,7 @@ mod tests {
236244
vcpu_config: VcpuConfig { num: 1 },
237245
block_config: None,
238246
net_config: None,
247+
console_config: None
239248
}
240249
);
241250

@@ -252,6 +261,7 @@ mod tests {
252261
vcpu_config: VcpuConfig { num: 1 },
253262
block_config: None,
254263
net_config: None,
264+
console_config: None
255265
}
256266
);
257267
}

src/arch/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ edition = "2018"
88

99
[dependencies]
1010
vm-fdt = "0.2.0"
11-
vm-memory = "0.7.0"
11+
vm-memory = "0.8.0"

src/devices/Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ kvm-ioctls = "0.11.0"
1111
libc = "0.2.76"
1212
linux-loader = "0.4.0"
1313
log = "0.4.6"
14-
vm-memory = "0.7.0"
14+
vm-memory = "0.8.0"
1515
vm-superio = "0.5.0"
1616
vmm-sys-util = "0.8.0"
1717
vm-device = "0.1.0"
1818

19-
virtio-blk = { git = "https://github.com/rust-vmm/vm-virtio.git", features = ["backend-stdio"] }
20-
virtio-device = { git = "https://github.com/rust-vmm/vm-virtio.git"}
21-
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio.git"}
19+
virtio-blk = { git = "https://github.com/RaduNiculae/vm-virtio.git", branch = "virtio-console", features = ["backend-stdio"] }
20+
virtio-device = { git = "https://github.com/RaduNiculae/vm-virtio.git", branch = "virtio-console"}
21+
virtio-queue = { git = "https://github.com/RaduNiculae/vm-virtio.git", branch = "virtio-console"}
22+
virtio-console = { git = "https://github.com/RaduNiculae/vm-virtio.git", branch = "virtio-console"}
2223

2324
utils = { path = "../utils" }
2425

2526
[dev-dependencies]
26-
vm-memory = { version = "0.7.0", features = ["backend-mmap"] }
27+
vm-memory = { version = "0.8.0", features = ["backend-mmap"] }
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use crate::virtio::console::{device_features, CONSOLE_DEVICE_ID};
2+
3+
use std::borrow::{Borrow, BorrowMut};
4+
use std::io::stdout;
5+
use std::ops::DerefMut;
6+
use std::sync::{Arc, Mutex};
7+
use virtio_console::console;
8+
9+
use super::inorder_handler::InOrderQueueHandler;
10+
use crate::virtio::console::queue_handler::QueueHandler;
11+
use crate::virtio::{CommonConfig, Env, SingleFdSignalQueue, QUEUE_MAX_SIZE};
12+
use virtio_device::{VirtioConfig, VirtioDeviceActions, VirtioDeviceType, VirtioMmioDevice};
13+
use virtio_queue::Queue;
14+
use vm_device::bus::MmioAddress;
15+
use vm_device::device_manager::MmioManager;
16+
use vm_device::{DeviceMmio, MutDeviceMmio};
17+
use vm_memory::GuestAddressSpace;
18+
19+
use super::{Error, Result};
20+
21+
pub struct Console<M: GuestAddressSpace> {
22+
cfg: CommonConfig<M>,
23+
}
24+
25+
impl<M> Console<M>
26+
where
27+
M: GuestAddressSpace + Clone + Send + 'static,
28+
{
29+
pub fn new<B>(env: &mut Env<M, B>) -> Result<Arc<Mutex<Self>>>
30+
where
31+
// We're using this (more convoluted) bound so we can pass both references and smart
32+
// pointers such as mutex guards here.
33+
B: DerefMut,
34+
B::Target: MmioManager<D = Arc<dyn DeviceMmio + Send + Sync>>,
35+
{
36+
let device_features = device_features();
37+
38+
let queues = vec![
39+
Queue::new(env.mem.clone(), QUEUE_MAX_SIZE),
40+
Queue::new(env.mem.clone(), QUEUE_MAX_SIZE),
41+
];
42+
43+
let config_space = Vec::new();
44+
let virtio_cfg = VirtioConfig::new(device_features, queues, config_space);
45+
46+
let common_cfg = CommonConfig::new(virtio_cfg, env).map_err(Error::Virtio)?;
47+
48+
let console = Arc::new(Mutex::new(Console { cfg: common_cfg }));
49+
50+
env.register_mmio_device(console.clone())
51+
.map_err(Error::Virtio)?;
52+
53+
Ok(console)
54+
}
55+
}
56+
57+
impl<M: GuestAddressSpace + Clone + Send + 'static> VirtioDeviceType for Console<M> {
58+
fn device_type(&self) -> u32 {
59+
CONSOLE_DEVICE_ID
60+
}
61+
}
62+
63+
impl<M: GuestAddressSpace + Clone + Send + 'static> Borrow<VirtioConfig<M>> for Console<M> {
64+
fn borrow(&self) -> &VirtioConfig<M> {
65+
&self.cfg.virtio
66+
}
67+
}
68+
69+
impl<M: GuestAddressSpace + Clone + Send + 'static> BorrowMut<VirtioConfig<M>> for Console<M> {
70+
fn borrow_mut(&mut self) -> &mut VirtioConfig<M> {
71+
&mut self.cfg.virtio
72+
}
73+
}
74+
75+
impl<M: GuestAddressSpace + Clone + Send + 'static> VirtioDeviceActions for Console<M> {
76+
type E = Error;
77+
78+
fn activate(&mut self) -> Result<()> {
79+
let driver_notify = SingleFdSignalQueue {
80+
irqfd: self.cfg.irqfd.clone(),
81+
interrupt_status: self.cfg.virtio.interrupt_status.clone(),
82+
};
83+
84+
let mut ioevents = self.cfg.prepare_activate().map_err(Error::Virtio)?;
85+
86+
let inner = InOrderQueueHandler {
87+
driver_notify,
88+
receiveq: self.cfg.virtio.queues.remove(0),
89+
transmitq: self.cfg.virtio.queues.remove(0),
90+
console: console::Console::new(stdout()),
91+
};
92+
93+
let handler = Arc::new(Mutex::new(QueueHandler {
94+
inner,
95+
receiveqfd: ioevents.remove(0),
96+
transmitqfd: ioevents.remove(0),
97+
}));
98+
99+
self.cfg.finalize_activate(handler).map_err(Error::Virtio)
100+
}
101+
102+
fn reset(&mut self) -> Result<()> {
103+
// Not implemented for now.
104+
Ok(())
105+
}
106+
}
107+
108+
impl<M: GuestAddressSpace + Clone + Send + 'static> VirtioMmioDevice<M> for Console<M> {}
109+
110+
impl<M: GuestAddressSpace + Clone + Send + 'static> MutDeviceMmio for Console<M> {
111+
fn mmio_read(&mut self, _base: MmioAddress, offset: u64, data: &mut [u8]) {
112+
self.read(offset, data);
113+
}
114+
115+
fn mmio_write(&mut self, _base: MmioAddress, offset: u64, data: &[u8]) {
116+
self.write(offset, data);
117+
}
118+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use crate::virtio::SignalUsedQueue;
2+
use std::io::Write;
3+
use std::result;
4+
use virtio_console::console;
5+
use virtio_queue::{Queue, QueueStateOwnedT, QueueStateT};
6+
use vm_memory::GuestAddressSpace;
7+
8+
#[derive(Debug)]
9+
pub enum Error {
10+
GuestMemory(vm_memory::GuestMemoryError),
11+
Queue(virtio_queue::Error),
12+
Console(console::Error),
13+
}
14+
15+
impl From<vm_memory::GuestMemoryError> for Error {
16+
fn from(e: vm_memory::GuestMemoryError) -> Self {
17+
Error::GuestMemory(e)
18+
}
19+
}
20+
21+
impl From<virtio_queue::Error> for Error {
22+
fn from(e: virtio_queue::Error) -> Self {
23+
Error::Queue(e)
24+
}
25+
}
26+
27+
impl From<console::Error> for Error {
28+
fn from(e: console::Error) -> Self {
29+
Error::Console(e)
30+
}
31+
}
32+
33+
pub struct InOrderQueueHandler<M: GuestAddressSpace, S: SignalUsedQueue, T: Write> {
34+
pub driver_notify: S,
35+
pub transmitq: Queue<M>,
36+
pub receiveq: Queue<M>,
37+
pub console: console::Console<T>,
38+
}
39+
40+
impl<M, S, T> InOrderQueueHandler<M, S, T>
41+
where
42+
M: GuestAddressSpace,
43+
S: SignalUsedQueue,
44+
T: Write,
45+
{
46+
pub fn process_transmitq(&mut self) -> result::Result<(), Error> {
47+
// To see why this is done in a loop, please look at the `Queue::enable_notification`
48+
// comments in `virtio_queue`.
49+
loop {
50+
self.transmitq.disable_notification()?;
51+
52+
while let Some(mut chain) = self
53+
.transmitq
54+
.state
55+
.pop_descriptor_chain(self.transmitq.mem.memory())
56+
{
57+
self.console.process_transmitq_chain(&mut chain)?;
58+
59+
self.transmitq.add_used(chain.head_index(), 0)?;
60+
}
61+
if !self.transmitq.enable_notification()? {
62+
break;
63+
}
64+
}
65+
if self.transmitq.needs_notification()? {
66+
self.driver_notify.signal_used_queue(1);
67+
}
68+
69+
Ok(())
70+
}
71+
72+
pub fn process_receiveq(&mut self) -> result::Result<(), Error> {
73+
// To see why this is done in a loop, please look at the `Queue::enable_notification`
74+
// comments in `virtio_queue`.
75+
let mut notify = false;
76+
77+
loop {
78+
self.receiveq.disable_notification()?;
79+
80+
while let Some(mut chain) = self
81+
.receiveq
82+
.state
83+
.pop_descriptor_chain(self.receiveq.mem.memory())
84+
{
85+
let used_len = match self.console.process_receiveq_chain(&mut chain) {
86+
Ok(used_len) => used_len,
87+
Err(e) => {
88+
self.receiveq.state.go_to_previous_position();
89+
return Err(Error::Console(e));
90+
}
91+
};
92+
if used_len == 0 {
93+
self.receiveq.state.go_to_previous_position();
94+
break;
95+
}
96+
self.receiveq
97+
.add_used(chain.head_index(), used_len as u32)?;
98+
notify = true;
99+
}
100+
101+
if self.console.is_input_buffer_empty() || !self.receiveq.enable_notification()? {
102+
break;
103+
}
104+
}
105+
106+
if notify && self.receiveq.needs_notification()? {
107+
self.driver_notify.signal_used_queue(0);
108+
}
109+
110+
Ok(())
111+
}
112+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
mod device;
2+
mod inorder_handler;
3+
mod queue_handler;
4+
5+
pub use device::Console;
6+
7+
use crate::virtio::features::VIRTIO_F_IN_ORDER;
8+
use crate::virtio::features::VIRTIO_F_RING_EVENT_IDX;
9+
use crate::virtio::features::VIRTIO_F_VERSION_1;
10+
11+
// Console device ID as defined by the standard.
12+
pub const CONSOLE_DEVICE_ID: u32 = 3;
13+
14+
#[derive(Debug)]
15+
pub enum Error {
16+
Virtio(crate::virtio::Error),
17+
Console(virtio_console::console::Error),
18+
}
19+
pub type Result<T> = std::result::Result<T, Error>;
20+
21+
pub fn device_features() -> u64 {
22+
1 << VIRTIO_F_VERSION_1 | 1 << VIRTIO_F_IN_ORDER | 1 << VIRTIO_F_RING_EVENT_IDX
23+
}

0 commit comments

Comments
 (0)