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