console.rs 6.4 KB

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