console.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. use super::*;
  2. use crate::queue::VirtQueue;
  3. use crate::transport::Transport;
  4. use crate::volatile::{volread, ReadOnly, WriteOnly};
  5. use bitflags::*;
  6. use core::hint::spin_loop;
  7. use log::*;
  8. const QUEUE_RECEIVEQ_PORT_0: u16 = 0;
  9. const QUEUE_TRANSMITQ_PORT_0: u16 = 1;
  10. const QUEUE_SIZE: u16 = 2;
  11. /// Virtio console. Only one single port is allowed since ``alloc'' is disabled.
  12. /// Emergency and cols/rows unimplemented.
  13. pub struct VirtIOConsole<'a, H: Hal, T: Transport> {
  14. transport: T,
  15. receiveq: VirtQueue<H>,
  16. transmitq: VirtQueue<H>,
  17. queue_buf_dma: DMA<H>,
  18. queue_buf_rx: &'a mut [u8],
  19. cursor: usize,
  20. pending_len: usize,
  21. }
  22. impl<H: Hal, T: Transport> VirtIOConsole<'_, H, T> {
  23. /// Create a new VirtIO-Console driver.
  24. pub fn new(mut transport: T) -> Result<Self> {
  25. transport.begin_init(|features| {
  26. let features = Features::from_bits_truncate(features);
  27. info!("Device features {:?}", features);
  28. let supported_features = Features::empty();
  29. (features & supported_features).bits()
  30. });
  31. let config_space = transport.config_space::<Config>()?;
  32. unsafe {
  33. let columns = volread!(config_space, cols);
  34. let rows = volread!(config_space, rows);
  35. let max_ports = volread!(config_space, max_nr_ports);
  36. info!(
  37. "Columns: {} Rows: {} Max ports: {}",
  38. columns, rows, max_ports,
  39. );
  40. }
  41. let receiveq = VirtQueue::new(&mut transport, QUEUE_RECEIVEQ_PORT_0, QUEUE_SIZE)?;
  42. let transmitq = VirtQueue::new(&mut transport, QUEUE_TRANSMITQ_PORT_0, QUEUE_SIZE)?;
  43. let queue_buf_dma = DMA::new(1)?;
  44. let queue_buf_rx = unsafe { &mut queue_buf_dma.as_buf()[0..] };
  45. transport.finish_init();
  46. let mut console = VirtIOConsole {
  47. transport,
  48. receiveq,
  49. transmitq,
  50. queue_buf_dma,
  51. queue_buf_rx,
  52. cursor: 0,
  53. pending_len: 0,
  54. };
  55. console.poll_retrieve()?;
  56. Ok(console)
  57. }
  58. fn poll_retrieve(&mut self) -> Result<()> {
  59. self.receiveq.add(&[], &[self.queue_buf_rx])?;
  60. Ok(())
  61. }
  62. /// Acknowledge interrupt.
  63. pub fn ack_interrupt(&mut self) -> Result<bool> {
  64. let ack = self.transport.ack_interrupt();
  65. if !ack {
  66. return Ok(false);
  67. }
  68. let mut flag = false;
  69. while let Ok((_token, len)) = self.receiveq.pop_used() {
  70. assert_eq!(flag, false);
  71. flag = true;
  72. assert_ne!(len, 0);
  73. self.cursor = 0;
  74. self.pending_len = len as usize;
  75. }
  76. Ok(flag)
  77. }
  78. /// Try get char.
  79. pub fn recv(&mut self, pop: bool) -> Result<Option<u8>> {
  80. if self.cursor == self.pending_len {
  81. return Ok(None);
  82. }
  83. let ch = self.queue_buf_rx[self.cursor];
  84. if pop {
  85. self.cursor += 1;
  86. if self.cursor == self.pending_len {
  87. self.poll_retrieve()?;
  88. }
  89. }
  90. Ok(Some(ch))
  91. }
  92. /// Put a char onto the device.
  93. pub fn send(&mut self, chr: u8) -> Result<()> {
  94. let buf: [u8; 1] = [chr];
  95. self.transmitq.add(&[&buf], &[])?;
  96. self.transport.notify(QUEUE_TRANSMITQ_PORT_0);
  97. while !self.transmitq.can_pop() {
  98. spin_loop();
  99. }
  100. self.transmitq.pop_used()?;
  101. Ok(())
  102. }
  103. }
  104. #[repr(C)]
  105. struct Config {
  106. cols: ReadOnly<u16>,
  107. rows: ReadOnly<u16>,
  108. max_nr_ports: ReadOnly<u32>,
  109. emerg_wr: WriteOnly<u32>,
  110. }
  111. bitflags! {
  112. struct Features: u64 {
  113. const SIZE = 1 << 0;
  114. const MULTIPORT = 1 << 1;
  115. const EMERG_WRITE = 1 << 2;
  116. // device independent
  117. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  118. const ANY_LAYOUT = 1 << 27; // legacy
  119. const RING_INDIRECT_DESC = 1 << 28;
  120. const RING_EVENT_IDX = 1 << 29;
  121. const UNUSED = 1 << 30; // legacy
  122. const VERSION_1 = 1 << 32; // detect legacy
  123. // since virtio v1.1
  124. const ACCESS_PLATFORM = 1 << 33;
  125. const RING_PACKED = 1 << 34;
  126. const IN_ORDER = 1 << 35;
  127. const ORDER_PLATFORM = 1 << 36;
  128. const SR_IOV = 1 << 37;
  129. const NOTIFICATION_DATA = 1 << 38;
  130. }
  131. }
  132. #[cfg(test)]
  133. mod tests {
  134. use super::*;
  135. use crate::{
  136. hal::fake::FakeHal,
  137. transport::fake::{FakeTransport, QueueStatus, State},
  138. };
  139. use alloc::{sync::Arc, vec};
  140. use core::ptr::NonNull;
  141. use std::sync::Mutex;
  142. #[test]
  143. fn receive() {
  144. let mut config_space = Config {
  145. cols: ReadOnly::new(0),
  146. rows: ReadOnly::new(0),
  147. max_nr_ports: ReadOnly::new(0),
  148. emerg_wr: WriteOnly::default(),
  149. };
  150. let state = Arc::new(Mutex::new(State {
  151. status: DeviceStatus::empty(),
  152. driver_features: 0,
  153. guest_page_size: 0,
  154. interrupt_pending: false,
  155. queues: vec![QueueStatus::default(); 2],
  156. }));
  157. let transport = FakeTransport {
  158. device_type: DeviceType::Console,
  159. max_queue_size: 2,
  160. device_features: 0,
  161. config_space: NonNull::from(&mut config_space),
  162. state: state.clone(),
  163. };
  164. let mut console = VirtIOConsole::<FakeHal, FakeTransport<Config>>::new(transport).unwrap();
  165. // Nothing is available to receive.
  166. assert_eq!(console.recv(false).unwrap(), None);
  167. assert_eq!(console.recv(true).unwrap(), None);
  168. // Still nothing after a spurious interrupt.
  169. assert_eq!(console.ack_interrupt(), Ok(false));
  170. assert_eq!(console.recv(false).unwrap(), None);
  171. // Make a character available, and simulate an interrupt.
  172. {
  173. let mut state = state.lock().unwrap();
  174. state.write_to_queue(QUEUE_SIZE, QUEUE_RECEIVEQ_PORT_0, &[42]);
  175. state.interrupt_pending = true;
  176. }
  177. assert_eq!(console.ack_interrupt(), Ok(true));
  178. assert_eq!(state.lock().unwrap().interrupt_pending, false);
  179. // Receive the character. If we don't pop it it is still there to read again.
  180. assert_eq!(console.recv(false).unwrap(), Some(42));
  181. assert_eq!(console.recv(true).unwrap(), Some(42));
  182. assert_eq!(console.recv(true).unwrap(), None);
  183. }
  184. }