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                if let Err((_e, tx_buffer)) = self.uart.transmit_buffer(buffer, transaction_len) {
216                    // The UART didn't start, so we will not get a transmit
217                    // done callback. Need to signal the app now.
218                    self.tx_buffer.replace(tx_buffer);
219                    self.tx_in_progress.clear();
220
221                    // Go ahead and signal the application
222                    let written = app.write_len;
223                    app.write_len = 0;
224                    kernel_data.schedule_upcall(1, (written, 0, 0)).ok();
225                }
226            });
227        } else {
228            app.pending_write = true;
229        }
230    }
231
232    /// Internal helper function for starting a receive operation
233    fn receive_new(
234        &self,
235        processid: ProcessId,
236        app: &mut App,
237        kernel_data: &GrantKernelData,
238        len: usize,
239    ) -> Result<(), ErrorCode> {
240        if self.rx_buffer.is_none() {
241            // For now, we tolerate only one concurrent receive operation on this console.
242            // Competing apps will have to retry until success.
243            return Err(ErrorCode::BUSY);
244        }
245
246        let read_len = kernel_data
247            .get_readwrite_processbuffer(rw_allow::READ)
248            .map_or(0, |read| read.len())
249            .min(len);
250        if read_len > self.rx_buffer.map_or(0, |buf| buf.len()) {
251            // For simplicity, impose a small maximum receive length
252            // instead of doing incremental reads
253            Err(ErrorCode::INVAL)
254        } else {
255            // Note: We have ensured above that rx_buffer is present
256            app.read_len = read_len;
257            self.rx_buffer
258                .take()
259                .map_or(Err(ErrorCode::INVAL), |buffer| {
260                    self.rx_in_progress.set(processid);
261                    if let Err((e, buf)) = self.uart.receive_buffer(buffer, app.read_len) {
262                        self.rx_buffer.replace(buf);
263                        return Err(e);
264                    }
265                    Ok(())
266                })
267        }
268    }
269}
270
271impl SyscallDriver for Console<'_> {
272    /// Initiate serial transfers
273    ///
274    /// ### `command_num`
275    ///
276    /// - `0`: Driver existence check.
277    /// - `1`: Transmits a buffer passed via `allow`, up to the length passed in
278    ///   `arg1`
279    /// - `2`: Receives into a buffer passed via `allow`, up to the length
280    ///   passed in `arg1`
281    /// - `3`: Cancel any in progress receives and return (via callback) what
282    ///   has been received so far.
283    fn command(
284        &self,
285        cmd_num: usize,
286        arg1: usize,
287        _: usize,
288        processid: ProcessId,
289    ) -> CommandReturn {
290        let res = self
291            .apps
292            .enter(processid, |app, kernel_data| {
293                match cmd_num {
294                    0 => Ok(()),
295                    1 => {
296                        // putstr
297                        let len = arg1;
298                        self.send_new(processid, app, kernel_data, len)
299                    }
300                    2 => {
301                        // getnstr
302                        let len = arg1;
303                        self.receive_new(processid, app, kernel_data, len)
304                    }
305                    3 => {
306                        // Abort RX
307                        let _ = self.uart.receive_abort();
308                        Ok(())
309                    }
310                    _ => Err(ErrorCode::NOSUPPORT),
311                }
312            })
313            .map_err(ErrorCode::from);
314        match res {
315            Ok(Ok(())) => CommandReturn::success(),
316            Ok(Err(e)) => CommandReturn::failure(e),
317            Err(e) => CommandReturn::failure(e),
318        }
319    }
320
321    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
322        self.apps.enter(processid, |_, _| {})
323    }
324}
325
326impl uart::TransmitClient for Console<'_> {
327    fn transmitted_buffer(
328        &self,
329        buffer: &'static mut [u8],
330        _tx_len: usize,
331        _rcode: Result<(), ErrorCode>,
332    ) {
333        // Either print more from the AppSlice or send a callback to the
334        // application.
335        self.tx_buffer.replace(buffer);
336        self.tx_in_progress.take().map(|processid| {
337            self.apps.enter(processid, |app, kernel_data| {
338                match self.send_continue(processid, app, kernel_data) {
339                    true => {
340                        // Still more to send. Wait to notify the process.
341                    }
342                    false => {
343                        // Go ahead and signal the application
344                        let written = app.write_len;
345                        app.write_len = 0;
346                        kernel_data
347                            .schedule_upcall(upcall::WRITE_DONE, (written, 0, 0))
348                            .ok();
349                    }
350                }
351            })
352        });
353
354        // If we are not printing more from the current AppSlice,
355        // see if any other applications have pending messages.
356        if self.tx_in_progress.is_none() {
357            for cntr in self.apps.iter() {
358                let processid = cntr.processid();
359                let started_tx = cntr.enter(|app, kernel_data| {
360                    if app.pending_write {
361                        app.pending_write = false;
362                        self.send_continue(processid, app, kernel_data)
363                    } else {
364                        false
365                    }
366                });
367                if started_tx {
368                    break;
369                }
370            }
371        }
372    }
373}
374
375impl uart::ReceiveClient for Console<'_> {
376    fn received_buffer(
377        &self,
378        buffer: &'static mut [u8],
379        rx_len: usize,
380        rcode: Result<(), ErrorCode>,
381        error: uart::Error,
382    ) {
383        self.rx_in_progress
384            .take()
385            .map(|processid| {
386                self.apps
387                    .enter(processid, |_, kernel_data| {
388                        // An iterator over the returned buffer yielding only the first `rx_len`
389                        // bytes
390                        let rx_buffer = buffer.iter().take(rx_len);
391                        match error {
392                            uart::Error::None | uart::Error::Aborted => {
393                                // Receive some bytes, signal error type and return bytes to process buffer
394                                let count = kernel_data
395                                    .get_readwrite_processbuffer(rw_allow::READ)
396                                    .and_then(|read| {
397                                        read.mut_enter(|data| {
398                                            let mut c = 0;
399                                            for (a, b) in data.iter().zip(rx_buffer) {
400                                                c += 1;
401                                                a.set(*b);
402                                            }
403                                            c
404                                        })
405                                    })
406                                    .unwrap_or(-1);
407
408                                // Make sure we report the same number
409                                // of bytes that we actually copied into
410                                // the app's buffer. This is defensive:
411                                // we shouldn't ever receive more bytes
412                                // than will fit in the app buffer since
413                                // we use the app_buffer's length when
414                                // calling `receive()`. However, a buggy
415                                // lower layer could return more bytes
416                                // than we asked for, and we don't want
417                                // to propagate that length error to
418                                // userspace. However, we do return an
419                                // error code so that userspace knows
420                                // something went wrong.
421                                //
422                                // If count < 0 this means the buffer
423                                // disappeared: return NOMEM.
424                                let read_buffer_len = kernel_data
425                                    .get_readwrite_processbuffer(rw_allow::READ)
426                                    .map_or(0, |read| read.len());
427                                let (ret, received_length) = if count < 0 {
428                                    (Err(ErrorCode::NOMEM), 0)
429                                } else if rx_len > read_buffer_len {
430                                    // Return `SIZE` indicating that
431                                    // some received bytes were dropped.
432                                    // We report the length that we
433                                    // actually copied into the buffer,
434                                    // but also indicate that there was
435                                    // an issue in the kernel with the
436                                    // receive.
437                                    (Err(ErrorCode::SIZE), read_buffer_len)
438                                } else {
439                                    // This is the normal and expected
440                                    // case.
441                                    (rcode, rx_len)
442                                };
443
444                                kernel_data
445                                    .schedule_upcall(
446                                        upcall::READ_DONE,
447                                        (
448                                            kernel::errorcode::into_statuscode(ret),
449                                            received_length,
450                                            0,
451                                        ),
452                                    )
453                                    .ok();
454                            }
455                            _ => {
456                                // Some UART error occurred
457                                kernel_data
458                                    .schedule_upcall(
459                                        upcall::READ_DONE,
460                                        (
461                                            kernel::errorcode::into_statuscode(Err(
462                                                ErrorCode::FAIL,
463                                            )),
464                                            0,
465                                            0,
466                                        ),
467                                    )
468                                    .ok();
469                            }
470                        }
471                    })
472                    .unwrap_or_default();
473            })
474            .unwrap_or_default();
475
476        // Whatever happens, we want to make sure to replace the rx_buffer for future transactions
477        self.rx_buffer.replace(buffer);
478    }
479}