source: mainline/generic/src/console/kconsole.c@ 91c78c9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 91c78c9 was 91c78c9, checked in by Ondrej Palkovsky <ondrap@…>, 20 years ago

String constants without spaces are now supported by call commands.
For more we would need some lexer.
The call? commands are not compatibile with stdarg functions on AMD
architectures, because of the calling sequence.

  • Property mode set to 100644
File size: 15.9 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#include <console/kconsole.h>
30#include <console/console.h>
31#include <console/chardev.h>
32#include <print.h>
33#include <panic.h>
34#include <typedefs.h>
35#include <arch/types.h>
36#include <list.h>
37#include <arch.h>
38#include <func.h>
39#include <macros.h>
40#include <debug.h>
41#include <symtab.h>
42
43#define MAX_CMDLINE 256
44
45/** Simple kernel console.
46 *
47 * The console is realized by kernel thread kconsole.
48 * It doesn't understand any useful command on its own,
49 * but makes it possible for other kernel subsystems to
50 * register their own commands.
51 */
52
53/** Locking.
54 *
55 * There is a list of cmd_info_t structures. This list
56 * is protected by cmd_lock spinlock. Note that specially
57 * the link elements of cmd_info_t are protected by
58 * this lock.
59 *
60 * Each cmd_info_t also has its own lock, which protects
61 * all elements thereof except the link element.
62 *
63 * cmd_lock must be acquired before any cmd_info lock.
64 * When locking two cmd info structures, structure with
65 * lower address must be locked first.
66 */
67
68spinlock_t cmd_lock; /**< Lock protecting command list. */
69link_t cmd_head; /**< Command list. */
70
71static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
72static bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end);
73
74/** Data and methods for 'help' command. */
75static int cmd_help(cmd_arg_t *argv);
76static cmd_info_t help_info = {
77 .name = "help",
78 .description = "List of supported commands.",
79 .func = cmd_help,
80 .argc = 0
81};
82
83/** Data and methods for 'description' command. */
84static int cmd_desc(cmd_arg_t *argv);
85static void desc_help(void);
86static char desc_buf[MAX_CMDLINE+1];
87static cmd_arg_t desc_argv = {
88 .type = ARG_TYPE_STRING,
89 .buffer = desc_buf,
90 .len = sizeof(desc_buf)
91};
92static cmd_info_t desc_info = {
93 .name = "describe",
94 .description = "Describe specified command.",
95 .help = desc_help,
96 .func = cmd_desc,
97 .argc = 1,
98 .argv = &desc_argv
99};
100
101/** Data and methods for 'symaddr' command. */
102static int cmd_symaddr(cmd_arg_t *argv);
103static char symaddr_buf[MAX_CMDLINE+1];
104static cmd_arg_t symaddr_argv = {
105 .type = ARG_TYPE_STRING,
106 .buffer = symaddr_buf,
107 .len = sizeof(symaddr_buf)
108};
109static cmd_info_t symaddr_info = {
110 .name = "symaddr",
111 .description = "Return symbol address.",
112 .func = cmd_symaddr,
113 .argc = 1,
114 .argv = &symaddr_argv
115};
116
117/** Call0 - call function with no parameters */
118static char call0_buf[MAX_CMDLINE+1];
119static char carg1_buf[MAX_CMDLINE+1];
120static char carg2_buf[MAX_CMDLINE+1];
121
122static int cmd_call0(cmd_arg_t *argv);
123static cmd_arg_t call0_argv = {
124 .type = ARG_TYPE_STRING,
125 .buffer = call0_buf,
126 .len = sizeof(call0_buf)
127};
128static cmd_info_t call0_info = {
129 .name = "call0",
130 .description = "call0 <function> -> call function().",
131 .func = cmd_call0,
132 .argc = 1,
133 .argv = &call0_argv
134};
135
136static int cmd_call1(cmd_arg_t *argv);
137static cmd_arg_t call1_argv[] = {
138 {
139 .type = ARG_TYPE_STRING,
140 .buffer = call0_buf,
141 .len = sizeof(call0_buf)
142 },
143 {
144 .type = ARG_TYPE_VAR,
145 .buffer = carg1_buf,
146 .len = sizeof(carg1_buf)
147 }
148};
149static cmd_info_t call1_info = {
150 .name = "call1",
151 .description = "call1 <function> <arg1> -> call function(arg1).",
152 .func = cmd_call1,
153 .argc = 2,
154 .argv = call1_argv
155};
156
157static int cmd_call2(cmd_arg_t *argv);
158static cmd_arg_t call2_argv[] = {
159 {
160 .type = ARG_TYPE_STRING,
161 .buffer = call0_buf,
162 .len = sizeof(call0_buf)
163 },
164 {
165 .type = ARG_TYPE_VAR,
166 .buffer = carg1_buf,
167 .len = sizeof(carg1_buf)
168 },
169 {
170 .type = ARG_TYPE_VAR,
171 .buffer = carg2_buf,
172 .len = sizeof(carg2_buf)
173 }
174};
175static cmd_info_t call2_info = {
176 .name = "call2",
177 .description = "call2 <function> <arg1> <arg2> -> call function(arg1,arg2).",
178 .func = cmd_call2,
179 .argc = 3,
180 .argv = call2_argv
181};
182
183
184/** Data and methods for 'halt' command. */
185static int cmd_halt(cmd_arg_t *argv);
186static cmd_info_t halt_info = {
187 .name = "halt",
188 .description = "Halt the kernel.",
189 .func = cmd_halt,
190 .argc = 0
191};
192
193/** Initialize kconsole data structures. */
194void kconsole_init(void)
195{
196 spinlock_initialize(&cmd_lock, "kconsole_cmd");
197 list_initialize(&cmd_head);
198
199 spinlock_initialize(&help_info.lock, "kconsole_help");
200 link_initialize(&help_info.link);
201 if (!cmd_register(&help_info))
202 panic("could not register command %s\n", help_info.name);
203
204
205 spinlock_initialize(&desc_info.lock, "kconsole_desc");
206 link_initialize(&desc_info.link);
207 if (!cmd_register(&desc_info))
208 panic("could not register command %s\n", desc_info.name);
209
210 spinlock_initialize(&symaddr_info.lock, "kconsole_symaddr");
211 link_initialize(&symaddr_info.link);
212 if (!cmd_register(&symaddr_info))
213 panic("could not register command %s\n", symaddr_info.name);
214
215 spinlock_initialize(&call0_info.lock, "kconsole_call0");
216 link_initialize(&call0_info.link);
217 if (!cmd_register(&call0_info))
218 panic("could not register command %s\n", call0_info.name);
219
220 spinlock_initialize(&call1_info.lock, "kconsole_call1");
221 link_initialize(&call1_info.link);
222 if (!cmd_register(&call1_info))
223 panic("could not register command %s\n", call1_info.name);
224
225
226 spinlock_initialize(&call2_info.lock, "kconsole_call2");
227 link_initialize(&call2_info.link);
228 if (!cmd_register(&call2_info))
229 panic("could not register command %s\n", call2_info.name);
230
231 spinlock_initialize(&halt_info.lock, "kconsole_halt");
232 link_initialize(&halt_info.link);
233 if (!cmd_register(&halt_info))
234 panic("could not register command %s\n", halt_info.name);
235}
236
237
238/** Register kconsole command.
239 *
240 * @param cmd Structure describing the command.
241 *
242 * @return 0 on failure, 1 on success.
243 */
244int cmd_register(cmd_info_t *cmd)
245{
246 ipl_t ipl;
247 link_t *cur;
248
249 spinlock_lock(&cmd_lock);
250
251 /*
252 * Make sure the command is not already listed.
253 */
254 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
255 cmd_info_t *hlp;
256
257 hlp = list_get_instance(cur, cmd_info_t, link);
258
259 if (hlp == cmd) {
260 /* The command is already there. */
261 spinlock_unlock(&cmd_lock);
262 return 0;
263 }
264
265 /* Avoid deadlock. */
266 if (hlp < cmd) {
267 spinlock_lock(&hlp->lock);
268 spinlock_lock(&cmd->lock);
269 } else {
270 spinlock_lock(&cmd->lock);
271 spinlock_lock(&hlp->lock);
272 }
273
274 if ((strncmp(hlp->name, cmd->name, strlen(cmd->name)) == 0)) {
275 /* The command is already there. */
276 spinlock_unlock(&hlp->lock);
277 spinlock_unlock(&cmd->lock);
278 spinlock_unlock(&cmd_lock);
279 return 0;
280 }
281
282 spinlock_unlock(&hlp->lock);
283 spinlock_unlock(&cmd->lock);
284 }
285
286 /*
287 * Now the command can be added.
288 */
289 list_append(&cmd->link, &cmd_head);
290
291 spinlock_unlock(&cmd_lock);
292 return 1;
293}
294
295/** Kernel console managing thread.
296 *
297 * @param arg Not used.
298 */
299void kconsole(void *arg)
300{
301 char cmdline[MAX_CMDLINE+1];
302 cmd_info_t *cmd_info;
303 count_t len;
304
305 if (!stdin) {
306 printf("%s: no stdin\n", __FUNCTION__);
307 return;
308 }
309
310 while (true) {
311 printf("%s> ", __FUNCTION__);
312 if (!(len = gets(stdin, cmdline, sizeof(cmdline))))
313 continue;
314 cmdline[len] = '\0';
315 cmd_info = parse_cmdline(cmdline, len);
316 if (!cmd_info)
317 continue;
318 (void) cmd_info->func(cmd_info->argv);
319 }
320}
321
322static int parse_int_arg(char *text, size_t len, __native *result)
323{
324 char symname[MAX_SYMBOL_NAME];
325 __address symaddr;
326 bool isaddr = false;
327
328 /* If we get a name, try to find it in symbol table */
329 if (text[0] < '0' | text[0] > '9') {
330 if (text[0] == '&') {
331 isaddr = true;
332 text++;len--;
333 }
334 strncpy(symname, text, min(len+1, MAX_SYMBOL_NAME));
335 symaddr = get_symbol_addr(symname);
336 if (!symaddr) {
337 printf("Symbol %s not found.\n",symname);
338 return -1;
339 }
340 if (symaddr == (__address) -1) {
341 printf("Duplicate symbol %s.\n",symname);
342 symtab_print_search(symname);
343 return -1;
344 }
345 if (isaddr)
346 *result = (__native)symaddr;
347 else
348 *result = *((__native *)symaddr);
349 } else /* It's a number - convert it */
350 *result = atoi(text);
351 return 0;
352}
353
354/** Parse command line.
355 *
356 * @param cmdline Command line as read from input device.
357 * @param len Command line length.
358 *
359 * @return Structure describing the command.
360 */
361cmd_info_t *parse_cmdline(char *cmdline, size_t len)
362{
363 index_t start = 0, end = 0;
364 cmd_info_t *cmd = NULL;
365 link_t *cur;
366 ipl_t ipl;
367 int i;
368
369 if (!parse_argument(cmdline, len, &start, &end)) {
370 /* Command line did not contain alphanumeric word. */
371 return NULL;
372 }
373
374 spinlock_lock(&cmd_lock);
375
376 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
377 cmd_info_t *hlp;
378
379 hlp = list_get_instance(cur, cmd_info_t, link);
380 spinlock_lock(&hlp->lock);
381
382 if (strncmp(hlp->name, &cmdline[start], (end - start) + 1) == 0) {
383 cmd = hlp;
384 break;
385 }
386
387 spinlock_unlock(&hlp->lock);
388 }
389
390 spinlock_unlock(&cmd_lock);
391
392 if (!cmd) {
393 /* Unknown command. */
394 printf("Unknown command.\n");
395 return NULL;
396 }
397
398 /* cmd == hlp is locked */
399
400 /*
401 * The command line must be further analyzed and
402 * the parameters therefrom must be matched and
403 * converted to those specified in the cmd info
404 * structure.
405 */
406
407 for (i = 0; i < cmd->argc; i++) {
408 char *buf;
409 start = end + 1;
410 if (!parse_argument(cmdline, len, &start, &end)) {
411 printf("Too few arguments.\n");
412 spinlock_unlock(&cmd->lock);
413 return NULL;
414 }
415
416 switch (cmd->argv[i].type) {
417 case ARG_TYPE_STRING:
418 buf = cmd->argv[i].buffer;
419 strncpy(buf, (const char *) &cmdline[start], min((end - start) + 2, cmd->argv[i].len));
420 buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0';
421 break;
422 case ARG_TYPE_INT:
423 if (parse_int_arg(cmdline+start, end-start+1,
424 &cmd->argv[i].intval))
425 return NULL;
426 break;
427 case ARG_TYPE_VAR:
428 if (start != end && cmdline[start] == '"' && cmdline[end] == '"') {
429 buf = cmd->argv[i].buffer;
430 strncpy(buf, (const char *) &cmdline[start+1],
431 min((end-start), cmd->argv[i].len));
432 buf[min((end - start), cmd->argv[i].len - 1)] = '\0';
433 cmd->argv[i].intval = (__native) buf;
434 cmd->argv[i].vartype = ARG_TYPE_STRING;
435 } else if (!parse_int_arg(cmdline+start, end-start+1,
436 &cmd->argv[i].intval))
437 cmd->argv[i].vartype = ARG_TYPE_INT;
438 else {
439 printf("Unrecognized variable argument.\n");
440 return NULL;
441 }
442 break;
443 case ARG_TYPE_INVALID:
444 default:
445 printf("invalid argument type\n");
446 return NULL;
447 break;
448 }
449 }
450
451 start = end + 1;
452 if (parse_argument(cmdline, len, &start, &end)) {
453 printf("Too many arguments.\n");
454 spinlock_unlock(&cmd->lock);
455 return NULL;
456 }
457
458 spinlock_unlock(&cmd->lock);
459 return cmd;
460}
461
462/** Parse argument.
463 *
464 * Find start and end positions of command line argument.
465 *
466 * @param cmdline Command line as read from the input device.
467 * @param len Number of characters in cmdline.
468 * @param start On entry, 'start' contains pointer to the index
469 * of first unprocessed character of cmdline.
470 * On successful exit, it marks beginning of the next argument.
471 * @param end Undefined on entry. On exit, 'end' points to the last character
472 * of the next argument.
473 *
474 * @return false on failure, true on success.
475 */
476bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
477{
478 int i;
479 bool found_start = false;
480
481 ASSERT(start != NULL);
482 ASSERT(end != NULL);
483
484 for (i = *start; i < len; i++) {
485 if (!found_start) {
486 if (is_white(cmdline[i]))
487 (*start)++;
488 else
489 found_start = true;
490 } else {
491 if (is_white(cmdline[i]))
492 break;
493 }
494 }
495 *end = i - 1;
496
497 return found_start;
498}
499
500
501/** List supported commands.
502 *
503 * @param argv Argument vector.
504 *
505 * @return 0 on failure, 1 on success.
506 */
507int cmd_help(cmd_arg_t *argv)
508{
509 link_t *cur;
510 ipl_t ipl;
511
512 spinlock_lock(&cmd_lock);
513
514 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
515 cmd_info_t *hlp;
516
517 hlp = list_get_instance(cur, cmd_info_t, link);
518 spinlock_lock(&hlp->lock);
519
520 printf("%s - %s\n", hlp->name, hlp->description);
521
522 spinlock_unlock(&hlp->lock);
523 }
524
525 spinlock_unlock(&cmd_lock);
526
527 return 1;
528}
529
530/** Describe specified command.
531 *
532 * @param argv Argument vector.
533 *
534 * @return 0 on failure, 1 on success.
535 */
536int cmd_desc(cmd_arg_t *argv)
537{
538 link_t *cur;
539 ipl_t ipl;
540
541 spinlock_lock(&cmd_lock);
542
543 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
544 cmd_info_t *hlp;
545
546 hlp = list_get_instance(cur, cmd_info_t, link);
547 spinlock_lock(&hlp->lock);
548
549 if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
550 printf("%s - %s\n", hlp->name, hlp->description);
551 if (hlp->help)
552 hlp->help();
553 spinlock_unlock(&hlp->lock);
554 break;
555 }
556
557 spinlock_unlock(&hlp->lock);
558 }
559
560 spinlock_unlock(&cmd_lock);
561
562 return 1;
563}
564
565/** Search symbol table */
566int cmd_symaddr(cmd_arg_t *argv)
567{
568 __address symaddr;
569 char *symbol;
570
571 symtab_print_search(argv->buffer);
572
573 return 1;
574}
575
576/** Call function with zero parameters */
577int cmd_call0(cmd_arg_t *argv)
578{
579 __address symaddr;
580 char *symbol;
581 __native (*f)(void);
582
583 symaddr = get_symbol_addr(argv->buffer);
584 if (!symaddr)
585 printf("Symbol %s not found.\n", argv->buffer);
586 else if (symaddr == (__address) -1) {
587 symtab_print_search(argv->buffer);
588 printf("Duplicate symbol, be more specific.\n");
589 } else {
590 symbol = get_symtab_entry(symaddr);
591 printf("Calling f(): 0x%p: %s\n", symaddr, symbol);
592 f = (__native (*)(void)) symaddr;
593 printf("Result: 0x%X\n", f());
594 }
595
596 return 1;
597}
598
599/** Call function with one parameter */
600int cmd_call1(cmd_arg_t *argv)
601{
602 __address symaddr;
603 char *symbol;
604 __native (*f)(__native);
605 __native arg1 = argv[1].intval;
606
607 symaddr = get_symbol_addr(argv->buffer);
608 if (!symaddr)
609 printf("Symbol %s not found.\n", argv->buffer);
610 else if (symaddr == (__address) -1) {
611 symtab_print_search(argv->buffer);
612 printf("Duplicate symbol, be more specific.\n");
613 } else {
614 symbol = get_symtab_entry(symaddr);
615 printf("Calling f(0x%x): 0x%p: %s\n", arg1, symaddr, symbol);
616 f = (__native (*)(__native)) symaddr;
617 printf("Result: 0x%x\n", f(arg1));
618 }
619
620 return 1;
621}
622
623/** Call function with two parameters */
624int cmd_call2(cmd_arg_t *argv)
625{
626 __address symaddr;
627 char *symbol;
628 __native (*f)(__native,__native);
629 __native arg1 = argv[1].intval;
630 __native arg2 = argv[2].intval;
631
632 symaddr = get_symbol_addr(argv->buffer);
633 if (!symaddr)
634 printf("Symbol %s not found.\n", argv->buffer);
635 else if (symaddr == (__address) -1) {
636 symtab_print_search(argv->buffer);
637 printf("Duplicate symbol, be more specific.\n");
638 } else {
639 symbol = get_symtab_entry(symaddr);
640 printf("Calling f(0x%x,0x%x): 0x%p: %s\n",
641 arg1, arg2, symaddr, symbol);
642 f = (__native (*)(__native,__native)) symaddr;
643 printf("Result: 0x%x\n", f(arg1, arg2));
644 }
645
646 return 1;
647}
648
649
650/** Print detailed description of 'describe' command. */
651void desc_help(void)
652{
653 printf("Syntax: describe command_name\n");
654}
655
656/** Halt the kernel.
657 *
658 * @param argv Argument vector (ignored).
659 *
660 * @return 0 on failure, 1 on success (never returns).
661 */
662int cmd_halt(cmd_arg_t *argv)
663{
664 halt();
665 return 1;
666}
Note: See TracBrowser for help on using the repository browser.