From 1b58b72d8336ed74c2484ec96108e8b0484a9b00 Mon Sep 17 00:00:00 2001 From: gjz010 Date: Tue, 11 May 2021 00:15:10 +0800 Subject: [PATCH 1/2] added virtio-console support. --- src/console.rs | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + 2 files changed, 132 insertions(+) create mode 100644 src/console.rs diff --git a/src/console.rs b/src/console.rs new file mode 100644 index 00000000..dc82ec39 --- /dev/null +++ b/src/console.rs @@ -0,0 +1,130 @@ +use super::*; +use crate::queue::VirtQueue; +use bitflags::*; +use core::sync::atomic::spin_loop_hint; +use log::*; +use volatile::{ReadOnly, WriteOnly}; + +const QUEUE_RECEIVEQ_PORT_0: usize = 0; +const QUEUE_TRANSMITQ_PORT_0: usize = 1; + +/// Virtio console. Only one single port is allowed since ``alloc'' is disabled. +/// Emergency and cols/rows unimplemented. +pub struct VirtIOConsole<'a> { + header: &'static mut VirtIOHeader, + receiveq: VirtQueue<'a>, + transmitq: VirtQueue<'a>, + queue_buf_dma: DMA, + queue_buf_rx: &'a mut [u8], + cursor: usize, + pending_len: usize, +} + +impl<'a> VirtIOConsole<'a> { + /// Create a new VirtIO-Console driver. + pub fn new(header: &'static mut VirtIOHeader) -> Result { + header.begin_init(|features| { + let features = Features::from_bits_truncate(features); + info!("Device features {:?}", features); + let supported_features = Features::empty(); + (features & supported_features).bits() + }); + let config = unsafe { &mut *(header.config_space() as *mut Config) }; + info!("Config: {:?}", config); + let receiveq = VirtQueue::new(header, QUEUE_RECEIVEQ_PORT_0, 2)?; + let transmitq = VirtQueue::new(header, QUEUE_TRANSMITQ_PORT_0, 2)?; + let queue_buf_dma = DMA::new(1)?; + let queue_buf_rx = unsafe { &mut queue_buf_dma.as_buf()[0..] }; + header.finish_init(); + let mut console = VirtIOConsole { + header, + receiveq, + transmitq, + queue_buf_dma, + queue_buf_rx, + cursor: 0, + pending_len: 0, + }; + console.poll_retrieve()?; + Ok(console) + } + fn poll_retrieve(&mut self) -> Result<()> { + self.receiveq.add(&[], &[self.queue_buf_rx])?; + Ok(()) + } + /// Acknowledge interrupt. + pub fn ack_interrupt(&mut self) -> Result { + let ack = self.header.ack_interrupt(); + if !ack { + return Ok(false); + } + let mut flag = false; + while let Ok((_token, len)) = self.receiveq.pop_used() { + assert_eq!(flag, false); + flag = true; + assert_ne!(len, 0); + self.cursor = 0; + self.pending_len = len as usize; + } + Ok(flag) + } + + /// Try get char. + pub fn recv(&mut self, pop: bool) -> Result> { + if self.cursor == self.pending_len { + return Ok(None); + } + let ch = self.queue_buf_rx[self.cursor]; + if pop { + self.cursor += 1; + if self.cursor == self.pending_len { + self.poll_retrieve()?; + } + } + Ok(Some(ch)) + } + /// Put a char onto the device. + pub fn send(&mut self, chr: u8) -> Result<()> { + let buf: [u8; 1] = [chr]; + self.transmitq.add(&[&buf], &[])?; + self.header.notify(QUEUE_TRANSMITQ_PORT_0 as u32); + while !self.transmitq.can_pop() { + spin_loop_hint(); + } + self.transmitq.pop_used()?; + Ok(()) + } +} + +#[repr(C)] +#[derive(Debug)] +struct Config { + cols: ReadOnly, + rows: ReadOnly, + max_nr_ports: ReadOnly, + emerg_wr: WriteOnly, +} + +bitflags! { + struct Features: u64 { + const SIZE = 1 << 0; + const MULTIPORT = 1 << 1; + const EMERG_WRITE = 1 << 2; + + // device independent + const NOTIFY_ON_EMPTY = 1 << 24; // legacy + const ANY_LAYOUT = 1 << 27; // legacy + const RING_INDIRECT_DESC = 1 << 28; + const RING_EVENT_IDX = 1 << 29; + const UNUSED = 1 << 30; // legacy + const VERSION_1 = 1 << 32; // detect legacy + + // since virtio v1.1 + const ACCESS_PLATFORM = 1 << 33; + const RING_PACKED = 1 << 34; + const IN_ORDER = 1 << 35; + const ORDER_PLATFORM = 1 << 36; + const SR_IOV = 1 << 37; + const NOTIFICATION_DATA = 1 << 38; + } +} diff --git a/src/lib.rs b/src/lib.rs index ab855c67..12232987 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ extern crate log; mod blk; +mod console; mod gpu; mod hal; mod header; @@ -17,6 +18,7 @@ mod net; mod queue; pub use self::blk::VirtIOBlk; +pub use self::console::VirtIOConsole; pub use self::gpu::VirtIOGpu; pub use self::header::*; pub use self::input::VirtIOInput; From 1201a0b40c016301c8135e564439e40a769facc8 Mon Sep 17 00:00:00 2001 From: gjz010 Date: Tue, 11 May 2021 00:20:39 +0800 Subject: [PATCH 2/2] readme --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 27d13c30..ef63b481 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,15 @@ VirtIO guest drivers in Rust. For **no_std + no_alloc** environment. ## Components -| Device | Status | -| ------ | ----------------- | -| Queue | ✅ | -| Block | ✅ | -| Net | ✅ | -| GPU | ✅ | -| Input | ✅ | -| ... | ❌ Not implemented | +| Device | Status | +| -------- | ------------------- | +| Queue | ✅ | +| Block | ✅ | +| Net | ✅ | +| GPU | ✅ | +| Input | ✅ | +| Console | ✅ | +| ... | ❌ Not implemented | ## Examples & Tests