components/
process_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//! Component for ProcessConsole, the command console.
6//!
7//! This provides one Component, ProcessConsoleComponent, which implements a
8//! command console for controlling processes over a UART bus. On imix this is
9//! typically USART3 (the DEBUG USB connector).
10//!
11//! Usage
12//! -----
13//! ```rust
14//! let pconsole = ProcessConsoleComponent::new(board_kernel, uart_mux, alarm_mux, process_printer, Some(reset_function))
15//!     .finalize(process_console_component_static!());
16//! ```
17
18// Author: Philip Levis <pal@cs.stanford.edu>
19// Last modified: 6/20/2018
20
21use capsules_core::process_console::{self, ProcessConsole};
22use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
23use capsules_core::virtualizers::virtual_uart::{MuxUart, UartDevice};
24use core::mem::MaybeUninit;
25use kernel::capabilities;
26use kernel::component::Component;
27use kernel::hil;
28use kernel::hil::time::Alarm;
29use kernel::process::ProcessPrinter;
30
31#[macro_export]
32macro_rules! process_console_component_static {
33    ($A: ty, $COMMAND_HISTORY_LEN: expr $(,)?) => {{
34        let alarm = kernel::static_buf!(capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>);
35        let uart = kernel::static_buf!(capsules_core::virtualizers::virtual_uart::UartDevice);
36        let pconsole = kernel::static_buf!(
37            capsules_core::process_console::ProcessConsole<
38                $COMMAND_HISTORY_LEN,
39                capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>,
40                components::process_console::Capability,
41            >
42        );
43
44        let write_buffer = kernel::static_buf!([u8; capsules_core::process_console::WRITE_BUF_LEN]);
45        let read_buffer = kernel::static_buf!([u8; capsules_core::process_console::READ_BUF_LEN]);
46        let queue_buffer = kernel::static_buf!([u8; capsules_core::process_console::QUEUE_BUF_LEN]);
47        let command_buffer = kernel::static_buf!([u8; capsules_core::process_console::COMMAND_BUF_LEN]);
48        let command_history_buffer = kernel::static_buf!(
49            [capsules_core::process_console::Command; $COMMAND_HISTORY_LEN]
50        );
51
52        (
53            alarm,
54            uart,
55            write_buffer,
56            read_buffer,
57            queue_buffer,
58            command_buffer,
59            command_history_buffer,
60            pconsole,
61        )
62    };};
63    ($A: ty $(,)?) => {{
64        $crate::process_console_component_static!($A, { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN })
65    };};
66}
67
68pub struct ProcessConsoleComponent<const COMMAND_HISTORY_LEN: usize, A: 'static + Alarm<'static>> {
69    board_kernel: &'static kernel::Kernel,
70    uart_mux: &'static MuxUart<'static>,
71    alarm_mux: &'static MuxAlarm<'static, A>,
72    process_printer: &'static dyn ProcessPrinter,
73    reset_function: Option<fn() -> !>,
74}
75
76impl<const COMMAND_HISTORY_LEN: usize, A: 'static + Alarm<'static>>
77    ProcessConsoleComponent<COMMAND_HISTORY_LEN, A>
78{
79    pub fn new(
80        board_kernel: &'static kernel::Kernel,
81        uart_mux: &'static MuxUart,
82        alarm_mux: &'static MuxAlarm<'static, A>,
83        process_printer: &'static dyn ProcessPrinter,
84        reset_function: Option<fn() -> !>,
85    ) -> ProcessConsoleComponent<COMMAND_HISTORY_LEN, A> {
86        ProcessConsoleComponent {
87            board_kernel,
88            uart_mux,
89            alarm_mux,
90            process_printer,
91            reset_function,
92        }
93    }
94}
95
96// These constants are defined in the linker script for where the
97// kernel is placed in memory on chip.
98extern "C" {
99    static _estack: u8;
100    static _sstack: u8;
101    static _stext: u8;
102    static _srodata: u8;
103    static _etext: u8;
104    static _srelocate: u8;
105    static _erelocate: u8;
106    static _szero: u8;
107    static _ezero: u8;
108}
109
110pub struct Capability;
111unsafe impl capabilities::ProcessManagementCapability for Capability {}
112unsafe impl capabilities::ProcessStartCapability for Capability {}
113
114impl<const COMMAND_HISTORY_LEN: usize, A: 'static + Alarm<'static>> Component
115    for ProcessConsoleComponent<COMMAND_HISTORY_LEN, A>
116{
117    type StaticInput = (
118        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
119        &'static mut MaybeUninit<UartDevice<'static>>,
120        &'static mut MaybeUninit<[u8; capsules_core::process_console::WRITE_BUF_LEN]>,
121        &'static mut MaybeUninit<[u8; capsules_core::process_console::READ_BUF_LEN]>,
122        &'static mut MaybeUninit<[u8; capsules_core::process_console::QUEUE_BUF_LEN]>,
123        &'static mut MaybeUninit<[u8; capsules_core::process_console::COMMAND_BUF_LEN]>,
124        &'static mut MaybeUninit<[capsules_core::process_console::Command; COMMAND_HISTORY_LEN]>,
125        &'static mut MaybeUninit<
126            ProcessConsole<'static, COMMAND_HISTORY_LEN, VirtualMuxAlarm<'static, A>, Capability>,
127        >,
128    );
129    type Output = &'static process_console::ProcessConsole<
130        'static,
131        COMMAND_HISTORY_LEN,
132        VirtualMuxAlarm<'static, A>,
133        Capability,
134    >;
135
136    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
137        // Create virtual device for console.
138        let console_uart = static_buffer.1.write(UartDevice::new(self.uart_mux, true));
139        console_uart.setup();
140
141        // Get addresses of where the kernel is placed to enable additional
142        // debugging in process console.
143        let kernel_addresses = process_console::KernelAddresses {
144            stack_start: core::ptr::addr_of!(_sstack),
145            stack_end: core::ptr::addr_of!(_estack),
146            text_start: core::ptr::addr_of!(_stext),
147            text_end: core::ptr::addr_of!(_etext),
148            read_only_data_start: core::ptr::addr_of!(_srodata),
149            relocations_start: core::ptr::addr_of!(_srelocate),
150            relocations_end: core::ptr::addr_of!(_erelocate),
151            bss_start: core::ptr::addr_of!(_szero),
152            bss_end: core::ptr::addr_of!(_ezero),
153        };
154
155        let console_alarm = static_buffer.0.write(VirtualMuxAlarm::new(self.alarm_mux));
156        console_alarm.setup();
157
158        let write_buffer = static_buffer
159            .2
160            .write([0; capsules_core::process_console::WRITE_BUF_LEN]);
161        let read_buffer = static_buffer
162            .3
163            .write([0; capsules_core::process_console::READ_BUF_LEN]);
164        let queue_buffer = static_buffer
165            .4
166            .write([0; capsules_core::process_console::QUEUE_BUF_LEN]);
167        let command_buffer = static_buffer
168            .5
169            .write([0; capsules_core::process_console::COMMAND_BUF_LEN]);
170        let command_history_buffer = static_buffer
171            .6
172            .write([capsules_core::process_console::Command::default(); COMMAND_HISTORY_LEN]);
173
174        let console = static_buffer.7.write(ProcessConsole::new(
175            console_uart,
176            console_alarm,
177            self.process_printer,
178            write_buffer,
179            read_buffer,
180            queue_buffer,
181            command_buffer,
182            command_history_buffer,
183            self.board_kernel,
184            kernel_addresses,
185            self.reset_function,
186            Capability,
187        ));
188        hil::uart::Transmit::set_transmit_client(console_uart, console);
189        hil::uart::Receive::set_receive_client(console_uart, console);
190        console_alarm.set_alarm_client(console);
191
192        console
193    }
194}