capsules_core/
console.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Provides userspace with access to a serial interface.
6//!
7//! Setup
8//! -----
9//!
10//! You need a device that provides the `hil::uart::UART` trait.
11//!
12//! ```rust,ignore
13//! # use kernel::static_init;
14//! # use capsules_core::console::Console;
15//!
16//! let console = static_init!(
17//!     Console<usart::USART>,
18//!     Console::new(&usart::USART0,
19//!                  115200,
20//!                  &mut console::WRITE_BUF,
21//!                  &mut console::READ_BUF,
22//!                  board_kernel.create_grant(&grant_cap)));
23//! hil::uart::UART::set_client(&usart::USART0, console);
24//! ```
25//!
26//! Usage
27//! -----
28//!
29//! The user must perform three steps in order to write a buffer:
30//!
31//! ```c
32//! // (Optional) Set a callback to be invoked when the buffer has been written
33//! subscribe(CONSOLE_DRIVER_NUM, 1, my_callback);
34//! // Share the buffer from userspace with the driver
35//! allow(CONSOLE_DRIVER_NUM, buffer, buffer_len_in_bytes);
36//! // Initiate the transaction
37//! command(CONSOLE_DRIVER_NUM, 1, len_to_write_in_bytes)
38//! ```
39//!
40//! When the buffer has been written successfully, the buffer is released from
41//! the driver. Successive writes must call `allow` each time a buffer is to be
42//! written.
43
44use kernel::grant::{AllowRoCount, AllowRwCount, Grant, GrantKernelData, UpcallCount};
45use kernel::hil::uart;
46use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
47use kernel::syscall::{CommandReturn, SyscallDriver};
48use kernel::utilities::cells::{OptionalCell, TakeCell};
49use kernel::{ErrorCode, ProcessId};
50
51/// Syscall driver number.
52use crate::driver;
53pub const DRIVER_NUM: usize = driver::NUM::Console as usize;
54
55/// Default size for the read and write buffers used by the console.
56/// Boards may pass different-size buffers if needed.
57pub const DEFAULT_BUF_SIZE: usize = 64;
58
59/// IDs for subscribed upcalls.
60mod upcall {
61    /// Write buffer completed callback
62    pub const WRITE_DONE: usize = 1;
63    /// Read buffer completed callback
64    pub const READ_DONE: usize = 2;
65    /// Number of upcalls. Even though we only use two, indexing starts at 0 so
66    /// to be able to use indices 1 and 2 we need to specify three upcalls.
67    pub const COUNT: u8 = 3;
68}
69
70/// Ids for read-only allow buffers
71mod ro_allow {
72    /// Readonly buffer for write buffer
73    ///
74    /// Before the allow syscall was handled by the kernel,
75    /// console used allow number "1", so to preserve compatibility
76    /// we still use allow number 1 now.
77    pub const WRITE: usize = 1;
78    /// The number of allow buffers the kernel stores for this grant
79    pub const COUNT: u8 = 2;
80}
81
82/// Ids for read-write allow buffers
83mod rw_allow {
84    /// Writeable buffer for read buffer
85    ///
86    /// Before the allow syscall was handled by the kernel,
87    /// console used allow number "1", so to preserve compatibility
88    /// we still use allow number 1 now.
89    pub const READ: usize = 1;
90    /// The number of allow buffers the kernel stores for this grant
91    pub const COUNT: u8 = 2;
92}
93
94#[derive(Default)]
95pub struct App {
96    write_len: usize,
97    write_remaining: usize, // How many bytes didn't fit in the buffer and still need to be printed.
98    pending_write: bool,
99    read_len: usize,
100}
101
102pub struct Console<'a> {
103    uart: &'a dyn uart::UartData<'a>,
104    apps: Grant<
105        App,
106        UpcallCount<{ upcall::COUNT }>,
107        AllowRoCount<{ ro_allow::COUNT }>,
108        AllowRwCount<{ rw_allow::COUNT }>,
109    >,
110    tx_in_progress: OptionalCell<ProcessId>,
111    tx_buffer: TakeCell<'static, [u8]>,
112    rx_in_progress: OptionalCell<ProcessId>,
113    rx_buffer: TakeCell<'static, [u8]>,
114}
115
116impl<'a> Console<'a> {
117    pub fn new(
118        uart: &'a dyn uart::UartData<'a>,
119        tx_buffer: &'static mut [u8],
120        rx_buffer: &'static mut [u8],
121        grant: Grant<
122            App,
123            UpcallCount<{ upcall::COUNT }>,
124            AllowRoCount<{ ro_allow::COUNT }>,
125            AllowRwCount<{ rw_allow::COUNT }>,
126        >,
127    ) -> Console<'a> {
128        Console {
129            uart,
130            apps: grant,
131            tx_in_progress: OptionalCell::empty(),
132            tx_buffer: TakeCell::new(tx_buffer),
133            rx_in_progress: OptionalCell::empty(),
134            rx_buffer: TakeCell::new(rx_buffer),
135        }
136    }
137
138    /// Internal helper function for setting up a new send transaction
139    fn send_new(
140        &self,
141        processid: ProcessId,
142        app: &mut App,
143        kernel_data: &GrantKernelData,
144        len: usize,
145    ) -> Result<(), ErrorCode> {
146        app.write_len = kernel_data
147            .get_readonly_processbuffer(ro_allow::WRITE)
148            .map_or(0, |write| write.len())
149            .min(len);
150        app.write_remaining = app.write_len;
151        self.send(processid, app, kernel_data);
152        Ok(())
153    }
154
155    /// Internal helper function for continuing a previously set up transaction.
156    /// Returns `true` if this send is still active, or `false` if it has
157    /// completed.
158    fn send_continue(
159        &self,
160        processid: ProcessId,
161        app: &mut App,
162        kernel_data: &GrantKernelData,
163    ) -> bool {
164        if app.write_remaining > 0 {
165            self.send(processid, app, kernel_data);
166
167            // The send may have errored, meaning nothing is being transmitted.
168            // In that case there is nothing pending and we return false. In the
169            // common case, this will return true.
170            self.tx_in_progress.is_some()
171        } else {
172            false
173        }
174    }
175
176    /// Internal helper function for sending data for an existing transaction.
177    /// Cannot fail. If can't send now, it will schedule for sending later.
178    fn send(&self, processid: ProcessId, app: &mut App, kernel_data: &GrantKernelData) {
179        if self.tx_in_progress.is_none() {
180            self.tx_in_progress.set(processid);
181            self.tx_buffer.take().map(|buffer| {
182                let transaction_len = kernel_data
183                    .get_readonly_processbuffer(ro_allow::WRITE)
184                    .and_then(|write| {
185                        write.enter(|data| {
186                            let remaining_data = match data
187                                .get(app.write_len - app.write_remaining..app.write_len)
188                            {
189                                Some(remaining_data) => remaining_data,
190                                None => {
191                                    // A slice has changed under us and is now
192                                    // smaller than what we need to write. Our
193                                    // behavior in this case is documented as
194                                    // undefined; the simplest thing we can do
195                                    // that doesn't panic is to abort the write.
196                                    // We update app.write_len so that the
197                                    // number of bytes written (which is passed
198                                    // to the write done upcall) is correct.
199                                    app.write_len -= app.write_remaining;
200                                    app.write_remaining = 0;
201                                    return 0;
202                                }
203                            };
204                            for (i, c) in remaining_data.iter().enumerate() {
205                                if buffer.len() <= i {
206                                    return i; // Short circuit on partial send
207                                }
208                                buffer[i] = c.get();
209                            }
210                            app.write_remaining
211                        })
212                    })
213                    .unwrap_or(0);
214                app.write_remaining -= transaction_len;
215                match self.uart.transmit_buffer(buffer, transaction_len) {
216                    Err((_e, tx_buffer)) => {
217                        // The UART didn't start, so we will not get a transmit
218                        // done callback. Need to signal the app now.
219                        self.tx_buffer.replace(tx_buffer);
220                        self.tx_in_progress.clear();
221
222                        // Go ahead and signal the application
223                        let written = app.write_len;
224                        app.write_len = 0;
225                        kernel_data.schedule_upcall(1, (written, 0, 0)).ok();
226                    }
227                    Ok(()) => {}
228                }
229            });
230        } else {
231            app.pending_write = true;
232        }
233    }
234
235    /// Internal helper function for starting a receive operation
236    fn receive_new(
237        &self,
238        processid: ProcessId,
239        app: &mut App,
240        kernel_data: &GrantKernelData,
241        len: usize,
242    ) -> Result<(), ErrorCode> {
243        if self.rx_buffer.is_none() {
244            // For now, we tolerate only one concurrent receive operation on this console.
245            // Competing apps will have to retry until success.
246            return Err(ErrorCode::BUSY);
247        }
248
249        let read_len = kernel_data
250            .get_readwrite_processbuffer(rw_allow::READ)
251            .map_or(0, |read| read.len())
252            .min(len);
253        if read_len > self.rx_buffer.map_or(0, |buf| buf.len()) {
254            // For simplicity, impose a small maximum receive length
255            // instead of doing incremental reads
256            Err(ErrorCode::INVAL)
257        } else {
258            // Note: We have ensured above that rx_buffer is present
259            app.read_len = read_len;
260            self.rx_buffer
261                .take()
262                .map_or(Err(ErrorCode::INVAL), |buffer| {
263                    self.rx_in_progress.set(processid);
264                    if let Err((e, buf)) = self.uart.receive_buffer(buffer, app.read_len) {
265                        self.rx_buffer.replace(buf);
266                        return Err(e);
267                    }
268                    Ok(())
269                })
270        }
271    }
272}
273
274impl SyscallDriver for Console<'_> {
275    /// Initiate serial transfers
276    ///
277    /// ### `command_num`
278    ///
279    /// - `0`: Driver existence check.
280    /// - `1`: Transmits a buffer passed via `allow`, up to the length passed in
281    ///   `arg1`
282    /// - `2`: Receives into a buffer passed via `allow`, up to the length
283    ///   passed in `arg1`
284    /// - `3`: Cancel any in progress receives and return (via callback) what
285    ///   has been received so far.
286    fn command(
287        &self,
288        cmd_num: usize,
289        arg1: usize,
290        _: usize,
291        processid: ProcessId,
292    ) -> CommandReturn {
293        let res = self
294            .apps
295            .enter(processid, |app, kernel_data| {
296                match cmd_num {
297                    0 => Ok(()),
298                    1 => {
299                        // putstr
300                        let len = arg1;
301                        self.send_new(processid, app, kernel_data, len)
302                    }
303                    2 => {
304                        // getnstr
305                        let len = arg1;
306                        self.receive_new(processid, app, kernel_data, len)
307                    }
308                    3 => {
309                        // Abort RX
310                        let _ = self.uart.receive_abort();
311                        Ok(())
312                    }
313                    _ => Err(ErrorCode::NOSUPPORT),
314                }
315            })
316            .map_err(ErrorCode::from);
317        match res {
318            Ok(Ok(())) => CommandReturn::success(),
319            Ok(Err(e)) => CommandReturn::failure(e),
320            Err(e) => CommandReturn::failure(e),
321        }
322    }
323
324    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
325        self.apps.enter(processid, |_, _| {})
326    }
327}
328
329impl uart::TransmitClient for Console<'_> {
330    fn transmitted_buffer(
331        &self,
332        buffer: &'static mut [u8],
333        _tx_len: usize,
334        _rcode: Result<(), ErrorCode>,
335    ) {
336        // Either print more from the AppSlice or send a callback to the
337        // application.
338        self.tx_buffer.replace(buffer);
339        self.tx_in_progress.take().map(|processid| {
340            self.apps.enter(processid, |app, kernel_data| {
341                match self.send_continue(processid, app, kernel_data) {
342                    true => {
343                        // Still more to send. Wait to notify the process.
344                    }
345                    false => {
346                        // Go ahead and signal the application
347                        let written = app.write_len;
348                        app.write_len = 0;
349                        kernel_data
350                            .schedule_upcall(upcall::WRITE_DONE, (written, 0, 0))
351                            .ok();
352                    }
353                }
354            })
355        });
356
357        // If we are not printing more from the current AppSlice,
358        // see if any other applications have pending messages.
359        if self.tx_in_progress.is_none() {
360            for cntr in self.apps.iter() {
361                let processid = cntr.processid();
362                let started_tx = cntr.enter(|app, kernel_data| {
363                    if app.pending_write {
364                        app.pending_write = false;
365                        self.send_continue(processid, app, kernel_data)
366                    } else {
367                        false
368                    }
369                });
370                if started_tx {
371                    break;
372                }
373            }
374        }
375    }
376}
377
378impl uart::ReceiveClient for Console<'_> {
379    fn received_buffer(
380        &self,
381        buffer: &'static mut [u8],
382        rx_len: usize,
383        rcode: Result<(), ErrorCode>,
384        error: uart::Error,
385    ) {
386        self.rx_in_progress
387            .take()
388            .map(|processid| {
389                self.apps
390                    .enter(processid, |_, kernel_data| {
391                        // An iterator over the returned buffer yielding only the first `rx_len`
392                        // bytes
393                        let rx_buffer = buffer.iter().take(rx_len);
394                        match error {
395                            uart::Error::None | uart::Error::Aborted => {
396                                // Receive some bytes, signal error type and return bytes to process buffer
397                                let count = kernel_data
398                                    .get_readwrite_processbuffer(rw_allow::READ)
399                                    .and_then(|read| {
400                                        read.mut_enter(|data| {
401                                            let mut c = 0;
402                                            for (a, b) in data.iter().zip(rx_buffer) {
403                                                c += 1;
404                                                a.set(*b);
405                                            }
406                                            c
407                                        })
408                                    })
409                                    .unwrap_or(-1);
410
411                                // Make sure we report the same number
412                                // of bytes that we actually copied into
413                                // the app's buffer. This is defensive:
414                                // we shouldn't ever receive more bytes
415                                // than will fit in the app buffer since
416                                // we use the app_buffer's length when
417                                // calling `receive()`. However, a buggy
418                                // lower layer could return more bytes
419                                // than we asked for, and we don't want
420                                // to propagate that length error to
421                                // userspace. However, we do return an
422                                // error code so that userspace knows
423                                // something went wrong.
424                                //
425                                // If count < 0 this means the buffer
426                                // disappeared: return NOMEM.
427                                let read_buffer_len = kernel_data
428                                    .get_readwrite_processbuffer(rw_allow::READ)
429                                    .map_or(0, |read| read.len());
430                                let (ret, received_length) = if count < 0 {
431                                    (Err(ErrorCode::NOMEM), 0)
432                                } else if rx_len > read_buffer_len {
433                                    // Return `SIZE` indicating that
434                                    // some received bytes were dropped.
435                                    // We report the length that we
436                                    // actually copied into the buffer,
437                                    // but also indicate that there was
438                                    // an issue in the kernel with the
439                                    // receive.
440                                    (Err(ErrorCode::SIZE), read_buffer_len)
441                                } else {
442                                    // This is the normal and expected
443                                    // case.
444                                    (rcode, rx_len)
445                                };
446
447                                kernel_data
448                                    .schedule_upcall(
449                                        upcall::READ_DONE,
450                                        (
451                                            kernel::errorcode::into_statuscode(ret),
452                                            received_length,
453                                            0,
454                                        ),
455                                    )
456                                    .ok();
457                            }
458                            _ => {
459                                // Some UART error occurred
460                                kernel_data
461                                    .schedule_upcall(
462                                        upcall::READ_DONE,
463                                        (
464                                            kernel::errorcode::into_statuscode(Err(
465                                                ErrorCode::FAIL,
466                                            )),
467                                            0,
468                                            0,
469                                        ),
470                                    )
471                                    .ok();
472                            }
473                        }
474                    })
475                    .unwrap_or_default();
476            })
477            .unwrap_or_default();
478
479        // Whatever happens, we want to make sure to replace the rx_buffer for future transactions
480        self.rx_buffer.replace(buffer);
481    }
482}