-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate initial virtio console implementation #217
base: main
Are you sure you want to change the base?
Conversation
9fc51ca
to
5cb7cef
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work, I'll finish the review tomorrow.
5cb7cef
to
f06f594
Compare
dcf40ba
to
dbbcf17
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few other comments. Will finish the review early next week.
Ok(used_len) => used_len, | ||
Err(e) => { | ||
self.receiveq.state.go_to_previous_position(); | ||
return Err(Error::Console(e)); | ||
} | ||
}; | ||
if used_len == 0 { | ||
self.receiveq.state.go_to_previous_position(); | ||
break; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have to think a bit more about this. I think process_receiveq_chain
can fail even if there were some bytes written to the chain, in which case we shouldn't go back one position in the available ring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be achieved by using a write
method in process_receiveq_chain
that also returns the numbers of bytes successfully written to memory, and return that value even when we fail with an error there (there is something similar done for block https://github.com/rust-vmm/vm-virtio/blob/main/crates/devices/virtio-blk/src/stdio_executor.rs#L339). This is a bit more complicated and requires some dive deep, I think we can postpone it for a future PR of virtio-console.
Ok(used_len) => used_len, | ||
Err(e) => { | ||
self.receiveq.state.go_to_previous_position(); | ||
return Err(Error::Console(e)); | ||
} | ||
}; | ||
if used_len == 0 { | ||
self.receiveq.state.go_to_previous_position(); | ||
break; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be achieved by using a write
method in process_receiveq_chain
that also returns the numbers of bytes successfully written to memory, and return that value even when we fail with an error there (there is something similar done for block https://github.com/rust-vmm/vm-virtio/blob/main/crates/devices/virtio-blk/src/stdio_executor.rs#L339). This is a bit more complicated and requires some dive deep, I think we can postpone it for a future PR of virtio-console.
src/api/src/lib.rs
Outdated
.long("console") | ||
.required(false) | ||
.takes_value(true) | ||
.help("Console configuration. \n\tFormat: \"type=<string>\"") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the possible types here? For the other ones it is self explanatory what the value of the configuration is (i.e. a path, kernel_load_addr, etc), but for this one it is not. We should write the possible values in the help here, and also when we are parsing it, we should check that the value is one of the supported ones.
src/api/src/lib.rs
Outdated
@@ -236,6 +244,7 @@ mod tests { | |||
vcpu_config: VcpuConfig { num: 1 }, | |||
block_config: None, | |||
net_config: None, | |||
console_config: None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should update the test to have a console_config that's being parsed as well. Best would be to have it with all possible values.
]; | ||
|
||
let config_space = Vec::new(); | ||
let virtio_cfg = VirtioConfig::new(device_features, queues, config_space); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: too many whitespaces. Why do we need them?
T: Write, | ||
{ | ||
pub fn process_transmitq(&mut self) -> result::Result<(), Error> { | ||
// To see why this is done in a loop, please look at the `Queue::enable_notification` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very likely to be outdated in the future. Can you add a short description at least for why we do the loop here? You can say that more details can be found in the Queue:enable_notification
function, but we should have at least a short description here as well.
const TRANSMITQ_EVENT: u32 = 1; | ||
const RECEIVEQ_EVENT: u32 = 2; | ||
|
||
const STDIN_BUFFER_SIZE: usize = 1024; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this taken from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a random value. To figure out a good one we should run some tests. I tried with some python tests but I could not measure the time it takes to send data to the driver accurately.
} | ||
} | ||
} | ||
if !failed { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this as opposed to just handling the errors as they happen? I think this can be significantly shorten by just returning the error directly.
if let Err(e) = self.transmitqfd.read() { | ||
error!("Could not read transmitq event fd: {:?}", e); | ||
} else if let Err(e) = self.inner.process_transmitq() { | ||
error!("Transmitq processing failed: {:?}", e); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you try to use and_then
to reduce some of these lines of code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried using and_then
/or_else
to keep the error messages and it made the code more convoluted. I think this is easier to understand. I will change it if you think it is better that way.
src/vmm/src/config/mod.rs
Outdated
#[derive(Clone, Debug, PartialEq)] | ||
pub struct ConsoleConfig { | ||
/// Type of console. | ||
pub console_type: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be an enum instead of a String
. In the enum we would then have 2 variants: uart and virtio.
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]>
dbbcf17
to
9e220e5
Compare
driver_notify, | ||
receiveq: self.cfg.virtio.queues.remove(0), | ||
transmitq: self.cfg.virtio.queues.remove(0), | ||
console: console::Console::new_with_capacity(console::DEFAULT_CAPACITY, stdout()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can use here the new
constructor or even the Default
implementation.
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause | ||
|
||
use crate::virtio::console::CONSOLE_DEVICE_ID; | ||
use crate::virtio::features::{VIRTIO_F_IN_ORDER, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_VERSION_1}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we group together the crate
imports, same comment for the external crates (see use virtio_console::console
below)?
type Error = ConversionError; | ||
|
||
fn try_from(console_cfg_str: &str) -> Result<Self, Self::Error> { | ||
// Supported options: `type=String` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct, we support only type=virtio/console.
@@ -252,6 +306,7 @@ mod tests { | |||
vcpu_config: VcpuConfig { num: 1 }, | |||
block_config: None, | |||
net_config: None, | |||
console_config: None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be uart?
let console_type_str: String = arg_parser | ||
.value_of("type") | ||
.map_err(ConversionError::new_console)? | ||
.ok_or_else(|| ConversionError::new_console("Missing required argument: type"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think type
is not required, right? So if the user doesn't pass it, then we set here the default value, or am I missing something?
output_lines = data.split(b'\r\n') | ||
last = output_lines[-1].strip() | ||
if prompt in last: | ||
total_data += data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to move this fix to a separate commit and explain a bit what is it about.
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]
Summary of the PR
Added a virtio console device with similar queue handling as the block and
network devices in vmm-reference. Part of the implementation is found in
the vm-virtio repository. For now it is linked to my personal repo until it
will be merged.
Requirements
Before submitting your PR, please make sure you addressed the following
requirements:
git commit -s
), and the commitmessage has max 60 characters for the summary and max 75 characters for each
description line.
test.
unsafe
code is properly documented.