1use fuchsia_async::{self as fasync, PacketReceiver, ReceiverRegistration};
6
7use futures::channel::mpsc;
8use futures::{Stream, StreamExt, TryStreamExt};
9use std::pin::Pin;
10use std::task::{Context, Poll};
11use thiserror::Error;
12
13const QUEUE_NOTIFY_MULTIPLIER: usize = 4;
30
31#[derive(Error, Debug, PartialEq, Eq)]
32pub enum BellError {
33 #[error("Received unexpected packet {0:?}")]
34 UnexpectedPacket(zx::Packet),
35 #[error("Trap address {0:?} did not map to a queue")]
36 BadAddress(zx::GPAddr),
37}
38
39#[derive(Debug, Eq, PartialEq)]
40enum Packet {
41 Bell(zx::GPAddr),
42 Other(zx::Packet),
43}
44
45#[derive(Debug)]
47pub struct PortForwarder {
48 channel: mpsc::UnboundedSender<Packet>,
49}
50
51impl PacketReceiver for PortForwarder {
52 fn receive_packet(&self, packet: zx::Packet) {
53 let packet = if let zx::PacketContents::GuestBell(bell) = packet.contents() {
54 Packet::Bell(bell.addr())
55 } else {
56 Packet::Other(packet)
57 };
58 self.channel.unbounded_send(packet).unwrap();
63 }
64}
65
66#[derive(Debug)]
73pub struct GuestBellTrap<T = ReceiverRegistration<PortForwarder>> {
74 _registration: T,
75 channel: mpsc::UnboundedReceiver<Packet>,
76 base: zx::GPAddr,
77 num_queues: u16,
78}
79
80impl GuestBellTrap {
81 pub fn new(guest: &zx::Guest, base: zx::GPAddr, len: usize) -> Result<Self, zx::Status> {
90 let (tx, rx) = mpsc::unbounded();
91 let registration =
92 fasync::EHandle::local().register_receiver(PortForwarder { channel: tx });
93 guest.set_trap_bell(base, len, registration.port(), registration.key())?;
94 Self::with_registration(base, len, rx, registration)
95 }
96}
97
98impl<T> GuestBellTrap<T> {
99 fn with_registration(
100 base: zx::GPAddr,
101 len: usize,
102 rx: mpsc::UnboundedReceiver<Packet>,
103 registration: T,
104 ) -> Result<Self, zx::Status> {
105 if (base.0 % QUEUE_NOTIFY_MULTIPLIER) != 0 {
107 return Err(zx::Status::INVALID_ARGS);
108 }
109 let num_queues = (len / QUEUE_NOTIFY_MULTIPLIER) as u16;
110 if num_queues as usize * QUEUE_NOTIFY_MULTIPLIER != len {
111 return Err(zx::Status::INVALID_ARGS);
112 }
113 if num_queues == 0 {
115 return Err(zx::Status::INVALID_ARGS);
116 }
117 Ok(GuestBellTrap { _registration: registration, channel: rx, base, num_queues })
118 }
119
120 pub fn queue_for_addr(&self, addr: zx::GPAddr) -> Option<u16> {
126 let queue =
127 ((addr.0.checked_sub(self.base.0)?) / QUEUE_NOTIFY_MULTIPLIER).try_into().ok()?;
128 if queue >= self.num_queues { None } else { Some(queue) }
129 }
130}
131
132impl<T: Unpin> GuestBellTrap<T> {
133 pub async fn complete<'a, N>(
138 self,
139 device: &crate::Device<'a, N>,
140 ) -> Result<(), crate::DeviceError> {
141 self.err_into()
142 .try_for_each(|queue| futures::future::ready(device.notify_queue(queue as u16)))
143 .await
144 }
145
146 pub async fn complete_or_pending<'a, N>(
153 maybe_trap: Option<Self>,
154 device: &crate::Device<'a, N>,
155 ) -> Result<(), crate::DeviceError> {
156 match maybe_trap {
157 Some(bell) => bell.complete(device).await,
158 None => futures::future::pending().await,
159 }
160 }
161}
162
163impl<T: Unpin> Stream for GuestBellTrap<T> {
164 type Item = Result<u16, BellError>;
165
166 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
167 self.channel.poll_next_unpin(cx).map(|maybe_packet| {
168 let packet = maybe_packet?;
171 match packet {
172 Packet::Bell(addr) => {
173 Some(self.queue_for_addr(addr).ok_or(BellError::BadAddress(addr)))
174 }
175 Packet::Other(packet) => Some(Err(BellError::UnexpectedPacket(packet))),
176 }
177 })
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use futures::FutureExt;
185 #[test]
186 fn trap_size() {
187 assert_eq!(
189 GuestBellTrap::with_registration(zx::GPAddr(3), 4, mpsc::unbounded().1, ()).err(),
190 Some(zx::Status::INVALID_ARGS)
191 );
192 assert_eq!(
193 GuestBellTrap::with_registration(zx::GPAddr(1), 4, mpsc::unbounded().1, ()).err(),
194 Some(zx::Status::INVALID_ARGS)
195 );
196
197 assert_eq!(
199 GuestBellTrap::with_registration(zx::GPAddr(8), 0, mpsc::unbounded().1, ()).err(),
200 Some(zx::Status::INVALID_ARGS)
201 );
202
203 assert_eq!(
205 GuestBellTrap::with_registration(zx::GPAddr(8), 1, mpsc::unbounded().1, ()).err(),
206 Some(zx::Status::INVALID_ARGS)
207 );
208 assert_eq!(
209 GuestBellTrap::with_registration(zx::GPAddr(8), 3, mpsc::unbounded().1, ()).err(),
210 Some(zx::Status::INVALID_ARGS)
211 );
212 assert_eq!(
213 GuestBellTrap::with_registration(zx::GPAddr(8), 9, mpsc::unbounded().1, ()).err(),
214 Some(zx::Status::INVALID_ARGS)
215 );
216 assert_eq!(
217 GuestBellTrap::with_registration(zx::GPAddr(8), 42, mpsc::unbounded().1, ()).err(),
218 Some(zx::Status::INVALID_ARGS)
219 );
220
221 assert!(
222 GuestBellTrap::with_registration(zx::GPAddr(64), 12, mpsc::unbounded().1, ()).is_ok()
223 );
224 }
225
226 #[test]
227 fn queue_conversion() {
228 let bell =
229 GuestBellTrap::with_registration(zx::GPAddr(80), 12, mpsc::unbounded().1, ()).unwrap();
230
231 assert_eq!(bell.queue_for_addr(zx::GPAddr(79)), None);
233 assert_eq!(bell.queue_for_addr(zx::GPAddr(76)), None);
234
235 assert_eq!(bell.queue_for_addr(zx::GPAddr(80)), Some(0));
237 assert_eq!(bell.queue_for_addr(zx::GPAddr(81)), Some(0));
238 assert_eq!(bell.queue_for_addr(zx::GPAddr(83)), Some(0));
239
240 assert_eq!(bell.queue_for_addr(zx::GPAddr(84)), Some(1));
242 assert_eq!(bell.queue_for_addr(zx::GPAddr(88)), Some(2));
243 assert_eq!(bell.queue_for_addr(zx::GPAddr(91)), Some(2));
244
245 assert_eq!(bell.queue_for_addr(zx::GPAddr(92)), None);
247 assert_eq!(bell.queue_for_addr(zx::GPAddr(94)), None);
248 assert_eq!(bell.queue_for_addr(zx::GPAddr(128)), None);
249 }
250
251 #[fuchsia::test(allow_stalls = false)]
252 async fn packet_stream() {
253 let (tx, rx) = mpsc::unbounded();
254
255 let bell = GuestBellTrap::with_registration(zx::GPAddr(64), 12, rx, ()).unwrap();
256
257 tx.unbounded_send(Packet::Bell(zx::GPAddr(64))).unwrap();
259 tx.unbounded_send(Packet::Bell(zx::GPAddr(68))).unwrap();
260 tx.unbounded_send(Packet::Bell(zx::GPAddr(100))).unwrap();
261
262 let mut stream = bell.peekable();
263 assert!(Pin::new(&mut stream).peek().now_or_never().is_some());
265
266 assert_eq!(stream.next().await, Some(Ok(0)));
268 assert_eq!(stream.next().await, Some(Ok(1)));
269 assert_eq!(stream.next().await, Some(Err(BellError::BadAddress(zx::GPAddr(100)))));
270
271 assert!(Pin::new(&mut stream).peek().now_or_never().is_none());
273 }
274}