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}