Skip to content

Commit 9e220e5

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 <[email protected]>
1 parent ad37189 commit 9e220e5

File tree

17 files changed

+707
-29
lines changed

17 files changed

+707
-29
lines changed

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: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ 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>\" \
60+
\nPossible values for \"type\":\
61+
\n\t * uart - Use the serial UART console.\
62+
\n\t * virtio - Use the virtio console.\
63+
\nUses the UART console by default if the \"--console\" \
64+
option is not present.")
5365
);
5466

5567
// Save the usage beforehand as a string, because `get_matches` consumes the `App`.
@@ -69,6 +81,7 @@ impl Cli {
6981
.vcpu_config(matches.value_of("vcpu"))
7082
.net_config(matches.value_of("net"))
7183
.block_config(matches.value_of("block"))
84+
.console_config(matches.value_of("console"))
7285
.build()
7386
.map_err(|e| format!("{:?}", e))
7487
}
@@ -82,7 +95,10 @@ mod tests {
8295

8396
use linux_loader::cmdline::Cmdline;
8497

85-
use vmm::{KernelConfig, MemoryConfig, VcpuConfig, DEFAULT_KERNEL_LOAD_ADDR};
98+
use vmm::{
99+
ConsoleConfig, ConsoleType, KernelConfig, MemoryConfig, VcpuConfig,
100+
DEFAULT_KERNEL_LOAD_ADDR,
101+
};
86102

87103
#[test]
88104
fn test_launch() {
@@ -214,7 +230,40 @@ mod tests {
214230
let mut foo_cmdline = Cmdline::new(4096);
215231
foo_cmdline.insert_str("\"foo=bar bar=foo\"").unwrap();
216232

217-
// OK.
233+
// OK. Virtio console.
234+
assert_eq!(
235+
Cli::launch(vec![
236+
"foobar",
237+
"--memory",
238+
"size_mib=128",
239+
"--vcpu",
240+
"num=1",
241+
"--kernel",
242+
"path=/foo/bar,cmdline=\"foo=bar bar=foo\",kernel_load_addr=42",
243+
"--console",
244+
"type=virtio",
245+
])
246+
.unwrap(),
247+
VMMConfig {
248+
kernel_config: KernelConfig {
249+
path: PathBuf::from("/foo/bar"),
250+
cmdline: foo_cmdline,
251+
load_addr: 42,
252+
},
253+
memory_config: MemoryConfig { size_mib: 128 },
254+
vcpu_config: VcpuConfig { num: 1 },
255+
block_config: None,
256+
net_config: None,
257+
console_config: Some(ConsoleConfig {
258+
console_type: ConsoleType::Virtio
259+
}),
260+
}
261+
);
262+
263+
let mut foo_cmdline = Cmdline::new(4096);
264+
foo_cmdline.insert_str("\"foo=bar bar=foo\"").unwrap();
265+
266+
// OK. UART console.
218267
assert_eq!(
219268
Cli::launch(vec![
220269
"foobar",
@@ -224,6 +273,8 @@ mod tests {
224273
"num=1",
225274
"--kernel",
226275
"path=/foo/bar,cmdline=\"foo=bar bar=foo\",kernel_load_addr=42",
276+
"--console",
277+
"type=uart",
227278
])
228279
.unwrap(),
229280
VMMConfig {
@@ -236,6 +287,9 @@ mod tests {
236287
vcpu_config: VcpuConfig { num: 1 },
237288
block_config: None,
238289
net_config: None,
290+
console_config: Some(ConsoleConfig {
291+
console_type: ConsoleType::Uart
292+
}),
239293
}
240294
);
241295

@@ -252,6 +306,7 @@ mod tests {
252306
vcpu_config: VcpuConfig { num: 1 },
253307
block_config: None,
254308
net_config: None,
309+
console_config: None
255310
}
256311
);
257312
}

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/rust-vmm/vm-virtio.git", rev = "1cde0af5c80aead5e44018029b5ecc0be83dea50", features = ["backend-stdio"] }
20+
virtio-device = { git = "https://github.com/rust-vmm/vm-virtio.git", rev = "1cde0af5c80aead5e44018029b5ecc0be83dea50"}
21+
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio.git", rev = "1cde0af5c80aead5e44018029b5ecc0be83dea50"}
22+
virtio-console = { git = "https://github.com/rust-vmm/vm-virtio.git", rev = "1cde0af5c80aead5e44018029b5ecc0be83dea50"}
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: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
3+
4+
use crate::virtio::console::CONSOLE_DEVICE_ID;
5+
use crate::virtio::features::{VIRTIO_F_IN_ORDER, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_VERSION_1};
6+
7+
use std::borrow::{Borrow, BorrowMut};
8+
use std::io::stdout;
9+
use std::ops::DerefMut;
10+
use std::sync::{Arc, Mutex};
11+
use virtio_console::console;
12+
13+
use super::inorder_handler::InOrderQueueHandler;
14+
use crate::virtio::console::queue_handler::QueueHandler;
15+
use crate::virtio::{CommonConfig, Env, SingleFdSignalQueue, QUEUE_MAX_SIZE};
16+
use virtio_device::{VirtioConfig, VirtioDeviceActions, VirtioDeviceType, VirtioMmioDevice};
17+
use virtio_queue::Queue;
18+
use vm_device::bus::MmioAddress;
19+
use vm_device::device_manager::MmioManager;
20+
use vm_device::{DeviceMmio, MutDeviceMmio};
21+
use vm_memory::GuestAddressSpace;
22+
23+
use super::{Error, Result};
24+
25+
pub struct Console<M: GuestAddressSpace> {
26+
cfg: CommonConfig<M>,
27+
}
28+
29+
impl<M> Console<M>
30+
where
31+
M: GuestAddressSpace + Clone + Send + 'static,
32+
{
33+
pub fn new<B>(env: &mut Env<M, B>) -> Result<Arc<Mutex<Self>>>
34+
where
35+
// We're using this (more convoluted) bound so we can pass both references and smart
36+
// pointers such as mutex guards here.
37+
B: DerefMut,
38+
B::Target: MmioManager<D = Arc<dyn DeviceMmio + Send + Sync>>,
39+
{
40+
let device_features =
41+
(1 << VIRTIO_F_VERSION_1) | (1 << VIRTIO_F_IN_ORDER) | (1 << VIRTIO_F_RING_EVENT_IDX);
42+
let queues = vec![
43+
Queue::new(env.mem.clone(), QUEUE_MAX_SIZE),
44+
Queue::new(env.mem.clone(), QUEUE_MAX_SIZE),
45+
];
46+
// TODO: Add a config space to implement the optional features of the console.
47+
// For basic operation it can be left empty.
48+
let config_space = Vec::new();
49+
let virtio_cfg = VirtioConfig::new(device_features, queues, config_space);
50+
let common_cfg = CommonConfig::new(virtio_cfg, env).map_err(Error::Virtio)?;
51+
let console = Arc::new(Mutex::new(Console { cfg: common_cfg }));
52+
53+
env.register_mmio_device(console.clone())
54+
.map_err(Error::Virtio)?;
55+
56+
Ok(console)
57+
}
58+
}
59+
60+
impl<M: GuestAddressSpace + Clone + Send + 'static> VirtioDeviceType for Console<M> {
61+
fn device_type(&self) -> u32 {
62+
CONSOLE_DEVICE_ID
63+
}
64+
}
65+
66+
impl<M: GuestAddressSpace + Clone + Send + 'static> Borrow<VirtioConfig<M>> for Console<M> {
67+
fn borrow(&self) -> &VirtioConfig<M> {
68+
&self.cfg.virtio
69+
}
70+
}
71+
72+
impl<M: GuestAddressSpace + Clone + Send + 'static> BorrowMut<VirtioConfig<M>> for Console<M> {
73+
fn borrow_mut(&mut self) -> &mut VirtioConfig<M> {
74+
&mut self.cfg.virtio
75+
}
76+
}
77+
78+
impl<M: GuestAddressSpace + Clone + Send + 'static> VirtioDeviceActions for Console<M> {
79+
type E = Error;
80+
81+
fn activate(&mut self) -> Result<()> {
82+
let driver_notify = SingleFdSignalQueue {
83+
irqfd: self.cfg.irqfd.clone(),
84+
interrupt_status: self.cfg.virtio.interrupt_status.clone(),
85+
};
86+
87+
let mut ioevents = self.cfg.prepare_activate().map_err(Error::Virtio)?;
88+
89+
let inner = InOrderQueueHandler {
90+
driver_notify,
91+
receiveq: self.cfg.virtio.queues.remove(0),
92+
transmitq: self.cfg.virtio.queues.remove(0),
93+
console: console::Console::new_with_capacity(console::DEFAULT_CAPACITY, stdout())
94+
.map_err(Error::Console)?,
95+
};
96+
97+
let handler = Arc::new(Mutex::new(QueueHandler {
98+
inner,
99+
receiveqfd: ioevents.remove(0),
100+
transmitqfd: ioevents.remove(0),
101+
}));
102+
103+
self.cfg.finalize_activate(handler).map_err(Error::Virtio)
104+
}
105+
106+
fn reset(&mut self) -> Result<()> {
107+
// Not implemented for now.
108+
Ok(())
109+
}
110+
}
111+
112+
impl<M: GuestAddressSpace + Clone + Send + 'static> VirtioMmioDevice<M> for Console<M> {}
113+
114+
impl<M: GuestAddressSpace + Clone + Send + 'static> MutDeviceMmio for Console<M> {
115+
fn mmio_read(&mut self, _base: MmioAddress, offset: u64, data: &mut [u8]) {
116+
self.read(offset, data);
117+
}
118+
119+
fn mmio_write(&mut self, _base: MmioAddress, offset: u64, data: &[u8]) {
120+
self.write(offset, data);
121+
}
122+
}

0 commit comments

Comments
 (0)