console.rs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. //! Driver for VirtIO console devices.
  2. use crate::hal::{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)?;
  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. Ok(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) -> bool {
  127. let mut flag = false;
  128. if let Some(receive_token) = self.receive_token {
  129. if let Ok((token, len)) = self.receiveq.pop_used() {
  130. assert_eq!(token, receive_token);
  131. flag = true;
  132. assert_ne!(len, 0);
  133. self.cursor = 0;
  134. self.pending_len = len as usize;
  135. }
  136. }
  137. flag
  138. }
  139. /// Returns the next available character from the console, if any.
  140. ///
  141. /// If no data has been received this will not block but immediately return `Ok<None>`.
  142. pub fn recv(&mut self, pop: bool) -> Result<Option<u8>> {
  143. self.finish_receive();
  144. if self.cursor == self.pending_len {
  145. return Ok(None);
  146. }
  147. let ch = self.queue_buf_rx[self.cursor];
  148. if pop {
  149. self.cursor += 1;
  150. self.poll_retrieve()?;
  151. }
  152. Ok(Some(ch))
  153. }
  154. /// Sends a character to the console.
  155. pub fn send(&mut self, chr: u8) -> Result<()> {
  156. let buf: [u8; 1] = [chr];
  157. // Safe because the buffer is valid until we pop_used below.
  158. self.transmitq
  159. .add_notify_wait_pop(&[&buf], &[], &mut self.transport)?;
  160. Ok(())
  161. }
  162. }
  163. impl<H: Hal, T: Transport> Drop for VirtIOConsole<'_, H, T> {
  164. fn drop(&mut self) {
  165. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  166. // after they have been freed.
  167. self.transport.queue_unset(QUEUE_RECEIVEQ_PORT_0);
  168. self.transport.queue_unset(QUEUE_TRANSMITQ_PORT_0);
  169. }
  170. }
  171. #[repr(C)]
  172. struct Config {
  173. cols: ReadOnly<u16>,
  174. rows: ReadOnly<u16>,
  175. max_nr_ports: ReadOnly<u32>,
  176. emerg_wr: WriteOnly<u32>,
  177. }
  178. bitflags! {
  179. struct Features: u64 {
  180. const SIZE = 1 << 0;
  181. const MULTIPORT = 1 << 1;
  182. const EMERG_WRITE = 1 << 2;
  183. // device independent
  184. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  185. const ANY_LAYOUT = 1 << 27; // legacy
  186. const RING_INDIRECT_DESC = 1 << 28;
  187. const RING_EVENT_IDX = 1 << 29;
  188. const UNUSED = 1 << 30; // legacy
  189. const VERSION_1 = 1 << 32; // detect legacy
  190. // since virtio v1.1
  191. const ACCESS_PLATFORM = 1 << 33;
  192. const RING_PACKED = 1 << 34;
  193. const IN_ORDER = 1 << 35;
  194. const ORDER_PLATFORM = 1 << 36;
  195. const SR_IOV = 1 << 37;
  196. const NOTIFICATION_DATA = 1 << 38;
  197. }
  198. }
  199. #[cfg(test)]
  200. mod tests {
  201. use super::*;
  202. use crate::{
  203. hal::fake::FakeHal,
  204. transport::{
  205. fake::{FakeTransport, QueueStatus, State},
  206. DeviceStatus, DeviceType,
  207. },
  208. };
  209. use alloc::{sync::Arc, vec};
  210. use core::ptr::NonNull;
  211. use std::sync::Mutex;
  212. #[test]
  213. fn receive() {
  214. let mut config_space = Config {
  215. cols: ReadOnly::new(0),
  216. rows: ReadOnly::new(0),
  217. max_nr_ports: ReadOnly::new(0),
  218. emerg_wr: WriteOnly::default(),
  219. };
  220. let state = Arc::new(Mutex::new(State {
  221. status: DeviceStatus::empty(),
  222. driver_features: 0,
  223. guest_page_size: 0,
  224. interrupt_pending: false,
  225. queues: vec![QueueStatus::default(); 2],
  226. }));
  227. let transport = FakeTransport {
  228. device_type: DeviceType::Console,
  229. max_queue_size: 2,
  230. device_features: 0,
  231. config_space: NonNull::from(&mut config_space),
  232. state: state.clone(),
  233. };
  234. let mut console = VirtIOConsole::<FakeHal, FakeTransport<Config>>::new(transport).unwrap();
  235. // Nothing is available to receive.
  236. assert_eq!(console.recv(false).unwrap(), None);
  237. assert_eq!(console.recv(true).unwrap(), None);
  238. // Still nothing after a spurious interrupt.
  239. assert_eq!(console.ack_interrupt(), Ok(false));
  240. assert_eq!(console.recv(false).unwrap(), None);
  241. // Make a character available, and simulate an interrupt.
  242. {
  243. let mut state = state.lock().unwrap();
  244. state.write_to_queue(QUEUE_SIZE, QUEUE_RECEIVEQ_PORT_0, &[42]);
  245. state.interrupt_pending = true;
  246. }
  247. assert_eq!(console.ack_interrupt(), Ok(true));
  248. assert_eq!(state.lock().unwrap().interrupt_pending, false);
  249. // Receive the character. If we don't pop it it is still there to read again.
  250. assert_eq!(console.recv(false).unwrap(), Some(42));
  251. assert_eq!(console.recv(true).unwrap(), Some(42));
  252. assert_eq!(console.recv(true).unwrap(), None);
  253. }
  254. }