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}