net.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. use core::mem::{size_of, MaybeUninit};
  2. use super::*;
  3. use crate::transport::Transport;
  4. use crate::volatile::{volread, ReadOnly, Volatile};
  5. use bitflags::*;
  6. use log::*;
  7. /// The virtio network device is a virtual ethernet card.
  8. ///
  9. /// It has enhanced rapidly and demonstrates clearly how support for new
  10. /// features are added to an existing device.
  11. /// Empty buffers are placed in one virtqueue for receiving packets, and
  12. /// outgoing packets are enqueued into another for transmission in that order.
  13. /// A third command queue is used to control advanced filtering features.
  14. pub struct VirtIONet<H: Hal, T: Transport> {
  15. transport: T,
  16. mac: EthernetAddress,
  17. recv_queue: VirtQueue<H>,
  18. send_queue: VirtQueue<H>,
  19. }
  20. impl<H: Hal, T: Transport> VirtIONet<H, T> {
  21. /// Create a new VirtIO-Net driver.
  22. pub fn new(mut transport: T) -> Result<Self> {
  23. transport.begin_init(|features| {
  24. let features = Features::from_bits_truncate(features);
  25. info!("Device features {:?}", features);
  26. let supported_features = Features::MAC | Features::STATUS;
  27. (features & supported_features).bits()
  28. });
  29. // read configuration space
  30. let config = transport.config_space::<Config>()?;
  31. let mac;
  32. // Safe because config points to a valid MMIO region for the config space.
  33. unsafe {
  34. mac = volread!(config, mac);
  35. debug!("Got MAC={:?}, status={:?}", mac, volread!(config, status));
  36. }
  37. let queue_num = 2; // for simplicity
  38. let recv_queue = VirtQueue::new(&mut transport, QUEUE_RECEIVE, queue_num)?;
  39. let send_queue = VirtQueue::new(&mut transport, QUEUE_TRANSMIT, queue_num)?;
  40. transport.finish_init();
  41. Ok(VirtIONet {
  42. transport,
  43. mac,
  44. recv_queue,
  45. send_queue,
  46. })
  47. }
  48. /// Acknowledge interrupt.
  49. pub fn ack_interrupt(&mut self) -> bool {
  50. self.transport.ack_interrupt()
  51. }
  52. /// Get MAC address.
  53. pub fn mac(&self) -> EthernetAddress {
  54. self.mac
  55. }
  56. /// Whether can send packet.
  57. pub fn can_send(&self) -> bool {
  58. self.send_queue.available_desc() >= 2
  59. }
  60. /// Whether can receive packet.
  61. pub fn can_recv(&self) -> bool {
  62. self.recv_queue.can_pop()
  63. }
  64. /// Receive a packet.
  65. pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize> {
  66. let mut header = MaybeUninit::<Header>::uninit();
  67. let header_buf = unsafe { (*header.as_mut_ptr()).as_buf_mut() };
  68. let len =
  69. self.recv_queue
  70. .add_notify_wait_pop(&[], &[header_buf, buf], &mut self.transport)?;
  71. // let header = unsafe { header.assume_init() };
  72. Ok(len as usize - size_of::<Header>())
  73. }
  74. /// Send a packet.
  75. pub fn send(&mut self, buf: &[u8]) -> Result {
  76. let header = unsafe { MaybeUninit::<Header>::zeroed().assume_init() };
  77. self.send_queue
  78. .add_notify_wait_pop(&[header.as_buf(), buf], &[], &mut self.transport)?;
  79. Ok(())
  80. }
  81. }
  82. impl<H: Hal, T: Transport> Drop for VirtIONet<H, T> {
  83. fn drop(&mut self) {
  84. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  85. // after they have been freed.
  86. self.transport.queue_unset(QUEUE_RECEIVE);
  87. self.transport.queue_unset(QUEUE_TRANSMIT);
  88. }
  89. }
  90. bitflags! {
  91. struct Features: u64 {
  92. /// Device handles packets with partial checksum.
  93. /// This "checksum offload" is a common feature on modern network cards.
  94. const CSUM = 1 << 0;
  95. /// Driver handles packets with partial checksum.
  96. const GUEST_CSUM = 1 << 1;
  97. /// Control channel offloads reconfiguration support.
  98. const CTRL_GUEST_OFFLOADS = 1 << 2;
  99. /// Device maximum MTU reporting is supported.
  100. ///
  101. /// If offered by the device, device advises driver about the value of
  102. /// its maximum MTU. If negotiated, the driver uses mtu as the maximum
  103. /// MTU value.
  104. const MTU = 1 << 3;
  105. /// Device has given MAC address.
  106. const MAC = 1 << 5;
  107. /// Device handles packets with any GSO type. (legacy)
  108. const GSO = 1 << 6;
  109. /// Driver can receive TSOv4.
  110. const GUEST_TSO4 = 1 << 7;
  111. /// Driver can receive TSOv6.
  112. const GUEST_TSO6 = 1 << 8;
  113. /// Driver can receive TSO with ECN.
  114. const GUEST_ECN = 1 << 9;
  115. /// Driver can receive UFO.
  116. const GUEST_UFO = 1 << 10;
  117. /// Device can receive TSOv4.
  118. const HOST_TSO4 = 1 << 11;
  119. /// Device can receive TSOv6.
  120. const HOST_TSO6 = 1 << 12;
  121. /// Device can receive TSO with ECN.
  122. const HOST_ECN = 1 << 13;
  123. /// Device can receive UFO.
  124. const HOST_UFO = 1 << 14;
  125. /// Driver can merge receive buffers.
  126. const MRG_RXBUF = 1 << 15;
  127. /// Configuration status field is available.
  128. const STATUS = 1 << 16;
  129. /// Control channel is available.
  130. const CTRL_VQ = 1 << 17;
  131. /// Control channel RX mode support.
  132. const CTRL_RX = 1 << 18;
  133. /// Control channel VLAN filtering.
  134. const CTRL_VLAN = 1 << 19;
  135. ///
  136. const CTRL_RX_EXTRA = 1 << 20;
  137. /// Driver can send gratuitous packets.
  138. const GUEST_ANNOUNCE = 1 << 21;
  139. /// Device supports multiqueue with automatic receive steering.
  140. const MQ = 1 << 22;
  141. /// Set MAC address through control channel.
  142. const CTL_MAC_ADDR = 1 << 23;
  143. // device independent
  144. const RING_INDIRECT_DESC = 1 << 28;
  145. const RING_EVENT_IDX = 1 << 29;
  146. const VERSION_1 = 1 << 32; // legacy
  147. }
  148. }
  149. bitflags! {
  150. struct Status: u16 {
  151. const LINK_UP = 1;
  152. const ANNOUNCE = 2;
  153. }
  154. }
  155. bitflags! {
  156. struct InterruptStatus : u32 {
  157. const USED_RING_UPDATE = 1 << 0;
  158. const CONFIGURATION_CHANGE = 1 << 1;
  159. }
  160. }
  161. #[repr(C)]
  162. struct Config {
  163. mac: ReadOnly<EthernetAddress>,
  164. status: ReadOnly<Status>,
  165. }
  166. type EthernetAddress = [u8; 6];
  167. // virtio 5.1.6 Device Operation
  168. #[repr(C)]
  169. #[derive(Debug)]
  170. struct Header {
  171. flags: Volatile<Flags>,
  172. gso_type: Volatile<GsoType>,
  173. hdr_len: Volatile<u16>, // cannot rely on this
  174. gso_size: Volatile<u16>,
  175. csum_start: Volatile<u16>,
  176. csum_offset: Volatile<u16>,
  177. // payload starts from here
  178. }
  179. unsafe impl AsBuf for Header {}
  180. bitflags! {
  181. struct Flags: u8 {
  182. const NEEDS_CSUM = 1;
  183. const DATA_VALID = 2;
  184. const RSC_INFO = 4;
  185. }
  186. }
  187. #[repr(u8)]
  188. #[derive(Debug, Copy, Clone, Eq, PartialEq)]
  189. enum GsoType {
  190. NONE = 0,
  191. TCPV4 = 1,
  192. UDP = 3,
  193. TCPV6 = 4,
  194. ECN = 0x80,
  195. }
  196. const QUEUE_RECEIVE: u16 = 0;
  197. const QUEUE_TRANSMIT: u16 = 1;