source: mainline/kernel/generic/src/console/kconsole.c@ da13982

topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da13982 was da13982, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Read symbol table from ELF sections

Instead of the currently broken data generated using genmap.py,
read the ELF symbol table for stack traces and symbol names.
In addition to that, prepare ground for accessing DWARF debug
sections.

Because neither .symtab, nor .debug_* sections are
normally part of the program image, these have to be provided
externally. Instead of the previous way of relinking kernel
to bake in the symbol data, we now only link kernel once
and the extra debug data is loaded as part of the initrd image.

  • Property mode set to 100644
File size: 19.1 KB
Line 
1/*
2 * Copyright (c) 2005 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_generic_console
30 * @{
31 */
32
33/**
34 * @file kconsole.c
35 * @brief Kernel console.
36 *
37 * This file contains kernel thread managing the kernel console.
38 *
39 */
40
41#include <assert.h>
42#include <console/kconsole.h>
43#include <console/console.h>
44#include <console/chardev.h>
45#include <console/cmd.h>
46#include <console/prompt.h>
47#include <stdio.h>
48#include <panic.h>
49#include <typedefs.h>
50#include <adt/list.h>
51#include <arch.h>
52#include <macros.h>
53#include <debug.h>
54#include <halt.h>
55#include <str.h>
56#include <sysinfo/sysinfo.h>
57#include <symtab.h>
58#include <errno.h>
59#include <putchar.h>
60#include <stdlib.h>
61
62/** Simple kernel console.
63 *
64 * The console is realized by kernel thread kconsole.
65 * It doesn't understand any useful command on its own,
66 * but makes it possible for other kernel subsystems to
67 * register their own commands.
68 */
69
70/** Locking.
71 *
72 * There is a list of cmd_info_t structures. This list
73 * is protected by cmd_lock spinlock. Note that specially
74 * the link elements of cmd_info_t are protected by
75 * this lock.
76 *
77 * Each cmd_info_t also has its own lock, which protects
78 * all elements thereof except the link element.
79 *
80 * cmd_lock must be acquired before any cmd_info lock.
81 * When locking two cmd info structures, structure with
82 * lower address must be locked first.
83 */
84
85SPINLOCK_INITIALIZE(cmd_lock); /**< Lock protecting command list. */
86LIST_INITIALIZE(cmd_list); /**< Command list. */
87
88#define MAX_SYMBOL_NAME 64
89
90static char32_t history[KCONSOLE_HISTORY][MAX_CMDLINE] = { };
91static size_t history_pos = 0;
92
93/** Initialize kconsole data structures
94 *
95 * This is the most basic initialization, almost no
96 * other kernel subsystem is ready yet.
97 *
98 */
99void kconsole_init(void)
100{
101 unsigned int i;
102
103 cmd_init();
104 for (i = 0; i < KCONSOLE_HISTORY; i++)
105 history[i][0] = 0;
106}
107
108/** Register kconsole command.
109 *
110 * @param cmd Structure describing the command.
111 *
112 * @return False on failure, true on success.
113 *
114 */
115bool cmd_register(cmd_info_t *cmd)
116{
117 spinlock_lock(&cmd_lock);
118
119 /*
120 * Make sure the command is not already listed.
121 */
122 list_foreach(cmd_list, link, cmd_info_t, hlp) {
123 if (hlp == cmd) {
124 /* The command is already there. */
125 spinlock_unlock(&cmd_lock);
126 return false;
127 }
128
129 /* Avoid deadlock. */
130 if (hlp < cmd) {
131 spinlock_lock(&hlp->lock);
132 spinlock_lock(&cmd->lock);
133 } else {
134 spinlock_lock(&cmd->lock);
135 spinlock_lock(&hlp->lock);
136 }
137
138 if (str_cmp(hlp->name, cmd->name) == 0) {
139 /* The command is already there. */
140 spinlock_unlock(&hlp->lock);
141 spinlock_unlock(&cmd->lock);
142 spinlock_unlock(&cmd_lock);
143 return false;
144 }
145
146 spinlock_unlock(&hlp->lock);
147 spinlock_unlock(&cmd->lock);
148 }
149
150 /*
151 * Now the command can be added.
152 */
153 list_append(&cmd->link, &cmd_list);
154
155 spinlock_unlock(&cmd_lock);
156 return true;
157}
158
159/** Print count times a character */
160_NO_TRACE static void print_cc(char32_t ch, size_t count)
161{
162 size_t i;
163 for (i = 0; i < count; i++)
164 putuchar(ch);
165}
166
167/** Try to find a command beginning with prefix */
168const char *cmdtab_enum(const char *name, const char **h, void **ctx)
169{
170 link_t **startpos = (link_t **) ctx;
171 size_t namelen = str_length(name);
172
173 spinlock_lock(&cmd_lock);
174
175 if (*startpos == NULL)
176 *startpos = list_first(&cmd_list);
177
178 for (; *startpos != NULL; *startpos = list_next(*startpos, &cmd_list)) {
179 cmd_info_t *hlp = list_get_instance(*startpos, cmd_info_t, link);
180
181 const char *curname = hlp->name;
182 if (str_length(curname) < namelen)
183 continue;
184
185 if (str_lcmp(curname, name, namelen) == 0) {
186 *startpos = list_next(*startpos, &cmd_list);
187 if (h)
188 *h = hlp->description;
189
190 spinlock_unlock(&cmd_lock);
191 return (curname + str_lsize(curname, namelen));
192 }
193 }
194
195 spinlock_unlock(&cmd_lock);
196 return NULL;
197}
198
199/** Command completion of the commands
200 *
201 * @param name String to match, changed to hint on exit
202 * @param size Input buffer size
203 *
204 * @return Number of found matches
205 *
206 */
207_NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t *indev,
208 hints_enum_func_t hints_enum)
209{
210 const char *name = input;
211
212 size_t found = 0;
213
214 /*
215 * Maximum Match Length: Length of longest matching common
216 * substring in case more than one match is found.
217 */
218 size_t max_match_len = size;
219 size_t max_match_len_tmp = size;
220 void *pos = NULL;
221 const char *hint;
222 const char *help;
223 size_t hints_to_show = MAX_TAB_HINTS - 1;
224 size_t total_hints_shown = 0;
225 bool continue_showing_hints = true;
226
227 char *output = malloc(MAX_CMDLINE);
228 if (!output) {
229 // TODO: fix the function so that it does not need allocation
230 printf("Can't complete command, out of memory.\n");
231 return 0;
232 }
233
234 output[0] = 0;
235
236 while ((hint = hints_enum(name, NULL, &pos))) {
237 if ((found == 0) || (str_length(hint) > str_length(output)))
238 str_cpy(output, MAX_CMDLINE, hint);
239
240 found++;
241 }
242
243 /*
244 * If the number of possible completions is more than MAX_TAB_HINTS,
245 * ask the user whether to display them or not.
246 */
247 if (found > MAX_TAB_HINTS) {
248 printf("\n");
249 continue_showing_hints =
250 console_prompt_display_all_hints(indev, found);
251 }
252
253 if ((found > 1) && (str_length(output) != 0)) {
254 printf("\n");
255 pos = NULL;
256 while ((hint = hints_enum(name, &help, &pos))) {
257
258 if (continue_showing_hints) {
259 if (help)
260 printf("%s%s (%s)\n", name, hint, help);
261 else
262 printf("%s%s\n", name, hint);
263
264 --hints_to_show;
265 ++total_hints_shown;
266
267 if ((hints_to_show == 0) && (total_hints_shown != found)) {
268 /* Ask user to continue */
269 continue_showing_hints =
270 console_prompt_more_hints(indev, &hints_to_show);
271 }
272 }
273
274 max_match_len_tmp = 0;
275 while ((output[max_match_len_tmp] ==
276 hint[max_match_len_tmp]) &&
277 (max_match_len_tmp < max_match_len))
278 ++max_match_len_tmp;
279
280 max_match_len = max_match_len_tmp;
281 }
282
283 /* Keep only the characters common in all completions */
284 output[max_match_len] = 0;
285 }
286
287 if (found > 0)
288 str_cpy(input, size, output);
289
290 free(output);
291 return found;
292}
293
294_NO_TRACE static cmd_info_t *parse_cmd(const char32_t *cmdline)
295{
296 size_t start = 0;
297 size_t end;
298 char *tmp;
299
300 while (isspace(cmdline[start]))
301 start++;
302
303 end = start + 1;
304
305 while (!isspace(cmdline[end]))
306 end++;
307
308 tmp = malloc(STR_BOUNDS(end - start + 1));
309 if (!tmp)
310 return NULL;
311
312 wstr_to_str(tmp, end - start + 1, &cmdline[start]);
313
314 spinlock_lock(&cmd_lock);
315
316 list_foreach(cmd_list, link, cmd_info_t, hlp) {
317 spinlock_lock(&hlp->lock);
318
319 if (str_cmp(hlp->name, tmp) == 0) {
320 spinlock_unlock(&hlp->lock);
321 spinlock_unlock(&cmd_lock);
322 free(tmp);
323 return hlp;
324 }
325
326 spinlock_unlock(&hlp->lock);
327 }
328
329 free(tmp);
330 spinlock_unlock(&cmd_lock);
331
332 return NULL;
333}
334
335_NO_TRACE static char32_t *clever_readline(const char *prompt, indev_t *indev,
336 char *tmp)
337{
338 printf("%s> ", prompt);
339
340 size_t position = 0;
341 char32_t *current = history[history_pos];
342 current[0] = 0;
343
344 while (true) {
345 char32_t ch = indev_pop_character(indev);
346
347 if (ch == '\n') {
348 /* Enter */
349 putuchar(ch);
350 break;
351 }
352
353 if (ch == '\b') {
354 /* Backspace */
355 if (position == 0)
356 continue;
357
358 if (wstr_remove(current, position - 1)) {
359 position--;
360 putuchar('\b');
361 printf("%ls ", current + position);
362 print_cc('\b', wstr_length(current) - position + 1);
363 continue;
364 }
365 }
366
367 if (ch == '\t') {
368 /* Tab completion */
369
370 /* Move to the end of the word */
371 for (; (current[position] != 0) && (!isspace(current[position]));
372 position++)
373 putuchar(current[position]);
374
375 /*
376 * Find the beginning of the word
377 * and copy it to tmp
378 */
379 size_t beg;
380 unsigned narg = 0;
381 if (position == 0) {
382 tmp[0] = '\0';
383 beg = 0;
384 } else {
385 beg = position - 1;
386 while ((beg > 0) && (!isspace(current[beg])))
387 beg--;
388
389 if (isspace(current[beg]))
390 beg++;
391
392 wstr_to_str(tmp, position - beg + 1, current + beg);
393 }
394
395 /* Count which argument number are we tabbing (narg=0 is cmd) */
396 bool sp = false;
397 for (; beg > 0; beg--) {
398 if (isspace(current[beg])) {
399 if (!sp) {
400 narg++;
401 sp = true;
402 }
403 } else
404 sp = false;
405 }
406
407 if (narg && isspace(current[0]))
408 narg--;
409
410 int found;
411 if (narg == 0) {
412 /* Command completion */
413 found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
414 cmdtab_enum);
415 } else {
416 /* Arguments completion */
417 cmd_info_t *cmd = parse_cmd(current);
418 if (!cmd || !cmd->hints_enum || cmd->argc < narg)
419 continue;
420 found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
421 cmd->hints_enum);
422 }
423
424 if (found == 0)
425 continue;
426
427 /*
428 * We have hints, possibly many. In case of more than one hint,
429 * tmp will contain the common prefix.
430 */
431 size_t off = 0;
432 size_t i = 0;
433 while ((ch = str_decode(tmp, &off, STR_NO_LIMIT)) != 0) {
434 if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
435 break;
436
437 i++;
438 }
439
440 if (found > 1) {
441 /* No unique hint, list was printed */
442 printf("%s> ", prompt);
443 printf("%ls", current);
444 position += str_length(tmp);
445 print_cc('\b', wstr_length(current) - position);
446 continue;
447 }
448
449 /* We have a hint */
450
451 printf("%ls", current + position);
452 position += str_length(tmp);
453 print_cc('\b', wstr_length(current) - position);
454
455 if (position == wstr_length(current)) {
456 /* Insert a space after the last completed argument */
457 if (wstr_linsert(current, ' ', position, MAX_CMDLINE)) {
458 printf("%ls", current + position);
459 position++;
460 }
461 }
462 continue;
463 }
464
465 if (ch == U_LEFT_ARROW) {
466 /* Left */
467 if (position > 0) {
468 putuchar('\b');
469 position--;
470 }
471 continue;
472 }
473
474 if (ch == U_RIGHT_ARROW) {
475 /* Right */
476 if (position < wstr_length(current)) {
477 putuchar(current[position]);
478 position++;
479 }
480 continue;
481 }
482
483 if ((ch == U_UP_ARROW) || (ch == U_DOWN_ARROW)) {
484 /* Up, down */
485 print_cc('\b', position);
486 print_cc(' ', wstr_length(current));
487 print_cc('\b', wstr_length(current));
488
489 if (ch == U_UP_ARROW) {
490 /* Up */
491 if (history_pos == 0)
492 history_pos = KCONSOLE_HISTORY - 1;
493 else
494 history_pos--;
495 } else {
496 /* Down */
497 history_pos++;
498 history_pos = history_pos % KCONSOLE_HISTORY;
499 }
500 current = history[history_pos];
501 printf("%ls", current);
502 position = wstr_length(current);
503 continue;
504 }
505
506 if (ch == U_HOME_ARROW) {
507 /* Home */
508 print_cc('\b', position);
509 position = 0;
510 continue;
511 }
512
513 if (ch == U_END_ARROW) {
514 /* End */
515 printf("%ls", current + position);
516 position = wstr_length(current);
517 continue;
518 }
519
520 if (ch == U_DELETE) {
521 /* Delete */
522 if (position == wstr_length(current))
523 continue;
524
525 if (wstr_remove(current, position)) {
526 printf("%ls ", current + position);
527 print_cc('\b', wstr_length(current) - position + 1);
528 }
529 continue;
530 }
531
532 if (wstr_linsert(current, ch, position, MAX_CMDLINE)) {
533 printf("%ls", current + position);
534 position++;
535 print_cc('\b', wstr_length(current) - position);
536 }
537 }
538
539 if (wstr_length(current) > 0) {
540 history_pos++;
541 history_pos = history_pos % KCONSOLE_HISTORY;
542 }
543
544 return current;
545}
546
547bool kconsole_check_poll(void)
548{
549 return check_poll(stdin);
550}
551
552_NO_TRACE static bool parse_int_arg(const char *text, size_t len,
553 sysarg_t *result)
554{
555 bool isaddr = false;
556 bool isptr = false;
557
558 /* If we get a name, try to find it in symbol table */
559 if (text[0] == '&') {
560 isaddr = true;
561 text++;
562 len--;
563 } else if (text[0] == '*') {
564 isptr = true;
565 text++;
566 len--;
567 }
568
569 if ((text[0] < '0') || (text[0] > '9')) {
570 char symname[MAX_SYMBOL_NAME];
571 str_ncpy(symname, MAX_SYMBOL_NAME, text, len + 1);
572
573 uintptr_t symaddr;
574 errno_t rc = symtab_addr_lookup(symname, &symaddr);
575 switch (rc) {
576 case ENOENT:
577 printf("Symbol %s not found.\n", symname);
578 return false;
579 case EOVERFLOW:
580 printf("Duplicate symbol %s.\n", symname);
581 symtab_print_search(symname);
582 return false;
583 case ENOTSUP:
584 printf("No symbol information available.\n");
585 return false;
586 case EOK:
587 if (isaddr)
588 *result = (sysarg_t) symaddr;
589 else if (isptr)
590 *result = **((sysarg_t **) symaddr);
591 else
592 *result = *((sysarg_t *) symaddr);
593 break;
594 default:
595 printf("Unknown error.\n");
596 return false;
597 }
598 } else {
599 /* It's a number - convert it */
600 uint64_t value;
601 char *end;
602 errno_t rc = str_uint64_t(text, &end, 0, false, &value);
603 if (end != text + len)
604 rc = EINVAL;
605 switch (rc) {
606 case EINVAL:
607 printf("Invalid number '%s'.\n", text);
608 return false;
609 case EOVERFLOW:
610 printf("Integer overflow in '%s'.\n", text);
611 return false;
612 case EOK:
613 *result = (sysarg_t) value;
614 if (isptr)
615 *result = *((sysarg_t *) *result);
616 break;
617 default:
618 printf("Unknown error parsing '%s'.\n", text);
619 return false;
620 }
621 }
622
623 return true;
624}
625
626/** Parse argument.
627 *
628 * Find start and end positions of command line argument.
629 *
630 * @param cmdline Command line as read from the input device.
631 * @param size Size (in bytes) of the string.
632 * @param start On entry, 'start' contains pointer to the offset
633 * of the first unprocessed character of cmdline.
634 * On successful exit, it marks beginning of the next argument.
635 * @param end Undefined on entry. On exit, 'end' is the offset of the first
636 * character behind the next argument.
637 *
638 * @return False on failure, true on success.
639 *
640 */
641_NO_TRACE static bool parse_argument(const char *cmdline, size_t size,
642 size_t *start, size_t *end)
643{
644 assert(start != NULL);
645 assert(end != NULL);
646
647 bool found_start = false;
648 size_t offset = *start;
649 size_t prev = *start;
650 char32_t ch;
651
652 while ((ch = str_decode(cmdline, &offset, size)) != 0) {
653 if (!found_start) {
654 if (!isspace(ch)) {
655 *start = prev;
656 found_start = true;
657 }
658 } else {
659 if (isspace(ch))
660 break;
661 }
662
663 prev = offset;
664 }
665 *end = prev;
666
667 return found_start;
668}
669
670/** Parse command line.
671 *
672 * @param cmdline Command line as read from input device.
673 * @param size Size (in bytes) of the string.
674 *
675 * @return Structure describing the command.
676 *
677 */
678_NO_TRACE static cmd_info_t *parse_cmdline(const char *cmdline, size_t size)
679{
680 size_t start = 0;
681 size_t end = 0;
682 if (!parse_argument(cmdline, size, &start, &end)) {
683 /* Command line did not contain alphanumeric word. */
684 return NULL;
685 }
686 spinlock_lock(&cmd_lock);
687
688 cmd_info_t *cmd = NULL;
689
690 list_foreach(cmd_list, link, cmd_info_t, hlp) {
691 spinlock_lock(&hlp->lock);
692
693 if (str_lcmp(hlp->name, cmdline + start,
694 max(str_length(hlp->name),
695 str_nlength(cmdline + start, (size_t) (end - start)))) == 0) {
696 cmd = hlp;
697 break;
698 }
699
700 spinlock_unlock(&hlp->lock);
701 }
702
703 spinlock_unlock(&cmd_lock);
704
705 if (!cmd) {
706 /* Unknown command. */
707 printf("Unknown command.\n");
708 return NULL;
709 }
710
711 /* cmd == hlp is locked */
712
713 /*
714 * The command line must be further analyzed and
715 * the parameters therefrom must be matched and
716 * converted to those specified in the cmd info
717 * structure.
718 */
719
720 bool error = false;
721 size_t i;
722 for (i = 0; i < cmd->argc; i++) {
723 char *buf;
724
725 start = end;
726 if (!parse_argument(cmdline, size, &start, &end)) {
727 if (cmd->argv[i].type == ARG_TYPE_STRING_OPTIONAL) {
728 buf = (char *) cmd->argv[i].buffer;
729 str_cpy(buf, cmd->argv[i].len, "");
730 continue;
731 }
732
733 printf("Too few arguments.\n");
734 spinlock_unlock(&cmd->lock);
735 return NULL;
736 }
737
738 switch (cmd->argv[i].type) {
739 case ARG_TYPE_STRING:
740 case ARG_TYPE_STRING_OPTIONAL:
741 buf = (char *) cmd->argv[i].buffer;
742 str_ncpy(buf, cmd->argv[i].len, cmdline + start,
743 end - start);
744 break;
745 case ARG_TYPE_INT:
746 if (!parse_int_arg(cmdline + start, end - start,
747 &cmd->argv[i].intval))
748 error = true;
749 break;
750 case ARG_TYPE_VAR:
751 if ((start < end - 1) && (cmdline[start] == '"')) {
752 if (cmdline[end - 1] == '"') {
753 buf = (char *) cmd->argv[i].buffer;
754 str_ncpy(buf, cmd->argv[i].len,
755 cmdline + start + 1,
756 (end - start) - 1);
757 cmd->argv[i].intval = (sysarg_t) buf;
758 cmd->argv[i].vartype = ARG_TYPE_STRING;
759 } else {
760 printf("Wrong syntax.\n");
761 error = true;
762 }
763 } else if (parse_int_arg(cmdline + start,
764 end - start, &cmd->argv[i].intval)) {
765 cmd->argv[i].vartype = ARG_TYPE_INT;
766 } else {
767 printf("Unrecognized variable argument.\n");
768 error = true;
769 }
770 break;
771 case ARG_TYPE_INVALID:
772 default:
773 printf("Invalid argument type\n");
774 error = true;
775 break;
776 }
777 }
778
779 if (error) {
780 spinlock_unlock(&cmd->lock);
781 return NULL;
782 }
783
784 start = end;
785 if (parse_argument(cmdline, size, &start, &end)) {
786 printf("Too many arguments.\n");
787 spinlock_unlock(&cmd->lock);
788 return NULL;
789 }
790
791 spinlock_unlock(&cmd->lock);
792 return cmd;
793}
794
795/** Kernel console prompt.
796 *
797 * @param prompt Kernel console prompt (e.g kconsole/panic).
798 * @param msg Message to display in the beginning.
799 * @param kcon Wait for keypress to show the prompt
800 * and never exit.
801 *
802 */
803void kconsole(const char *prompt, const char *msg, bool kcon)
804{
805 if (!stdin) {
806 LOG("No stdin for kernel console");
807 return;
808 }
809
810 if (msg)
811 printf("%s", msg);
812
813 if (kcon)
814 indev_pop_character(stdin);
815 else
816 printf("Type \"exit\" to leave the console.\n");
817
818 char *buffer = malloc(STR_BOUNDS(MAX_CMDLINE));
819 char *cmdline = malloc(STR_BOUNDS(MAX_CMDLINE));
820 if (!buffer || !cmdline) {
821 // TODO: fix the function so that it does not need allocations
822 printf("Can't start console, out of memory.\n");
823 free(buffer);
824 free(cmdline);
825 return;
826 }
827
828 while (true) {
829 char32_t *tmp = clever_readline((char *) prompt, stdin, buffer);
830 size_t len = wstr_length(tmp);
831 if (!len)
832 continue;
833
834 wstr_to_str(cmdline, STR_BOUNDS(MAX_CMDLINE), tmp);
835
836 if ((!kcon) && (len == 4) && (str_lcmp(cmdline, "exit", 4) == 0))
837 break;
838
839 cmd_info_t *cmd_info = parse_cmdline(cmdline, STR_BOUNDS(MAX_CMDLINE));
840 if (!cmd_info)
841 continue;
842
843 (void) cmd_info->func(cmd_info->argv);
844 }
845 free(buffer);
846 free(cmdline);
847}
848
849/** Kernel console managing thread.
850 *
851 */
852void kconsole_thread(void *data)
853{
854 kconsole("kconsole", "Kernel console ready (press any key to activate)\n", true);
855}
856
857/** @}
858 */
Note: See TracBrowser for help on using the repository browser.