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 let _ = kernel_data.schedule_upcall(1, (written, 0, 0));
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 let _ = kernel_data.schedule_upcall(upcall::WRITE_DONE, (written, 0, 0));
347 }
348 }
349 })
350 });
351
352 // If we are not printing more from the current AppSlice,
353 // see if any other applications have pending messages.
354 if self.tx_in_progress.is_none() {
355 for cntr in self.apps.iter() {
356 let processid = cntr.processid();
357 let started_tx = cntr.enter(|app, kernel_data| {
358 if app.pending_write {
359 app.pending_write = false;
360 self.send_continue(processid, app, kernel_data)
361 } else {
362 false
363 }
364 });
365 if started_tx {
366 break;
367 }
368 }
369 }
370 }
371}
372
373impl uart::ReceiveClient for Console<'_> {
374 fn received_buffer(
375 &self,
376 buffer: &'static mut [u8],
377 rx_len: usize,
378 rcode: Result<(), ErrorCode>,
379 error: uart::Error,
380 ) {
381 self.rx_in_progress
382 .take()
383 .map(|processid| {
384 self.apps
385 .enter(processid, |_, kernel_data| {
386 // An iterator over the returned buffer yielding only the first `rx_len`
387 // bytes
388 let rx_buffer = buffer.iter().take(rx_len);
389 match error {
390 uart::Error::None | uart::Error::Aborted => {
391 // Receive some bytes, signal error type and return bytes to process buffer
392 let count = kernel_data
393 .get_readwrite_processbuffer(rw_allow::READ)
394 .and_then(|read| {
395 read.mut_enter(|data| {
396 let mut c = 0;
397 for (a, b) in data.iter().zip(rx_buffer) {
398 c += 1;
399 a.set(*b);
400 }
401 c
402 })
403 })
404 .unwrap_or(-1);
405
406 // Make sure we report the same number
407 // of bytes that we actually copied into
408 // the app's buffer. This is defensive:
409 // we shouldn't ever receive more bytes
410 // than will fit in the app buffer since
411 // we use the app_buffer's length when
412 // calling `receive()`. However, a buggy
413 // lower layer could return more bytes
414 // than we asked for, and we don't want
415 // to propagate that length error to
416 // userspace. However, we do return an
417 // error code so that userspace knows
418 // something went wrong.
419 //
420 // If count < 0 this means the buffer
421 // disappeared: return NOMEM.
422 let read_buffer_len = kernel_data
423 .get_readwrite_processbuffer(rw_allow::READ)
424 .map_or(0, |read| read.len());
425 let (ret, received_length) = if count < 0 {
426 (Err(ErrorCode::NOMEM), 0)
427 } else if rx_len > read_buffer_len {
428 // Return `SIZE` indicating that
429 // some received bytes were dropped.
430 // We report the length that we
431 // actually copied into the buffer,
432 // but also indicate that there was
433 // an issue in the kernel with the
434 // receive.
435 (Err(ErrorCode::SIZE), read_buffer_len)
436 } else {
437 // This is the normal and expected
438 // case.
439 (rcode, rx_len)
440 };
441
442 let _ = kernel_data.schedule_upcall(
443 upcall::READ_DONE,
444 (kernel::errorcode::into_statuscode(ret), received_length, 0),
445 );
446 }
447 _ => {
448 // Some UART error occurred
449 let _ = kernel_data.schedule_upcall(
450 upcall::READ_DONE,
451 (
452 kernel::errorcode::into_statuscode(Err(ErrorCode::FAIL)),
453 0,
454 0,
455 ),
456 );
457 }
458 }
459 })
460 .unwrap_or_default();
461 })
462 .unwrap_or_default();
463
464 // Whatever happens, we want to make sure to replace the rx_buffer for future transactions
465 self.rx_buffer.replace(buffer);
466 }
467}