console.rs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. //! Driver for VirtIO console devices.
  2. use crate::hal::{BufferDirection, Dma, Hal};
  3. use crate::queue::VirtQueue;
  4. use crate::transport::Transport;
  5. use crate::volatile::{volread, ReadOnly, WriteOnly};
  6. use crate::Result;
  7. use bitflags::bitflags;
  8. use core::ptr::NonNull;
  9. use log::info;
  10. const QUEUE_RECEIVEQ_PORT_0: u16 = 0;
  11. const QUEUE_TRANSMITQ_PORT_0: u16 = 1;
  12. const QUEUE_SIZE: u16 = 2;
  13. /// Driver for a VirtIO console device.
  14. ///
  15. /// Only a single port is allowed since `alloc` is disabled. Emergency write and cols/rows are not
  16. /// implemented.
  17. ///
  18. /// # Example
  19. ///
  20. /// ```
  21. /// # use virtio_drivers::{Error, Hal, transport::Transport};
  22. /// use virtio_drivers::device::console::VirtIOConsole;
  23. /// # fn example<HalImpl: Hal, T: Transport>(transport: T) -> Result<(), Error> {
  24. /// let mut console = VirtIOConsole::<HalImpl, _>::new(transport)?;
  25. ///
  26. /// let info = console.info();
  27. /// println!("VirtIO console {}x{}", info.rows, info.columns);
  28. ///
  29. /// for &c in b"Hello console!\n" {
  30. /// console.send(c)?;
  31. /// }
  32. ///
  33. /// let c = console.recv(true)?;
  34. /// println!("Read {:?} from console.", c);
  35. /// # Ok(())
  36. /// # }
  37. /// ```
  38. pub struct VirtIOConsole<'a, H: Hal, T: Transport> {
  39. transport: T,
  40. config_space: NonNull<Config>,
  41. receiveq: VirtQueue<H>,
  42. transmitq: VirtQueue<H>,
  43. queue_buf_dma: Dma<H>,
  44. queue_buf_rx: &'a mut [u8],
  45. cursor: usize,
  46. pending_len: usize,
  47. /// The token of the outstanding receive request, if there is one.
  48. receive_token: Option<u16>,
  49. }
  50. /// Information about a console device, read from its configuration space.
  51. #[derive(Clone, Debug, Eq, PartialEq)]
  52. pub struct ConsoleInfo {
  53. /// The console height in characters.
  54. pub rows: u16,
  55. /// The console width in characters.
  56. pub columns: u16,
  57. /// The maxumum number of ports supported by the console device.
  58. pub max_ports: u32,
  59. }
  60. impl<H: Hal, T: Transport> VirtIOConsole<'_, H, T> {
  61. /// Creates a new VirtIO console driver.
  62. pub fn new(mut transport: T) -> Result<Self> {
  63. transport.begin_init(|features| {
  64. let features = Features::from_bits_truncate(features);
  65. info!("Device features {:?}", features);
  66. let supported_features = Features::empty();
  67. (features & supported_features).bits()
  68. });
  69. let config_space = transport.config_space::<Config>()?;
  70. let receiveq = VirtQueue::new(&mut transport, QUEUE_RECEIVEQ_PORT_0, QUEUE_SIZE)?;
  71. let transmitq = VirtQueue::new(&mut transport, QUEUE_TRANSMITQ_PORT_0, QUEUE_SIZE)?;
  72. let queue_buf_dma = Dma::new(1, BufferDirection::DeviceToDriver)?;
  73. let queue_buf_rx = unsafe { &mut queue_buf_dma.as_buf()[0..] };
  74. transport.finish_init();
  75. let mut console = VirtIOConsole {
  76. transport,
  77. config_space,
  78. receiveq,
  79. transmitq,
  80. queue_buf_dma,
  81. queue_buf_rx,
  82. cursor: 0,
  83. pending_len: 0,
  84. receive_token: None,
  85. };
  86. console.poll_retrieve()?;
  87. Ok(console)
  88. }
  89. /// Returns a struct with information about the console device, such as the number of rows and columns.
  90. pub fn info(&self) -> ConsoleInfo {
  91. // Safe because config_space is a valid pointer to the device configuration space.
  92. unsafe {
  93. let columns = volread!(self.config_space, cols);
  94. let rows = volread!(self.config_space, rows);
  95. let max_ports = volread!(self.config_space, max_nr_ports);
  96. ConsoleInfo {
  97. rows,
  98. columns,
  99. max_ports,
  100. }
  101. }
  102. }
  103. /// Makes a request to the device to receive data, if there is not already an outstanding
  104. /// receive request or some data already received and not yet returned.
  105. fn poll_retrieve(&mut self) -> Result<()> {
  106. if self.receive_token.is_none() && self.cursor == self.pending_len {
  107. // Safe because the buffer lasts at least as long as the queue, and there are no other
  108. // outstanding requests using the buffer.
  109. self.receive_token = Some(unsafe { self.receiveq.add(&[], &[self.queue_buf_rx]) }?);
  110. }
  111. Ok(())
  112. }
  113. /// Acknowledges a pending interrupt, if any, and completes the outstanding finished read
  114. /// request if there is one.
  115. ///
  116. /// Returns true if new data has been received.
  117. pub fn ack_interrupt(&mut self) -> Result<bool> {
  118. if !self.transport.ack_interrupt() {
  119. return Ok(false);
  120. }
  121. self.finish_receive()
  122. }
  123. /// If there is an outstanding receive request and it has finished, completes it.
  124. ///
  125. /// Returns true if new data has been received.
  126. fn finish_receive(&mut self) -> Result<bool> {
  127. let mut flag = false;
  128. if let Some(receive_token) = self.receive_token {
  129. if self.receive_token == self.receiveq.peek_used() {
  130. let len = self
  131. .receiveq
  132. .pop_used(receive_token, &[], &[self.queue_buf_rx])?;
  133. flag = true;
  134. assert_ne!(len, 0);
  135. self.cursor = 0;
  136. self.pending_len = len as usize;
  137. }
  138. }
  139. Ok(flag)
  140. }
  141. /// Returns the next available character from the console, if any.
  142. ///
  143. /// If no data has been received this will not block but immediately return `Ok<None>`.
  144. pub fn recv(&mut self, pop: bool) -> Result<Option<u8>> {
  145. self.finish_receive()?;
  146. if self.cursor == self.pending_len {
  147. return Ok(None);
  148. }
  149. let ch = self.queue_buf_rx[self.cursor];
  150. if pop {
  151. self.cursor += 1;
  152. self.poll_retrieve()?;
  153. }
  154. Ok(Some(ch))
  155. }
  156. /// Sends a character to the console.
  157. pub fn send(&mut self, chr: u8) -> Result<()> {
  158. let buf: [u8; 1] = [chr];
  159. // Safe because the buffer is valid until we pop_used below.
  160. self.transmitq
  161. .add_notify_wait_pop(&[&buf], &[], &mut self.transport)?;
  162. Ok(())
  163. }
  164. }
  165. impl<H: Hal, T: Transport> Drop for VirtIOConsole<'_, H, T> {
  166. fn drop(&mut self) {
  167. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  168. // after they have been freed.
  169. self.transport.queue_unset(QUEUE_RECEIVEQ_PORT_0);
  170. self.transport.queue_unset(QUEUE_TRANSMITQ_PORT_0);
  171. }
  172. }
  173. #[repr(C)]
  174. struct Config {
  175. cols: ReadOnly<u16>,
  176. rows: ReadOnly<u16>,
  177. max_nr_ports: ReadOnly<u32>,
  178. emerg_wr: WriteOnly<u32>,
  179. }
  180. bitflags! {
  181. struct Features: u64 {
  182. const SIZE = 1 << 0;
  183. const MULTIPORT = 1 << 1;
  184. const EMERG_WRITE = 1 << 2;
  185. // device independent
  186. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  187. const ANY_LAYOUT = 1 << 27; // legacy
  188. const RING_INDIRECT_DESC = 1 << 28;
  189. const RING_EVENT_IDX = 1 << 29;
  190. const UNUSED = 1 << 30; // legacy
  191. const VERSION_1 = 1 << 32; // detect legacy
  192. // since virtio v1.1
  193. const ACCESS_PLATFORM = 1 << 33;
  194. const RING_PACKED = 1 << 34;
  195. const IN_ORDER = 1 << 35;
  196. const ORDER_PLATFORM = 1 << 36;
  197. const SR_IOV = 1 << 37;
  198. const NOTIFICATION_DATA = 1 << 38;
  199. }
  200. }
  201. #[cfg(test)]
  202. mod tests {
  203. use super::*;
  204. use crate::{
  205. hal::fake::FakeHal,
  206. transport::{
  207. fake::{FakeTransport, QueueStatus, State},
  208. DeviceStatus, DeviceType,
  209. },
  210. };
  211. use alloc::{sync::Arc, vec};
  212. use core::ptr::NonNull;
  213. use std::sync::Mutex;
  214. #[test]
  215. fn receive() {
  216. let mut config_space = Config {
  217. cols: ReadOnly::new(0),
  218. rows: ReadOnly::new(0),
  219. max_nr_ports: ReadOnly::new(0),
  220. emerg_wr: WriteOnly::default(),
  221. };
  222. let state = Arc::new(Mutex::new(State {
  223. status: DeviceStatus::empty(),
  224. driver_features: 0,
  225. guest_page_size: 0,
  226. interrupt_pending: false,
  227. queues: vec![QueueStatus::default(); 2],
  228. }));
  229. let transport = FakeTransport {
  230. device_type: DeviceType::Console,
  231. max_queue_size: 2,
  232. device_features: 0,
  233. config_space: NonNull::from(&mut config_space),
  234. state: state.clone(),
  235. };
  236. let mut console = VirtIOConsole::<FakeHal, FakeTransport<Config>>::new(transport).unwrap();
  237. // Nothing is available to receive.
  238. assert_eq!(console.recv(false).unwrap(), None);
  239. assert_eq!(console.recv(true).unwrap(), None);
  240. // Still nothing after a spurious interrupt.
  241. assert_eq!(console.ack_interrupt(), Ok(false));
  242. assert_eq!(console.recv(false).unwrap(), None);
  243. // Make a character available, and simulate an interrupt.
  244. {
  245. let mut state = state.lock().unwrap();
  246. state.write_to_queue(QUEUE_SIZE, QUEUE_RECEIVEQ_PORT_0, &[42]);
  247. state.interrupt_pending = true;
  248. }
  249. assert_eq!(console.ack_interrupt(), Ok(true));
  250. assert_eq!(state.lock().unwrap().interrupt_pending, false);
  251. // Receive the character. If we don't pop it it is still there to read again.
  252. assert_eq!(console.recv(false).unwrap(), Some(42));
  253. assert_eq!(console.recv(true).unwrap(), Some(42));
  254. assert_eq!(console.recv(true).unwrap(), None);
  255. }
  256. }