console.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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: usize = 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, QUEUE_SIZE>,
  42. transmitq: VirtQueue<H, QUEUE_SIZE>,
  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)?;
  71. let transmitq = VirtQueue::new(&mut transport, QUEUE_TRANSMITQ_PORT_0)?;
  72. let queue_buf_dma = Dma::new(1, BufferDirection::DeviceToDriver)?;
  73. // Safe because no alignment or initialisation is required for [u8], the DMA buffer is
  74. // dereferenceable, and the lifetime of the reference matches the lifetime of the DMA buffer
  75. // (which we don't otherwise access).
  76. let queue_buf_rx = unsafe { queue_buf_dma.raw_slice().as_mut() };
  77. transport.finish_init();
  78. let mut console = VirtIOConsole {
  79. transport,
  80. config_space,
  81. receiveq,
  82. transmitq,
  83. queue_buf_dma,
  84. queue_buf_rx,
  85. cursor: 0,
  86. pending_len: 0,
  87. receive_token: None,
  88. };
  89. console.poll_retrieve()?;
  90. Ok(console)
  91. }
  92. /// Returns a struct with information about the console device, such as the number of rows and columns.
  93. pub fn info(&self) -> ConsoleInfo {
  94. // Safe because config_space is a valid pointer to the device configuration space.
  95. unsafe {
  96. let columns = volread!(self.config_space, cols);
  97. let rows = volread!(self.config_space, rows);
  98. let max_ports = volread!(self.config_space, max_nr_ports);
  99. ConsoleInfo {
  100. rows,
  101. columns,
  102. max_ports,
  103. }
  104. }
  105. }
  106. /// Makes a request to the device to receive data, if there is not already an outstanding
  107. /// receive request or some data already received and not yet returned.
  108. fn poll_retrieve(&mut self) -> Result<()> {
  109. if self.receive_token.is_none() && self.cursor == self.pending_len {
  110. // Safe because the buffer lasts at least as long as the queue, and there are no other
  111. // outstanding requests using the buffer.
  112. self.receive_token = Some(unsafe { self.receiveq.add(&[], &[self.queue_buf_rx]) }?);
  113. }
  114. Ok(())
  115. }
  116. /// Acknowledges a pending interrupt, if any, and completes the outstanding finished read
  117. /// request if there is one.
  118. ///
  119. /// Returns true if new data has been received.
  120. pub fn ack_interrupt(&mut self) -> Result<bool> {
  121. if !self.transport.ack_interrupt() {
  122. return Ok(false);
  123. }
  124. self.finish_receive()
  125. }
  126. /// If there is an outstanding receive request and it has finished, completes it.
  127. ///
  128. /// Returns true if new data has been received.
  129. fn finish_receive(&mut self) -> Result<bool> {
  130. let mut flag = false;
  131. if let Some(receive_token) = self.receive_token {
  132. if self.receive_token == self.receiveq.peek_used() {
  133. let len = self
  134. .receiveq
  135. .pop_used(receive_token, &[], &[self.queue_buf_rx])?;
  136. flag = true;
  137. assert_ne!(len, 0);
  138. self.cursor = 0;
  139. self.pending_len = len as usize;
  140. }
  141. }
  142. Ok(flag)
  143. }
  144. /// Returns the next available character from the console, if any.
  145. ///
  146. /// If no data has been received this will not block but immediately return `Ok<None>`.
  147. pub fn recv(&mut self, pop: bool) -> Result<Option<u8>> {
  148. self.finish_receive()?;
  149. if self.cursor == self.pending_len {
  150. return Ok(None);
  151. }
  152. let ch = self.queue_buf_rx[self.cursor];
  153. if pop {
  154. self.cursor += 1;
  155. self.poll_retrieve()?;
  156. }
  157. Ok(Some(ch))
  158. }
  159. /// Sends a character to the console.
  160. pub fn send(&mut self, chr: u8) -> Result<()> {
  161. let buf: [u8; 1] = [chr];
  162. // Safe because the buffer is valid until we pop_used below.
  163. self.transmitq
  164. .add_notify_wait_pop(&[&buf], &[], &mut self.transport)?;
  165. Ok(())
  166. }
  167. }
  168. impl<H: Hal, T: Transport> Drop for VirtIOConsole<'_, H, T> {
  169. fn drop(&mut self) {
  170. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  171. // after they have been freed.
  172. self.transport.queue_unset(QUEUE_RECEIVEQ_PORT_0);
  173. self.transport.queue_unset(QUEUE_TRANSMITQ_PORT_0);
  174. }
  175. }
  176. #[repr(C)]
  177. struct Config {
  178. cols: ReadOnly<u16>,
  179. rows: ReadOnly<u16>,
  180. max_nr_ports: ReadOnly<u32>,
  181. emerg_wr: WriteOnly<u32>,
  182. }
  183. bitflags! {
  184. struct Features: u64 {
  185. const SIZE = 1 << 0;
  186. const MULTIPORT = 1 << 1;
  187. const EMERG_WRITE = 1 << 2;
  188. // device independent
  189. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  190. const ANY_LAYOUT = 1 << 27; // legacy
  191. const RING_INDIRECT_DESC = 1 << 28;
  192. const RING_EVENT_IDX = 1 << 29;
  193. const UNUSED = 1 << 30; // legacy
  194. const VERSION_1 = 1 << 32; // detect legacy
  195. // since virtio v1.1
  196. const ACCESS_PLATFORM = 1 << 33;
  197. const RING_PACKED = 1 << 34;
  198. const IN_ORDER = 1 << 35;
  199. const ORDER_PLATFORM = 1 << 36;
  200. const SR_IOV = 1 << 37;
  201. const NOTIFICATION_DATA = 1 << 38;
  202. }
  203. }
  204. #[cfg(test)]
  205. mod tests {
  206. use super::*;
  207. use crate::{
  208. hal::fake::FakeHal,
  209. transport::{
  210. fake::{FakeTransport, QueueStatus, State},
  211. DeviceStatus, DeviceType,
  212. },
  213. };
  214. use alloc::{sync::Arc, vec};
  215. use core::ptr::NonNull;
  216. use std::{sync::Mutex, thread, time::Duration};
  217. #[test]
  218. fn receive() {
  219. let mut config_space = Config {
  220. cols: ReadOnly::new(0),
  221. rows: ReadOnly::new(0),
  222. max_nr_ports: ReadOnly::new(0),
  223. emerg_wr: WriteOnly::default(),
  224. };
  225. let state = Arc::new(Mutex::new(State {
  226. status: DeviceStatus::empty(),
  227. driver_features: 0,
  228. guest_page_size: 0,
  229. interrupt_pending: false,
  230. queues: vec![QueueStatus::default(); 2],
  231. }));
  232. let transport = FakeTransport {
  233. device_type: DeviceType::Console,
  234. max_queue_size: 2,
  235. device_features: 0,
  236. config_space: NonNull::from(&mut config_space),
  237. state: state.clone(),
  238. };
  239. let mut console = VirtIOConsole::<FakeHal, FakeTransport<Config>>::new(transport).unwrap();
  240. // Nothing is available to receive.
  241. assert_eq!(console.recv(false).unwrap(), None);
  242. assert_eq!(console.recv(true).unwrap(), None);
  243. // Still nothing after a spurious interrupt.
  244. assert_eq!(console.ack_interrupt(), Ok(false));
  245. assert_eq!(console.recv(false).unwrap(), None);
  246. // Make a character available, and simulate an interrupt.
  247. {
  248. let mut state = state.lock().unwrap();
  249. state.write_to_queue::<QUEUE_SIZE>(QUEUE_RECEIVEQ_PORT_0, &[42]);
  250. state.interrupt_pending = true;
  251. }
  252. assert_eq!(console.ack_interrupt(), Ok(true));
  253. assert_eq!(state.lock().unwrap().interrupt_pending, false);
  254. // Receive the character. If we don't pop it it is still there to read again.
  255. assert_eq!(console.recv(false).unwrap(), Some(42));
  256. assert_eq!(console.recv(true).unwrap(), Some(42));
  257. assert_eq!(console.recv(true).unwrap(), None);
  258. }
  259. #[test]
  260. fn send() {
  261. let mut config_space = Config {
  262. cols: ReadOnly::new(0),
  263. rows: ReadOnly::new(0),
  264. max_nr_ports: ReadOnly::new(0),
  265. emerg_wr: WriteOnly::default(),
  266. };
  267. let state = Arc::new(Mutex::new(State {
  268. status: DeviceStatus::empty(),
  269. driver_features: 0,
  270. guest_page_size: 0,
  271. interrupt_pending: false,
  272. queues: vec![QueueStatus::default(); 2],
  273. }));
  274. let transport = FakeTransport {
  275. device_type: DeviceType::Console,
  276. max_queue_size: 2,
  277. device_features: 0,
  278. config_space: NonNull::from(&mut config_space),
  279. state: state.clone(),
  280. };
  281. let mut console = VirtIOConsole::<FakeHal, FakeTransport<Config>>::new(transport).unwrap();
  282. // Start a thread to simulate the device waiting for characters.
  283. let handle = thread::spawn(move || {
  284. println!("Device waiting for a character.");
  285. while !state.lock().unwrap().queues[usize::from(QUEUE_TRANSMITQ_PORT_0)].notified {
  286. thread::sleep(Duration::from_millis(10));
  287. }
  288. println!("Transmit queue was notified.");
  289. let data = state
  290. .lock()
  291. .unwrap()
  292. .read_from_queue::<QUEUE_SIZE>(QUEUE_TRANSMITQ_PORT_0);
  293. assert_eq!(data, b"Q");
  294. });
  295. assert_eq!(console.send(b'Q'), Ok(()));
  296. handle.join().unwrap();
  297. }
  298. }