virtio_drivers/device/
virtio_9p.rs1use alloc::string::String;
4use alloc::vec::Vec;
5use log::warn;
6
7use super::common::Feature;
8use crate::{Error, Hal, Result, queue::VirtQueue, transport::Transport};
9
10const QUEUE: u16 = 0;
11const QUEUE_SIZE: usize = 16;
12const P9_HEADER_SIZE: usize = 7; const SUPPORTED_FEATURES: Feature = Feature::RING_INDIRECT_DESC
14 .union(Feature::RING_EVENT_IDX)
15 .union(Feature::VERSION_1);
16
17pub struct VirtIO9p<H: Hal, T: Transport> {
19 transport: T,
20 queue: VirtQueue<H, QUEUE_SIZE>,
21 mount_tag: String,
22}
23
24impl<H: Hal, T: Transport> VirtIO9p<H, T> {
25 pub fn new(mut transport: T) -> Result<Self> {
27 let features = transport.begin_init(SUPPORTED_FEATURES);
28
29 let queue = VirtQueue::new(
30 &mut transport,
31 QUEUE,
32 features.contains(Feature::RING_INDIRECT_DESC),
33 features.contains(Feature::RING_EVENT_IDX),
34 )?;
35 transport.finish_init();
36
37 let mount_tag = read_mount_tag(&transport)?;
38
39 Ok(Self {
40 transport,
41 queue,
42 mount_tag,
43 })
44 }
45
46 pub fn mount_tag(&self) -> &str {
48 &self.mount_tag
49 }
50
51 pub fn request(&mut self, req: &[u8], resp: &mut [u8]) -> Result<u32> {
53 if req.is_empty() || resp.len() < P9_HEADER_SIZE {
54 return Err(Error::InvalidParam);
55 }
56 let used_len = self
57 .queue
58 .add_notify_wait_pop(&[req], &mut [resp], &mut self.transport)?;
59
60 let size = u32::from_le_bytes([resp[0], resp[1], resp[2], resp[3]]);
61 if size != used_len {
62 warn!(
63 "virtio-9p response size mismatch: size from header is {size} but used length is {used_len}"
64 );
65 return Err(Error::IoError);
66 }
67 Ok(used_len)
68 }
69}
70
71fn read_mount_tag<T: Transport>(transport: &T) -> Result<String> {
72 transport.read_consistent(|| {
73 let tag_len: u16 = transport.read_config_space(0)?;
74 if tag_len == 0 {
75 return Err(Error::InvalidParam);
76 }
77
78 let mut bytes = Vec::with_capacity(tag_len as usize);
79 for idx in 0..tag_len as usize {
80 let b: u8 = transport.read_config_space(2 + idx)?;
81 bytes.push(b);
82 }
83
84 Ok(String::from_utf8(bytes)?)
85 })
86}