opentitanlib/transport/common/
uart.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use std::cell::{Cell, RefCell};
6use std::collections::VecDeque;
7use std::io::{ErrorKind, Read, Write};
8use std::os::fd::{AsRawFd, BorrowedFd};
9use std::task::{Context, Poll, Waker, ready};
10use std::time::Duration;
11
12use anyhow::{Context as _, Result};
13use serialport::{ClearBuffer, Parity, SerialPort, TTYPort};
14use tokio::io::unix::AsyncFd;
15
16//use crate::io::uart::{Uart, UartError};
17use crate::io::uart::{FlowControl, Uart, UartError};
18use crate::transport::TransportError;
19use crate::util;
20use crate::util::runtime::MultiWaker;
21
22/// Implementation of the `Uart` trait on top of a serial device, such as `/dev/ttyUSB0`.
23pub struct SerialPortUart {
24    port_name: String,
25    port: RefCell<AsyncFd<TTYPort>>,
26    pseudo_baud: Cell<u32>,
27    multi_waker: MultiWaker,
28}
29
30impl SerialPortUart {
31    // Not really forever, but close enough.  I'd rather use Duration::MAX, but
32    // it seems that the serialport library can compute an invalid `timeval` struct
33    // to pass to `poll`, which then leads to an `Invalid argument` error when
34    // trying to `read` or `write` without a timeout.  One hundred years should be
35    // longer than any invocation of this program.
36    const FOREVER: Duration = Duration::from_secs(100 * 365 * 86400);
37
38    /// Open the given serial device, such as `/dev/ttyUSB0`.
39    pub fn open(port_name: &str, baud: u32) -> Result<Self> {
40        let port = TTYPort::open(&serialport::new(port_name, baud).preserve_dtr_on_open())
41            .map_err(|e| UartError::OpenError(e.to_string()))?;
42        let _runtime_guard = crate::util::runtime().enter();
43        let port = AsyncFd::new(port)?;
44        flock_serial(port.get_ref(), port_name)?;
45        Ok(SerialPortUart {
46            port_name: port_name.to_string(),
47            port: RefCell::new(port),
48            pseudo_baud: Cell::new(0),
49            multi_waker: MultiWaker::new(),
50        })
51    }
52
53    /// Open a pseudo port (e.g. a verilator pts device).
54    pub fn open_pseudo(port_name: &str, baud: u32) -> Result<Self> {
55        let port = TTYPort::open(&serialport::new(port_name, baud).preserve_dtr_on_open())
56            .map_err(|e| UartError::OpenError(e.to_string()))?;
57        let _runtime_guard = crate::util::runtime().enter();
58        let port = AsyncFd::new(port)?;
59        flock_serial(port.get_ref(), port_name)?;
60        Ok(SerialPortUart {
61            port_name: port_name.to_string(),
62            port: RefCell::new(port),
63            pseudo_baud: Cell::new(baud),
64            multi_waker: MultiWaker::new(),
65        })
66    }
67}
68
69impl Uart for SerialPortUart {
70    /// Returns the UART baudrate.  May return zero for virtual UARTs.
71    fn get_baudrate(&self) -> Result<u32> {
72        let pseudo = self.pseudo_baud.get();
73        if pseudo == 0 {
74            self.port
75                .borrow()
76                .get_ref()
77                .baud_rate()
78                .context("getting baudrate")
79        } else {
80            Ok(pseudo)
81        }
82    }
83
84    /// Sets the UART baudrate.  May do nothing for virtual UARTs.
85    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
86        let pseudo = self.pseudo_baud.get();
87        if pseudo == 0 {
88            self.port
89                .borrow_mut()
90                .get_mut()
91                .set_baud_rate(baudrate)
92                .map_err(|_| UartError::InvalidSpeed(baudrate))?;
93        } else {
94            self.pseudo_baud.set(baudrate);
95        }
96        Ok(())
97    }
98
99    fn get_device_path(&self) -> Result<String> {
100        Ok(self.port_name.clone())
101    }
102
103    fn poll_read(&self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize>> {
104        let mut port = self.port.borrow_mut();
105
106        loop {
107            let mut guard = ready!(
108                self.multi_waker
109                    .poll_with(cx, |cx| port.poll_read_ready_mut(cx))
110            )?;
111
112            match guard.try_io(|inner| {
113                inner.get_mut().set_timeout(Duration::ZERO)?;
114                let result = match inner.get_mut().read(buf) {
115                    Ok(n) => Ok(n),
116                    Err(ioerr) if ioerr.kind() == ErrorKind::TimedOut => {
117                        Err(std::io::Error::new(std::io::ErrorKind::WouldBlock, ioerr))
118                    }
119                    Err(ioerr) => Err(ioerr)?,
120                };
121                inner.get_mut().set_timeout(Self::FOREVER)?;
122                result
123            }) {
124                Ok(result) => return Poll::Ready(Ok(result?)),
125                Err(_would_block) => continue,
126            }
127        }
128    }
129
130    /// Writes data from `buf` to the UART.
131    fn write(&self, buf: &[u8]) -> Result<()> {
132        // Perform blocking write of all bytes in `buf` even if the mio library has put the
133        // file descriptor into non-blocking mode.
134        let mut port = self.port.borrow_mut();
135        let mut idx = 0;
136        while idx < buf.len() {
137            match port.get_mut().write(&buf[idx..]) {
138                Ok(n) => idx += n,
139                Err(ioerr) if ioerr.kind() == ErrorKind::TimedOut => {
140                    // Buffers are full, file descriptor is non-blocking.  Explicitly wait for
141                    // this one file descriptor to again become ready for writing.  Since this
142                    // is a UART, we know that it will become ready in bounded time.
143                    util::file::wait_timeout(
144                        // SAFETY: The file descriptor is owned by `port` and is valid.
145                        unsafe { BorrowedFd::borrow_raw(port.as_raw_fd()) },
146                        rustix::event::PollFlags::OUT,
147                        Duration::from_secs(5),
148                    )?;
149                }
150                Err(ioerr) => return Err(ioerr).context("UART communication error"),
151            }
152        }
153
154        Ok(())
155    }
156
157    fn set_break(&self, enable: bool) -> Result<()> {
158        let mut port = self.port.borrow_mut();
159        if enable {
160            port.get_mut().set_break()?;
161        } else {
162            port.get_mut().clear_break()?;
163        }
164        Ok(())
165    }
166
167    fn set_parity(&self, parity: Parity) -> Result<()> {
168        self.port.borrow_mut().get_mut().set_parity(parity)?;
169        Ok(())
170    }
171
172    /// Clears the UART RX buffer.
173    fn clear_rx_buffer(&self) -> Result<()> {
174        self.port.borrow_mut().get_mut().clear(ClearBuffer::Input)?;
175
176        // There might still be data in the device buffer, try to
177        // drain that as well.
178        //
179        // NOTE This code will only have an effect on backends that
180        // use SerialPortUart and do not override clear_rx_buffer,
181        // such as the chip_whisperer backend (which uses the SAM3x
182        // for UART). On backends such as hyperdebug which have a specific
183        // mechanism to clear the device buffers, following code will not
184        // doing anything useful.
185        const TIMEOUT: Duration = Duration::from_millis(5);
186        let mut buf = [0u8; 256];
187        while self.read_timeout(&mut buf, TIMEOUT)? > 0 {}
188        Ok(())
189    }
190}
191
192/// Invoke Linux `flock()` on the given serial port, lock will be released when the file
193/// descriptor is closed (or when the process terminates).
194pub fn flock_serial(port: &TTYPort, port_name: &str) -> Result<()> {
195    // SAFETY: `fd` is owned by `port` and is valid.
196    let fd = unsafe { BorrowedFd::borrow_raw(port.as_raw_fd()) };
197    rustix::fs::flock(fd, rustix::fs::FlockOperation::NonBlockingLockExclusive).map_err(|_| {
198        TransportError::OpenError(port_name.to_string(), "Device is locked".to_string())
199    })?;
200    Ok(())
201}
202
203/// Add software flow control to a UART device.
204///
205/// Flow control is performed using XON/XOFF bytes.
206pub struct SoftwareFlowControl<T> {
207    inner: T,
208    flow_control: Cell<FlowControl>,
209    rxbuf: RefCell<VecDeque<u8>>,
210}
211
212impl<T: Uart> SoftwareFlowControl<T> {
213    /// Open the given serial device, such as `/dev/ttyUSB0`.
214    pub fn new(inner: T) -> Self {
215        SoftwareFlowControl {
216            inner,
217            flow_control: Cell::new(FlowControl::None),
218            rxbuf: RefCell::default(),
219        }
220    }
221
222    /// Attempt to read more data into the buffer, and handle flow control characters.
223    ///
224    /// This may not add more data to the buffer if all characters are flow control.
225    fn poll_read_to_buffer(&self, cx: &mut Context<'_>) -> Poll<Result<()>> {
226        let mut buf = [0u8; 256];
227        let len = ready!(self.inner.poll_read(cx, &mut buf)).context("UART read error")?;
228
229        for &ch in &buf[..len] {
230            if self.flow_control.get() != FlowControl::None {
231                if ch == FlowControl::Resume as u8 {
232                    log::debug!("Got RESUME");
233                    self.flow_control.set(FlowControl::Resume);
234                    continue;
235                } else if ch == FlowControl::Pause as u8 {
236                    log::debug!("Got PAUSE");
237                    self.flow_control.set(FlowControl::Pause);
238                    continue;
239                }
240            }
241            self.rxbuf.borrow_mut().push_back(ch);
242        }
243        Poll::Ready(Ok(()))
244    }
245}
246
247impl<T: Uart> Uart for SoftwareFlowControl<T> {
248    fn get_baudrate(&self) -> Result<u32> {
249        self.inner.get_baudrate()
250    }
251
252    /// Sets the UART baudrate.  May do nothing for virtual UARTs.
253    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
254        self.inner.set_baudrate(baudrate)
255    }
256
257    fn get_flow_control(&self) -> Result<FlowControl> {
258        Ok(self.flow_control.get())
259    }
260
261    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
262        self.flow_control.set(match flow_control {
263            false => FlowControl::None,
264            // When flow-control is enabled, assume we haven't
265            // already been put into a pause state.
266            true => FlowControl::Resume,
267        });
268        Ok(())
269    }
270
271    fn get_device_path(&self) -> Result<String> {
272        self.inner.get_device_path()
273    }
274
275    fn poll_read(&self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize>> {
276        let mut rxbuf = self.rxbuf.borrow_mut();
277
278        while rxbuf.is_empty() {
279            drop(rxbuf);
280            ready!(self.poll_read_to_buffer(cx))?;
281            rxbuf = self.rxbuf.borrow_mut();
282        }
283
284        // `VecDeque` can be viewed as two slices.
285        let (front, back) = rxbuf.as_slices();
286
287        let front_copy = std::cmp::min(buf.len(), front.len());
288        buf[..front_copy].copy_from_slice(&front[..front_copy]);
289
290        let back_copy = std::cmp::min(buf.len() - front_copy, back.len());
291        buf[front_copy..][..back_copy].copy_from_slice(&back[..back_copy]);
292
293        let copy_len = front_copy + back_copy;
294        rxbuf.drain(..copy_len);
295        Poll::Ready(Ok(copy_len))
296    }
297
298    /// Writes data from `buf` to the UART.
299    fn write(&self, buf: &[u8]) -> Result<()> {
300        if self.flow_control.get() == FlowControl::None {
301            return self.inner.write(buf);
302        }
303
304        // The constant of 10 is approximately 10 uart bit times per byte.
305        let pacing = Duration::from_nanos(10 * 1_000_000_000u64 / (self.get_baudrate()? as u64));
306        log::debug!(
307            "flow control: {:?}, pacing = {:?}",
308            self.flow_control.get(),
309            pacing
310        );
311
312        for b in buf.iter() {
313            // If flow control is enabled, read data from the input stream and
314            // process the flow control chars.
315            loop {
316                let _ = self.poll_read_to_buffer(&mut Context::from_waker(Waker::noop()))?;
317                // If we're ok to send, then break out of the flow-control loop and send the data.
318                if self.flow_control.get() == FlowControl::Resume {
319                    break;
320                }
321                // Sleep one uart character time to avoid busy polling the UART.
322                std::thread::sleep(pacing);
323            }
324            self.inner
325                .write(std::slice::from_ref(b))
326                .context("UART write error")?;
327            // Sleep one uart character time after writing to the uart to pace characters into the
328            // usb-serial device so that we don't fill any device-internal buffers.  The Chip Whisperer board (for
329            // example) appears to have a large internal buffer that will keep transmitting to OT
330            // even if an XOFF is sent.
331            std::thread::sleep(pacing);
332        }
333        Ok(())
334    }
335
336    fn set_break(&self, enable: bool) -> Result<()> {
337        self.inner.set_break(enable)
338    }
339
340    fn set_parity(&self, parity: Parity) -> Result<()> {
341        self.inner.set_parity(parity)
342    }
343
344    /// Clears the UART RX buffer.
345    fn clear_rx_buffer(&self) -> Result<()> {
346        self.rxbuf.borrow_mut().clear();
347
348        // Clear the host input buffer.
349        self.inner.clear_rx_buffer()
350    }
351}