console.rs 11 KB

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