1use core::cell::Cell;
10use core::cmp;
11use core::fmt;
12use core::fmt::write;
13use core::str;
14use kernel::capabilities::ProcessManagementCapability;
15use kernel::capabilities::ProcessStartCapability;
16use kernel::hil::time::ConvertTicks;
17use kernel::utilities::cells::MapCell;
18use kernel::utilities::cells::TakeCell;
19use kernel::ProcessId;
20
21use kernel::debug;
22use kernel::hil::time::{Alarm, AlarmClient};
23use kernel::hil::uart;
24use kernel::introspection::KernelInfo;
25use kernel::process::{ProcessPrinter, ProcessPrinterContext, State};
26use kernel::utilities::binary_write::BinaryWrite;
27use kernel::ErrorCode;
28use kernel::Kernel;
29
30pub const WRITE_BUF_LEN: usize = 500;
32pub const QUEUE_BUF_LEN: usize = 300;
35pub const READ_BUF_LEN: usize = 4;
38pub const COMMAND_BUF_LEN: usize = 64;
41pub const DEFAULT_COMMAND_HISTORY_LEN: usize = 10;
43
44const VALID_COMMANDS_STR: &[u8] =
47 b"help status list stop start fault boot terminate process kernel reset panic console-start console-stop\r\n";
48
49const ESC: u8 = b'\x1B';
51
52const EOL: u8 = b'\x00';
54
55const BS: u8 = b'\x08';
57
58const DEL: u8 = b'\x7F';
60
61const SPACE: u8 = b'\x20';
63
64const CR: u8 = b'\x0D';
66
67const NLINE: u8 = b'\x0A';
69
70const ASCII_LIMIT: u8 = 128;
72
73#[derive(PartialEq, Eq, Copy, Clone, Default)]
77enum WriterState {
78 #[default]
79 Empty,
80 KernelStart,
81 KernelBss,
82 KernelInit,
83 KernelStack,
84 KernelRoData,
85 KernelText,
86 ProcessPrint {
87 process_id: ProcessId,
88 context: Option<ProcessPrinterContext>,
89 },
90 List {
91 index: isize,
92 total: isize,
93 },
94}
95
96#[derive(Copy, Clone)]
98enum EscKey {
99 Up,
100 Down,
101 Left,
102 Right,
103 Home,
104 End,
105 Delete,
106}
107
108#[derive(Copy, Clone)]
111enum EscState {
112 Bypass,
115
116 Complete(EscKey),
119
120 Started,
124
125 Bracket,
129 Bracket3,
130
131 Unrecognized,
137
138 UnrecognizedDone,
142}
143
144impl EscState {
145 fn next_state(self, data: u8) -> Self {
146 use self::{
147 EscKey::{Delete, Down, End, Home, Left, Right, Up},
148 EscState::{
149 Bracket, Bracket3, Bypass, Complete, Started, Unrecognized, UnrecognizedDone,
150 },
151 };
152 match (self, data) {
153 (Bypass, ESC) | (UnrecognizedDone, ESC) | (Complete(_), ESC) => Started,
154 (Bypass, DEL) | (UnrecognizedDone, DEL) | (Complete(_), DEL) => Complete(Delete),
157 (Bypass, _) | (UnrecognizedDone, _) | (Complete(_), _) => Bypass,
158 (Started, b'[') => Bracket,
159 (Bracket, b'A') => Complete(Up),
160 (Bracket, b'B') => Complete(Down),
161 (Bracket, b'D') => Complete(Left),
162 (Bracket, b'C') => Complete(Right),
163 (Bracket, b'H') => Complete(Home),
164 (Bracket, b'F') => Complete(End),
165 (Bracket, b'3') => Bracket3,
166 (Bracket3, b'~') => Complete(Delete),
167 _ => {
168 if EscState::terminator_esc_char(data) {
169 UnrecognizedDone
170 } else {
171 Unrecognized
172 }
173 }
174 }
175 }
176
177 fn in_progress(&self) -> bool {
180 matches!(self, EscState::Bracket) || matches!(self, EscState::Bracket3)
181 }
182
183 fn has_started(&self) -> bool {
186 matches!(self, EscState::Started)
187 }
188
189 fn terminator_esc_char(data: u8) -> bool {
190 data.is_ascii_alphabetic() || data == b'~'
191 }
192}
193
194pub struct KernelAddresses {
200 pub stack_start: *const u8,
201 pub stack_end: *const u8,
202 pub text_start: *const u8,
203 pub text_end: *const u8,
204 pub read_only_data_start: *const u8,
205 pub relocations_start: *const u8,
206 pub relocations_end: *const u8,
207 pub bss_start: *const u8,
208 pub bss_end: *const u8,
209}
210
211#[derive(Clone, Copy, PartialEq)]
213enum ProcessConsoleState {
214 Off,
216 Active,
218 Hibernating,
223}
224
225pub struct ProcessConsole<
226 'a,
227 const COMMAND_HISTORY_LEN: usize,
228 A: Alarm<'a>,
229 C: ProcessManagementCapability + ProcessStartCapability,
230> {
231 uart: &'a dyn uart::UartData<'a>,
232 alarm: &'a A,
233 process_printer: &'a dyn ProcessPrinter,
234 tx_in_progress: Cell<bool>,
235 tx_buffer: TakeCell<'static, [u8]>,
236 queue_buffer: TakeCell<'static, [u8]>,
237 queue_size: Cell<usize>,
238 writer_state: Cell<WriterState>,
239 rx_buffer: TakeCell<'static, [u8]>,
240 command_buffer: TakeCell<'static, [u8]>,
241 command_index: Cell<usize>,
242
243 mode: Cell<ProcessConsoleState>,
246
247 esc_state: Cell<EscState>,
249
250 command_history: MapCell<CommandHistory<'static, COMMAND_HISTORY_LEN>>,
252
253 cursor: Cell<usize>,
255
256 previous_byte: Cell<u8>,
259
260 execute: Cell<bool>,
263
264 kernel: &'static Kernel,
266
267 kernel_addresses: KernelAddresses,
269
270 reset_function: Option<fn() -> !>,
272
273 capability: C,
276}
277
278#[derive(Copy, Clone)]
279pub struct Command {
280 buf: [u8; COMMAND_BUF_LEN],
281 len: usize,
282}
283
284impl Command {
285 fn write(&mut self, buf: &[u8; COMMAND_BUF_LEN]) {
289 self.len = buf
290 .iter()
291 .position(|a| *a == EOL)
292 .unwrap_or(COMMAND_BUF_LEN);
293
294 (self.buf).copy_from_slice(buf);
295 }
296
297 fn insert_byte(&mut self, byte: u8, pos: usize) {
298 for i in (pos..self.len).rev() {
299 self.buf[i + 1] = self.buf[i];
300 }
301
302 if let Some(buf_byte) = self.buf.get_mut(pos) {
303 *buf_byte = byte;
304 self.len += 1;
305 }
306 }
307
308 fn delete_byte(&mut self, pos: usize) {
309 for i in pos..self.len {
310 self.buf[i] = self.buf[i + 1];
311 }
312
313 if let Some(buf_byte) = self.buf.get_mut(self.len - 1) {
314 *buf_byte = EOL;
315 self.len -= 1;
316 }
317 }
318
319 fn clear(&mut self) {
320 self.buf.iter_mut().for_each(|x| *x = EOL);
321 self.len = 0;
322 }
323}
324
325impl Default for Command {
326 fn default() -> Self {
327 Command {
328 buf: [EOL; COMMAND_BUF_LEN],
329 len: 0,
330 }
331 }
332}
333
334impl PartialEq<[u8; COMMAND_BUF_LEN]> for Command {
335 fn eq(&self, other_buf: &[u8; COMMAND_BUF_LEN]) -> bool {
336 self.buf
337 .iter()
338 .zip(other_buf.iter())
339 .take_while(|(a, b)| **a != EOL || **b != EOL)
340 .all(|(a, b)| *a == *b)
341 }
342}
343
344struct CommandHistory<'a, const COMMAND_HISTORY_LEN: usize> {
345 cmds: &'a mut [Command; COMMAND_HISTORY_LEN],
346 cmd_idx: usize,
347 cmd_is_modified: bool,
348}
349
350impl<'a, const COMMAND_HISTORY_LEN: usize> CommandHistory<'a, COMMAND_HISTORY_LEN> {
351 fn new(cmds_buffer: &'a mut [Command; COMMAND_HISTORY_LEN]) -> Self {
352 Self {
353 cmds: cmds_buffer,
354 cmd_idx: 0,
355 cmd_is_modified: false,
356 }
357 }
358
359 fn make_space(&mut self, cmd: &[u8]) {
361 let mut cmd_arr = [0; COMMAND_BUF_LEN];
362 cmd_arr.copy_from_slice(cmd);
363
364 if self.cmds[1] != cmd_arr {
365 self.cmds.rotate_right(1);
366 self.cmds[0].clear();
367 self.cmds[1].write(&cmd_arr);
368 }
369 }
370
371 fn write_to_first(&mut self, cmd: &[u8]) {
372 let mut cmd_arr = [0; COMMAND_BUF_LEN];
373 cmd_arr.copy_from_slice(cmd);
374 self.cmds[0].write(&cmd_arr);
375 }
376
377 fn next_cmd_idx(&mut self) -> Option<usize> {
379 if self.cmd_idx + 1 >= COMMAND_HISTORY_LEN {
380 None
381 } else if self.cmds[self.cmd_idx + 1].len == 0 {
382 None
383 } else {
384 self.cmd_idx += 1;
385
386 Some(self.cmd_idx)
387 }
388 }
389
390 fn prev_cmd_idx(&mut self) -> Option<usize> {
392 if self.cmd_idx > 0 {
393 self.cmd_idx -= 1;
394
395 Some(self.cmd_idx)
396 } else {
397 None
398 }
399 }
400}
401
402pub struct ConsoleWriter {
403 buf: [u8; 500],
404 size: usize,
405}
406impl ConsoleWriter {
407 pub fn new() -> ConsoleWriter {
408 ConsoleWriter {
409 buf: [EOL; 500],
410 size: 0,
411 }
412 }
413 pub fn clear(&mut self) {
414 self.size = 0;
415 }
416}
417impl fmt::Write for ConsoleWriter {
418 fn write_str(&mut self, s: &str) -> fmt::Result {
419 let curr = s.len();
420 self.buf[self.size..self.size + curr].copy_from_slice(s.as_bytes());
421 self.size += curr;
422 Ok(())
423 }
424}
425
426impl BinaryWrite for ConsoleWriter {
427 fn write_buffer(&mut self, buffer: &[u8]) -> Result<usize, ()> {
428 let start = self.size;
429 let remaining = self.buf.len() - start;
430 let to_send = core::cmp::min(buffer.len(), remaining);
431 self.buf[start..start + to_send].copy_from_slice(&buffer[..to_send]);
432 self.size += to_send;
433 Ok(to_send)
434 }
435}
436
437impl<
438 'a,
439 const COMMAND_HISTORY_LEN: usize,
440 A: Alarm<'a>,
441 C: ProcessManagementCapability + ProcessStartCapability,
442 > ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
443{
444 pub fn new(
445 uart: &'a dyn uart::UartData<'a>,
446 alarm: &'a A,
447 process_printer: &'a dyn ProcessPrinter,
448 tx_buffer: &'static mut [u8],
449 rx_buffer: &'static mut [u8],
450 queue_buffer: &'static mut [u8],
451 cmd_buffer: &'static mut [u8],
452 cmd_history_buffer: &'static mut [Command; COMMAND_HISTORY_LEN],
453 kernel: &'static Kernel,
454 kernel_addresses: KernelAddresses,
455 reset_function: Option<fn() -> !>,
456 capability: C,
457 ) -> ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C> {
458 ProcessConsole {
459 uart,
460 alarm,
461 process_printer,
462 tx_in_progress: Cell::new(false),
463 tx_buffer: TakeCell::new(tx_buffer),
464 queue_buffer: TakeCell::new(queue_buffer),
465 queue_size: Cell::new(0),
466 writer_state: Cell::new(WriterState::Empty),
467 rx_buffer: TakeCell::new(rx_buffer),
468 command_buffer: TakeCell::new(cmd_buffer),
469 command_index: Cell::new(0),
470 mode: Cell::new(ProcessConsoleState::Off),
471 esc_state: Cell::new(EscState::Bypass),
472 command_history: MapCell::new(CommandHistory::new(cmd_history_buffer)),
473 cursor: Cell::new(0),
474 previous_byte: Cell::new(EOL),
475 execute: Cell::new(false),
476 kernel,
477 kernel_addresses,
478 reset_function,
479 capability,
480 }
481 }
482
483 pub fn start(&self) -> Result<(), ErrorCode> {
485 if self.mode.get() == ProcessConsoleState::Off {
486 self.alarm
487 .set_alarm(self.alarm.now(), self.alarm.ticks_from_ms(100));
488 self.mode.set(ProcessConsoleState::Active);
489 }
490 Ok(())
491 }
492
493 pub fn start_hibernated(&self) -> Result<(), ErrorCode> {
498 if self.mode.get() == ProcessConsoleState::Off {
499 self.alarm
500 .set_alarm(self.alarm.now(), self.alarm.ticks_from_ms(100));
501 self.mode.set(ProcessConsoleState::Hibernating)
502 }
503 Ok(())
504 }
505
506 pub fn display_welcome(&self) {
509 if self.mode.get() == ProcessConsoleState::Off {
511 self.rx_buffer.take().map(|buffer| {
512 let _ = self.uart.receive_buffer(buffer, 1);
513 self.mode.set(ProcessConsoleState::Active);
514 });
515 }
516
517 let mut console_writer = ConsoleWriter::new();
519 let _ = write(
520 &mut console_writer,
521 format_args!(
522 "Kernel version: {}.{} (build {})\r\n",
523 kernel::KERNEL_MAJOR_VERSION,
524 kernel::KERNEL_MINOR_VERSION,
525 option_env!("TOCK_KERNEL_VERSION").unwrap_or("unknown"),
526 ),
527 );
528 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
529
530 let _ = self.write_bytes(b"Welcome to the process console.\r\n");
531 let _ = self.write_bytes(b"Valid commands are: ");
532 let _ = self.write_bytes(VALID_COMMANDS_STR);
533 self.prompt();
534 }
535
536 fn next_state(&self, state: WriterState) -> WriterState {
539 match state {
540 WriterState::KernelStart => WriterState::KernelBss,
541 WriterState::KernelBss => WriterState::KernelInit,
542 WriterState::KernelInit => WriterState::KernelStack,
543 WriterState::KernelStack => WriterState::KernelRoData,
544 WriterState::KernelRoData => WriterState::KernelText,
545 WriterState::KernelText => WriterState::Empty,
546 WriterState::ProcessPrint {
547 process_id,
548 context,
549 } => WriterState::ProcessPrint {
550 process_id,
551 context,
552 },
553 WriterState::List { index, total } => {
554 if index + 1 == total {
557 WriterState::Empty
558 } else {
559 WriterState::List {
560 index: index + 1,
561 total,
562 }
563 }
564 }
565 WriterState::Empty => WriterState::Empty,
566 }
567 }
568
569 fn create_state_buffer(&self, state: WriterState) {
571 match state {
572 WriterState::KernelBss => {
573 let mut console_writer = ConsoleWriter::new();
574
575 let bss_start = self.kernel_addresses.bss_start as usize;
576 let bss_end = self.kernel_addresses.bss_end as usize;
577 let bss_size = bss_end - bss_start;
578
579 let _ = write(
580 &mut console_writer,
581 format_args!(
582 "\r\n ╔═══════════╤══════════════════════════════╗\
583 \r\n ║ Address │ Region Name Used (bytes) ║\
584 \r\n ╚{:#010X}═╪══════════════════════════════╝\
585 \r\n │ BSS {:6}",
586 bss_end, bss_size
587 ),
588 );
589
590 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
591 }
592 WriterState::KernelInit => {
593 let mut console_writer = ConsoleWriter::new();
594
595 let relocate_start = self.kernel_addresses.relocations_start as usize;
596 let relocate_end = self.kernel_addresses.relocations_end as usize;
597 let relocate_size = relocate_end - relocate_start;
598
599 let _ = write(
600 &mut console_writer,
601 format_args!(
602 "\
603 \r\n {:#010X} ┼─────────────────────────────── S\
604 \r\n │ Relocate {:6} R",
605 relocate_end, relocate_size
606 ),
607 );
608 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
609 }
610 WriterState::KernelStack => {
611 let mut console_writer = ConsoleWriter::new();
612
613 let stack_start = self.kernel_addresses.stack_start as usize;
614 let stack_end = self.kernel_addresses.stack_end as usize;
615 let stack_size = stack_end - stack_start;
616
617 let _ = write(
618 &mut console_writer,
619 format_args!(
620 "\
621 \r\n {:#010X} ┼─────────────────────────────── A\
622 \r\n │ ▼ Stack {:6} M\
623 \r\n {:#010X} ┼───────────────────────────────",
624 stack_end, stack_size, stack_start
625 ),
626 );
627 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
628 }
629 WriterState::KernelRoData => {
630 let mut console_writer = ConsoleWriter::new();
631
632 let rodata_start = self.kernel_addresses.read_only_data_start as usize;
633 let text_end = self.kernel_addresses.text_end as usize;
634 let rodata_size = text_end - rodata_start;
635
636 let _ = write(
637 &mut console_writer,
638 format_args!(
639 "\
640 \r\n .....\
641 \r\n {:#010X} ┼─────────────────────────────── F\
642 \r\n │ RoData {:6} L",
643 text_end, rodata_size
644 ),
645 );
646 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
647 }
648 WriterState::KernelText => {
649 let mut console_writer = ConsoleWriter::new();
650
651 let code_start = self.kernel_addresses.text_start as usize;
652 let code_end = self.kernel_addresses.read_only_data_start as usize;
653 let code_size = code_end - code_start;
654
655 let _ = write(
656 &mut console_writer,
657 format_args!(
658 "\
659 \r\n {:#010X} ┼─────────────────────────────── A\
660 \r\n │ Code {:6} S\
661 \r\n {:#010X} ┼─────────────────────────────── H\
662 \r\n",
663 code_end, code_size, code_start
664 ),
665 );
666 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
667 }
668 WriterState::ProcessPrint {
669 process_id,
670 context,
671 } => {
672 self.kernel
673 .process_each_capability(&self.capability, |process| {
674 if process_id == process.processid() {
675 let mut console_writer = ConsoleWriter::new();
676 let new_context = self.process_printer.print_overview(
677 process,
678 &mut console_writer,
679 context,
680 );
681
682 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
683
684 if new_context.is_some() {
685 self.writer_state.replace(WriterState::ProcessPrint {
686 process_id,
687 context: new_context,
688 });
689 } else {
690 self.writer_state.replace(WriterState::Empty);
691 self.prompt();
695 }
696 }
697 });
698 }
699 WriterState::List { index, total: _ } => {
700 let mut local_index = -1;
701 self.kernel
702 .process_each_capability(&self.capability, |process| {
703 local_index += 1;
704 if local_index == index {
705 let info: KernelInfo = KernelInfo::new(self.kernel);
706
707 let pname = process.get_process_name();
708 let process_id = process.processid();
709 let short_id = process.short_app_id();
710
711 let (grants_used, grants_total) =
712 info.number_app_grant_uses(process_id, &self.capability);
713 let mut console_writer = ConsoleWriter::new();
714
715 let _ = write(&mut console_writer, format_args!(" {:<7?}", process_id));
717 match short_id {
719 kernel::process::ShortId::LocallyUnique => {
720 let _ = write(
721 &mut console_writer,
722 format_args!("{}", "Unique ",),
723 );
724 }
725 kernel::process::ShortId::Fixed(id) => {
726 let _ =
727 write(&mut console_writer, format_args!("0x{:<8x} ", id));
728 }
729 }
730 let _ = write(
732 &mut console_writer,
733 format_args!(
734 "{:<20}{:6}{:10}{:10} {:2}/{:2} {:?}\r\n",
735 pname,
736 process.debug_timeslice_expiration_count(),
737 process.debug_syscall_count(),
738 process.get_restart_count(),
739 grants_used,
740 grants_total,
741 process.get_state(),
742 ),
743 );
744
745 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
746 }
747 });
748 }
749 WriterState::Empty => {
750 self.prompt();
751 }
752 _ => {}
753 }
754 }
755
756 fn read_command(&self) {
758 self.command_buffer.map(|command| {
759 let terminator = command.iter().position(|&x| x == 0).unwrap_or(0);
760
761 if terminator > 0 {
765 let cmd_str = str::from_utf8(&command[0..terminator]);
766
767 match cmd_str {
768 Ok(s) => {
769 let clean_str = s.trim();
770
771 if COMMAND_HISTORY_LEN > 1 {
774 if clean_str.len() > 0 {
775 self.command_history.map(|ht| {
776 ht.make_space(command);
777 });
778 }
779 }
780
781 if clean_str.starts_with("console-start") {
782 self.mode.set(ProcessConsoleState::Active);
783 } else if self.mode.get() == ProcessConsoleState::Hibernating {
784 } else if clean_str.starts_with("help") {
788 let _ = self.write_bytes(b"Welcome to the process console.\r\n");
789 let _ = self.write_bytes(b"Valid commands are: ");
790 let _ = self.write_bytes(VALID_COMMANDS_STR);
791 } else if clean_str.starts_with("console-stop") {
792 let _ = self.write_bytes(b"Disabling the process console.\r\n");
793 let _ = self.write_bytes(b"Run console-start to reactivate.\r\n");
794 self.mode.set(ProcessConsoleState::Hibernating);
795 } else if clean_str.starts_with("start") {
796 let argument = clean_str.split_whitespace().nth(1);
797 argument.map(|name| {
798 self.kernel
799 .process_each_capability(&self.capability, |proc| {
800 let proc_name = proc.get_process_name();
801 if proc_name == name {
802 proc.resume();
803 let mut console_writer = ConsoleWriter::new();
804 let _ = write(
805 &mut console_writer,
806 format_args!("Process {} resumed.\r\n", name),
807 );
808
809 let _ = self.write_bytes(
810 &(console_writer.buf)[..console_writer.size],
811 );
812 }
813 });
814 });
815 } else if clean_str.starts_with("stop") {
816 let argument = clean_str.split_whitespace().nth(1);
817 argument.map(|name| {
818 self.kernel
819 .process_each_capability(&self.capability, |proc| {
820 let proc_name = proc.get_process_name();
821 if proc_name == name {
822 proc.stop();
823 let mut console_writer = ConsoleWriter::new();
824 let _ = write(
825 &mut console_writer,
826 format_args!("Process {} stopped\r\n", proc_name),
827 );
828
829 let _ = self.write_bytes(
830 &(console_writer.buf)[..console_writer.size],
831 );
832 }
833 });
834 });
835 } else if clean_str.starts_with("fault") {
836 let argument = clean_str.split_whitespace().nth(1);
837 argument.map(|name| {
838 self.kernel
839 .process_each_capability(&self.capability, |proc| {
840 let proc_name = proc.get_process_name();
841 if proc_name == name {
842 proc.set_fault_state();
843 let mut console_writer = ConsoleWriter::new();
844 let _ = write(
845 &mut console_writer,
846 format_args!(
847 "Process {} now faulted\r\n",
848 proc_name
849 ),
850 );
851
852 let _ = self.write_bytes(
853 &(console_writer.buf)[..console_writer.size],
854 );
855 }
856 });
857 });
858 } else if clean_str.starts_with("terminate") {
859 let argument = clean_str.split_whitespace().nth(1);
860 argument.map(|name| {
861 self.kernel
862 .process_each_capability(&self.capability, |proc| {
863 let proc_name = proc.get_process_name();
864 if proc_name == name {
865 proc.terminate(None);
866 let mut console_writer = ConsoleWriter::new();
867 let _ = write(
868 &mut console_writer,
869 format_args!(
870 "Process {} terminated\r\n",
871 proc_name
872 ),
873 );
874
875 let _ = self.write_bytes(
876 &(console_writer.buf)[..console_writer.size],
877 );
878 }
879 });
880 });
881 } else if clean_str.starts_with("boot") {
882 let argument = clean_str.split_whitespace().nth(1);
883 argument.map(|name| {
884 self.kernel
885 .process_each_capability(&self.capability, |proc| {
886 let proc_name = proc.get_process_name();
887 if proc_name == name
888 && proc.get_state() == State::Terminated
889 {
890 proc.start(&self.capability);
891 }
892 });
893 });
894 } else if clean_str.starts_with("list") {
895 let _ = self
896 .write_bytes(b" PID ShortID Name Quanta ");
897 let _ = self.write_bytes(b"Syscalls Restarts Grants State\r\n");
898
899 let mut count = 0;
901 self.kernel.process_each_capability(&self.capability, |_| {
902 count += 1;
903 });
904
905 if count > 0 {
906 self.write_state(WriterState::List {
908 index: -1,
909 total: count,
910 });
911 }
912 } else if clean_str.starts_with("status") {
913 let info: KernelInfo = KernelInfo::new(self.kernel);
914 let mut console_writer = ConsoleWriter::new();
915 let _ = write(
916 &mut console_writer,
917 format_args!(
918 "Total processes: {}\r\n",
919 info.number_loaded_processes(&self.capability)
920 ),
921 );
922 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
923 console_writer.clear();
924 let _ = write(
925 &mut console_writer,
926 format_args!(
927 "Active processes: {}\r\n",
928 info.number_active_processes(&self.capability)
929 ),
930 );
931 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
932 console_writer.clear();
933 let _ = write(
934 &mut console_writer,
935 format_args!(
936 "Timeslice expirations: {}\r\n",
937 info.timeslice_expirations(&self.capability)
938 ),
939 );
940 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
941 } else if clean_str.starts_with("process") {
942 let argument = clean_str.split_whitespace().nth(1);
943 argument.map(|name| {
944 let mut found = false;
947 self.kernel
948 .process_each_capability(&self.capability, |proc| {
949 if found {
950 return;
951 }
952 let proc_name = proc.get_process_name();
953 if proc_name == name {
954 let mut console_writer = ConsoleWriter::new();
955 let mut context: Option<ProcessPrinterContext> = None;
956 context = self.process_printer.print_overview(
957 proc,
958 &mut console_writer,
959 context,
960 );
961
962 let _ = self.write_bytes(
963 &(console_writer.buf)[..console_writer.size],
964 );
965
966 if context.is_some() {
967 self.writer_state.replace(
968 WriterState::ProcessPrint {
969 process_id: proc.processid(),
970 context,
971 },
972 );
973 }
974
975 found = true;
976 }
977 });
978 });
979 } else if clean_str.starts_with("kernel") {
980 let mut console_writer = ConsoleWriter::new();
981 let _ = write(
982 &mut console_writer,
983 format_args!(
984 "Kernel version: {}.{} (build {})\r\n",
985 kernel::KERNEL_MAJOR_VERSION,
986 kernel::KERNEL_MINOR_VERSION,
987 option_env!("TOCK_KERNEL_VERSION").unwrap_or("unknown")
988 ),
989 );
990 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
991 console_writer.clear();
992
993 self.writer_state.replace(WriterState::KernelStart);
996 } else if clean_str.starts_with("reset") {
997 self.reset_function.map_or_else(
998 || {
999 let _ = self.write_bytes(b"Reset function is not implemented");
1000 },
1001 |f| {
1002 f();
1003 },
1004 );
1005 } else if clean_str.starts_with("panic") {
1006 panic!("Process Console forced a kernel panic.");
1007 } else {
1008 let _ = self.write_bytes(b"Valid commands are: ");
1009 let _ = self.write_bytes(VALID_COMMANDS_STR);
1010 }
1011 }
1012 Err(_e) => {
1013 let mut console_writer = ConsoleWriter::new();
1014 let _ = write(
1015 &mut console_writer,
1016 format_args!("Invalid command: {:?}", command),
1017 );
1018 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
1019 }
1020 }
1021 }
1022 });
1023 self.command_buffer.map(|command| {
1024 command[0] = 0;
1025 });
1026 self.command_index.set(0);
1027 if self.writer_state.get() == WriterState::Empty {
1028 self.prompt();
1029 }
1030 }
1031
1032 fn prompt(&self) {
1033 match self.mode.get() {
1035 ProcessConsoleState::Active => {
1036 let _ = self.write_bytes(b"tock$ ");
1037 }
1038 _ => {}
1039 }
1040 }
1041
1042 fn write_state(&self, state: WriterState) {
1045 self.writer_state.replace(self.next_state(state));
1046 self.create_state_buffer(self.writer_state.get());
1047 }
1048
1049 fn write_byte(&self, byte: u8) -> Result<(), ErrorCode> {
1050 if self.tx_in_progress.get() {
1051 self.queue_buffer.map(|buf| {
1052 buf[self.queue_size.get()] = byte;
1053 self.queue_size.set(self.queue_size.get() + 1);
1054 });
1055 Err(ErrorCode::BUSY)
1056 } else {
1057 self.tx_in_progress.set(true);
1058 self.tx_buffer.take().map(|buffer| {
1059 buffer[0] = byte;
1060 let _ = self.uart.transmit_buffer(buffer, 1);
1061 });
1062 Ok(())
1063 }
1064 }
1065
1066 fn write_bytes(&self, bytes: &[u8]) -> Result<(), ErrorCode> {
1067 if self.tx_in_progress.get() {
1068 self.queue_buffer.map(|buf| {
1069 let size = self.queue_size.get();
1070 let len = cmp::min(bytes.len(), buf.len() - size);
1071 (buf[size..size + len]).copy_from_slice(&bytes[..len]);
1072 self.queue_size.set(size + len);
1073 });
1074 Err(ErrorCode::BUSY)
1075 } else {
1076 self.tx_in_progress.set(true);
1077 self.tx_buffer.take().map(|buffer| {
1078 let len = cmp::min(bytes.len(), buffer.len());
1079 (buffer[..len]).copy_from_slice(&bytes[..len]);
1081 let _ = self.uart.transmit_buffer(buffer, len);
1082 });
1083 Ok(())
1084 }
1085 }
1086
1087 fn handle_queue(&self) -> Result<usize, ErrorCode> {
1093 if self.tx_in_progress.get() {
1094 return Err(ErrorCode::BUSY);
1098 }
1099
1100 self.queue_buffer.map_or(Err(ErrorCode::FAIL), |qbuf| {
1101 let qlen = self.queue_size.get();
1102
1103 if qlen > 0 {
1104 self.tx_buffer.take().map_or(Err(ErrorCode::FAIL), |txbuf| {
1105 let txlen = cmp::min(qlen, txbuf.len());
1106
1107 (txbuf[..txlen]).copy_from_slice(&qbuf[..txlen]);
1109
1110 let remaining = qlen - txlen;
1119 self.queue_size.set(remaining);
1120
1121 self.tx_in_progress.set(true);
1122 let _ = self.uart.transmit_buffer(txbuf, txlen);
1123 Ok(txlen)
1124 })
1125 } else {
1126 Ok(0)
1128 }
1129 })
1130 }
1131}
1132
1133impl<
1134 'a,
1135 const COMMAND_HISTORY_LEN: usize,
1136 A: Alarm<'a>,
1137 C: ProcessManagementCapability + ProcessStartCapability,
1138 > AlarmClient for ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
1139{
1140 fn alarm(&self) {
1141 self.prompt();
1142 self.rx_buffer.take().map(|buffer| {
1143 let _ = self.uart.receive_buffer(buffer, 1);
1144 });
1145 }
1146}
1147
1148impl<
1149 'a,
1150 const COMMAND_HISTORY_LEN: usize,
1151 A: Alarm<'a>,
1152 C: ProcessManagementCapability + ProcessStartCapability,
1153 > uart::TransmitClient for ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
1154{
1155 fn transmitted_buffer(
1156 &self,
1157 buffer: &'static mut [u8],
1158 _tx_len: usize,
1159 _rcode: Result<(), ErrorCode>,
1160 ) {
1161 self.tx_buffer.replace(buffer);
1164 self.tx_in_progress.set(false);
1165
1166 let ret = self.handle_queue();
1169 if ret.ok() == Some(0) || ret.is_err() {
1170 let current_state = self.writer_state.get();
1173 if current_state != WriterState::Empty {
1174 self.write_state(current_state);
1175 return;
1176 }
1177
1178 if self.execute.get() {
1181 self.execute.set(false);
1182 self.read_command();
1183 }
1184 }
1185 }
1186}
1187
1188impl<
1189 'a,
1190 const COMMAND_HISTORY_LEN: usize,
1191 A: Alarm<'a>,
1192 C: ProcessManagementCapability + ProcessStartCapability,
1193 > uart::ReceiveClient for ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
1194{
1195 fn received_buffer(
1196 &self,
1197 read_buf: &'static mut [u8],
1198 rx_len: usize,
1199 _rcode: Result<(), ErrorCode>,
1200 error: uart::Error,
1201 ) {
1202 if error == uart::Error::None {
1203 match rx_len {
1204 0 => debug!("ProcessConsole had read of 0 bytes"),
1205 1 => {
1206 self.command_buffer.map(|command| {
1207 let esc_state = self.esc_state.get().next_state(read_buf[0]);
1208 self.esc_state.set(esc_state);
1209
1210 let previous_byte = self.previous_byte.get();
1211 self.previous_byte.set(read_buf[0]);
1212 let index = self.command_index.get();
1213
1214 let cursor = self.cursor.get();
1215
1216 if let EscState::Complete(key) = esc_state {
1217 match key {
1218 EscKey::Up | EscKey::Down if COMMAND_HISTORY_LEN >= 1 => {
1219 self.command_history.map(|ht| {
1220 if let Some(next_index) = if matches!(key, EscKey::Up) {
1221 ht.next_cmd_idx()
1222 } else {
1223 ht.prev_cmd_idx()
1224 } {
1225 let next_command_len = ht.cmds[next_index].len;
1226
1227 for _ in cursor..index {
1228 let _ = self.write_byte(SPACE);
1229 }
1230
1231 for _ in 0..index {
1233 let _ = self.write_bytes(&[BS, SPACE, BS]);
1234 }
1235
1236 for i in 0..next_command_len {
1238 let byte = ht.cmds[next_index].buf[i];
1239 let _ = self.write_byte(byte);
1240 command[i] = byte;
1241 }
1242
1243 ht.cmd_is_modified = true;
1244 self.command_index.set(next_command_len);
1245 self.cursor.set(next_command_len);
1246 command[next_command_len] = EOL;
1247 }
1248 });
1249 }
1250 EscKey::Left if cursor > 0 => {
1251 let _ = self.write_byte(BS);
1252 self.cursor.set(cursor - 1);
1253 }
1254 EscKey::Right if cursor < index => {
1255 let _ = self.write_byte(command[cursor]);
1256 self.cursor.set(cursor + 1);
1257 }
1258 EscKey::Home if cursor > 0 => {
1259 for _ in 0..cursor {
1260 let _ = self.write_byte(BS);
1261 }
1262
1263 self.cursor.set(0);
1264 }
1265 EscKey::End if cursor < index => {
1266 for i in cursor..index {
1267 let _ = self.write_byte(command[i]);
1268 }
1269
1270 self.cursor.set(index);
1271 }
1272 EscKey::Delete if cursor < index => {
1273 for i in cursor..(index - 1) {
1275 command[i] = command[i + 1];
1276 let _ = self.write_byte(command[i]);
1277 }
1278 command[index - 1] = command[index];
1280
1281 let _ = self.write_bytes(&[SPACE, BS]);
1288
1289 for _ in cursor..(index - 1) {
1291 let _ = self.write_byte(BS);
1292 }
1293
1294 self.command_index.set(index - 1);
1295
1296 if COMMAND_HISTORY_LEN > 1 {
1299 self.command_history.map(|ht| {
1300 if ht.cmd_is_modified {
1301 ht.cmds[0].clear();
1304 ht.write_to_first(command);
1305 ht.cmd_is_modified = false;
1306 } else {
1307 ht.cmds[0].delete_byte(cursor);
1308 }
1309 });
1310 }
1311 }
1312 _ => {}
1313 }
1314 } else if read_buf[0] == NLINE || read_buf[0] == CR {
1315 if (previous_byte == NLINE || previous_byte == CR)
1316 && previous_byte != read_buf[0]
1317 {
1318 self.previous_byte.set(EOL);
1320 } else {
1321 self.cursor.set(0);
1322 self.execute.set(true);
1323
1324 let _ = self.write_bytes(&[CR, NLINE]);
1325
1326 if COMMAND_HISTORY_LEN > 1 {
1327 self.command_history.map(|ht| {
1329 ht.cmd_idx = 0;
1330 ht.cmd_is_modified = false;
1331 ht.cmds[0].clear();
1332 });
1333 }
1334 }
1335 } else if read_buf[0] == BS {
1336 if cursor > 0 {
1337 let _ = self.write_bytes(&[BS, SPACE, BS]);
1341
1342 for i in (cursor - 1)..(index - 1) {
1344 command[i] = command[i + 1];
1345 let _ = self.write_byte(command[i]);
1346 }
1347 command[index - 1] = command[index];
1349
1350 let _ = self.write_bytes(&[SPACE, BS]);
1357
1358 for _ in cursor..index {
1360 let _ = self.write_byte(BS);
1361 }
1362
1363 self.command_index.set(index - 1);
1364 self.cursor.set(cursor - 1);
1365
1366 if COMMAND_HISTORY_LEN > 1 {
1369 self.command_history.map(|ht| {
1370 if ht.cmd_is_modified {
1371 ht.cmds[0].clear();
1374 ht.write_to_first(command);
1375 ht.cmd_is_modified = false;
1376 } else {
1377 ht.cmds[0].delete_byte(cursor - 1);
1378 }
1379 });
1380 }
1381 }
1382 } else if index < (command.len() - 1)
1383 && read_buf[0] < ASCII_LIMIT
1384 && !esc_state.has_started()
1385 && !esc_state.in_progress()
1386 {
1387 let _ = self.write_byte(read_buf[0]);
1392
1393 for i in cursor..index {
1395 let _ = self.write_byte(command[i]);
1396 }
1397
1398 for i in (cursor..(index + 1)).rev() {
1400 command[i + 1] = command[i];
1401 }
1402
1403 for _ in cursor..index {
1405 let _ = self.write_byte(BS);
1406 }
1407
1408 command[cursor] = read_buf[0];
1409 self.cursor.set(cursor + 1);
1410 self.command_index.set(index + 1);
1411
1412 if COMMAND_HISTORY_LEN > 1 {
1413 self.command_history.map(|ht| {
1414 if ht.cmd_is_modified {
1415 ht.cmds[0].clear();
1418 ht.write_to_first(command);
1419 ht.cmd_is_modified = false;
1420 } else {
1421 ht.cmds[0].insert_byte(read_buf[0], cursor);
1422 }
1423 });
1424 }
1425 }
1426 });
1427 }
1428 _ => debug!(
1429 "ProcessConsole issues reads of 1 byte, but receive_complete was length {}",
1430 rx_len
1431 ),
1432 }
1433 }
1434 let _ = self.uart.receive_buffer(read_buf, 1);
1435 }
1436}