xref: /aosp_15_r20/external/crosvm/devices/src/virtio/p9.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::BTreeMap;
6 use std::io;
7 use std::io::Write;
8 use std::mem;
9 use std::result;
10 
11 use anyhow::anyhow;
12 use anyhow::Context;
13 use base::error;
14 use base::warn;
15 use base::Error as SysError;
16 use base::Event;
17 use base::EventToken;
18 use base::RawDescriptor;
19 use base::WaitContext;
20 use base::WorkerThread;
21 use remain::sorted;
22 use thiserror::Error;
23 use vm_memory::GuestMemory;
24 
25 use super::copy_config;
26 use super::queue::Queue;
27 use super::DeviceType;
28 use super::Interrupt;
29 use super::VirtioDevice;
30 
31 const QUEUE_SIZE: u16 = 128;
32 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
33 
34 // The only virtio_9p feature.
35 const VIRTIO_9P_MOUNT_TAG: u8 = 0;
36 
37 /// Errors that occur during operation of a virtio 9P device.
38 #[sorted]
39 #[derive(Error, Debug)]
40 pub enum P9Error {
41     /// Failed to create a 9p server.
42     #[error("failed to create 9p server: {0}")]
43     CreateServer(io::Error),
44     /// Creating WaitContext failed.
45     #[error("failed to create WaitContext: {0}")]
46     CreateWaitContext(SysError),
47     /// An internal I/O error occurred.
48     #[error("P9 internal server error: {0}")]
49     Internal(io::Error),
50     /// A request is missing readable descriptors.
51     #[error("request does not have any readable descriptors")]
52     NoReadableDescriptors,
53     /// A request is missing writable descriptors.
54     #[error("request does not have any writable descriptors")]
55     NoWritableDescriptors,
56     /// Error while reading from the virtio queue's Event.
57     #[error("failed to read from virtio queue Event: {0}")]
58     ReadQueueEvent(SysError),
59     /// Failed to signal the virio used queue.
60     #[error("failed to signal used queue: {0}")]
61     SignalUsedQueue(SysError),
62     /// The tag for the 9P device was too large to fit in the config space.
63     #[error("P9 device tag is too long: len = {0}, max = {}", u16::MAX)]
64     TagTooLong(usize),
65     /// Error while polling for events.
66     #[error("failed to wait for events: {0}")]
67     WaitError(SysError),
68 }
69 
70 pub type P9Result<T> = result::Result<T, P9Error>;
71 
72 struct Worker {
73     interrupt: Interrupt,
74     queue: Queue,
75     server: p9::Server,
76 }
77 
78 impl Worker {
process_queue(&mut self) -> P9Result<()>79     fn process_queue(&mut self) -> P9Result<()> {
80         while let Some(mut avail_desc) = self.queue.pop() {
81             self.server
82                 .handle_message(&mut avail_desc.reader, &mut avail_desc.writer)
83                 .map_err(P9Error::Internal)?;
84 
85             let len = avail_desc.writer.bytes_written() as u32;
86 
87             self.queue.add_used(avail_desc, len);
88         }
89         self.queue.trigger_interrupt();
90 
91         Ok(())
92     }
93 
run(&mut self, kill_evt: Event) -> P9Result<()>94     fn run(&mut self, kill_evt: Event) -> P9Result<()> {
95         #[derive(EventToken)]
96         enum Token {
97             // A request is ready on the queue.
98             QueueReady,
99             // Check if any interrupts need to be re-asserted.
100             InterruptResample,
101             // The parent thread requested an exit.
102             Kill,
103         }
104 
105         let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
106             (self.queue.event(), Token::QueueReady),
107             (&kill_evt, Token::Kill),
108         ])
109         .map_err(P9Error::CreateWaitContext)?;
110         if let Some(resample_evt) = self.interrupt.get_resample_evt() {
111             wait_ctx
112                 .add(resample_evt, Token::InterruptResample)
113                 .map_err(P9Error::CreateWaitContext)?;
114         }
115 
116         loop {
117             let events = wait_ctx.wait().map_err(P9Error::WaitError)?;
118             for event in events.iter().filter(|e| e.is_readable) {
119                 match event.token {
120                     Token::QueueReady => {
121                         self.queue.event().wait().map_err(P9Error::ReadQueueEvent)?;
122                         self.process_queue()?;
123                     }
124                     Token::InterruptResample => {
125                         self.interrupt.interrupt_resample();
126                     }
127                     Token::Kill => return Ok(()),
128                 }
129             }
130         }
131     }
132 }
133 
134 /// Virtio device for sharing specific directories on the host system with the guest VM.
135 pub struct P9 {
136     config: Vec<u8>,
137     server: Option<p9::Server>,
138     avail_features: u64,
139     acked_features: u64,
140     worker: Option<WorkerThread<P9Result<()>>>,
141 }
142 
143 impl P9 {
new(base_features: u64, tag: &str, p9_cfg: p9::Config) -> P9Result<P9>144     pub fn new(base_features: u64, tag: &str, p9_cfg: p9::Config) -> P9Result<P9> {
145         if tag.len() > u16::MAX as usize {
146             return Err(P9Error::TagTooLong(tag.len()));
147         }
148 
149         let len = tag.len() as u16;
150         let mut cfg = Vec::with_capacity(tag.len() + mem::size_of::<u16>());
151         cfg.push(len as u8);
152         cfg.push((len >> 8) as u8);
153 
154         cfg.write_all(tag.as_bytes()).map_err(P9Error::Internal)?;
155 
156         let server = p9::Server::with_config(p9_cfg).map_err(P9Error::CreateServer)?;
157         Ok(P9 {
158             config: cfg,
159             server: Some(server),
160             avail_features: base_features | 1 << VIRTIO_9P_MOUNT_TAG,
161             acked_features: 0,
162             worker: None,
163         })
164     }
165 }
166 
167 impl VirtioDevice for P9 {
keep_rds(&self) -> Vec<RawDescriptor>168     fn keep_rds(&self) -> Vec<RawDescriptor> {
169         self.server
170             .as_ref()
171             .map(p9::Server::keep_fds)
172             .unwrap_or_default()
173     }
174 
device_type(&self) -> DeviceType175     fn device_type(&self) -> DeviceType {
176         DeviceType::P9
177     }
178 
queue_max_sizes(&self) -> &[u16]179     fn queue_max_sizes(&self) -> &[u16] {
180         QUEUE_SIZES
181     }
182 
features(&self) -> u64183     fn features(&self) -> u64 {
184         self.avail_features
185     }
186 
ack_features(&mut self, value: u64)187     fn ack_features(&mut self, value: u64) {
188         let mut v = value;
189 
190         // Check if the guest is ACK'ing a feature that we didn't claim to have.
191         let unrequested_features = v & !self.avail_features;
192         if unrequested_features != 0 {
193             warn!("virtio_9p got unknown feature ack: {:x}", v);
194 
195             // Don't count these features as acked.
196             v &= !unrequested_features;
197         }
198         self.acked_features |= v;
199     }
200 
read_config(&self, offset: u64, data: &mut [u8])201     fn read_config(&self, offset: u64, data: &mut [u8]) {
202         copy_config(data, 0, self.config.as_slice(), offset);
203     }
204 
activate( &mut self, _guest_mem: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>205     fn activate(
206         &mut self,
207         _guest_mem: GuestMemory,
208         interrupt: Interrupt,
209         mut queues: BTreeMap<usize, Queue>,
210     ) -> anyhow::Result<()> {
211         if queues.len() != 1 {
212             return Err(anyhow!("expected 1 queue, got {}", queues.len()));
213         }
214 
215         let queue = queues.remove(&0).unwrap();
216 
217         let server = self.server.take().context("missing server")?;
218 
219         self.worker = Some(WorkerThread::start("v_9p", move |kill_evt| {
220             let mut worker = Worker {
221                 interrupt,
222                 queue,
223                 server,
224             };
225 
226             worker.run(kill_evt)
227         }));
228 
229         Ok(())
230     }
231 }
232